kang-components 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,49 @@
1
+ /**
2
+ * AnimatedText — a domain-free cross-fading text cycler.
3
+ *
4
+ * Shows one of several string `variants`, periodically cross-fading to the next
5
+ * (a swap at the opacity-0 midpoint via react-spring's `onRest`). With two
6
+ * variants it simply toggles back and forth; with more it rotates in order.
7
+ *
8
+ * Domain-free: it knows nothing about languages, characters, or app state. The
9
+ * consumer decides what the variants are (e.g. an i18n layer maps its own
10
+ * language model down to `variants` + `staticIndex`). This keeps the multilingual
11
+ * knowledge in the app and the motion mechanics here.
12
+ *
13
+ * Layout never reflows during a swap: every candidate string is also rendered as
14
+ * a hidden sizer span stacked in the same grid cell, so the box is always sized
15
+ * to the widest candidate. Pass `sizers` when the set of strings that must fit is
16
+ * wider than the visible `variants` (e.g. the variants you cycle are a subset of
17
+ * all possible values).
18
+ *
19
+ * react-spring is used deliberately (not CSS): the text swap must happen exactly
20
+ * at the fade's midpoint, which needs `onRest`. This matches the project's
21
+ * CSS-first animation policy, which routes "animations requiring onRest" to
22
+ * react-spring. `@react-spring/web` and `react` are optional peer dependencies —
23
+ * only this module pulls them in.
24
+ */
25
+ import { CSSProperties } from 'react';
26
+ export type AnimatedTextProps = {
27
+ /** Strings to cross-fade between, in order. Two → toggle; more → rotate. */
28
+ variants: string[];
29
+ /** Cycle through variants (true) or hold a single static variant (false). Default true. */
30
+ animate?: boolean;
31
+ /** Which variant to show when `animate` is false. Default 0. */
32
+ staticIndex?: number;
33
+ /**
34
+ * Strings reserved (rendered hidden) purely to size the box so it never
35
+ * reflows mid-swap. Defaults to `variants`. Provide a wider set when the
36
+ * cycled variants are a subset of all possible values.
37
+ */
38
+ sizers?: string[];
39
+ /** Start at opacity 0 and fade in on mount. */
40
+ fadeIn?: boolean;
41
+ /** Maximum ms between cross-fade cycles (the minimum is 3500). Default 15000. */
42
+ maxDelay?: number;
43
+ /** Element to render the text grid as. Default 'div'. */
44
+ htmlElement?: keyof JSX.IntrinsicElements;
45
+ /** Styles for the text; font-related props are applied to every (visible + sizer) span. */
46
+ textStyles?: CSSProperties;
47
+ };
48
+ export default function AnimatedText({ variants, animate, staticIndex, sizers, fadeIn, maxDelay, htmlElement, textStyles, }: AnimatedTextProps): import("react").JSX.Element;
49
+ //# sourceMappingURL=animated-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animated-text.d.ts","sourceRoot":"","sources":["../src/animated-text.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAiB,aAAa,EAA+B,MAAM,OAAO,CAAC;AAGlF,MAAM,MAAM,iBAAiB,GAAG;IAC/B,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,2FAA2F;IAC3F,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,GAAG,CAAC,iBAAiB,CAAC;IAC1C,2FAA2F;IAC3F,UAAU,CAAC,EAAE,aAAa,CAAC;CAC3B,CAAC;AAKF,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACpC,QAAQ,EACR,OAAc,EACd,WAAe,EACf,MAAM,EACN,MAAc,EACd,QAAgB,EAChB,WAAmB,EACnB,UAAU,GACV,EAAE,iBAAiB,+BAwDnB"}
@@ -0,0 +1,70 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * AnimatedText — a domain-free cross-fading text cycler.
4
+ *
5
+ * Shows one of several string `variants`, periodically cross-fading to the next
6
+ * (a swap at the opacity-0 midpoint via react-spring's `onRest`). With two
7
+ * variants it simply toggles back and forth; with more it rotates in order.
8
+ *
9
+ * Domain-free: it knows nothing about languages, characters, or app state. The
10
+ * consumer decides what the variants are (e.g. an i18n layer maps its own
11
+ * language model down to `variants` + `staticIndex`). This keeps the multilingual
12
+ * knowledge in the app and the motion mechanics here.
13
+ *
14
+ * Layout never reflows during a swap: every candidate string is also rendered as
15
+ * a hidden sizer span stacked in the same grid cell, so the box is always sized
16
+ * to the widest candidate. Pass `sizers` when the set of strings that must fit is
17
+ * wider than the visible `variants` (e.g. the variants you cycle are a subset of
18
+ * all possible values).
19
+ *
20
+ * react-spring is used deliberately (not CSS): the text swap must happen exactly
21
+ * at the fade's midpoint, which needs `onRest`. This matches the project's
22
+ * CSS-first animation policy, which routes "animations requiring onRest" to
23
+ * react-spring. `@react-spring/web` and `react` are optional peer dependencies —
24
+ * only this module pulls them in.
25
+ */
26
+ import { createElement, useEffect, useRef, useState } from 'react';
27
+ import { animated, useSpring } from '@react-spring/web';
28
+ const MIN_DELAY = 3500;
29
+ const FIRST_CYCLE_DELAY = 500;
30
+ export default function AnimatedText({ variants, animate = true, staticIndex = 0, sizers, fadeIn = false, maxDelay = 15000, htmlElement = 'div', textStyles, }) {
31
+ const [cycle, setCycle] = useState(0);
32
+ const [spring, springApi] = useSpring(() => ({
33
+ opacity: fadeIn ? 0 : 1,
34
+ config: { duration: 600 },
35
+ }));
36
+ const wasAnimating = useRef(animate);
37
+ useEffect(() => {
38
+ if (!animate) {
39
+ wasAnimating.current = animate;
40
+ return;
41
+ }
42
+ const justActivated = !wasAnimating.current && animate;
43
+ wasAnimating.current = animate;
44
+ const delay = justActivated
45
+ ? FIRST_CYCLE_DELAY
46
+ : Math.floor(Math.random() * (maxDelay - MIN_DELAY + 1)) + MIN_DELAY;
47
+ const timer = setTimeout(() => {
48
+ springApi.start({
49
+ opacity: 0,
50
+ onRest: () => {
51
+ setCycle((c) => c + 1);
52
+ springApi.start({ opacity: 1 });
53
+ },
54
+ });
55
+ }, delay);
56
+ return () => clearTimeout(timer);
57
+ }, [cycle, animate, springApi, maxDelay]);
58
+ const count = variants.length || 1;
59
+ const visibleText = animate
60
+ ? variants[cycle % count]
61
+ : variants[staticIndex] ?? variants[0];
62
+ const { fontSize, fontFamily, fontWeight, fontStyle, letterSpacing, lineHeight, ...rest } = textStyles || {};
63
+ const fontStyles = { fontSize, fontFamily, fontWeight, fontStyle, letterSpacing, lineHeight };
64
+ const gridStyle = { ...rest, display: 'inline-grid', alignContent: 'center' };
65
+ const visibleStyle = { ...fontStyles, gridArea: '1 / 1' };
66
+ const hiddenStyle = { ...fontStyles, gridArea: '1 / 1', visibility: 'hidden' };
67
+ const sizerStrings = sizers ?? variants;
68
+ return (_jsx(animated.div, { style: { ...spring, display: 'inline-block' }, children: createElement(htmlElement, { style: gridStyle }, createElement('span', { style: visibleStyle, key: 'visible' }, visibleText), ...sizerStrings.map((s, i) => createElement('span', { style: hiddenStyle, key: `sizer-${i}`, 'aria-hidden': true }, s))) }));
69
+ }
70
+ //# sourceMappingURL=animated-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animated-text.js","sourceRoot":"","sources":["../src/animated-text.tsx"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,10 @@
1
1
  export { BOUNCE_CURVE, PRESS_SCALE_PRIMARY, PRESS_SCALE_SUBTLE, pressPrimary, pressSubtle, pressPrimaryScale, pressSubtleScale, } from './press.js';
2
2
  export { useAnimatedAction } from './use-animated-action.js';
3
3
  export { actionSheetContainer, actionSheetList, actionSheetRow, } from './action-sheet.js';
4
+ export { Ripple, rippleAnimation, useRipple } from './ripple.js';
5
+ export type { RippleState } from './ripple.js';
6
+ export { SPRING_COMFORTABLE, SPRING_COMFORTABLE_SLOW, SPRING_SNAPPY, SPRING_RESPONSIVE, SPRING_STAGGERED, SPRING_INSTANT, SPRING_GENTLE, SPRING_VERY_SLOW, SPRING_LANDING, SPRING_RISING, } from './spring.js';
7
+ export type { SpringConfigConstant } from './spring.js';
8
+ export { default as AnimatedText } from './animated-text.js';
9
+ export type { AnimatedTextProps } from './animated-text.js';
4
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,cAAc,GACd,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,cAAc,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EACN,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,aAAa,GACb,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  export { BOUNCE_CURVE, PRESS_SCALE_PRIMARY, PRESS_SCALE_SUBTLE, pressPrimary, pressSubtle, pressPrimaryScale, pressSubtleScale, } from './press.js';
2
2
  export { useAnimatedAction } from './use-animated-action.js';
3
3
  export { actionSheetContainer, actionSheetList, actionSheetRow, } from './action-sheet.js';
4
+ export { Ripple, rippleAnimation, useRipple } from './ripple.js';
5
+ export { SPRING_COMFORTABLE, SPRING_COMFORTABLE_SLOW, SPRING_SNAPPY, SPRING_RESPONSIVE, SPRING_STAGGERED, SPRING_INSTANT, SPRING_GENTLE, SPRING_VERY_SLOW, SPRING_LANDING, SPRING_RISING, } from './spring.js';
6
+ export { default as AnimatedText } from './animated-text.js';
4
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,cAAc,GACd,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,WAAW,EACX,iBAAiB,EACjB,gBAAgB,GAChB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,OAAO,EACN,oBAAoB,EACpB,eAAe,EACf,cAAc,GACd,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGjE,OAAO,EACN,kBAAkB,EAClB,uBAAuB,EACvB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,cAAc,EACd,aAAa,GACb,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Material-style ripple — a domain-free press-feedback overlay.
3
+ *
4
+ * Two pieces that work together:
5
+ * - `useRipple<T>()` — a pure React hook that tracks the active ripple's
6
+ * position and which target fired it. `trigger(event, target)` records the
7
+ * click point relative to the element; `isTarget(value)` tells a given
8
+ * element whether it owns the current ripple.
9
+ * - `Ripple` — a styled `<span>` placed inside the (relatively-positioned)
10
+ * pressable element. Give it `key={ripple.key}` so each press restarts the
11
+ * animation, and `$x`/`$y` from the ripple state.
12
+ *
13
+ * The fill reads `theme.colors.ripple` (a generic styling token, not app
14
+ * domain) and falls back to `rgba(0, 0, 0, 0.1)` when absent — so it works with
15
+ * or without a themed `ThemeProvider`.
16
+ *
17
+ * `styled-components` is an optional peer dependency, used only by this module;
18
+ * consumers that import only the press / action-sheet string primitives never
19
+ * pull it in.
20
+ */
21
+ import { type MouseEvent } from 'react';
22
+ export interface RippleState<T> {
23
+ x: number;
24
+ y: number;
25
+ key: number;
26
+ target: T;
27
+ }
28
+ export declare const rippleAnimation: import("styled-components/dist/models/Keyframes").default;
29
+ export declare const Ripple: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "$x" | "$y"> & {
30
+ $x: number;
31
+ $y: number;
32
+ }, never> & Partial<Pick<import("styled-components").FastOmit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, "$x" | "$y"> & {
33
+ $x: number;
34
+ $y: number;
35
+ }, never>>> & string;
36
+ export declare function useRipple<T>(): {
37
+ ripple: RippleState<T> | null;
38
+ trigger: (e: MouseEvent<HTMLElement>, target: T) => void;
39
+ isTarget: (value: T) => boolean;
40
+ };
41
+ //# sourceMappingURL=ripple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ripple.d.ts","sourceRoot":"","sources":["../src/ripple.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAM/D,MAAM,WAAW,WAAW,CAAC,CAAC;IAC7B,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,CAAC,CAAC;CACV;AAED,eAAO,MAAM,eAAe,2DAS3B,CAAC;AAEF,eAAO,MAAM,MAAM;QAAqB,MAAM;QAAM,MAAM;;QAAlB,MAAM;QAAM,MAAM;oBAazD,CAAC;AAEF,wBAAgB,SAAS,CAAC,CAAC;;iBAGM,UAAU,CAAC,WAAW,CAAC,UAAU,CAAC;sBAWzD,CAAC;EAKV"}
package/dist/ripple.js ADDED
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Material-style ripple — a domain-free press-feedback overlay.
3
+ *
4
+ * Two pieces that work together:
5
+ * - `useRipple<T>()` — a pure React hook that tracks the active ripple's
6
+ * position and which target fired it. `trigger(event, target)` records the
7
+ * click point relative to the element; `isTarget(value)` tells a given
8
+ * element whether it owns the current ripple.
9
+ * - `Ripple` — a styled `<span>` placed inside the (relatively-positioned)
10
+ * pressable element. Give it `key={ripple.key}` so each press restarts the
11
+ * animation, and `$x`/`$y` from the ripple state.
12
+ *
13
+ * The fill reads `theme.colors.ripple` (a generic styling token, not app
14
+ * domain) and falls back to `rgba(0, 0, 0, 0.1)` when absent — so it works with
15
+ * or without a themed `ThemeProvider`.
16
+ *
17
+ * `styled-components` is an optional peer dependency, used only by this module;
18
+ * consumers that import only the press / action-sheet string primitives never
19
+ * pull it in.
20
+ */
21
+ import { useCallback, useState } from 'react';
22
+ // Named imports (not the default) so this resolves consistently across bundler
23
+ // and raw ESM/CJS environments — styled-components v6's default export is the
24
+ // CJS namespace under Node's interop, where `styled.span` is undefined.
25
+ import { styled, keyframes } from 'styled-components';
26
+ export const rippleAnimation = keyframes `
27
+ 0% {
28
+ transform: scale(0);
29
+ opacity: 0.6;
30
+ }
31
+ 100% {
32
+ transform: scale(10);
33
+ opacity: 0;
34
+ }
35
+ `;
36
+ export const Ripple = styled.span `
37
+ position: absolute;
38
+ left: ${({ $x }) => $x}px;
39
+ top: ${({ $y }) => $y}px;
40
+ width: 50px;
41
+ height: 50px;
42
+ margin-left: -25px;
43
+ margin-top: -25px;
44
+ border-radius: 50%;
45
+ background-color: ${({ theme }) => theme?.colors?.ripple ?? 'rgba(0, 0, 0, 0.1)'};
46
+ pointer-events: none;
47
+ animation: ${rippleAnimation} 0.4s ease-out forwards;
48
+ `;
49
+ export function useRipple() {
50
+ const [ripple, setRipple] = useState(null);
51
+ const trigger = useCallback((e, target) => {
52
+ const rect = e.currentTarget.getBoundingClientRect();
53
+ setRipple({
54
+ x: e.clientX - rect.left,
55
+ y: e.clientY - rect.top,
56
+ key: Date.now(),
57
+ target,
58
+ });
59
+ }, []);
60
+ const isTarget = useCallback((value) => ripple !== null && ripple.target === value, [ripple]);
61
+ return { ripple, trigger, isTarget };
62
+ }
63
+ //# sourceMappingURL=ripple.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ripple.js","sourceRoot":"","sources":["../src/ripple.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAmB,MAAM,OAAO,CAAC;AAC/D,+EAA+E;AAC/E,8EAA8E;AAC9E,wEAAwE;AACxE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAStD,MAAM,CAAC,MAAM,eAAe,GAAG,SAAS,CAAA;;;;;;;;;CASvC,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAA4B;;SAEpD,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;QACf,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE;;;;;;qBAMD,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAChC,KAA0C,EAAE,MAAM,EAAE,MAAM,IAAI,oBAAoB;;cAEvE,eAAe;CAC5B,CAAC;AAEF,MAAM,UAAU,SAAS;IACxB,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAwB,IAAI,CAAC,CAAC;IAElE,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAA0B,EAAE,MAAS,EAAE,EAAE;QACrE,MAAM,IAAI,GAAG,CAAC,CAAC,aAAa,CAAC,qBAAqB,EAAE,CAAC;QACrD,SAAS,CAAC;YACT,CAAC,EAAE,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI;YACxB,CAAC,EAAE,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG;YACvB,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE;YACf,MAAM;SACN,CAAC,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,QAAQ,GAAG,WAAW,CAC3B,CAAC,KAAQ,EAAE,EAAE,CAAC,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,MAAM,KAAK,KAAK,EACxD,CAAC,MAAM,CAAC,CACR,CAAC;IAEF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtC,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared spring-animation configuration constants — the generic motion
3
+ * vocabulary for Kang consumers.
4
+ *
5
+ * Domain-free and dependency-free: each constant is a plain
6
+ * `{ tension, friction, mass? }` object. That shape is structurally
7
+ * assignable to `@react-spring/web`'s `SpringConfig` (whose fields are all
8
+ * optional), so a consumer can pass these straight into `useSpring`/`api.start`
9
+ * `config:` without Kang taking a react-spring dependency.
10
+ *
11
+ * These mirror the presets that previously lived in `ymy-components` so feel is
12
+ * identical across apps. Use the named constant instead of an inline literal so
13
+ * every animation shares one tuned set of physics.
14
+ */
15
+ /** A react-spring-compatible spring physics config (mass defaults to 1 in react-spring). */
16
+ export interface SpringConfigConstant {
17
+ tension: number;
18
+ friction: number;
19
+ mass?: number;
20
+ }
21
+ /** Base comfortable config — smooth, relaxed animations. */
22
+ export declare const SPRING_COMFORTABLE: SpringConfigConstant;
23
+ /** Slower comfortable variant for background/gradient transitions. */
24
+ export declare const SPRING_COMFORTABLE_SLOW: SpringConfigConstant;
25
+ /** Snappy config — quick, responsive animations. */
26
+ export declare const SPRING_SNAPPY: SpringConfigConstant;
27
+ /** Responsive config — for UI elements that need quick feedback. */
28
+ export declare const SPRING_RESPONSIVE: SpringConfigConstant;
29
+ /** Staggered/lagged config — for cascading animations. */
30
+ export declare const SPRING_STAGGERED: SpringConfigConstant;
31
+ /** Instant config — near-immediate transitions. */
32
+ export declare const SPRING_INSTANT: SpringConfigConstant;
33
+ /** Gentle config — subtle, unobtrusive animations. */
34
+ export declare const SPRING_GENTLE: SpringConfigConstant;
35
+ /** Very slow config — for delayed/transitional animations. */
36
+ export declare const SPRING_VERY_SLOW: SpringConfigConstant;
37
+ /** Landing config — for "settling" hero animations with slight overshoot. */
38
+ export declare const SPRING_LANDING: SpringConfigConstant;
39
+ /** Rising config — for reverse hero animations, smoother deceleration. */
40
+ export declare const SPRING_RISING: SpringConfigConstant;
41
+ //# sourceMappingURL=spring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.d.ts","sourceRoot":"","sources":["../src/spring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,4FAA4F;AAC5F,MAAM,WAAW,oBAAoB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd;AAED,4DAA4D;AAC5D,eAAO,MAAM,kBAAkB,EAAE,oBAAqD,CAAC;AAEvF,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,EAAE,oBAAqD,CAAC;AAE5F,oDAAoD;AACpD,eAAO,MAAM,aAAa,EAAE,oBAAqD,CAAC;AAElF,oEAAoE;AACpE,eAAO,MAAM,iBAAiB,EAAE,oBAAqD,CAAC;AAEtF,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,EAAE,oBAAqD,CAAC;AAErF,mDAAmD;AACnD,eAAO,MAAM,cAAc,EAAE,oBAAqD,CAAC;AAEnF,sDAAsD;AACtD,eAAO,MAAM,aAAa,EAAE,oBAAqD,CAAC;AAElF,8DAA8D;AAC9D,eAAO,MAAM,gBAAgB,EAAE,oBAAoD,CAAC;AAEpF,6EAA6E;AAC7E,eAAO,MAAM,cAAc,EAAE,oBAA8D,CAAC;AAE5F,0EAA0E;AAC1E,eAAO,MAAM,aAAa,EAAE,oBAA8D,CAAC"}
package/dist/spring.js ADDED
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Shared spring-animation configuration constants — the generic motion
3
+ * vocabulary for Kang consumers.
4
+ *
5
+ * Domain-free and dependency-free: each constant is a plain
6
+ * `{ tension, friction, mass? }` object. That shape is structurally
7
+ * assignable to `@react-spring/web`'s `SpringConfig` (whose fields are all
8
+ * optional), so a consumer can pass these straight into `useSpring`/`api.start`
9
+ * `config:` without Kang taking a react-spring dependency.
10
+ *
11
+ * These mirror the presets that previously lived in `ymy-components` so feel is
12
+ * identical across apps. Use the named constant instead of an inline literal so
13
+ * every animation shares one tuned set of physics.
14
+ */
15
+ /** Base comfortable config — smooth, relaxed animations. */
16
+ export const SPRING_COMFORTABLE = { tension: 200, friction: 25 };
17
+ /** Slower comfortable variant for background/gradient transitions. */
18
+ export const SPRING_COMFORTABLE_SLOW = { tension: 150, friction: 25 };
19
+ /** Snappy config — quick, responsive animations. */
20
+ export const SPRING_SNAPPY = { tension: 325, friction: 30 };
21
+ /** Responsive config — for UI elements that need quick feedback. */
22
+ export const SPRING_RESPONSIVE = { tension: 300, friction: 30 };
23
+ /** Staggered/lagged config — for cascading animations. */
24
+ export const SPRING_STAGGERED = { tension: 750, friction: 30 };
25
+ /** Instant config — near-immediate transitions. */
26
+ export const SPRING_INSTANT = { tension: 900, friction: 30 };
27
+ /** Gentle config — subtle, unobtrusive animations. */
28
+ export const SPRING_GENTLE = { tension: 185, friction: 25 };
29
+ /** Very slow config — for delayed/transitional animations. */
30
+ export const SPRING_VERY_SLOW = { tension: 50, friction: 20 };
31
+ /** Landing config — for "settling" hero animations with slight overshoot. */
32
+ export const SPRING_LANDING = { tension: 280, friction: 22, mass: 1 };
33
+ /** Rising config — for reverse hero animations, smoother deceleration. */
34
+ export const SPRING_RISING = { tension: 220, friction: 26, mass: 1 };
35
+ //# sourceMappingURL=spring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spring.js","sourceRoot":"","sources":["../src/spring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,4DAA4D;AAC5D,MAAM,CAAC,MAAM,kBAAkB,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAEvF,sEAAsE;AACtE,MAAM,CAAC,MAAM,uBAAuB,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAE5F,oDAAoD;AACpD,MAAM,CAAC,MAAM,aAAa,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAElF,oEAAoE;AACpE,MAAM,CAAC,MAAM,iBAAiB,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAEtF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,gBAAgB,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAErF,mDAAmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAEnF,sDAAsD;AACtD,MAAM,CAAC,MAAM,aAAa,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAElF,8DAA8D;AAC9D,MAAM,CAAC,MAAM,gBAAgB,GAAyB,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAEpF,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;AAE5F,0EAA0E;AAC1E,MAAM,CAAC,MAAM,aAAa,GAAyB,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "kang-components",
3
- "version": "0.2.0",
4
- "description": "Generic, domain-free React UI primitives (CSS-first press feedback, delayed-action hook).",
3
+ "version": "0.4.0",
4
+ "description": "Generic, domain-free React UI primitives (CSS-first press feedback, delayed-action hook, spring presets, cross-fading text).",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -26,16 +26,26 @@
26
26
  "prepublishOnly": "npm run build"
27
27
  },
28
28
  "peerDependencies": {
29
- "react": ">=18"
29
+ "@react-spring/web": ">=9",
30
+ "react": ">=18",
31
+ "styled-components": ">=6"
30
32
  },
31
33
  "peerDependenciesMeta": {
34
+ "@react-spring/web": {
35
+ "optional": true
36
+ },
32
37
  "react": {
33
38
  "optional": true
39
+ },
40
+ "styled-components": {
41
+ "optional": true
34
42
  }
35
43
  },
36
44
  "devDependencies": {
45
+ "@react-spring/web": "^9.7.5",
37
46
  "@types/react": "^18.3.18",
38
47
  "react": "^18.3.1",
48
+ "styled-components": "^6.1.16",
39
49
  "typescript": "~5.6.2"
40
50
  }
41
51
  }