MaterialLibrary factory before building layers. The library covers the defined surface roles and preserves the standard material’s coordinated focus, press, and partial-focus behavior. Each factory returns a fresh ContainerMaterial.useMemo, keyed on the factory’s dependencies. This keeps ownership and transitions stable across renders.import { useMemo } from 'react';
import { Container, MaterialLibrary } from '@wearables-ui-toolkit/mrbd';
export function GhostRow({ label, onOpen }: { label: string; onOpen: () => void }) {
const material = useMemo(() => MaterialLibrary.unbounded(), []);
return (
<Container
material={material}
focusable
clickable
onClick={onOpen}
className="ghost-row"
>
<span className="uit-text-body1">{label}</span>
</Container>
);
}
.ghost-row {
padding-block: var(--uit-spacing-small);
padding-inline: var(--uit-spacing-medium);
color: var(--uit-color-text-primary);
}
| Factory | Description |
|---|---|
MaterialLibrary.default(options?) | The standard interactive material. Takes the same DefaultContainerMaterialOptions as createDefaultContainerMaterial. |
MaterialLibrary.defaultWithDropShadow() | The standard material with its drop-shadow layer kept. |
MaterialLibrary.button() | Button surface. The same layer stack as default(). |
MaterialLibrary.flat() | Alias of default(); the standard material already drops its shadow layer. |
MaterialLibrary.notificationCenterItem() | Notification item surface: the standard material with a drop shadow. |
MaterialLibrary.unbounded() | Transparent at rest. The idle fill is replaced by a layer that draws nothing, and the glow stroke is hidden in NONE and DEFAULT, so only focus and press paint. |
| Factory | Description |
|---|---|
MaterialLibrary.defaultStatic(options?) | Static surface for non-interactive hosts: solid idle fill plus the standard glow stroke, with no focus fill, inner shadow, noise, or press overlay. Options are withDropShadow, idleColor, and secondary. |
MaterialLibrary.reducedOpacityStatic() | Idle fill at reduced opacity, keeping the standard press overlay and glow stroke. No focus fill and no inner shadow. |
MaterialLibrary.statusIndicatorPanel() | Status-indicator panel: a top-to-bottom surface scrim that fades to transparent just before the bottom edge of the path, plus inner shadow, press overlay, and glow stroke. |
MaterialLibrary.clockPill() | Clock pill: nothing at rest, a vertical translucent surface gradient on focus and press, the standard press overlay, and a glow stroke hidden in NONE and DEFAULT. |
MaterialLibrary.panel() | Panel surface. See Panel. |
MaterialLibrary.actionHint() | Action-hint surface: a diagonal linear gradient from a faint white to transparent, plus a low-alpha radial glow stroke. Both layers paint identically in every visual state. |
defaultStatic({ secondary: true }) additionally draws its idle fill with the screen blend mode and turns on backgroundBlendsWithBackdrop, so the surface lightens whatever is behind it instead of covering it.MaterialLibrary.panel() wraps every layer of the standard material in a per-state opacity multiplier — half at NONE and DEFAULT, three quarters at FOCUSED, nine tenths at PRESSED — and interpolates that multiplier across a transition like any other per-state value. The wrapper scales each layer’s own alpha while it still paints onto the shared canvas, so screen and overlay layers keep blending against the layers beneath them.panel-scrim layer: a vertical gradient from transparent to opaque that reaches full opacity a short distance above the bottom edge. The scrim fills its own rectangle rather than the rounded shape path, and it paints at full opacity in every state.| Factory | Description |
|---|---|
MaterialLibrary.card() | Card surface: a solid background fill, and in the foreground a press overlay, an idle border stroke visible only in DEFAULT, and back and front glow strokes that appear on focus with hard-light blending. No focus gradient, inner shadow, noise, or drop shadow. Only the front glow tracks partial focus. |
MaterialLibrary.fullScreenCard() | Full-screen card: the same solid fill, a foreground press overlay, and a single foreground hard-light border stroke that stays visible in every state except NONE, widens on focus and press, and tracks partial focus. |
foregroundBlendsWithContent, so their strokes blend with the card’s live content rather than with an isolated buffer.| Factory | Description |
|---|---|
MaterialLibrary.contextMenuItem() | Context-menu item: the standard material with no idle fill and the glow stroke hidden in NONE and DEFAULT, so unfocused items sit directly on the menu surface and the border fades up from zero. |
MaterialLibrary.controlTileCheckedIcon() | Checked control-tile icon backdrop: a single solid fill in the highlight color. |
MaterialLibrary.textInput() | Text input field: the standard stack with a replaced idle fill, plus a directional inner shadow and a border stroke that are visible at rest and fade out on focus — the inverse of the standard material. |
| Factory | Description |
|---|---|
MaterialLibrary.themedPrimary(theme?) | Standard stack recolored by a theme object. Defaults to the neutral primary theme. |
MaterialLibrary.themedSecondary() | Quieter neutral variant. |
MaterialLibrary.themedPrimaryBlue() | Blue accent variant. |
MaterialLibrary.themedPrimaryGreen() | Green accent variant. |
MaterialLibrary.themedPrimaryRed() | Red accent variant. |
MaterialLibrary.positive(useDefaultIdleState?) | Positive semantic variant. Defaults to true, keeping the neutral idle fill; pass false to use the accent color at rest. |
MaterialLibrary.negative(useDefaultIdleState?) | Negative semantic variant, with the same idle-state switch. |
MaterialLibrary.system() | Neutral system variant. |
MaterialLibrary.outboundMessage(theme?) | Outbound-message material. Uses the standard theme by default; pass a theme object for application-specific colors. |
MaterialLibrary.inboundMessage() | Inbound message surface. |
| Field | Role |
|---|---|
idleFill | Resting surface. Quiet enough that focus is clearly distinguishable. |
gradientStep1 | Brightest focus core, at the start of the gradient. |
gradientStep2 | Transition color after the core. |
gradientStep3 | Deep falloff toward the outer region. |
gradientStep4 | Darkest outer extent, close to the surrounding surface. |
glowTint | Inner-glow tint. Usually related to step 1. |
var(--uit-color-...) reference will not resolve there. Keep the values in one application palette module and pass them in, rather than writing color literals at each call site. Build the ramp perceptually — decreasing lightness and usually chroma from step 1 to step 4, stable hue — instead of varying alpha on one value.const material = useMemo(
() =>
MaterialLibrary.themedPrimary({
idleFill: appPalette.primary.idle,
gradientStep1: appPalette.primary.focusCore,
gradientStep2: appPalette.primary.focusMid,
gradientStep3: appPalette.primary.focusFalloff,
gradientStep4: appPalette.primary.focusExtent,
glowTint: appPalette.primary.glow,
}),
[appPalette],
);
MaterialLibrary.contentFocus() is for interactive containers whose content supplies the visible fill, such as a full-bleed image. It keeps the content unchanged at rest, then places a blurred radial light in the foreground during focus and press. The light follows partial focus, including discrete edge feedback. The same material is available directly as createContentFocusContainerMaterial().MaterialLibrary.backgroundImageBlur(imageSrc?) renders four layers: a blurred image clipped to the shape and a dark fill overlay in the background, then a press overlay and a glow stroke in the foreground. The stroke is visible in every state except NONE and widens on focus and press. The material sets foregroundBlendsWithContent and reports supportsDiscretePartialFocus as false, so it does not follow partial focus.createBackgroundImageBlurContainerMaterial(imageSrc?) and as the BackgroundImageBlurContainerMaterial class. Unlike other materials it is mutable: setImage(url) swaps the source and notifies the host to repaint, and getImage() returns the current source. Because the instance holds that state, the one-instance-per-host rule matters even more here. Passing null clears the image. The source is fetched through the shared canvas image cache, which loads images in anonymous cross-origin mode, so a remote origin has to serve permissive cross-origin resource sharing headers for the bitmap to reach the canvas.const material = useMemo(
() => createBackgroundImageBlurContainerMaterial(coverUrl),
[],
);
useEffect(() => {
material.setImage(coverUrl);
}, [material, coverUrl]);
withInset and the other derivations preserve the subclass and its current image.MaterialLibrary entries, for code that does not want the whole object:createDefaultContainerMaterial(options?)createClockPillContainerMaterial()createReducedOpacityStaticContainerMaterial()createStatusIndicatorPanelContainerMaterial()createBackgroundImageBlurContainerMaterial(imageSrc?)createContentFocusContainerMaterial()MaterialLibrary.themedPrimary before considering custom layers; it preserves the standard stack.