expo-orb 0.1.0 → 0.2.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 (39) hide show
  1. package/README.md +1 -1
  2. package/android/src/main/java/expo/modules/breathing/BreathingConfiguration.kt +20 -0
  3. package/android/src/main/java/expo/modules/breathing/BreathingExerciseView.kt +247 -0
  4. package/android/src/main/java/expo/modules/breathing/BreathingSharedState.kt +104 -0
  5. package/android/src/main/java/expo/modules/breathing/BreathingTextCue.kt +41 -0
  6. package/android/src/main/java/expo/modules/breathing/ExpoBreathingExerciseModule.kt +156 -0
  7. package/android/src/main/java/expo/modules/breathing/ExpoBreathingExerciseView.kt +123 -0
  8. package/android/src/main/java/expo/modules/breathing/MorphingBlobView.kt +128 -0
  9. package/android/src/main/java/expo/modules/breathing/ProgressRingView.kt +50 -0
  10. package/build/ExpoBreathingExercise.types.d.ts +48 -0
  11. package/build/ExpoBreathingExercise.types.d.ts.map +1 -0
  12. package/build/ExpoBreathingExercise.types.js +2 -0
  13. package/build/ExpoBreathingExercise.types.js.map +1 -0
  14. package/build/ExpoBreathingExerciseModule.d.ts +16 -0
  15. package/build/ExpoBreathingExerciseModule.d.ts.map +1 -0
  16. package/build/ExpoBreathingExerciseModule.js +52 -0
  17. package/build/ExpoBreathingExerciseModule.js.map +1 -0
  18. package/build/ExpoBreathingExerciseView.d.ts +4 -0
  19. package/build/ExpoBreathingExerciseView.d.ts.map +1 -0
  20. package/build/ExpoBreathingExerciseView.js +7 -0
  21. package/build/ExpoBreathingExerciseView.js.map +1 -0
  22. package/build/index.d.ts +3 -0
  23. package/build/index.d.ts.map +1 -1
  24. package/build/index.js +3 -0
  25. package/build/index.js.map +1 -1
  26. package/expo-module.config.json +2 -2
  27. package/ios/Breathing/BreathingConfiguration.swift +57 -0
  28. package/ios/Breathing/BreathingExerciseView.swift +451 -0
  29. package/ios/Breathing/BreathingSharedState.swift +84 -0
  30. package/ios/Breathing/BreathingTextCue.swift +14 -0
  31. package/ios/Breathing/MorphingBlobView.swift +242 -0
  32. package/ios/Breathing/ProgressRingView.swift +27 -0
  33. package/ios/ExpoBreathingExerciseModule.swift +182 -0
  34. package/ios/ExpoBreathingExerciseView.swift +124 -0
  35. package/package.json +8 -5
  36. package/src/ExpoBreathingExercise.types.ts +50 -0
  37. package/src/ExpoBreathingExerciseModule.ts +67 -0
  38. package/src/ExpoBreathingExerciseView.tsx +11 -0
  39. package/src/index.ts +11 -0
@@ -0,0 +1,128 @@
1
+ package expo.modules.breathing
2
+
3
+ import androidx.compose.foundation.Canvas
4
+ import androidx.compose.runtime.Composable
5
+ import androidx.compose.ui.Modifier
6
+ import androidx.compose.ui.geometry.Offset
7
+ import androidx.compose.ui.graphics.Brush
8
+ import androidx.compose.ui.graphics.Color
9
+ import androidx.compose.ui.graphics.Path
10
+ import androidx.compose.ui.graphics.drawscope.DrawScope
11
+ import kotlin.math.PI
12
+ import kotlin.math.cos
13
+ import kotlin.math.min
14
+ import kotlin.math.sin
15
+ import kotlin.math.tan
16
+
17
+ @Composable
18
+ fun MorphingBlobView(
19
+ baseRadius: Float,
20
+ pointCount: Int,
21
+ offsets: List<Double>,
22
+ colors: List<Color>,
23
+ innerColor: Color,
24
+ showInnerBlob: Boolean,
25
+ modifier: Modifier = Modifier
26
+ ) {
27
+ Canvas(modifier = modifier) {
28
+ val size = min(this.size.width, this.size.height)
29
+ val center = Offset(this.size.width / 2f, this.size.height / 2f)
30
+ val effectiveRadius = baseRadius * size / 2f
31
+
32
+ // Draw main blob
33
+ val mainPath = createBlobPath(center, effectiveRadius, pointCount, offsets)
34
+ drawPath(
35
+ path = mainPath,
36
+ brush = Brush.radialGradient(
37
+ colors = colors,
38
+ center = center,
39
+ radius = effectiveRadius
40
+ )
41
+ )
42
+
43
+ // Draw inner blob for depth
44
+ if (showInnerBlob) {
45
+ val innerPath = createBlobPath(
46
+ center = center,
47
+ baseRadius = effectiveRadius * 0.6f,
48
+ pointCount = pointCount,
49
+ offsets = offsets.map { it * 0.7 }
50
+ )
51
+ drawPath(
52
+ path = innerPath,
53
+ color = innerColor
54
+ )
55
+ }
56
+ }
57
+ }
58
+
59
+ private fun DrawScope.createBlobPath(
60
+ center: Offset,
61
+ baseRadius: Float,
62
+ pointCount: Int,
63
+ offsets: List<Double>
64
+ ): Path {
65
+ val path = Path()
66
+ if (pointCount < 3) return path
67
+
68
+ // Generate points around the circle with offsets
69
+ val points = mutableListOf<Offset>()
70
+ for (i in 0 until pointCount) {
71
+ val angle = (i.toDouble() / pointCount) * 2 * PI - PI / 2
72
+ val offset = if (i < offsets.size) offsets[i] else 0.0
73
+ val radius = baseRadius * (1.0 + offset).toFloat()
74
+
75
+ points.add(
76
+ Offset(
77
+ x = center.x + (cos(angle) * radius).toFloat(),
78
+ y = center.y + (sin(angle) * radius).toFloat()
79
+ )
80
+ )
81
+ }
82
+
83
+ // Tangent coefficient for smooth cubic bezier curves
84
+ val tangentCoeff = ((4.0 / 3.0) * tan(PI / (2.0 * pointCount))).toFloat()
85
+
86
+ // Start at first point
87
+ path.moveTo(points[0].x, points[0].y)
88
+
89
+ // Draw cubic bezier curves between each pair of points
90
+ for (i in 0 until pointCount) {
91
+ val current = points[i]
92
+ val next = points[(i + 1) % pointCount]
93
+
94
+ // Calculate angles for tangent directions
95
+ val currentAngle = (i.toDouble() / pointCount) * 2 * PI - PI / 2
96
+ val nextAngle = (((i + 1) % pointCount).toDouble() / pointCount) * 2 * PI - PI / 2
97
+
98
+ // Current point's radius and tangent
99
+ val currentOffset = if (i < offsets.size) offsets[i] else 0.0
100
+ val currentRadius = baseRadius * (1.0 + currentOffset).toFloat()
101
+ val currentTangentLength = currentRadius * tangentCoeff
102
+
103
+ // Next point's radius and tangent
104
+ val nextOffset = if ((i + 1) % pointCount < offsets.size) offsets[(i + 1) % pointCount] else 0.0
105
+ val nextRadius = baseRadius * (1.0 + nextOffset).toFloat()
106
+ val nextTangentLength = nextRadius * tangentCoeff
107
+
108
+ // Control points are perpendicular to radial direction
109
+ val control1 = Offset(
110
+ x = current.x + (cos(currentAngle + PI / 2) * currentTangentLength).toFloat(),
111
+ y = current.y + (sin(currentAngle + PI / 2) * currentTangentLength).toFloat()
112
+ )
113
+
114
+ val control2 = Offset(
115
+ x = next.x + (cos(nextAngle - PI / 2) * nextTangentLength).toFloat(),
116
+ y = next.y + (sin(nextAngle - PI / 2) * nextTangentLength).toFloat()
117
+ )
118
+
119
+ path.cubicTo(
120
+ control1.x, control1.y,
121
+ control2.x, control2.y,
122
+ next.x, next.y
123
+ )
124
+ }
125
+
126
+ path.close()
127
+ return path
128
+ }
@@ -0,0 +1,50 @@
1
+ package expo.modules.breathing
2
+
3
+ import androidx.compose.foundation.Canvas
4
+ import androidx.compose.runtime.Composable
5
+ import androidx.compose.ui.Modifier
6
+ import androidx.compose.ui.geometry.Offset
7
+ import androidx.compose.ui.geometry.Size
8
+ import androidx.compose.ui.graphics.Color
9
+ import androidx.compose.ui.graphics.StrokeCap
10
+ import androidx.compose.ui.graphics.drawscope.Stroke
11
+ import kotlin.math.min
12
+
13
+ @Composable
14
+ fun ProgressRingView(
15
+ progress: Double,
16
+ color: Color,
17
+ lineWidth: Float,
18
+ modifier: Modifier = Modifier
19
+ ) {
20
+ Canvas(modifier = modifier) {
21
+ val size = min(this.size.width, this.size.height)
22
+ val radius = (size - lineWidth) / 2f
23
+ val center = Offset(this.size.width / 2f, this.size.height / 2f)
24
+ val topLeft = Offset(center.x - radius, center.y - radius)
25
+ val arcSize = Size(radius * 2, radius * 2)
26
+
27
+ // Background ring
28
+ drawArc(
29
+ color = color.copy(alpha = 0.2f),
30
+ startAngle = 0f,
31
+ sweepAngle = 360f,
32
+ useCenter = false,
33
+ topLeft = topLeft,
34
+ size = arcSize,
35
+ style = Stroke(width = lineWidth)
36
+ )
37
+
38
+ // Progress arc
39
+ val clampedProgress = progress.coerceIn(0.0, 1.0).toFloat()
40
+ drawArc(
41
+ color = color,
42
+ startAngle = -90f, // Start from top
43
+ sweepAngle = 360f * clampedProgress,
44
+ useCenter = false,
45
+ topLeft = topLeft,
46
+ size = arcSize,
47
+ style = Stroke(width = lineWidth, cap = StrokeCap.Round)
48
+ )
49
+ }
50
+ }
@@ -0,0 +1,48 @@
1
+ import type { ColorValue, StyleProp, ViewStyle } from 'react-native';
2
+ export type BreathPhase = 'inhale' | 'holdIn' | 'exhale' | 'holdOut';
3
+ export interface BreathPhaseConfig {
4
+ phase: BreathPhase;
5
+ duration: number;
6
+ targetScale: number;
7
+ label: string;
8
+ }
9
+ export interface BreathingPattern {
10
+ phases: BreathPhaseConfig[];
11
+ cycles?: number;
12
+ }
13
+ export type BreathingPreset = 'relaxing' | 'box' | 'energizing' | 'calming';
14
+ export interface PhaseChangeEvent {
15
+ phase: BreathPhase;
16
+ label: string;
17
+ phaseIndex: number;
18
+ cycle: number;
19
+ }
20
+ export interface ExerciseCompleteEvent {
21
+ totalCycles: number;
22
+ totalDuration: number;
23
+ }
24
+ export interface ExpoBreathingExerciseViewProps {
25
+ blobColors?: ColorValue[];
26
+ innerBlobColor?: ColorValue;
27
+ glowColor?: ColorValue;
28
+ particleColor?: ColorValue;
29
+ progressRingColor?: ColorValue;
30
+ textColor?: ColorValue;
31
+ showProgressRing?: boolean;
32
+ showTextCue?: boolean;
33
+ showInnerBlob?: boolean;
34
+ showShadow?: boolean;
35
+ showParticles?: boolean;
36
+ showWavyBlobs?: boolean;
37
+ showGlowEffects?: boolean;
38
+ pointCount?: number;
39
+ wobbleIntensity?: number;
40
+ onPhaseChange?: (event: {
41
+ nativeEvent: PhaseChangeEvent;
42
+ }) => void;
43
+ onExerciseComplete?: (event: {
44
+ nativeEvent: ExerciseCompleteEvent;
45
+ }) => void;
46
+ style?: StyleProp<ViewStyle>;
47
+ }
48
+ //# sourceMappingURL=ExpoBreathingExercise.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoBreathingExercise.types.d.ts","sourceRoot":"","sources":["../src/ExpoBreathingExercise.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,KAAK,GAAG,YAAY,GAAG,SAAS,CAAC;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,8BAA8B;IAC7C,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAC/B,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,gBAAgB,CAAA;KAAE,KAAK,IAAI,CAAC;IACnE,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,qBAAqB,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7E,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ExpoBreathingExercise.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoBreathingExercise.types.js","sourceRoot":"","sources":["../src/ExpoBreathingExercise.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ColorValue, StyleProp, ViewStyle } from 'react-native';\n\nexport type BreathPhase = 'inhale' | 'holdIn' | 'exhale' | 'holdOut';\n\nexport interface BreathPhaseConfig {\n phase: BreathPhase;\n duration: number; // milliseconds\n targetScale: number; // e.g., 1.0 to 1.3\n label: string; // \"Breathe In\"\n}\n\nexport interface BreathingPattern {\n phases: BreathPhaseConfig[];\n cycles?: number; // undefined = infinite\n}\n\nexport type BreathingPreset = 'relaxing' | 'box' | 'energizing' | 'calming';\n\nexport interface PhaseChangeEvent {\n phase: BreathPhase;\n label: string;\n phaseIndex: number;\n cycle: number;\n}\n\nexport interface ExerciseCompleteEvent {\n totalCycles: number;\n totalDuration: number;\n}\n\nexport interface ExpoBreathingExerciseViewProps {\n blobColors?: ColorValue[];\n innerBlobColor?: ColorValue;\n glowColor?: ColorValue;\n particleColor?: ColorValue;\n progressRingColor?: ColorValue;\n textColor?: ColorValue;\n showProgressRing?: boolean;\n showTextCue?: boolean;\n showInnerBlob?: boolean;\n showShadow?: boolean;\n showParticles?: boolean;\n showWavyBlobs?: boolean;\n showGlowEffects?: boolean;\n pointCount?: number; // Morphing points (default: 8)\n wobbleIntensity?: number; // 0-1\n onPhaseChange?: (event: { nativeEvent: PhaseChangeEvent }) => void;\n onExerciseComplete?: (event: { nativeEvent: ExerciseCompleteEvent }) => void;\n style?: StyleProp<ViewStyle>;\n}\n"]}
@@ -0,0 +1,16 @@
1
+ import { NativeModule } from 'expo';
2
+ import type { BreathingPattern, BreathingPreset } from './ExpoBreathingExercise.types';
3
+ declare class ExpoBreathingExerciseModuleType extends NativeModule {
4
+ startBreathingExercise(pattern: BreathingPattern): void;
5
+ stopBreathingExercise(): void;
6
+ pauseBreathingExercise(): void;
7
+ resumeBreathingExercise(): void;
8
+ }
9
+ declare const module: ExpoBreathingExerciseModuleType;
10
+ export default module;
11
+ export declare function startBreathingExercise(pattern: BreathingPattern): void;
12
+ export declare function stopBreathingExercise(): void;
13
+ export declare function pauseBreathingExercise(): void;
14
+ export declare function resumeBreathingExercise(): void;
15
+ export declare function getBreathingPreset(preset: BreathingPreset): BreathingPattern;
16
+ //# sourceMappingURL=ExpoBreathingExerciseModule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoBreathingExerciseModule.d.ts","sourceRoot":"","sources":["../src/ExpoBreathingExerciseModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEvF,OAAO,OAAO,+BAAgC,SAAQ,YAAY;IAChE,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IACvD,qBAAqB,IAAI,IAAI;IAC7B,sBAAsB,IAAI,IAAI;IAC9B,uBAAuB,IAAI,IAAI;CAChC;AAED,QAAA,MAAM,MAAM,iCAAgF,CAAC;AAE7F,eAAe,MAAM,CAAC;AAEtB,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAEtE;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAoCD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,gBAAgB,CAE5E"}
@@ -0,0 +1,52 @@
1
+ import { requireNativeModule } from 'expo';
2
+ const module = requireNativeModule('ExpoBreathingExercise');
3
+ export default module;
4
+ export function startBreathingExercise(pattern) {
5
+ module.startBreathingExercise(pattern);
6
+ }
7
+ export function stopBreathingExercise() {
8
+ module.stopBreathingExercise();
9
+ }
10
+ export function pauseBreathingExercise() {
11
+ module.pauseBreathingExercise();
12
+ }
13
+ export function resumeBreathingExercise() {
14
+ module.resumeBreathingExercise();
15
+ }
16
+ const BREATHING_PRESETS = {
17
+ relaxing: {
18
+ phases: [
19
+ { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },
20
+ { phase: 'holdIn', duration: 7000, targetScale: 1.35, label: 'Hold' },
21
+ { phase: 'exhale', duration: 8000, targetScale: 0.75, label: 'Breathe Out' },
22
+ ],
23
+ cycles: 4,
24
+ },
25
+ box: {
26
+ phases: [
27
+ { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },
28
+ { phase: 'holdIn', duration: 4000, targetScale: 1.35, label: 'Hold' },
29
+ { phase: 'exhale', duration: 4000, targetScale: 0.75, label: 'Breathe Out' },
30
+ { phase: 'holdOut', duration: 4000, targetScale: 0.75, label: 'Hold' },
31
+ ],
32
+ cycles: 4,
33
+ },
34
+ energizing: {
35
+ phases: [
36
+ { phase: 'inhale', duration: 2000, targetScale: 1.35, label: 'Breathe In' },
37
+ { phase: 'exhale', duration: 2000, targetScale: 0.75, label: 'Breathe Out' },
38
+ ],
39
+ cycles: 10,
40
+ },
41
+ calming: {
42
+ phases: [
43
+ { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },
44
+ { phase: 'exhale', duration: 6000, targetScale: 0.75, label: 'Breathe Out' },
45
+ ],
46
+ cycles: 6,
47
+ },
48
+ };
49
+ export function getBreathingPreset(preset) {
50
+ return BREATHING_PRESETS[preset];
51
+ }
52
+ //# sourceMappingURL=ExpoBreathingExerciseModule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoBreathingExerciseModule.js","sourceRoot":"","sources":["../src/ExpoBreathingExerciseModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAUzD,MAAM,MAAM,GAAG,mBAAmB,CAAkC,uBAAuB,CAAC,CAAC;AAE7F,eAAe,MAAM,CAAC;AAEtB,MAAM,UAAU,sBAAsB,CAAC,OAAyB;IAC9D,MAAM,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,MAAM,CAAC,qBAAqB,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,MAAM,CAAC,sBAAsB,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,MAAM,CAAC,uBAAuB,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,iBAAiB,GAA8C;IACnE,QAAQ,EAAE;QACR,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3E,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;YACrE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;SAC7E;QACD,MAAM,EAAE,CAAC;KACV;IACD,GAAG,EAAE;QACH,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3E,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;YACrE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;YAC5E,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;SACvE;QACD,MAAM,EAAE,CAAC;KACV;IACD,UAAU,EAAE;QACV,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3E,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;SAC7E;QACD,MAAM,EAAE,EAAE;KACX;IACD,OAAO,EAAE;QACP,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3E,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;SAC7E;QACD,MAAM,EAAE,CAAC;KACV;CACF,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,MAAuB;IACxD,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\nimport type { BreathingPattern, BreathingPreset } from './ExpoBreathingExercise.types';\n\ndeclare class ExpoBreathingExerciseModuleType extends NativeModule {\n startBreathingExercise(pattern: BreathingPattern): void;\n stopBreathingExercise(): void;\n pauseBreathingExercise(): void;\n resumeBreathingExercise(): void;\n}\n\nconst module = requireNativeModule<ExpoBreathingExerciseModuleType>('ExpoBreathingExercise');\n\nexport default module;\n\nexport function startBreathingExercise(pattern: BreathingPattern): void {\n module.startBreathingExercise(pattern);\n}\n\nexport function stopBreathingExercise(): void {\n module.stopBreathingExercise();\n}\n\nexport function pauseBreathingExercise(): void {\n module.pauseBreathingExercise();\n}\n\nexport function resumeBreathingExercise(): void {\n module.resumeBreathingExercise();\n}\n\nconst BREATHING_PRESETS: Record<BreathingPreset, BreathingPattern> = {\n relaxing: {\n phases: [\n { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },\n { phase: 'holdIn', duration: 7000, targetScale: 1.35, label: 'Hold' },\n { phase: 'exhale', duration: 8000, targetScale: 0.75, label: 'Breathe Out' },\n ],\n cycles: 4,\n },\n box: {\n phases: [\n { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },\n { phase: 'holdIn', duration: 4000, targetScale: 1.35, label: 'Hold' },\n { phase: 'exhale', duration: 4000, targetScale: 0.75, label: 'Breathe Out' },\n { phase: 'holdOut', duration: 4000, targetScale: 0.75, label: 'Hold' },\n ],\n cycles: 4,\n },\n energizing: {\n phases: [\n { phase: 'inhale', duration: 2000, targetScale: 1.35, label: 'Breathe In' },\n { phase: 'exhale', duration: 2000, targetScale: 0.75, label: 'Breathe Out' },\n ],\n cycles: 10,\n },\n calming: {\n phases: [\n { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },\n { phase: 'exhale', duration: 6000, targetScale: 0.75, label: 'Breathe Out' },\n ],\n cycles: 6,\n },\n};\n\nexport function getBreathingPreset(preset: BreathingPreset): BreathingPattern {\n return BREATHING_PRESETS[preset];\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import * as React from 'react';
2
+ import { ExpoBreathingExerciseViewProps } from './ExpoBreathingExercise.types';
3
+ export default function ExpoBreathingExerciseView(props: ExpoBreathingExerciseViewProps): React.JSX.Element;
4
+ //# sourceMappingURL=ExpoBreathingExerciseView.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoBreathingExerciseView.d.ts","sourceRoot":"","sources":["../src/ExpoBreathingExerciseView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAK/E,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,8BAA8B,qBAEtF"}
@@ -0,0 +1,7 @@
1
+ import { requireNativeView } from 'expo';
2
+ import * as React from 'react';
3
+ const NativeView = requireNativeView('ExpoBreathingExercise');
4
+ export default function ExpoBreathingExerciseView(props) {
5
+ return <NativeView {...props}/>;
6
+ }
7
+ //# sourceMappingURL=ExpoBreathingExerciseView.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExpoBreathingExerciseView.js","sourceRoot":"","sources":["../src/ExpoBreathingExerciseView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,UAAU,GACd,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;AAE7C,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAqC;IACrF,OAAO,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,EAAG,CAAC;AACnC,CAAC","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\n\nimport { ExpoBreathingExerciseViewProps } from './ExpoBreathingExercise.types';\n\nconst NativeView: React.ComponentType<ExpoBreathingExerciseViewProps> =\n requireNativeView('ExpoBreathingExercise');\n\nexport default function ExpoBreathingExerciseView(props: ExpoBreathingExerciseViewProps) {\n return <NativeView {...props} />;\n}\n"]}
package/build/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
1
  export { default, setOrbActivity } from './ExpoOrbModule';
