kang-components
v0.3.0
Published
Generic, domain-free React UI primitives (CSS-first press feedback, delayed-action hook).
Readme
kang-components
Generic, domain-free React UI primitives. Built to be consumed by Xunzi (and
anything else) while it migrates off ymy-components — see the
Xunzi straddle epic.
Design constraints
- No app domain knowledge. No HSK, challenge, friend, route, or Redux concepts. Primitives only.
- CSS-first. Simple interaction primitives return plain CSS strings — no CSS-in-JS runtime dependency. Use JS animation only when it earns the cost.
- Additive, non-breaking APIs before each manual npm publication.
Install
npm install kang-componentsreact is an optional peer dependency — only required if you use a hook
(e.g. useAnimatedAction). The press primitives are pure strings and need
nothing.
Press primitives
CSS-first press feedback. Each helper returns a plain CSS string you interpolate into your styling layer (styled-components shown):
import styled from 'styled-components';
import { pressPrimary, pressSubtle } from 'kang-components';
// Action buttons (scale 0.95)
const Button = styled.button`
${pressPrimary()}
`;
// Large tappable surfaces (scale 0.97)
const Tile = styled.button`
${pressSubtle()}
`;When the element also transitions other properties, pass them via
extraTransition so they share the one transition declaration:
const Row = styled.button`
${pressSubtle('background-color 0.15s ease-out')}
`;For elements whose transform is driven elsewhere (e.g. a JS spring), use the
*Scale variants, which animate the CSS scale property instead:
import { pressPrimaryScale, pressSubtleScale } from 'kang-components';Exports: pressPrimary, pressSubtle, pressPrimaryScale, pressSubtleScale,
plus the constants BOUNCE_CURVE, PRESS_SCALE_PRIMARY, PRESS_SCALE_SUBTLE.
useAnimatedAction
Delays an action callback so visual feedback (ripple, press animation) is perceived before the UI transitions away. Defaults to 180ms; clears pending timeouts on unmount.
import { useAnimatedAction } from 'kang-components';
const act = useAnimatedAction();
const onClick = () => act(() => navigate('/next'));Action-sheet primitives
CSS-first layout for a bottom-sheet "actions" panel — a vertical container, a
list, and tappable action rows with subtle press feedback. Colors stay with the
consumer: actionSheetRow takes the pressed-state background, so Kang carries no
theme knowledge.
import styled from 'styled-components';
import { actionSheetContainer, actionSheetList, actionSheetRow } from 'kang-components';
const Container = styled.div`${actionSheetContainer()}`;
const List = styled.div`${actionSheetList()}`;
const Row = styled.button`
${({ theme }) => actionSheetRow(theme.colors.surfaceVariant)}
`;Per-row content (leading icon, label, destructive tint, ripple) is the consumer's to layer on top of the row.
Build
npm run build # tsc → dist (ESM + .d.ts)