Audit fixes: a11y, gesture correctness, math edge cases
- Keyboard focus-visible ring on all controls (WCAG 2.4.7), suppressed for pointer grabs; focusRing prop to customize or disable - aria-orientation on track modes; data-dragging/-disabled/-readonly/ -focus-visible state attributes; disabled dims, readOnly drops the grab cursor - Escape cancels a drag and restores the pre-gesture value - Controlled mode no longer desyncs when the parent rejects onChange - Second concurrent pointer can no longer hijack a drag session; drags cancel when disabled/readOnly flips mid-gesture - Wheel: onChangeStart symmetry, settle flush on unsubscribe, dominant- axis direction (fixes macOS Shift+scroll reversal), ignored mid-drag - Shift+wheel and fine multipliers now work on stepped/values knobs - Fader/LEDFader track mapping inset-aligned with handle travel (no value jump when grabbing the cap); LEDFader zones sorted - roundTo no longer returns NaN for exponential-notation values; logTaper falls back to linear for invalid ranges; decimalsFromStep shaves float noise; findClosest([]) returns the input - Double-click reset brackets with onChangeStart/End - MetalKnob honors showValue/unit/format; VintageKnob omits them from its type; TickLabels extracted as a public primitive - SegmentDisplay: letters/hex charset, dash overflow instead of 888
This commit is contained in:
parent
60a02cb1db
commit
da352d3695
13 changed files with 378 additions and 82 deletions
53
packages/dreamknob/src/primitives/TickLabels.tsx
Normal file
53
packages/dreamknob/src/primitives/TickLabels.tsx
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import * as React from 'react';
|
||||
import { useKnobContext } from '../core/context';
|
||||
import { polarToCartesian } from '../core/math';
|
||||
|
||||
export interface TickLabelsProps {
|
||||
/** Labels distributed evenly across the travel, e.g. ['0','','5','','10']. */
|
||||
labels: readonly string[];
|
||||
/** Radius of the label ring. Defaults to just inside the canvas edge. */
|
||||
radius?: number;
|
||||
fontSize?: number;
|
||||
color?: string;
|
||||
fontFamily?: string;
|
||||
/** Extra props per label, by index. */
|
||||
getLabelProps?: (index: number) => React.SVGProps<SVGTextElement> | undefined;
|
||||
}
|
||||
|
||||
/** Printed scale labels around the knob's travel (0…10 amp-style scales). */
|
||||
export const TickLabels: React.FC<TickLabelsProps> = ({
|
||||
labels,
|
||||
radius,
|
||||
fontSize,
|
||||
color = 'currentColor',
|
||||
fontFamily,
|
||||
getLabelProps,
|
||||
}) => {
|
||||
const { size, center: c, angleOffset, angleRange } = useKnobContext();
|
||||
const r = radius ?? size / 2 - size * 0.02;
|
||||
return (
|
||||
<g>
|
||||
{labels.map((text, i) => {
|
||||
if (!text) return null;
|
||||
const t = labels.length === 1 ? 0 : i / (labels.length - 1);
|
||||
const p = polarToCartesian(c, c, r, angleOffset + t * angleRange);
|
||||
return (
|
||||
<text
|
||||
key={i}
|
||||
x={p.x}
|
||||
y={p.y}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="central"
|
||||
fontSize={fontSize ?? size * 0.085}
|
||||
fontFamily={fontFamily}
|
||||
fill={color}
|
||||
style={{ pointerEvents: 'none' }}
|
||||
{...getLabelProps?.(i)}
|
||||
>
|
||||
{text}
|
||||
</text>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue