react-native-ai-animations 0.0.0-stage → 0.8.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.
Files changed (125) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +174 -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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ahmet Kar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,175 @@
1
- # Temporary Holding Version
1
+ # React Native AI Animations
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Animated React Native and Expo components for AI chat apps: streaming text,
4
+ shimmer loading text, thinking and status indicators, voice orbs and
5
+ waveforms, image and video generation loaders, question cards and reasoning
6
+ effort bars. Built on Reanimated and Skia, themeable, and reduce motion aware.
7
+
8
+ ```bash
9
+ npx expo install react-native-ai-animations react-native-reanimated react-native-worklets
10
+ ```
11
+
12
+ Formerly published as `nami-motion`: replace `nami-motion` with
13
+ `react-native-ai-animations` in your imports.
14
+
15
+ ## Components
16
+
17
+ <table>
18
+ <tr>
19
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/spinning-mark.gif" width="200" alt="Spinning Mark recording" /><br /><b>Spinning Mark</b><br /><code>react-native-ai-animations/brand</code></td>
20
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/shimmer-text.gif" width="200" alt="Shimmer Text recording" /><br /><b>Shimmer Text</b><br /><code>react-native-ai-animations/text</code></td>
21
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/streaming-text.gif" width="200" alt="Streaming Text recording" /><br /><b>Streaming Text</b><br /><code>react-native-ai-animations/text</code></td>
22
+ </tr>
23
+ <tr>
24
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/status-row.gif" width="200" alt="Status Row recording" /><br /><b>Status Row</b><br /><code>react-native-ai-animations/chat</code></td>
25
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/thinking-block.gif" width="200" alt="Thinking Block recording" /><br /><b>Thinking Block</b><br /><code>react-native-ai-animations/chat</code></td>
26
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/question-card.gif" width="200" alt="Question Card recording" /><br /><b>Question Card</b><br /><code>react-native-ai-animations/chat</code></td>
27
+ </tr>
28
+ <tr>
29
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/effort-bar.gif" width="200" alt="Effort Bar recording" /><br /><b>Effort Bar</b><br /><code>react-native-ai-animations/chat</code></td>
30
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/media-generating.gif" width="200" alt="Media Generating recording" /><br /><b>Media Generating</b><br /><code>react-native-ai-animations/skia</code></td>
31
+ <td align="center" valign="top" width="33%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/voice-wave.gif" width="200" alt="Voice Wave recording" /><br /><b>Voice Wave</b><br /><code>react-native-ai-animations/skia</code></td>
32
+ </tr>
33
+ </table>
34
+
35
+ <table>
36
+ <tr>
37
+ <td align="center" valign="top" width="50%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/shimmer-text.gif" width="160" alt="Shimmer Text recording" /><br /><b>Shimmer Text</b><br /><code>react-native-ai-animations/text</code><br /><a href="https://github.com/AhmeetKaar/nami-motion/raw/main/media/shimmer-text.mp4">10s video</a></td>
38
+ <td align="center" valign="top" width="50%"><img src="https://raw.githubusercontent.com/AhmeetKaar/nami-motion/main/media/voice-wave.gif" width="160" alt="Voice Wave recording" /><br /><b>Voice Wave</b><br /><code>react-native-ai-animations/skia</code><br /><a href="https://github.com/AhmeetKaar/nami-motion/raw/main/media/voice-wave.mp4">10s video</a></td>
39
+ </tr>
40
+ </table>
41
+
42
+ | Component | Entry | What it does |
43
+ | --- | --- | --- |
44
+ | Shimmer Text | `react-native-ai-animations/text` | A light band sweeping across text while a response is being generated. |
45
+ | Streaming Text | `react-native-ai-animations/text` | Words of a streaming answer fade and rise in, with a blinking caret. |
46
+ | Spoken Text | `react-native-ai-animations/text` | Highlights the word being spoken and dims the words already read aloud, for voice replies. |
47
+ | Spinning Mark | `react-native-ai-animations/brand` | Spins any icon you pass (your logo) with optional breathing and entrance. |
48
+ | Media Generating | `react-native-ai-animations/skia` | One loading state shared by image and video generation, with six variants (blobs, matrix, orbit, scan, constellation, helix). `ImageGenerating` and `VideoGenerating` are its presets. |
49
+ | DotOrb | `react-native-ai-animations/skia` | Dot sphere pictures behind the media variants, also usable on their own. |
50
+ | Liquid Orb | `react-native-ai-animations/skia` | Liquid voice orb in metal, water, iridescent or ring material that reacts to idle, listening, thinking and speaking states and a live level. |
51
+ | Voice Wave | `react-native-ai-animations/skia` | Live microphone waveform in four styles: lines, bars, dots and pulse. |
52
+ | Status Row | `react-native-ai-animations/chat` | Pulsing icon, shimmering label and elapsed timer for agent status. |
53
+ | Thinking Block | `react-native-ai-animations/chat` | "Thought for Ns" header that springs open into a step timeline. |
54
+ | Question Card | `react-native-ai-animations/chat` | Paged questions with numbered options and a custom answer, for cards or sheets. |
55
+ | Effort Bar | `react-native-ai-animations/chat` | Reasoning effort bar wired to `reasoning.effort` (low, medium, high) in four styles: rising bars (default), track, segmented pill and a slider whose knob stretches as you drag and snaps to a level under a tab with your model name, each with a compact form and a per level icon. |
56
+
57
+ Every style is also its own component with the same props minus `variant`:
58
+ `VoiceWaveLines`, `VoiceWaveBars`, `VoiceWaveDots` and `VoiceWavePulse`;
59
+ `EffortBars`, `EffortTrack`, `EffortSegmented` and
60
+ `EffortSlider`; `MediaGeneratingBlobs`, `MediaGeneratingMatrix`,
61
+ `MediaGeneratingOrbit`, `MediaGeneratingScan`, `MediaGeneratingConstellation`
62
+ and `MediaGeneratingHelix`; and `QuestionSheet`.
63
+
64
+ Every component takes its icon, font, colors and timing as props and falls back
65
+ to a static state when reduce motion is on. `react-native-ai-animations/theme` ships the
66
+ Moodstone palette with `MotionThemeProvider` and `useMotionPalette`; pass
67
+ `colors` to override one component.
68
+
69
+ Optional peer: `@shopify/react-native-skia` for `react-native-ai-animations/skia`.
70
+
71
+ ### Shimmer Text
72
+
73
+ ```tsx
74
+ import { ShimmerText } from "react-native-ai-animations/text";
75
+
76
+ <ShimmerText text="Generating a response" activeColor={colors.text} mutedColor={colors.textTertiary} />;
77
+ ```
78
+
79
+ ### Spinning Mark
80
+
81
+ ```tsx
82
+ import { SpinningMark } from "react-native-ai-animations/brand";
83
+
84
+ <SpinningMark size={160} duration={3600} breathe entrance>
85
+ <Image source={require("./logo.png")} style={{ width: 160, height: 160 }} />
86
+ </SpinningMark>;
87
+ ```
88
+
89
+ ### Streaming Text, Status Row, Thinking Block
90
+
91
+ ```tsx
92
+ import { StreamingText } from "react-native-ai-animations/text";
93
+ import { StatusRow, ThinkingBlock } from "react-native-ai-animations/chat";
94
+
95
+ <StatusRow label="Searching the web" icon={<Logo />} startedAt={startedAt} />;
96
+ <ThinkingBlock thinking={thinking} startedAt={startedAt} steps={steps} />;
97
+ <StreamingText text={answer} streaming={streaming} textStyle={{ fontFamily: "Inter" }} />;
98
+ ```
99
+
100
+ ### Media Generating (shared by image and video)
101
+
102
+ ```tsx
103
+ import { ImageGenerating, MediaGenerating, VideoGenerating } from "react-native-ai-animations/skia";
104
+
105
+ <MediaGenerating variant="constellation" label="Creating image" startedAt={startedAt} />;
106
+ <MediaGenerating variant="scan" chrome="overlay" status="generating" progress={0.42} meta="720p · 6s" aspectRatio={16 / 9} />;
107
+ <ImageGenerating variant="helix" startedAt={startedAt} />;
108
+ <VideoGenerating status="queued" variant="orbit" />;
109
+ ```
110
+
111
+ ### Effort Bar
112
+
113
+ `REASONING_EFFORTS` matches the `reasoning.effort` values OpenRouter and most reasoning APIs take (`low`, `medium`, `high`), with each level's share of max_tokens. `variant` picks the style: `bars` (default), `track`, `segmented` or `slider`; `size="compact"` gives each one a small inline form for model rows, `fillColors` tints any of them, `tabLabel` puts your model name in the slider's tab and `levelIcon` swaps every level name for your own icon, so the state reads without text. EffortBar is only the bar: put your own title, level label or description around it, wherever your UX needs it.
114
+
115
+ ```tsx
116
+ import { EffortBar, REASONING_EFFORTS, reasoningRequest } from "react-native-ai-animations/chat";
117
+
118
+ <EffortBar levels={REASONING_EFFORTS} value={index} onChange={(i, level) => setEffort(level.value)} accessibilityLabel="Reasoning" />;
119
+ <EffortBar levels={REASONING_EFFORTS} value={index} onChange={(i) => setIndex(i)} variant="segmented" />;
120
+ <EffortBar levels={REASONING_EFFORTS} value={index} onChange={(i) => setIndex(i)} variant="slider" tabLabel={model.name} fillColors={["#5AA2FF", "#2F7BF5"]} levelIcon={(i, color) => <BrainIcon level={i} color={color} />} />;
121
+ <EffortBar levels={REASONING_EFFORTS} value={index} variant="slider" size="compact" />;
122
+
123
+ const body = { model, messages, max_tokens: 16000, ...reasoningRequest(effort) };
124
+ ```
125
+
126
+ ### Question Card
127
+
128
+ ```tsx
129
+ import { QuestionCard } from "react-native-ai-animations/chat";
130
+
131
+ <QuestionCard questions={questions} variant="sheet" onSubmit={(answers) => send(answers)} />;
132
+ ```
133
+
134
+ Both components take a `ref` with `select(index)`, `goTo(page)` and `submit()`, so a demo, a voice flow or a test can drive the questions without touches.
135
+
136
+ ### Voice Wave
137
+
138
+ ```tsx
139
+ import { useSharedValue } from "react-native-reanimated";
140
+ import { VoiceWave } from "react-native-ai-animations/skia";
141
+
142
+ const level = useSharedValue(0);
143
+
144
+ <VoiceWave level={level} variant="bars" colors={["#1F8A70", "#88C9F7", "#5FC7B0"]} />;
145
+ ```
146
+
147
+ ### Liquid Orb and Spoken Text (voice mode)
148
+
149
+ `LiquidOrb` is a Skia liquid orb in `metal`, `water` or `iridescent`, or three glowing loops with `ring` (color them with `colors`); `state` switches between `idle`, `listening`, `thinking` and `speaking`, and `level` (0-1) makes it swell while listening or speaking. `SpokenText` highlights the word being read aloud: pass the index of the current word as `spoken`.
150
+
151
+ ```tsx
152
+ import { useSharedValue } from "react-native-reanimated";
153
+ import { LiquidOrb } from "react-native-ai-animations/skia";
154
+ import { SpokenText } from "react-native-ai-animations/text";
155
+
156
+ const level = useSharedValue(0);
157
+
158
+ <LiquidOrb material="water" state={isRecording ? "listening" : "idle"} level={level} size={240} />;
159
+ <LiquidOrb material="ring" state="listening" level={level} size={240} colors={["#1F8A70", "#88C9F7", "#5FC7B0"]} />;
160
+ <SpokenText text={reply} spoken={wordIndex} textStyle={{ fontFamily: "Inter", fontSize: 20, lineHeight: 28 }} />;
161
+ ```
162
+
163
+ ## Development
164
+
165
+ ```bash
166
+ npm install
167
+ npm run typecheck
168
+ npm run build
169
+ ```
170
+
171
+ Changes that affect the package need a changeset: `npm run changeset`.
172
+
173
+ ## License
174
+
175
+ MIT.
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export { SpinningMark } from "./spinning-mark.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["SpinningMark"],"sourceRoot":"../../../src","sources":["brand/index.ts"],"mappings":";;AAAA,SACEA,YAAY,QAGP,oBAAiB","ignoreList":[]}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+
3
+ import { useEffect } from "react";
4
+ import Animated, { cancelAnimation, Easing, useAnimatedStyle, useReducedMotion, useSharedValue, withRepeat, withSequence, withSpring, withTiming } from "react-native-reanimated";
5
+ import { jsx as _jsx } from "react/jsx-runtime";
6
+ const DEFAULT_DURATION = 3630;
7
+ const DEFAULT_BREATHE = {
8
+ scale: 1.06,
9
+ duration: 1800
10
+ };
11
+ const ENTRANCE_SPRING = {
12
+ damping: 14,
13
+ stiffness: 120,
14
+ mass: 1
15
+ };
16
+ export function SpinningMark({
17
+ children,
18
+ size,
19
+ duration = DEFAULT_DURATION,
20
+ direction = "clockwise",
21
+ easing = Easing.linear,
22
+ breathe = false,
23
+ entrance = false,
24
+ paused = false,
25
+ style,
26
+ accessibilityLabel
27
+ }) {
28
+ const reduceMotion = useReducedMotion();
29
+ const angle = useSharedValue(0);
30
+ const pulse = useSharedValue(1);
31
+ const intro = useSharedValue(entrance && !reduceMotion ? 0 : 1);
32
+ const sign = direction === "clockwise" ? 1 : -1;
33
+ const breatheScale = breathe ? (breathe === true ? undefined : breathe.scale) ?? DEFAULT_BREATHE.scale : 1;
34
+ const breatheDuration = breathe ? (breathe === true ? undefined : breathe.duration) ?? DEFAULT_BREATHE.duration : 0;
35
+ useEffect(() => {
36
+ if (reduceMotion || paused) {
37
+ cancelAnimation(angle);
38
+ return;
39
+ }
40
+ const start = angle.value % 360;
41
+ angle.value = start;
42
+ angle.value = withRepeat(withTiming(start + 360, {
43
+ duration,
44
+ easing
45
+ }), -1, false);
46
+ return () => cancelAnimation(angle);
47
+ }, [angle, duration, easing, paused, reduceMotion]);
48
+ useEffect(() => {
49
+ if (reduceMotion || paused || breatheScale === 1) {
50
+ cancelAnimation(pulse);
51
+ pulse.value = withTiming(1, {
52
+ duration: 200
53
+ });
54
+ return;
55
+ }
56
+ const half = breatheDuration / 2;
57
+ const curve = Easing.inOut(Easing.sin);
58
+ pulse.value = withRepeat(withSequence(withTiming(breatheScale, {
59
+ duration: half,
60
+ easing: curve
61
+ }), withTiming(1, {
62
+ duration: half,
63
+ easing: curve
64
+ })), -1, false);
65
+ return () => cancelAnimation(pulse);
66
+ }, [breatheDuration, breatheScale, paused, pulse, reduceMotion]);
67
+ useEffect(() => {
68
+ if (!entrance || reduceMotion) {
69
+ intro.value = 1;
70
+ return;
71
+ }
72
+ intro.value = withSpring(1, ENTRANCE_SPRING);
73
+ }, [entrance, intro, reduceMotion]);
74
+ const animatedStyle = useAnimatedStyle(() => ({
75
+ opacity: Math.min(1, intro.value * 1.4),
76
+ transform: [{
77
+ rotate: `${sign * angle.value - (1 - intro.value) * 90 * sign}deg`
78
+ }, {
79
+ scale: pulse.value * (0.6 + intro.value * 0.4)
80
+ }]
81
+ }));
82
+ return /*#__PURE__*/_jsx(Animated.View, {
83
+ accessible: !!accessibilityLabel,
84
+ accessibilityRole: accessibilityLabel ? "image" : undefined,
85
+ accessibilityLabel: accessibilityLabel,
86
+ style: [size !== undefined && {
87
+ width: size,
88
+ height: size
89
+ }, {
90
+ alignItems: "center",
91
+ justifyContent: "center"
92
+ }, style, animatedStyle],
93
+ children: children
94
+ });
95
+ }
96
+ //# sourceMappingURL=spinning-mark.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useEffect","Animated","cancelAnimation","Easing","useAnimatedStyle","useReducedMotion","useSharedValue","withRepeat","withSequence","withSpring","withTiming","jsx","_jsx","DEFAULT_DURATION","DEFAULT_BREATHE","scale","duration","ENTRANCE_SPRING","damping","stiffness","mass","SpinningMark","children","size","direction","easing","linear","breathe","entrance","paused","style","accessibilityLabel","reduceMotion","angle","pulse","intro","sign","breatheScale","undefined","breatheDuration","start","value","half","curve","inOut","sin","animatedStyle","opacity","Math","min","transform","rotate","View","accessible","accessibilityRole","width","height","alignItems","justifyContent"],"sourceRoot":"../../../src","sources":["brand/spinning-mark.tsx"],"mappings":"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","ignoreList":[]}