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.
- package/dist/animated-text.d.ts +49 -0
- package/dist/animated-text.d.ts.map +1 -0
- package/dist/animated-text.js +70 -0
- package/dist/animated-text.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/ripple.d.ts +41 -0
- package/dist/ripple.d.ts.map +1 -0
- package/dist/ripple.js +63 -0
- package/dist/ripple.js.map +1 -0
- package/dist/spring.d.ts +41 -0
- package/dist/spring.d.ts.map +1 -0
- package/dist/spring.js +35 -0
- package/dist/spring.js.map +1 -0
- package/package.json +13 -3
|
@@ -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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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"}
|
package/dist/ripple.d.ts
ADDED
|
@@ -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"}
|
package/dist/spring.d.ts
ADDED
|
@@ -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.
|
|
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": ">=
|
|
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
|
}
|