Initial release: dreamknob library + showcase
React + TypeScript knob/fader library with a headless interaction core (rotary, relative-drag and track modes, wheel, keyboard, a11y), SVG primitives, nine prebuilt skins, seven-segment display engine, and a Vite showcase with gallery, live playground and API docs.
This commit is contained in:
commit
60a02cb1db
46 changed files with 6186 additions and 0 deletions
73
packages/dreamknob/src/primitives/Pointer.tsx
Normal file
73
packages/dreamknob/src/primitives/Pointer.tsx
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
import * as React from 'react';
|
||||
import { useKnobContext } from '../core/context';
|
||||
|
||||
export interface PointerProps {
|
||||
/** Built-in shapes. Provide children instead for a custom pointer. */
|
||||
type?: 'line' | 'circle' | 'triangle';
|
||||
/** Distance from center to the pointer's outer end. Defaults to size/2 - 4. */
|
||||
radius?: number;
|
||||
/** Length of the pointer along the radial axis. */
|
||||
length?: number;
|
||||
width?: number;
|
||||
color?: string;
|
||||
cap?: 'butt' | 'round';
|
||||
/** Extra SVG props applied to the shape. */
|
||||
shapeProps?: React.SVGProps<SVGElement>;
|
||||
/** Custom pointer content, drawn pointing at 12 o'clock and rotated for you. */
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
/** Rotating indicator. Children (or the built-in shape) are authored pointing up. */
|
||||
export const Pointer: React.FC<PointerProps> = ({
|
||||
type = 'line',
|
||||
radius,
|
||||
length = 12,
|
||||
width = 4,
|
||||
color = 'currentColor',
|
||||
cap = 'round',
|
||||
shapeProps,
|
||||
children,
|
||||
}) => {
|
||||
const { size, center, angle } = useKnobContext();
|
||||
const r = radius ?? size / 2 - 4;
|
||||
|
||||
let shape: React.ReactNode = children;
|
||||
if (!shape) {
|
||||
if (type === 'line') {
|
||||
shape = (
|
||||
<line
|
||||
x1={center}
|
||||
y1={center - r}
|
||||
x2={center}
|
||||
y2={center - r + length}
|
||||
stroke={color}
|
||||
strokeWidth={width}
|
||||
strokeLinecap={cap}
|
||||
{...(shapeProps as React.SVGProps<SVGLineElement>)}
|
||||
/>
|
||||
);
|
||||
} else if (type === 'circle') {
|
||||
shape = (
|
||||
<circle
|
||||
cx={center}
|
||||
cy={center - r + width / 2}
|
||||
r={width}
|
||||
fill={color}
|
||||
{...(shapeProps as React.SVGProps<SVGCircleElement>)}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
const half = width / 2;
|
||||
const tipY = center - r;
|
||||
shape = (
|
||||
<polygon
|
||||
points={`${center},${tipY} ${center - half},${tipY + length} ${center + half},${tipY + length}`}
|
||||
fill={color}
|
||||
{...(shapeProps as React.SVGProps<SVGPolygonElement>)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return <g transform={`rotate(${angle} ${center} ${center})`}>{shape}</g>;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue