Readout legibility (the #1 ask): - bold own-cell decimal point + colon in seven/fourteen-seg (not hairlines) - weight prop thickens strokes; gap controls inter-cell kerning Display colors: - SegmentDisplay defaults to theme.ledGreen, AlphaDisplay to theme.ledAmber - valueColor fn + value-space zones on SegmentDisplay (self-coloring readouts) - charset: colon in both, $ and % in 14-seg; disabled + data-disabled Knob captions: sublabel (second line) + labelSize (independent of dial size). New components: - ToggleSwitch (rocker/slider boolean, role=switch) - Gauge (read-only radial arc meter, round sibling of Meter) - TransportButton (play/stop/record/pause/panic, record blinks) - LampRow (console-print lamp bank), LabeledField, Rack (panel chrome) Responsiveness: fill on Meter + Fader (stretch to container). Niceties: PushButton leadingIcon; theme ledGreen/ledAmber/panel tokens. 54 -> 63 exports. 38 unit tests. Browser-verified.
91 lines
2.3 KiB
TypeScript
91 lines
2.3 KiB
TypeScript
import * as React from 'react';
|
|
import { useKnobTheme } from '../core/theme';
|
|
|
|
export interface LabeledFieldProps {
|
|
/** Field name printed beside the control. */
|
|
label: string;
|
|
/** The control (a knob, fader, ScrubField, ToggleSwitch, …). */
|
|
children: React.ReactNode;
|
|
/** Unit printed after the control, e.g. "px", "dB". */
|
|
unit?: string;
|
|
/**
|
|
* Label column width — set the same value on a stack of fields so their
|
|
* controls line up. Number = px. Default: auto.
|
|
*/
|
|
labelWidth?: number | string;
|
|
/** 'row' (label · control · unit, default) or 'column' (label above). */
|
|
orientation?: 'row' | 'column';
|
|
/** Push the control to the right edge of the row. Default: false. */
|
|
spread?: boolean;
|
|
gap?: number;
|
|
labelColor?: string;
|
|
className?: string;
|
|
style?: React.CSSProperties;
|
|
}
|
|
|
|
/**
|
|
* One aligned inspector row: a label, a control and an optional unit. Give a
|
|
* stack of fields the same `labelWidth` and their controls line up — the
|
|
* boilerplate every properties panel rewrites, owned in one place.
|
|
*/
|
|
export const LabeledField: React.FC<LabeledFieldProps> = ({
|
|
label,
|
|
children,
|
|
unit,
|
|
labelWidth,
|
|
orientation = 'row',
|
|
spread = false,
|
|
gap = 10,
|
|
labelColor,
|
|
className,
|
|
style,
|
|
}) => {
|
|
const theme = useKnobTheme();
|
|
const column = orientation === 'column';
|
|
const labelEl = (
|
|
<span
|
|
style={{
|
|
flex: 'none',
|
|
width: column ? undefined : labelWidth,
|
|
fontFamily: theme.fontUI,
|
|
fontSize: 11,
|
|
letterSpacing: '0.05em',
|
|
textTransform: 'uppercase',
|
|
color: labelColor ?? theme.label,
|
|
whiteSpace: 'nowrap',
|
|
}}
|
|
>
|
|
{label}
|
|
</span>
|
|
);
|
|
|
|
return (
|
|
<div
|
|
className={className}
|
|
style={{
|
|
display: 'flex',
|
|
flexDirection: column ? 'column' : 'row',
|
|
alignItems: column ? 'flex-start' : 'center',
|
|
gap: column ? 4 : gap,
|
|
...style,
|
|
}}
|
|
>
|
|
{labelEl}
|
|
<div
|
|
style={{
|
|
display: 'inline-flex',
|
|
alignItems: 'center',
|
|
gap: 6,
|
|
marginLeft: spread && !column ? 'auto' : undefined,
|
|
}}
|
|
>
|
|
{children}
|
|
{unit && (
|
|
<span style={{ fontFamily: theme.fontMono, fontSize: 11, color: theme.label, whiteSpace: 'nowrap' }}>
|
|
{unit}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|