react-native-ai-animations 0.0.0-stage → 0.8.1

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.
Files changed (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +226 -2
  3. package/lib/module/brand/index.js +4 -0
  4. package/lib/module/brand/index.js.map +1 -0
  5. package/lib/module/brand/spinning-mark.js +96 -0
  6. package/lib/module/brand/spinning-mark.js.map +1 -0
  7. package/lib/module/chat/effort-bar.js +853 -0
  8. package/lib/module/chat/effort-bar.js.map +1 -0
  9. package/lib/module/chat/index.js +8 -0
  10. package/lib/module/chat/index.js.map +1 -0
  11. package/lib/module/chat/question-card.js +720 -0
  12. package/lib/module/chat/question-card.js.map +1 -0
  13. package/lib/module/chat/reasoning.js +38 -0
  14. package/lib/module/chat/reasoning.js.map +1 -0
  15. package/lib/module/chat/status-row.js +140 -0
  16. package/lib/module/chat/status-row.js.map +1 -0
  17. package/lib/module/chat/thinking-block.js +255 -0
  18. package/lib/module/chat/thinking-block.js.map +1 -0
  19. package/lib/module/index.js +5 -0
  20. package/lib/module/index.js.map +1 -0
  21. package/lib/module/internal/color.js +15 -0
  22. package/lib/module/internal/color.js.map +1 -0
  23. package/lib/module/internal/use-elapsed.js +20 -0
  24. package/lib/module/internal/use-elapsed.js.map +1 -0
  25. package/lib/module/package.json +1 -0
  26. package/lib/module/skia/dot-orb.js +256 -0
  27. package/lib/module/skia/dot-orb.js.map +1 -0
  28. package/lib/module/skia/index.js +8 -0
  29. package/lib/module/skia/index.js.map +1 -0
  30. package/lib/module/skia/liquid-orb.js +303 -0
  31. package/lib/module/skia/liquid-orb.js.map +1 -0
  32. package/lib/module/skia/matrix-orb.js +272 -0
  33. package/lib/module/skia/matrix-orb.js.map +1 -0
  34. package/lib/module/skia/media-generating.js +524 -0
  35. package/lib/module/skia/media-generating.js.map +1 -0
  36. package/lib/module/skia/voice-wave.js +278 -0
  37. package/lib/module/skia/voice-wave.js.map +1 -0
  38. package/lib/module/text/index.js +6 -0
  39. package/lib/module/text/index.js.map +1 -0
  40. package/lib/module/text/shimmer-text.js +122 -0
  41. package/lib/module/text/shimmer-text.js.map +1 -0
  42. package/lib/module/text/spoken-text.js +85 -0
  43. package/lib/module/text/spoken-text.js.map +1 -0
  44. package/lib/module/text/streaming-text.js +135 -0
  45. package/lib/module/text/streaming-text.js.map +1 -0
  46. package/lib/module/theme/index.js +5 -0
  47. package/lib/module/theme/index.js.map +1 -0
  48. package/lib/module/theme/palette.js +45 -0
  49. package/lib/module/theme/palette.js.map +1 -0
  50. package/lib/module/theme/provider.js +65 -0
  51. package/lib/module/theme/provider.js.map +1 -0
  52. package/lib/typescript/package.json +1 -0
  53. package/lib/typescript/src/brand/index.d.ts +2 -0
  54. package/lib/typescript/src/brand/index.d.ts.map +1 -0
  55. package/lib/typescript/src/brand/spinning-mark.d.ts +21 -0
  56. package/lib/typescript/src/brand/spinning-mark.d.ts.map +1 -0
  57. package/lib/typescript/src/chat/effort-bar.d.ts +42 -0
  58. package/lib/typescript/src/chat/effort-bar.d.ts.map +1 -0
  59. package/lib/typescript/src/chat/index.d.ts +6 -0
  60. package/lib/typescript/src/chat/index.d.ts.map +1 -0
  61. package/lib/typescript/src/chat/question-card.d.ts +73 -0
  62. package/lib/typescript/src/chat/question-card.d.ts.map +1 -0
  63. package/lib/typescript/src/chat/reasoning.d.ts +20 -0
  64. package/lib/typescript/src/chat/reasoning.d.ts.map +1 -0
  65. package/lib/typescript/src/chat/status-row.d.ts +20 -0
  66. package/lib/typescript/src/chat/status-row.d.ts.map +1 -0
  67. package/lib/typescript/src/chat/thinking-block.d.ts +35 -0
  68. package/lib/typescript/src/chat/thinking-block.d.ts.map +1 -0
  69. package/lib/typescript/src/index.d.ts +3 -0
  70. package/lib/typescript/src/index.d.ts.map +1 -0
  71. package/lib/typescript/src/internal/color.d.ts +2 -0
  72. package/lib/typescript/src/internal/color.d.ts.map +1 -0
  73. package/lib/typescript/src/internal/use-elapsed.d.ts +3 -0
  74. package/lib/typescript/src/internal/use-elapsed.d.ts.map +1 -0
  75. package/lib/typescript/src/skia/dot-orb.d.ts +16 -0
  76. package/lib/typescript/src/skia/dot-orb.d.ts.map +1 -0
  77. package/lib/typescript/src/skia/index.d.ts +6 -0
  78. package/lib/typescript/src/skia/index.d.ts.map +1 -0
  79. package/lib/typescript/src/skia/liquid-orb.d.ts +20 -0
  80. package/lib/typescript/src/skia/liquid-orb.d.ts.map +1 -0
  81. package/lib/typescript/src/skia/matrix-orb.d.ts +12 -0
  82. package/lib/typescript/src/skia/matrix-orb.d.ts.map +1 -0
  83. package/lib/typescript/src/skia/media-generating.d.ts +59 -0
  84. package/lib/typescript/src/skia/media-generating.d.ts.map +1 -0
  85. package/lib/typescript/src/skia/voice-wave.d.ts +17 -0
  86. package/lib/typescript/src/skia/voice-wave.d.ts.map +1 -0
  87. package/lib/typescript/src/text/index.d.ts +4 -0
  88. package/lib/typescript/src/text/index.d.ts.map +1 -0
  89. package/lib/typescript/src/text/shimmer-text.d.ts +13 -0
  90. package/lib/typescript/src/text/shimmer-text.d.ts.map +1 -0
  91. package/lib/typescript/src/text/spoken-text.d.ts +15 -0
  92. package/lib/typescript/src/text/spoken-text.d.ts.map +1 -0
  93. package/lib/typescript/src/text/streaming-text.d.ts +16 -0
  94. package/lib/typescript/src/text/streaming-text.d.ts.map +1 -0
  95. package/lib/typescript/src/theme/index.d.ts +3 -0
  96. package/lib/typescript/src/theme/index.d.ts.map +1 -0
  97. package/lib/typescript/src/theme/palette.d.ts +33 -0
  98. package/lib/typescript/src/theme/palette.d.ts.map +1 -0
  99. package/lib/typescript/src/theme/provider.d.ts +13 -0
  100. package/lib/typescript/src/theme/provider.d.ts.map +1 -0
  101. package/package.json +133 -4
  102. package/src/brand/index.ts +5 -0
  103. package/src/brand/spinning-mark.tsx +118 -0
  104. package/src/chat/effort-bar.tsx +748 -0
  105. package/src/chat/index.ts +45 -0
  106. package/src/chat/question-card.tsx +649 -0
  107. package/src/chat/reasoning.ts +30 -0
  108. package/src/chat/status-row.tsx +127 -0
  109. package/src/chat/thinking-block.tsx +250 -0
  110. package/src/index.ts +2 -0
  111. package/src/internal/color.ts +18 -0
  112. package/src/internal/use-elapsed.ts +21 -0
  113. package/src/skia/dot-orb.tsx +248 -0
  114. package/src/skia/index.ts +34 -0
  115. package/src/skia/liquid-orb.tsx +274 -0
  116. package/src/skia/matrix-orb.tsx +337 -0
  117. package/src/skia/media-generating.tsx +389 -0
  118. package/src/skia/voice-wave.tsx +215 -0
  119. package/src/text/index.ts +3 -0
  120. package/src/text/shimmer-text.tsx +140 -0
  121. package/src/text/spoken-text.tsx +82 -0
  122. package/src/text/streaming-text.tsx +144 -0
  123. package/src/theme/index.ts +11 -0
  124. package/src/theme/palette.ts +62 -0
  125. package/src/theme/provider.tsx +54 -0
@@ -0,0 +1,4 @@
1
+ export { ShimmerText, type ShimmerTextProps } from "./shimmer-text.js";
2
+ export { StreamingText, type StreamingTextProps } from "./streaming-text.js";
3
+ export { SpokenText, type SpokenTextProps } from "./spoken-text.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/text/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,gBAAgB,EAAE,MAAM,mBAAgB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,KAAK,kBAAkB,EAAE,MAAM,qBAAkB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,kBAAe,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type StyleProp, type TextStyle } from "react-native";
2
+ export type ShimmerTextProps = {
3
+ text: string;
4
+ activeColor: string;
5
+ mutedColor: string;
6
+ textStyle?: StyleProp<TextStyle>;
7
+ duration?: number;
8
+ highlightWidth?: number;
9
+ pause?: number;
10
+ direction?: "ltr" | "rtl";
11
+ };
12
+ export declare function ShimmerText({ text, activeColor, mutedColor, textStyle, duration, highlightWidth, pause, direction, }: ShimmerTextProps): import("react").JSX.Element;
13
+ //# sourceMappingURL=shimmer-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shimmer-text.d.ts","sourceRoot":"","sources":["../../../../src/text/shimmer-text.tsx"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AA0B1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;CAC3B,CAAC;AAIF,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,WAAW,EACX,UAAU,EACV,SAA8B,EAC9B,QAA2B,EAC3B,cAAwC,EACxC,KAAS,EACT,SAAiB,GAClB,EAAE,gBAAgB,+BA2DlB"}
@@ -0,0 +1,15 @@
1
+ import { type StyleProp, type TextStyle, type ViewStyle } from "react-native";
2
+ import { type MotionPalette } from "../theme/palette.js";
3
+ export type SpokenTextProps = {
4
+ text: string;
5
+ spoken: number;
6
+ textStyle?: StyleProp<TextStyle>;
7
+ activeColor?: string;
8
+ spokenColor?: string;
9
+ upcomingColor?: string;
10
+ align?: "left" | "center";
11
+ colors?: Partial<MotionPalette>;
12
+ style?: StyleProp<ViewStyle>;
13
+ };
14
+ export declare function SpokenText({ text, spoken, textStyle, activeColor, spokenColor, upcomingColor, align, colors, style, }: SpokenTextProps): import("react").JSX.Element;
15
+ //# sourceMappingURL=spoken-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spoken-text.d.ts","sourceRoot":"","sources":["../../../../src/text/spoken-text.tsx"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE1F,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAkB,CAAC;AAKtD,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AAEF,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,MAAM,EACN,SAA8B,EAC9B,WAAW,EACX,WAAW,EACX,aAAa,EACb,KAAgB,EAChB,MAAM,EACN,KAAK,GACN,EAAE,eAAe,+BAqCjB"}
@@ -0,0 +1,16 @@
1
+ import { type ReactNode } from "react";
2
+ import { type StyleProp, type TextStyle, type ViewStyle } from "react-native";
3
+ import { type MotionPalette } from "../theme/palette.js";
4
+ export type StreamingTextProps = {
5
+ text: string;
6
+ streaming: boolean;
7
+ textStyle?: StyleProp<TextStyle>;
8
+ paragraphGap?: number;
9
+ fadeDuration?: number;
10
+ rise?: number;
11
+ caret?: boolean | ReactNode;
12
+ colors?: Partial<MotionPalette>;
13
+ style?: StyleProp<ViewStyle>;
14
+ };
15
+ export declare function StreamingText({ text, streaming, textStyle, paragraphGap, fadeDuration, rise, caret, colors, style, }: StreamingTextProps): import("react").JSX.Element;
16
+ //# sourceMappingURL=streaming-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"streaming-text.d.ts","sourceRoot":"","sources":["../../../../src/text/streaming-text.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA4C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACjF,OAAO,EAA0B,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAWtG,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAkB,CAAC;AAQtD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B,CAAC;AASF,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,SAAS,EACT,SAA8B,EAC9B,YAAiB,EACjB,YAA2B,EAC3B,IAAmB,EACnB,KAAY,EACZ,MAAM,EACN,KAAK,GACN,EAAE,kBAAkB,+BA4CpB"}
@@ -0,0 +1,3 @@
1
+ export { moodstone, moodstoneSwatches, type MotionPalette, type MotionPaletteSet, } from "./palette.js";
2
+ export { MotionThemeProvider, useMotionPalette, type MotionThemeProviderProps, } from "./provider.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/theme/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,iBAAiB,EACjB,KAAK,aAAa,EAClB,KAAK,gBAAgB,GACtB,MAAM,cAAW,CAAC;AACnB,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,KAAK,wBAAwB,GAC9B,MAAM,eAAY,CAAC"}
@@ -0,0 +1,33 @@
1
+ export type MotionPalette = {
2
+ background: string;
3
+ card: string;
4
+ surface: string;
5
+ raised: string;
6
+ text: string;
7
+ textSecondary: string;
8
+ textTertiary: string;
9
+ accent: string;
10
+ accentContrast: string;
11
+ success: string;
12
+ danger: string;
13
+ };
14
+ export type MotionPaletteSet = {
15
+ light: MotionPalette;
16
+ dark: MotionPalette;
17
+ };
18
+ export declare const moodstone: MotionPaletteSet;
19
+ export declare const moodstoneSwatches: {
20
+ readonly sand: "#F5D48A";
21
+ readonly sun: "#FFD447";
22
+ readonly tangerine: "#FF9F43";
23
+ readonly blossom: "#F48FB1";
24
+ readonly coral: "#F2705B";
25
+ readonly ember: "#D63A2F";
26
+ readonly lilac: "#C9B8F0";
27
+ readonly sky: "#3FC1F5";
28
+ readonly plum: "#9B59B6";
29
+ readonly lime: "#C5D94A";
30
+ readonly mint: "#5FC7B0";
31
+ readonly pine: "#1F8A70";
32
+ };
33
+ //# sourceMappingURL=palette.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../../../src/theme/palette.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,aAAa,CAAC;IACrB,IAAI,EAAE,aAAa,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,gBA2BvB,CAAC;AAEF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;CAapB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type ReactNode } from "react";
2
+ import { type MotionPalette } from "./palette.js";
3
+ export type MotionThemeProviderProps = {
4
+ palette?: Partial<MotionPalette> | {
5
+ light?: Partial<MotionPalette>;
6
+ dark?: Partial<MotionPalette>;
7
+ };
8
+ colorScheme?: "light" | "dark";
9
+ children?: ReactNode;
10
+ };
11
+ export declare function MotionThemeProvider({ palette, colorScheme, children }: MotionThemeProviderProps): import("react").JSX.Element;
12
+ export declare function useMotionPalette(override?: Partial<MotionPalette>): MotionPalette;
13
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../../src/theme/provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE3E,OAAO,EAAa,KAAK,aAAa,EAAyB,MAAM,cAAW,CAAC;AASjF,MAAM,MAAM,wBAAwB,GAAG;IACrC,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,CAAA;KAAE,CAAC;IACrG,WAAW,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAQF,wBAAgB,mBAAmB,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,EAAE,wBAAwB,+BAsB/F;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAAG,aAAa,CAMjF"}
package/package.json CHANGED
@@ -1,6 +1,135 @@
1
1
  {
2
2
  "name": "react-native-ai-animations",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.8.1",
4
+ "description": "Animated React Native and Expo components for AI chat apps: streaming text, shimmer loading text, thinking and status indicators, voice orbs and waveforms, image and video generation loaders, question cards and reasoning effort bars. Built on Reanimated and Skia.",
5
+ "license": "MIT",
6
+ "author": "Ahmet Kar",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/AhmeetKaar/nami-motion.git"
10
+ },
11
+ "homepage": "https://nami-motion-web.vercel.app/",
12
+ "keywords": [
13
+ "react-native",
14
+ "expo",
15
+ "ai",
16
+ "ai-chat",
17
+ "chatbot",
18
+ "llm",
19
+ "chat-ui",
20
+ "animation",
21
+ "animations",
22
+ "reanimated",
23
+ "skia",
24
+ "streaming-text",
25
+ "shimmer",
26
+ "loading",
27
+ "loader",
28
+ "typing-indicator",
29
+ "thinking",
30
+ "reasoning",
31
+ "voice",
32
+ "waveform",
33
+ "orb",
34
+ "generative-ui",
35
+ "ios",
36
+ "android"
37
+ ],
38
+ "sideEffects": false,
39
+ "main": "./lib/module/index.js",
40
+ "types": "./lib/typescript/src/index.d.ts",
41
+ "source": "./src/index.ts",
42
+ "exports": {
43
+ ".": {
44
+ "source": "./src/index.ts",
45
+ "types": "./lib/typescript/src/index.d.ts",
46
+ "default": "./lib/module/index.js"
47
+ },
48
+ "./theme": {
49
+ "source": "./src/theme/index.ts",
50
+ "types": "./lib/typescript/src/theme/index.d.ts",
51
+ "default": "./lib/module/theme/index.js"
52
+ },
53
+ "./text": {
54
+ "source": "./src/text/index.ts",
55
+ "types": "./lib/typescript/src/text/index.d.ts",
56
+ "default": "./lib/module/text/index.js"
57
+ },
58
+ "./brand": {
59
+ "source": "./src/brand/index.ts",
60
+ "types": "./lib/typescript/src/brand/index.d.ts",
61
+ "default": "./lib/module/brand/index.js"
62
+ },
63
+ "./chat": {
64
+ "source": "./src/chat/index.ts",
65
+ "types": "./lib/typescript/src/chat/index.d.ts",
66
+ "default": "./lib/module/chat/index.js"
67
+ },
68
+ "./skia": {
69
+ "source": "./src/skia/index.ts",
70
+ "types": "./lib/typescript/src/skia/index.d.ts",
71
+ "default": "./lib/module/skia/index.js"
72
+ },
73
+ "./package.json": "./package.json"
74
+ },
75
+ "files": [
76
+ "src",
77
+ "lib",
78
+ "!**/__tests__",
79
+ "LICENSE",
80
+ "README.md"
81
+ ],
82
+ "scripts": {
83
+ "build": "bob build",
84
+ "typecheck": "tsc --noEmit",
85
+ "prepack": "bob build",
86
+ "changeset": "changeset",
87
+ "release": "bob build && changeset publish"
88
+ },
89
+ "peerDependencies": {
90
+ "@shopify/react-native-skia": ">=2.4.0",
91
+ "react": ">=19.2.0",
92
+ "react-native": ">=0.83.0",
93
+ "react-native-reanimated": ">=4.2.0",
94
+ "react-native-worklets": ">=0.7.0"
95
+ },
96
+ "peerDependenciesMeta": {
97
+ "@shopify/react-native-skia": {
98
+ "optional": true
99
+ }
100
+ },
101
+ "react-native-builder-bob": {
102
+ "source": "src",
103
+ "output": "lib",
104
+ "targets": [
105
+ [
106
+ "module",
107
+ {
108
+ "esm": true
109
+ }
110
+ ],
111
+ [
112
+ "typescript",
113
+ {
114
+ "project": "tsconfig.build.json"
115
+ }
116
+ ]
117
+ ]
118
+ },
119
+ "publishConfig": {
120
+ "access": "public",
121
+ "provenance": true
122
+ },
123
+ "devDependencies": {
124
+ "@changesets/cli": "^3.0.3",
125
+ "@shopify/react-native-skia": "2.4.18",
126
+ "@types/react": "~19.2.2",
127
+ "react": "19.2.0",
128
+ "react-native": "0.83.10",
129
+ "react-native-builder-bob": "^0.43.2",
130
+ "react-native-reanimated": "4.2.1",
131
+ "react-native-worklets": "0.7.4",
132
+ "typescript": "~5.9.2"
133
+ },
134
+ "packageManager": "npm@11.6.2"
135
+ }
@@ -0,0 +1,5 @@
1
+ export {
2
+ SpinningMark,
3
+ type SpinningMarkBreathe,
4
+ type SpinningMarkProps,
5
+ } from "./spinning-mark";
@@ -0,0 +1,118 @@
1
+ import { useEffect, type ReactNode } from "react";
2
+ import { type StyleProp, type ViewStyle } from "react-native";
3
+ import Animated, {
4
+ cancelAnimation,
5
+ Easing,
6
+ type EasingFunction,
7
+ useAnimatedStyle,
8
+ useReducedMotion,
9
+ useSharedValue,
10
+ withRepeat,
11
+ withSequence,
12
+ withSpring,
13
+ withTiming,
14
+ } from "react-native-reanimated";
15
+
16
+ const DEFAULT_DURATION = 3630;
17
+ const DEFAULT_BREATHE = { scale: 1.06, duration: 1800 };
18
+ const ENTRANCE_SPRING = { damping: 14, stiffness: 120, mass: 1 };
19
+
20
+ export type SpinningMarkBreathe = { scale?: number; duration?: number };
21
+
22
+ export type SpinningMarkProps = {
23
+ children: ReactNode;
24
+ size?: number;
25
+ duration?: number;
26
+ direction?: "clockwise" | "counterclockwise";
27
+ easing?: EasingFunction;
28
+ breathe?: boolean | SpinningMarkBreathe;
29
+ entrance?: boolean;
30
+ paused?: boolean;
31
+ style?: StyleProp<ViewStyle>;
32
+ accessibilityLabel?: string;
33
+ };
34
+
35
+ export function SpinningMark({
36
+ children,
37
+ size,
38
+ duration = DEFAULT_DURATION,
39
+ direction = "clockwise",
40
+ easing = Easing.linear,
41
+ breathe = false,
42
+ entrance = false,
43
+ paused = false,
44
+ style,
45
+ accessibilityLabel,
46
+ }: SpinningMarkProps) {
47
+ const reduceMotion = useReducedMotion();
48
+ const angle = useSharedValue(0);
49
+ const pulse = useSharedValue(1);
50
+ const intro = useSharedValue(entrance && !reduceMotion ? 0 : 1);
51
+ const sign = direction === "clockwise" ? 1 : -1;
52
+ const breatheScale = breathe ? ((breathe === true ? undefined : breathe.scale) ?? DEFAULT_BREATHE.scale) : 1;
53
+ const breatheDuration = breathe
54
+ ? ((breathe === true ? undefined : breathe.duration) ?? DEFAULT_BREATHE.duration)
55
+ : 0;
56
+
57
+ useEffect(() => {
58
+ if (reduceMotion || paused) {
59
+ cancelAnimation(angle);
60
+ return;
61
+ }
62
+ const start = angle.value % 360;
63
+ angle.value = start;
64
+ angle.value = withRepeat(withTiming(start + 360, { duration, easing }), -1, false);
65
+ return () => cancelAnimation(angle);
66
+ }, [angle, duration, easing, paused, reduceMotion]);
67
+
68
+ useEffect(() => {
69
+ if (reduceMotion || paused || breatheScale === 1) {
70
+ cancelAnimation(pulse);
71
+ pulse.value = withTiming(1, { duration: 200 });
72
+ return;
73
+ }
74
+ const half = breatheDuration / 2;
75
+ const curve = Easing.inOut(Easing.sin);
76
+ pulse.value = withRepeat(
77
+ withSequence(
78
+ withTiming(breatheScale, { duration: half, easing: curve }),
79
+ withTiming(1, { duration: half, easing: curve }),
80
+ ),
81
+ -1,
82
+ false,
83
+ );
84
+ return () => cancelAnimation(pulse);
85
+ }, [breatheDuration, breatheScale, paused, pulse, reduceMotion]);
86
+
87
+ useEffect(() => {
88
+ if (!entrance || reduceMotion) {
89
+ intro.value = 1;
90
+ return;
91
+ }
92
+ intro.value = withSpring(1, ENTRANCE_SPRING);
93
+ }, [entrance, intro, reduceMotion]);
94
+
95
+ const animatedStyle = useAnimatedStyle(() => ({
96
+ opacity: Math.min(1, intro.value * 1.4),
97
+ transform: [
98
+ { rotate: `${sign * angle.value - (1 - intro.value) * 90 * sign}deg` },
99
+ { scale: pulse.value * (0.6 + intro.value * 0.4) },
100
+ ],
101
+ }));
102
+
103
+ return (
104
+ <Animated.View
105
+ accessible={!!accessibilityLabel}
106
+ accessibilityRole={accessibilityLabel ? "image" : undefined}
107
+ accessibilityLabel={accessibilityLabel}
108
+ style={[
109
+ size !== undefined && { width: size, height: size },
110
+ { alignItems: "center", justifyContent: "center" },
111
+ style,
112
+ animatedStyle,
113
+ ]}
114
+ >
115
+ {children}
116
+ </Animated.View>
117
+ );
118
+ }