|
|
2 months ago | |
|---|---|---|
| .. | ||
| README.md | 3 months ago | |
| context.ts | 4 months ago | |
| float-panel-action.svelte | 4 months ago | |
| float-panel-body.svelte | 4 months ago | |
| float-panel-close.svelte | 4 months ago | |
| float-panel-content.svelte | 3 months ago | |
| float-panel-controls.svelte | 4 months ago | |
| float-panel-header.svelte | 4 months ago | |
| float-panel-resize-grip.svelte | 4 months ago | |
| float-panel-resize-handle.svelte | 4 months ago | |
| float-panel-stage-trigger.svelte | 4 months ago | |
| float-panel-title.svelte | 4 months ago | |
| float-panel-trigger.svelte | 4 months ago | |
| float-panel.css | 2 months ago | |
| float-panel.svelte | 4 months ago | |
| index.ts | 4 months ago | |
| types.ts | 2 months ago | |
README.md
FloatPanel (eidos)
Visual wrapper over Soma's draggable/resizable panel. Adds only chrome —
variant, color (propagated to Content via context) — and the recipe that
styles the surface, the header drag-handle, the scrollable body and the resize
handles. Drag, resize, stacking, dismissal, focus and positioning are Soma's.
<!-- Zero-config: <FloatPanel.Header> auto-renders a Close (closable, default true). -->
<FloatPanel bind:open anchor={el} resizable variant="surface" color="primary">
<FloatPanel.Content>
<FloatPanel.Header>
<FloatPanel.Title>Inspector</FloatPanel.Title>
</FloatPanel.Header>
<FloatPanel.Body>…</FloatPanel.Body>
<FloatPanel.ResizeHandle edge="se" />
</FloatPanel.Content>
</FloatPanel>
<!-- Custom header buttons: set closable={false} and compose Controls. -->
<FloatPanel.Header closable={false}>
<FloatPanel.Title>Properties</FloatPanel.Title>
<FloatPanel.Controls>
<FloatPanel.Action aria-label="Delete object" onclick={remove}>🗑</FloatPanel.Action>
<FloatPanel.Close />
</FloatPanel.Controls>
</FloatPanel.Header>
Controls is the right-aligned button group (Ark's control); Action is a
generic header icon-button sharing Close's chrome, for consumer-wired actions.
closable (default true) is the zero-config convenience; set it false when you
compose your own Controls.
StageTrigger (min/max/restore) shares the same chrome and goes in Controls
too — it takes a stage prop and toggles to it:
<FloatPanel.Controls>
<FloatPanel.StageTrigger stage="minimized" aria-label="Minimize">–</FloatPanel.StageTrigger>
<FloatPanel.StageTrigger stage="maximized" aria-label="Maximize">▢</FloatPanel.StageTrigger>
<FloatPanel.Close />
</FloatPanel.Controls>
minimized collapses to the header, maximized fills bounds (corners squared,
drag/resize off), default restores. See the soma README for the stage model.
<FloatPanel.ResizeGrip /> renders a focusable se-corner grip (the diagonal-line
mark) inside Content next to the ResizeHandle parts — it's the keyboard
resize affordance (Enter to grab, arrows to resize). The header is itself a
focusable keyboard move-handle. Full grab-mode model + live-region announcements
are in the soma README ("Keyboard move / resize"); the recipe only adds the
:focus-visible rings and the data-grabbed styling.
Props (visual)
| Prop | Type | Default |
|---|---|---|
variant |
'surface' | 'outline' | 'ghost' (canonical ControlVariant) |
'surface' |
color |
ComponentColorProp (rol / intent / 33 escalas / valor CSS) |
'neutral' |
All Soma Provider props pass through (open, anchor, position, size, draggable, resizable, minWidth, …).
There is intentionally no visual size prop — the panel's size is its width/height geometry.
<FloatPanel.Content> additionally takes motion?: MotionPresetName (default 'scale-fade', 'none'
to disable) — the open/close presence preset, mirroring <Popover.Content motion>.
Recipe
Tokens live under the float-panel key in src/uix/eidos/lib/recipes/base.ts (--float-panel-*).
The surface uses --color-surface-overlay + --shadow-4 (→ --shadow-5 when data-topmost); the
header is the grab handle (cursor grab→grabbing on data-dragging); the body scrolls; resize
handles position absolutely per data-resize-edge with edge-appropriate cursors.
Open/close motion comes from the motion system (uix.motion), not hand-rolled CSS: the Content
wrapper writes data-animation-style (prop motion, default 'scale-fade') and the generated preset
animates scale + opacity keyed on [data-state]; Soma's Presence waits for that animation
before unmounting. scale-fade is chosen over the popover/menu default slide-fade precisely because
it never animates translate — the panel's drag position is also translate, and the two must not
fight. Timing is tuned per-component via --motion-duration-{enter,exit} (normal in / fast out).
Reduced-motion degrades to opacity-only automatically (the preset's reduce policy). Position
(translate) is never transitioned, so the drag stays 1:1. See eidos-motion.md.
Comparativa externa
Closest reference is Ark UI Floating Panel (draggable+resizable, stages, persist, grid-snap). UIX
FloatPanel matches its core (drag, resize, bounds, min/max, stacking/topmost, anchored→free, stages
min/max/restore, composable header buttons) and adds the perceptual layer (sound/haptic on grab/
release/resize) that no framework ships; persist/snap are deferred (see soma README Gaps). Radix/Chakra/
MUI have no draggable panel; Mantine FloatingWindow is drag-only; react-rnd matches drag/resize but
lacks a11y/theming/perception.
Sources: Ark UI Floating Panel · react-rnd · Mantine FloatingWindow · WAI-ARIA Dialog.
Decisiones
variant/colorvia context (root is virtual, like toggle-group) — set on the root, applied onContent.- No visual
size— would clash with the panel's geometric size. - Surface =
overlayladder + elevation shadow;data-topmostlifts it.
Gaps
Same v2 roadmap as the soma layer (stages, persistence, snap-grid, keyboard move/resize). A docked / fixed mode (answer to Figma's floating-panel-fatigue lesson) is a candidate v2 addition.