InteractableBase, overriding Container’s state mapping, or creating a custom material. In application code, prefer component props that express user intent rather than forcing a visual state.State plus a disabled flag) from the state rendered by a material (VisualState). This separation lets the toolkit evolve behavior and appearance independently while keeping interaction feedback consistent.import {
ContentScaleInsets,
State,
VisualState,
getContentScaleForState,
} from '@wearables-ui-toolkit/mrbd';
import {
DefaultContentScaleInsets,
getDefaultContentScaleForState,
} from '@wearables-ui-toolkit/foundation';
import type {
InteractionState,
Platform,
} from '@wearables-ui-toolkit/mrbd';
import type {ContentScaleForStateFn} from '@wearables-ui-toolkit/foundation';
State and VisualState are each exported as a value and a type. For example, State.FOCUSED and state: State work without separate imports.import {Container, State, VisualState} from '@wearables-ui-toolkit/mrbd';
import type {InteractionState} from '@wearables-ui-toolkit/mrbd';
function StatusTile() {
return (
<Container
clickable
onActivate={openStatus}
ariaLabel="Status"
visualStateForInteractionStateFn={(interaction: InteractionState) => {
// Render nothing at rest; light up only on focus and press.
if (interaction.isDisabled) {
return VisualState.DEFAULT;
}
switch (interaction.state) {
case State.FOCUSED:
return VisualState.FOCUSED;
case State.PRESSED:
return VisualState.PRESSED;
default:
return VisualState.NONE;
}
}}
>
<StatusContent />
</Container>
);
}
import {Container, State} from '@wearables-ui-toolkit/mrbd';
import type {InteractionState} from '@wearables-ui-toolkit/mrbd';
import {useState} from 'react';
function LabelledTarget() {
const [isActive, setIsActive] = useState(false);
return (
<div className="labelled-target">
<Container
clickable
ariaLabel="Capture"
onActivate={capture}
onStateChange={(_previous: InteractionState, next: InteractionState) => {
setIsActive(next.state !== State.DEFAULT);
}}
>
<CaptureGlyph />
</Container>
<CaptureCaption isEmphasized={isActive} />
</div>
);
}
State describes the control’s logical interaction state. Exactly one member is active at a time.| Member | Value | Meaning |
|---|---|---|
State.DEFAULT | 'default' | Resting. Neither focused nor pressed. |
State.FOCUSED | 'focused' | The control owns focus. |
State.PRESSED | 'pressed' | The control is being pressed, by pointer or by Enter/Space. |
PRESSED while it is being pressed, then returns to FOCUSED when the press ends if it still owns focus.VisualState describes the state rendered by a material. It adds NONE for a material that draws nothing.| Member | Value | Meaning |
|---|---|---|
VisualState.NONE | 'none' | No material is drawn. |
VisualState.DEFAULT | 'default' | Resting appearance. |
VisualState.FOCUSED | 'focused' | Focused appearance. |
VisualState.PRESSED | 'pressed' | Pressed appearance. |
interface InteractionState {
state: State;
isDisabled: boolean;
}
State member. Every interactive component passes this shape to onStateChange as (previous, next).type Platform = 'mrbd';
Platform identifies the target for a content-scale lookup. The package targets Meta Ray-Ban Display, so this closed union has one member. App supplies 'mrbd' through platform context, and components such as Container and Surface read it automatically. Use Platform when calling a platform-aware helper directly, and read values from ContentScaleInsets rather than maintaining a separate table.ContentScaleInsets provides the horizontal content-scale inset for each Platform and State:ContentScaleInsets[platform][state].horizontal;
getContentScaleForState(state, platform, size) applies the same profile and returns the uniform scale factor for the supplied element size.DefaultContentScaleInsets is the foundation-level form of the same default profile, without a platform key. getDefaultContentScaleForState(state, size) calculates its uniform scale directly and satisfies ContentScaleForStateFn, whose signature is:type ContentScaleForStateFn = (
state: State,
containerSize: {width: number; height: number},
) => number;
ContentScaleInsets and getContentScaleForState when implementing custom content-scale behavior. Container and Surface already use the profile supplied by App; override contentScaleForStateFn only when a component needs a different curve.DEFAULT and PRESSED share an inset, while FOCUSED has no inset and therefore renders at full size.Container needs the same motion rhythm. Avoid hardcoded duplicate values because they can make controls respond inconsistently. When a Container-based component needs a different curve, override contentScaleForStateFn instead of adding a second scale.DEFAULT, FOCUSED, or PRESSED with isDisabled: true. It remains focusable so directional navigation does not leave a hole in the layout, and it renders its resting visual state at the disabled opacity.DEFAULT maps to VisualState.DEFAULT, FOCUSED maps to VisualState.FOCUSED, PRESSED maps to VisualState.PRESSED, and every disabled state maps to VisualState.DEFAULT.NONE is a material decision, not a logical state. No control reports NONE as its logical state. A component or material selects it to suppress drawing, as StaticContainer does for its NONE background style.tooltipHidesFocusState, onStateChange reports DEFAULT while the tooltip is open. This keeps the anchor from rendering focus under the tooltip. The control still owns focus; only its reported state is masked.InteractionState in onStateChange when a sibling needs to follow a control’s state.VisualState when authoring a material or custom state mapping.isDisabled before switching on state in a custom mapping.isDisabled flag, not as a fourth State member.ContentScaleInsets for resting and pressed insets instead of defining new values, so controls share the same breathing rhythm.