Placing.AnchorRect
interface · packages/primitives/src/interaction/placing.ts:89
interface AnchorRect {
readonly left: number
readonly top: number
readonly bottom: number
readonly width: number
readonly height: number
}Primitives / foldkit-primitives/interaction
namespace · packages/primitives/src/interaction/placing.ts:36
export * as Placing from './placing.js'Keeps a floating panel inside the viewport: on insert it shifts left past
the right edge and flips above its trigger when the bottom overflows and
the room overhead fits; on release every inline prop goes. placeFor is
pure geometry over rects, so the rule is unit-tested and the Mount only
reads and writes. Inert without layout (zero rects never overflow), with
no timers, observers, or reposition loops.
placeAt is the other half, for a popup that must open under the trigger
that opened it. It writes left and --fk-placed-top once, relative to
the popup's offset parent; the panel's stylesheet reads the variable as
top, so keepWithin can still replace top when it flips. Key the
popup by the trigger: a Mount reads its args at insert and never again.
placeAtPoint is the same write for a viewport point, when the open
event carried coordinates the message builder dropped. The two mounts
start together, so the fit may run before that write; the write measures
again. A point that would hang past the bottom shifts up. A trigger still
flips, and the panel is marked data-fk-placed="above" so a hover bridge
can follow the side that opened.
Zero-size rects stay at the origin, so an inert document writes nothing
a layout pass would have to undo.
Three related pieces this is not:
Anchor.behavior (foldkit-mixins-ui) binds a floating element to
another element's id through floating-ui, with portals and continuous
repositioning. It relocates nodes out from under the runtime (portal by
default) and burns under zero geometry; reach for it when the panel must
track a moving anchor, not for a popup placed once.KeepInView (foldkit-primitives/dom) scrolls newly marked content
into view. Same verb, opposite direction: that one moves the page to
the panel, this one moves the panel into the page.Overlay.behaviors owns dismissal, focus, scroll lock, and inertness,
but no positioning; spread this alongside it for the full overlay.Placing.AnchorRectinterface · packages/primitives/src/interaction/placing.ts:89
interface AnchorRect {
readonly left: number
readonly top: number
readonly bottom: number
readonly width: number
readonly height: number
}Placing.KeepWithinconst · packages/primitives/src/interaction/placing.ts:202
const KeepWithin: Mount.MountDefinitionNoArgs<'KeepWithin', never>Placing.keepWithinfunction · packages/primitives/src/interaction/placing.ts:329
function keepWithin<Slots>(
slots: Slots,
): <Input, ParentMessage>(options: {
readonly panel: keyof Slots & string
}) => Behavior.NamedBehavior<Slots, Input, ParentMessage>Placing.OriginRectinterface · packages/primitives/src/interaction/placing.ts:97
interface OriginRect {
readonly left: number
readonly top: number
}Placing.PanelRectinterface · packages/primitives/src/interaction/placing.ts:40
interface PanelRect {
readonly top: number
readonly right: number
readonly bottom: number
readonly height: number
}Placing.PlaceAtconst · packages/primitives/src/interaction/placing.ts:236
const PlaceAt: Mount.MountDefinitionWithArgs<
'PlaceAt',
{ triggerId: Schema.String; gap: Schema.Number },
never
>Placing.placeAtfunction · packages/primitives/src/interaction/placing.ts:113
function placeAt(
trigger: AnchorRect,
origin: OriginRect,
gap?: number,
): PlacedAtWhere a popup sits under its trigger's left edge, in the offset parent's coordinates. A zero-size trigger (an inert document) stays at the origin.
Placing.PlaceAtPointconst · packages/primitives/src/interaction/placing.ts:277
const PlaceAtPoint: Mount.MountDefinitionWithArgs<
'PlaceAtPoint',
{ x: Schema.Number; y: Schema.Number },
never
>Placing.placeAtPointfunction · packages/primitives/src/interaction/placing.ts:129
function placeAtPoint(point: ViewportPoint, origin: OriginRect): PlacedAtWhere a popup's top-left sits on a viewport point, in the offset parent's
coordinates. A context menu uses it: the right-click event carries the
point, and OnContextMenu does not.
Placing.placeAtTriggerfunction · packages/primitives/src/interaction/placing.ts:303
function placeAtTrigger<Slots>(
slots: Slots,
): <Input, ParentMessage>(options: {
readonly panel: keyof Slots & string
readonly triggerId: (input: Input) => string
readonly gap?: number
readonly at?: (input: Input) => Option.Option<ViewportPoint>
}) => Behavior.NamedBehavior<Slots, Input, ParentMessage>Placing.Placedinterface · packages/primitives/src/interaction/placing.ts:52
interface Placed {
readonly dx: number
readonly flip: boolean
}Placing.placedAboveconst · packages/primitives/src/interaction/placing.ts:87
const placedAbove: 'above'Value of placedSide while the panel stands above its anchor.
Placing.PlacedAtinterface · packages/primitives/src/interaction/placing.ts:102
interface PlacedAt {
readonly left: number
readonly top: number
}Placing.placedSideconst · packages/primitives/src/interaction/placing.ts:84
const placedSide: 'data-fk-placed'Attribute keepWithin sets to placedAbove when the panel flips.
Placing.placedTopconst · packages/primitives/src/interaction/placing.ts:109
const placedTop: '--fk-placed-top'Custom property PlaceAt writes. A panel reads it as top so a viewport
flip, which sets the top property, still wins.
Placing.placeForfunction · packages/primitives/src/interaction/placing.ts:61
function placeFor(rect: PanelRect, viewport: Viewport, margin?: number): PlacedWhere the panel goes so it fits: left by the overflow, above when the bottom clears the window and the room overhead fits the panel.
Placing.shiftIntoViewportfunction · packages/primitives/src/interaction/placing.ts:71
function shiftIntoViewport(
rect: {
readonly top: number
readonly bottom: number
},
viewportHeight: number,
margin?: number,
): numberPixels to move a box up so its bottom sits margin inside the viewport.
0 when it already fits, or when its top is already at the margin.
Placing.Viewportinterface · packages/primitives/src/interaction/placing.ts:47
interface Viewport {
readonly width: number
readonly height: number
}Placing.ViewportPointinterface · packages/primitives/src/interaction/placing.ts:121
interface ViewportPoint {
readonly x: number
readonly y: number
}