@net-advantage/jo-ui-side-panel
v2.1.0
Published
A sheet anchored to the right edge. While it is the topmost overlay, focus stays inside the panel and Escape closes it.
Readme
@net-advantage/jo-ui-side-panel
A sheet anchored to the right edge. While it is the topmost overlay, focus stays inside the panel and Escape closes it.
The panel follows a strict MVVM split. The model resolves the heading, kicker, class, and portal container. The view-model owns the focus trap and the scrim guard. The view renders the view-model.
MVVM
flowchart LR
Props["SidePanelProps"] --> ViewModel["useSidePanelViewModel"]
Model["jo-ui-side-panel.model.ts<br/>heading, container, class"] --> ViewModel
Trap["useFocusTrap"] --> ViewModel
ViewModel --> View["SidePanel.tsx"]
View -->|"close and scrim"| ViewModel
ViewModel -->|"onClose"| Host["Host application"]| Layer | File | Responsibility |
| --- | --- | --- |
| Contract | jo-ui-side-panel.types.ts | Props and view-model |
| Model | jo-ui-side-panel.model.ts | Heading, kicker, narrow name, close variant, class, and portal container |
| View-model | jo-ui-side-panel.view-model.ts | Framework-free side panel observable; close and scrim guard |
| View | jo-ui-side-panel.use-view-model.ts | useSidePanelViewModel reads that observable and owns the focus trap |
| View | SidePanel.tsx | Render the sheet through a portal |
Models
flowchart TD
Props["SidePanelProps"] --> Heading["heading and kicker"]
Props --> Container["portal container"]
Heading --> ViewModel["SidePanelViewModel"]
Container --> ViewModel
Trap["useFocusTrap"] --> ViewModelopencontrols visibility. A closed panel renders nothing.container={null}renders nothing. Omit it to portal todocument.body.headingandkickerfall back totitle. The accessible name is the heading.name, when it differs from the heading, replaces that name below 600px.closeVariantistextby default.iconshows the close mark alone.icon-textshows the mark and the label. The accessible name stayscloseLabel.panelRefpoints at the dialog element. Omit it and the sheet keeps its own ref.active={false}leaves the sheet open and inert. Otherwise the sheet joins the shared overlay stack.- The scrim calls
onCloseonly when the pointer starts on the scrim itself. - Escape calls
onCloseonly while this sheet is the topmost overlay. A ConfirmDialog opened over it takes Escape and focus, and the sheet does not close. Tab stays inside the topmost overlay. The trap isuseFocusTrapfrom@net-advantage/jo-ui-dialog. - The scrim uses
--jo-color-scrim. The sheet uses--jo-color-surfaceand--jo-radius-card.
Publish footprint
This package publishes dist and README.md.