2
2
  export { default as ExpoOrbView } from './ExpoOrbView';
3
3
  export * from './ExpoOrb.types';
4
+ export { default as ExpoBreathingExerciseModule, startBreathingExercise, stopBreathingExercise, pauseBreathingExercise, resumeBreathingExercise, getBreathingPreset, } from './ExpoBreathingExerciseModule';
5
+ export { default as ExpoBreathingExerciseView } from './ExpoBreathingExerciseView';
6
+ export * from './ExpoBreathingExercise.types';
4
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAe,iBAAiB,CAAC;AAEjC,OAAO,EACL,OAAO,IAAI,2BAA2B,EACtC,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,cAAc,+BAA+B,CAAC"}
package/build/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  export { default, setOrbActivity } from './ExpoOrbModule';
2
2
  export { default as ExpoOrbView } from './ExpoOrbView';
3
3
  export * from './ExpoOrb.types';
4
+ export { default as ExpoBreathingExerciseModule, startBreathingExercise, stopBreathingExercise, pauseBreathingExercise, resumeBreathingExercise, getBreathingPreset, } from './ExpoBreathingExerciseModule';
5
+ export { default as ExpoBreathingExerciseView } from './ExpoBreathingExerciseView';
6
+ export * from './ExpoBreathingExercise.types';
4
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAe,iBAAiB,CAAC","sourcesContent":["export { default, setOrbActivity } from './ExpoOrbModule';\nexport { default as ExpoOrbView } from './ExpoOrbView';\nexport * from './ExpoOrb.types';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAe,iBAAiB,CAAC;AAEjC,OAAO,EACL,OAAO,IAAI,2BAA2B,EACtC,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,cAAc,+BAA+B,CAAC","sourcesContent":["export { default, setOrbActivity } from './ExpoOrbModule';\nexport { default as ExpoOrbView } from './ExpoOrbView';\nexport * from './ExpoOrb.types';\n\nexport {\n default as ExpoBreathingExerciseModule,\n startBreathingExercise,\n stopBreathingExercise,\n pauseBreathingExercise,\n resumeBreathingExercise,\n getBreathingPreset,\n} from './ExpoBreathingExerciseModule';\nexport { default as ExpoBreathingExerciseView } from './ExpoBreathingExerciseView';\nexport * from './ExpoBreathingExercise.types';\n"]}
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "platforms": ["apple", "android", "web"],
3
3
  "apple": {
4
- "modules": ["ExpoOrbModule"]
4
+ "modules": ["ExpoOrbModule", "ExpoBreathingExerciseModule"]
5
5
  },
