Skip to content

feat(webkit): add the resizable-panel layout primitive - #902

Open
gabriel-lisboa-azion wants to merge 3 commits into
mainfrom
feat/resizable-panel
Open

feat(webkit): add the resizable-panel layout primitive#902
gabriel-lisboa-azion wants to merge 3 commits into
mainfrom
feat/resizable-panel

Conversation

@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator

Summary

  • New layout/resizable-panel composition component: adjacent regions whose shared edges the reader drags. ResizablePanel + Pane + Handle, with both the compound and the tree-shakeable -root / per-sub-component exports.
  • It exists because Sidebar was doing two jobs. Sidebar is the navigation rail — it collapses to icons, it is the thing you leave to go somewhere. An editor, a terminal and a preview are the work, not destinations, and dressing them as rails produced a screen with three "sidebars" and one document — on an axis Sidebar does not have (no horizontal edge, so a terminal under an editor hand-rolled its own splitter).
  • Ships the spec, a browser-mode test suite (9 tests), the story, a size budget, and the rebuilt catalog.

How to test

  1. cd packages/webkit && npx vitest run src/components/layout/resizable-panel → 9 passed.
  2. pnpm --filter @aziontech/webkit run catalog:check → clean. pnpm --filter @aziontech/webkit run sizeresizable-panel-root under its 3 KB budget.
  3. pnpm storybook:dev → Components/Layout/ResizablePanel. Drag a handle: both panes resize and stay clamped. Keyboard: focus a separator, arrow keys move it. Check orientation="vertical" stacks and drags on the horizontal edge.

Notes

  • Additive — no existing component changes, so nothing can regress.
  • The compound in index.ts names its static surface and casts once instead of using Object.assign, whose inferred type walks each part's local interface Props into the emitted declaration and trips TS4082.

@gabriel-lisboa-azion
gabriel-lisboa-azion marked this pull request as draft August 17, 2026 10:01
gabriel-lisboa-azion added a commit that referenced this pull request Aug 17, 2026
Brings the three commits demo lacked, so the deployed sample exercises them
alongside the four fixes carved out of this branch (#899#902), whose content was
already here:

  - feat(webkit): chip's three kinds (#883)
  - feat(theme): the semantic/layouts container system (#884)
  - feat(theme): lightened heading and body type (#876)

Conflict resolutions worth knowing:

`build-tokens.mjs` — main has no illustration tokens, so main's side of all six
hunks was empty. Taking it would have silently deleted this branch's illustration
wiring; ours was kept. The merge then produced a DUPLICATE `emitUtilities` and
`emitLayoutUtilities` with no conflict at all (both sides had added an identical
helper in different places), which is a syntax error the merge itself reported as
clean — the second copy is removed and `emitIllustrationUtilities` reuses the
first.

`texts.data.js` — the five conflicts were all `text-body-*` weight, resolved to
main's `light` since that is the change being previewed. Resolved in place rather
than with `--theirs`, which would have discarded the file's auto-merged hunks.
Entry count held at 144.

`.size-limit.json` — union, not a side: main's `chip` plus this branch's
`footer-root` and `resizable-panel-root`.

`dist/v4/globals.*` are generated, so they were rebuilt from the merged sources
rather than hand-merged. The 466 conflicting visual baselines took main's copies;
neither side is valid for a merged tree, and this branch opens no PR the visual
gate guards.

Verified after: no `undefined` in the built CSS, illustration tokens still emitted,
main's layout utilities present, body weights now 300, no token data file lost
entries, and 154 tests pass across toast, table, sidebar, resizable-panel and chip.
@gabriel-lisboa-azion
gabriel-lisboa-azion marked this pull request as ready for review August 18, 2026 11:15
@gabriel-lisboa-azion

Copy link
Copy Markdown
Collaborator Author

All eight review findings were one pattern in resizable-panel.test.ts, addressed in c3953a7.

The suite composed its fixtures through the root's statics — h(ResizablePanel.Pane, …) — and it was the only composition suite in the package that did. Every sibling (accordion, dropdown, select, menu, table) renders through the named sub-component exports and checks dot-notation once, as an identity assertion. That divergence is what the scanner caught: a .vue default export is generated by the SFC compiler, so static analysis sees no export default, reads the imported binding as undefined, and flags every .Pane / .Handle read on it.

The fix follows the house pattern rather than adding guards at each of the eight call sites:

  • fixtures compose through ResizablePanelPane / ResizablePanelHandle, imported as named exports from ./index;
  • the compound contract stays in the one test where dot-notation is the subject rather than the vehicle, now asserting identity against those exports (toBe(ResizablePanelPane), tighter than the previous toBeTruthy) through a guarded read.

index.ts is unchanged — it is byte-for-byte the shape dropdown/index.ts already uses.

Verified: 9/9 tests pass, eslint --max-warnings 0 clean, vue-tsc --noEmit clean.

A group of adjacent regions whose shared edges the reader can drag — the layout
behind a workspace, where an editor, a terminal under it and a preview beside it
are all content and the split between them is the reader's to set.

It exists because `Sidebar` was being used for both jobs. `Sidebar` is the app's
NAVIGATION rail: it collapses to icons, it hides, it is the thing you leave to go
somewhere. A terminal, a preview and a code editor are not places you navigate to
— they are the work — and dressing two of them as navigation rails produced a
screen with three "sidebars" and one document, on an axis `Sidebar` does not even
have: it has no horizontal edge, so a terminal under an editor had to hand-roll
its own splitter. This component owns the EDGE; `Sidebar` goes back to owning
navigation.

Composition: `ResizablePanel` with `Pane` and `Handle`, attached for dot-notation
and exported standalone. The compound is built by naming the static surface and
casting once rather than with `Object.assign`, whose inferred type walks each
part's local `interface Props` into the declaration and trips TS4082.

Ships the spec, a browser-mode test suite, the story, the `-root` and
per-sub-component exports, and a size budget.
Adds the 24 snapshots for the four new ResizablePanel stories across the 6-mode
matrix. Generated by the Storybook Regenerate Baseline workflow on this branch's
HEAD — baselines are ubuntu-only, so a local run would not match the folder the
visual gate compares against.

No existing snapshot is modified or deleted; the component is additive.
… exports

Every other composition suite in the package renders through the named exports
(`AccordionItem`, `DropdownTrigger`, …) and checks dot-notation once, as an
identity assertion against those same exports. This file was the only one that
rendered through the root's statics — `h(ResizablePanel.Pane, …)` — which made
static analysis flag eight unguarded member accesses: a `.vue` default export is
generated by the SFC compiler, so the analyzer sees no `export default`, reads
the imported binding as undefined, and reports every `.Pane` / `.Handle` read on
it.

Compose through `ResizablePanelPane` / `ResizablePanelHandle` instead, and keep
the compound contract in the one place it is the subject rather than the vehicle,
asserting identity against those exports through a guarded read.

Same nine tests, same behaviour covered — the dot-notation contract is now
verified more tightly than `toBeTruthy` did.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant