feat(ui): stabilize laboratory viewer primitives

This commit is contained in:
Codex
2026-08-24 22:31:35 +03:00
parent c7e136cc14
commit 6e7255ecdb
17 changed files with 590 additions and 30 deletions
+23 -2
View File
@@ -10,8 +10,10 @@
"summary": "Matte application surfaces, the Engine V4 modal material and the light translucent surface used over Cesium imagery.",
"anatomy": ["theme-provided surface", "modal tint", "map-only light translucency", "gradient rim", "backdrop blur/saturation/brightness", "content"],
"variants": ["default", "strong", "soft", "map"],
"radiusVariants": ["card", "panel", "modal", "pill"],
"rules": [
"Geometry is invariant across application themes.",
"Compact rails of canonical round actions use the pill radius; consumers do not recreate it with a local border radius.",
"A material rim is a glass highlight, not a hard product-colored border.",
"Nested surfaces must use a softer tone to avoid card-inside-card noise.",
"GlassyMaterialSurface is restricted to modal Windows and the draggable Inspector.",
@@ -29,6 +31,7 @@
"shapes": ["default", "pill", "rounded"],
"rules": [
"Icon-only actions are circular by default.",
"Controlled toggle actions expose aria-pressed and use the canonical active surface without changing geometry.",
"Filled accent actions derive foreground contrast from the actual accent.",
"Destructive actions remain neutral until confirmation unless danger is the principal message."
]
@@ -129,11 +132,12 @@
"domPackage": "@nodedc/ui-dom",
"domExports": ["createSelectController"],
"summary": "Theme-independent selection control using the canonical dropdown layer.",
"variants": ["integrated", "split"],
"variants": ["integrated", "split", "inline"],
"behavior": ["controlled value", "optional search", "disabled options", "selected state", "portal menu"],
"rules": [
"Integrated is the single-pill Hub/Launcher form.",
"Split is the Engine form: a separate value surface and a 46 px toggle separated by an 8 px gap.",
"Inline is a compact label-only toolbar trigger without a persistent surface or chevron; its menu and keyboard behavior remain canonical.",
"Integrated Select is forbidden inside Inspector; use InspectorSelectField so the visible label is above a full-width split control.",
"The portal menu preserves its source-family row geometry instead of inheriting card radii."
]
@@ -179,6 +183,22 @@
"summary": "Async-safe confirmation window for destructive and consequential operations.",
"behavior": ["pending state", "double-submit protection", "disabled close policy while pending"]
},
{
"id": "split-pane",
"status": "baseline",
"package": "@nodedc/ui-react",
"exports": ["SplitPane", "SplitPaneProps", "SplitPaneOrientation"],
"domContract": ["nodedc-split-pane", "nodedc-split-pane__panel", "nodedc-split-pane__separator"],
"summary": "Controlled two-panel layout with a pointer- and keyboard-resizable accessible separator.",
"anatomy": ["primary panel", "structural separator", "secondary panel"],
"variants": ["vertical", "horizontal"],
"behavior": ["controlled percentage", "optional resizable separator", "pointer capture drag", "Arrow/Home/End keyboard sizing", "ARIA separator range", "ratio preservation across host resize"],
"rules": [
"The application owns the controlled primary percentage and panel content; the component owns separator interaction and accessibility.",
"Minimum primary and secondary percentages clamp both pointer and keyboard changes.",
"The separator is a necessary structural divider, never a decorative perimeter border."
]
},
{
"id": "share-access-modal",
"status": "baseline",
@@ -385,9 +405,10 @@
"domContract": ["nodedc-toast-viewport", "nodedc-toast", "nodedc-toast__icon", "nodedc-toast__copy"],
"summary": "Tasker-derived non-blocking status notification with a bottom-right glass stack.",
"variants": ["success", "error", "warning", "info", "loading"],
"behavior": ["controlled items", "optional auto-dismiss", "manual dismiss", "portal viewport", "polite live region"],
"behavior": ["controlled items", "independent 10 second default auto-dismiss per terminal item", "manual dismiss", "portal viewport", "polite live region"],
"rules": [
"Applications own operation state and message copy; ToastStack owns viewport geometry and dismissal timing.",
"Adding or updating another notification never restarts the lifetime of an existing item; each item owns its timer by stable id.",
"Loading notifications remain until the operation updates or dismisses them.",
"Status notifications never replace a blocking confirmation modal."
]