6
6
  "android": {
7
- "modules": ["expo.modules.orb.ExpoOrbModule"]
7
+ "modules": ["expo.modules.orb.ExpoOrbModule", "expo.modules.breathing.ExpoBreathingExerciseModule"]
8
8
  }
9
9
  }
@@ -0,0 +1,57 @@
1
+ import SwiftUI
2
+
3
+ public struct BreathingConfiguration {
4
+ var blobColors: [Color]
5
+ var innerBlobColor: Color
6
+ var glowColor: Color
7
+ var particleColor: Color
8
+ var progressRingColor: Color
9
+ var textColor: Color
10
+ var showProgressRing: Bool
11
+ var showTextCue: Bool
12
+ var showInnerBlob: Bool
13
+ var showShadow: Bool
14
+ var showParticles: Bool
15
+ var showWavyBlobs: Bool
16
+ var showGlowEffects: Bool
17
+ var pointCount: Int
18
+ var wobbleIntensity: Double
19
+
20
+ public init(
21
+ blobColors: [Color] = [
22
+ Color(red: 0.4, green: 0.7, blue: 0.9),
23
+ Color(red: 0.3, green: 0.5, blue: 0.8),
24
+ Color(red: 0.5, green: 0.3, blue: 0.7)
25
+ ],
26
+ innerBlobColor: Color = Color.white.opacity(0.3),
27
+ glowColor: Color = .white,
28
+ particleColor: Color = .white,
29
+ progressRingColor: Color = Color.white.opacity(0.5),
30
+ textColor: Color = .white,
31
+ showProgressRing: Bool = true,
32
+ showTextCue: Bool = true,
33
+ showInnerBlob: Bool = true,
34
+ showShadow: Bool = true,
35
+ showParticles: Bool = true,
36
+ showWavyBlobs: Bool = true,
37
+ showGlowEffects: Bool = true,
38
+ pointCount: Int = 8,
39
+ wobbleIntensity: Double = 1.0
40
+ ) {
41
+ self.blobColors = blobColors
42
+ self.innerBlobColor = innerBlobColor
43
+ self.glowColor = glowColor
44
+ self.particleColor = particleColor
45
+ self.progressRingColor = progressRingColor
46
+ self.textColor = textColor
47
+ self.showProgressRing = showProgressRing
48
+ self.showTextCue = showTextCue
49
+ self.showInnerBlob = showInnerBlob
50
+ self.showShadow = showShadow
51
+ self.showParticles = showParticles
52
+ self.showWavyBlobs = showWavyBlobs
53
+ self.showGlowEffects = showGlowEffects
54
+ self.pointCount = pointCount
55
+ self.wobbleIntensity = wobbleIntensity
56
+ }
57
+ }