@frosted-ui/react-native 0.0.1-canary.94 → 0.0.1-canary.95

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ import type { Color } from '../lib/types';
2
+ import * as React from 'react';
3
+ import { type ViewProps } from 'react-native';
4
+ type CircularProgressSize = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
5
+ type CircularProgressProps = ViewProps & {
6
+ /** Size of the circular progress indicator */
7
+ size?: CircularProgressSize;
8
+ /** Color theme for the progress indicator */
9
+ color?: Color;
10
+ /** Current progress value */
11
+ value?: number;
12
+ /** Maximum progress value */
13
+ max?: number;
14
+ };
15
+ declare function CircularProgress({ size, color, value, max, style, ...props }: CircularProgressProps): React.JSX.Element;
16
+ declare namespace CircularProgress {
17
+ var displayName: string;
18
+ }
19
+ export { CircularProgress };
20
+ export type { CircularProgressProps, CircularProgressSize };
21
+ //# sourceMappingURL=circular-progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circular-progress.d.ts","sourceRoot":"","sources":["../../src/components/circular-progress.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAQ,KAAK,SAAS,EAAkB,MAAM,cAAc,CAAC;AAOpE,KAAK,oBAAoB,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEhF,KAAK,qBAAqB,GAAG,SAAS,GAAG;IACvC,8CAA8C;IAC9C,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,6CAA6C;IAC7C,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,6BAA6B;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6BAA6B;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAsCF,iBAAS,gBAAgB,CAAC,EACxB,IAAU,EACV,KAAK,EACL,KAAS,EACT,GAAS,EACT,KAAK,EACL,GAAG,KAAK,EACT,EAAE,qBAAqB,qBAqFvB;kBA5FQ,gBAAgB;;;AAgGzB,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAC5B,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,CAAC"}
@@ -0,0 +1,78 @@
1
+ import { useThemeTokens } from '../lib/use-theme-tokens';
2
+ import * as React from 'react';
3
+ import { View } from 'react-native';
4
+ import Svg, { Circle } from 'react-native-svg';
5
+ function getSizeConfig(size) {
6
+ switch (size) {
7
+ case '1':
8
+ return { diameter: 16, strokeWidth: 3 };
9
+ case '2':
10
+ return { diameter: 20, strokeWidth: 4 };
11
+ case '3':
12
+ return { diameter: 24, strokeWidth: 5 };
13
+ case '4':
14
+ return { diameter: 32, strokeWidth: 5 };
15
+ case '5':
16
+ return { diameter: 40, strokeWidth: 6 };
17
+ case '6':
18
+ return { diameter: 48, strokeWidth: 7 };
19
+ case '7':
20
+ return { diameter: 56, strokeWidth: 8 };
21
+ case '8':
22
+ return { diameter: 64, strokeWidth: 9 };
23
+ case '9':
24
+ return { diameter: 72, strokeWidth: 10 };
25
+ }
26
+ }
27
+ // ============================================================================
28
+ // Component
29
+ // ============================================================================
30
+ function CircularProgress({ size = '3', color, value = 0, max = 100, style, ...props }) {
31
+ const { colors } = useThemeTokens();
32
+ // Get size configuration
33
+ const { diameter, strokeWidth } = getSizeConfig(size);
34
+ // Calculate SVG geometry
35
+ const radius = (diameter - strokeWidth) / 2;
36
+ const circumference = 2 * Math.PI * radius;
37
+ const center = diameter / 2;
38
+ // Calculate progress (0 to 1)
39
+ const progress = Math.max(0, Math.min((value || 0) / max, 1));
40
+ // Round caps add visual length beyond the arc endpoints
41
+ // Each cap extends by strokeWidth/2, total extension = strokeWidth
42
+ const capArcLength = strokeWidth / 2;
43
+ const totalCapArc = strokeWidth;
44
+ // Calculate the arc to draw (reduced to account for cap visual extension)
45
+ // Minimum arc ensures at least a dot (rounded cap) is visible when progress > 0
46
+ const targetVisualArc = progress * circumference;
47
+ const compensatedArc = targetVisualArc - totalCapArc;
48
+ const minArc = progress > 0 ? 0.1 : 0;
49
+ const actualArcToDraw = Math.max(minArc, compensatedArc);
50
+ // Stroke dash offset (how much of the circumference to hide)
51
+ const strokeDashoffset = circumference - actualArcToDraw;
52
+ // Rotate to position start cap's outer edge at 12 o'clock
53
+ const capAngle = (capArcLength / circumference) * 360;
54
+ const rotation = -90 + capAngle;
55
+ // Get colors
56
+ const gray = colors.palettes.gray;
57
+ const palette = colors.palettes[color ?? 'accent'] ?? gray;
58
+ // Track color (background circle) - uses alpha variant
59
+ const trackColor = palette.a3;
60
+ // Indicator color
61
+ const indicatorColor = palette['9'];
62
+ const containerStyle = {
63
+ width: diameter,
64
+ height: diameter,
65
+ };
66
+ return (<View role="progressbar" aria-valuemin={0} aria-valuemax={max} aria-valuenow={value} style={[containerStyle, style]} {...props}>
67
+ <Svg width={diameter} height={diameter} viewBox={`0 0 ${diameter} ${diameter}`}>
68
+ {/* Track (background circle) */}
69
+ <Circle cx={center} cy={center} r={radius} stroke={trackColor} strokeWidth={strokeWidth} fill="none"/>
70
+
71
+ {/* Progress indicator */}
72
+ {progress > 0 && (<Circle cx={center} cy={center} r={radius} stroke={indicatorColor} strokeWidth={strokeWidth} fill="none" strokeDasharray={progress >= 1 ? undefined : circumference} strokeDashoffset={progress >= 1 ? undefined : strokeDashoffset} strokeLinecap={progress >= 1 ? 'butt' : 'round'} transform={progress >= 1 ? undefined : `rotate(${rotation} ${center} ${center})`}/>)}
73
+ </Svg>
74
+ </View>);
75
+ }
76
+ CircularProgress.displayName = 'CircularProgress';
77
+ export { CircularProgress };
78
+ //# sourceMappingURL=circular-progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"circular-progress.js","sourceRoot":"","sources":["../../src/components/circular-progress.tsx"],"names":[],"mappings":"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"}
@@ -4,10 +4,12 @@ export * from './link';
4
4
  export * from './text';
5
5
  export * from './code';
6
6
  export * from './checkbox';
7
+ export * from './circular-progress';
7
8
  export * from './label';
8
9
  export * from './progress';
9
10
  export * from './radio-group';
10
11
  export * from './select';
12
+ export * from './slider';
11
13
  export * from './switch';
12
14
  export * from './text-area';
13
15
  export * from './text-field';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAC;AAI/B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AAIvB,cAAc,QAAQ,CAAC;AAIvB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAI7B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAI1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAEA,cAAc,gBAAgB,CAAC;AAI/B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AAIvB,cAAc,QAAQ,CAAC;AAIvB,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAI7B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAI1B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC"}
@@ -12,10 +12,12 @@ export * from './code';
12
12
  // FORMS
13
13
  //------------------------------------------------------------------------------
14
14
  export * from './checkbox';
15
+ export * from './circular-progress';
15
16
  export * from './label';
16
17
  export * from './progress';
17
18
  export * from './radio-group';
18
19
  export * from './select';
20
+ export * from './slider';
19
21
  export * from './switch';
20
22
  export * from './text-area';
21
23
  export * from './text-field';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,SAAS;AACT,gFAAgF;AAChF,cAAc,gBAAgB,CAAC;AAE/B,aAAa;AACb,gFAAgF;AAChF,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AAEvB,aAAa;AACb,gFAAgF;AAChF,cAAc,QAAQ,CAAC;AAEvB,QAAQ;AACR,gFAAgF;AAChF,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAE7B,WAAW;AACX,gFAAgF;AAChF,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAE1B,aAAa;AACb,gFAAgF;AAChF,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,SAAS;AACT,gFAAgF;AAChF,cAAc,gBAAgB,CAAC;AAE/B,aAAa;AACb,gFAAgF;AAChF,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AAEvB,aAAa;AACb,gFAAgF;AAChF,cAAc,QAAQ,CAAC;AAEvB,QAAQ;AACR,gFAAgF;AAChF,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAE7B,WAAW;AACX,gFAAgF;AAChF,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,UAAU,CAAC;AACzB,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAE1B,aAAa;AACb,gFAAgF;AAChF,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC;AACvB,cAAc,QAAQ,CAAC;AACvB,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC;AACvB,cAAc,qBAAqB,CAAC;AACpC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { Color } from '../lib/types';
2
+ import * as React from 'react';
3
+ import { type ViewStyle } from 'react-native';
4
+ type SliderSize = '1' | '2' | '3';
5
+ type SliderProps = {
6
+ /** Size of the slider track and thumb */
7
+ size?: SliderSize;
8
+ /** Accent color for the filled range */
9
+ color?: Color;
10
+ /** Current value - controlled mode */
11
+ value?: number;
12
+ /** Default value - uncontrolled mode */
13
+ defaultValue?: number;
14
+ /** Minimum value */
15
+ min?: number;
16
+ /** Maximum value */
17
+ max?: number;
18
+ /** Step increment */
19
+ step?: number;
20
+ /** Callback when value changes */
21
+ onValueChange?: (value: number) => void;
22
+ /** Whether the slider is disabled */
23
+ disabled?: boolean;
24
+ /** Container style */
25
+ style?: ViewStyle;
26
+ };
27
+ declare function Slider({ size, color, value: controlledValue, defaultValue, min, max, step, onValueChange, disabled, style, }: SliderProps): React.JSX.Element;
28
+ export { Slider };
29
+ export type { SliderProps };
30
+ //# sourceMappingURL=slider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slider.d.ts","sourceRoot":"","sources":["../../src/components/slider.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAA0C,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAWtF,KAAK,UAAU,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AA8BlC,KAAK,WAAW,GAAG;IACjB,yCAAyC;IACzC,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,wCAAwC;IACxC,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oBAAoB;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qBAAqB;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,qCAAqC;IACrC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB;IACtB,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB,CAAC;AAEF,iBAAS,MAAM,CAAC,EACd,IAAU,EACV,KAAK,EACL,KAAK,EAAE,eAAe,EACtB,YAAiB,EACjB,GAAO,EACP,GAAS,EACT,IAAQ,EACR,aAAa,EACb,QAAgB,EAChB,KAAK,GACN,EAAE,WAAW,qBA4Gb;AA4PD,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,YAAY,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,248 @@
1
+ import { useThemeTokens } from '../lib/use-theme-tokens';
2
+ import * as SliderPrimitive from '@rn-primitives/slider';
3
+ import * as React from 'react';
4
+ import { Platform, View } from 'react-native';
5
+ import { Gesture, GestureDetector, GestureHandlerRootView, } from 'react-native-gesture-handler';
6
+ import Animated, { runOnJS, useAnimatedStyle, useSharedValue } from 'react-native-reanimated';
7
+ // Size styles from CSS:
8
+ // Size 1: --slider-track-size: calc(var(--space-2) * 0.75) = 6px
9
+ // Size 2: --slider-track-size: var(--space-2) = 8px
10
+ // Size 3: --slider-track-size: calc(var(--space-2) * 1.25) = 10px
11
+ // --slider-thumb-size: calc(var(--slider-track-size) + var(--space-1)) = track + 4px
12
+ function getSizeStyle(size) {
13
+ switch (size) {
14
+ case '1': {
15
+ const trackHeight = 6;
16
+ const thumbSize = trackHeight + 4; // 10
17
+ return { trackHeight, thumbSize };
18
+ }
19
+ case '2': {
20
+ const trackHeight = 8;
21
+ const thumbSize = trackHeight + 4; // 12
22
+ return { trackHeight, thumbSize };
23
+ }
24
+ case '3': {
25
+ const trackHeight = 10;
26
+ const thumbSize = trackHeight + 4; // 14
27
+ return { trackHeight, thumbSize };
28
+ }
29
+ }
30
+ }
31
+ function Slider({ size = '2', color, value: controlledValue, defaultValue = 50, min = 0, max = 100, step = 1, onValueChange, disabled = false, style, }) {
32
+ const { colors } = useThemeTokens();
33
+ // Internal state for uncontrolled mode
34
+ const [internalValue, setInternalValue] = React.useState(defaultValue);
35
+ // Use controlled value if provided, otherwise use internal state
36
+ const currentValue = controlledValue !== undefined ? controlledValue : internalValue;
37
+ const gray = colors.palettes.gray;
38
+ const palette = colors.palettes[color ?? 'accent'] ?? gray;
39
+ const { trackHeight, thumbSize } = getSizeStyle(size);
40
+ // The thumb has a visible pseudo-element that's slightly larger
41
+ const thumbVisibleSize = thumbSize + Math.floor(trackHeight * 0.5);
42
+ // Range (filled track) color
43
+ const rangeColor = disabled ? gray.a5 : palette['9'];
44
+ // Calculate range width based on value
45
+ const rangePercent = ((currentValue - min) / (max - min)) * 100;
46
+ // Update value helper
47
+ const updateValue = React.useCallback((newValue) => {
48
+ if (controlledValue === undefined) {
49
+ setInternalValue(newValue);
50
+ }
51
+ onValueChange?.(newValue);
52
+ }, [controlledValue, onValueChange]);
53
+ // Handle value changes from rn-primitives (receives array)
54
+ const handlePrimitiveValueChange = React.useCallback((newValue) => {
55
+ updateValue(newValue[0] ?? min);
56
+ }, [updateValue, min]);
57
+ // Track styles
58
+ const trackStyle = {
59
+ height: trackHeight,
60
+ borderRadius: trackHeight / 2,
61
+ backgroundColor: gray.a4,
62
+ justifyContent: 'center',
63
+ position: 'relative',
64
+ };
65
+ const rangeStyle = {
66
+ height: trackHeight,
67
+ borderRadius: trackHeight / 2,
68
+ backgroundColor: rangeColor,
69
+ position: 'absolute',
70
+ left: 0,
71
+ width: `${rangePercent}%`,
72
+ };
73
+ // Container style
74
+ const containerStyle = {
75
+ height: thumbVisibleSize + 8,
76
+ justifyContent: 'center',
77
+ opacity: disabled ? 0.5 : 1,
78
+ ...style,
79
+ };
80
+ // Web implementation using rn-primitives for accessibility (keyboard, focus)
81
+ if (Platform.OS === 'web') {
82
+ return (<WebSlider currentValue={currentValue} min={min} max={max} step={step} disabled={disabled} handlePrimitiveValueChange={handlePrimitiveValueChange} containerStyle={containerStyle} trackStyle={trackStyle} rangeStyle={rangeStyle} thumbVisibleSize={thumbVisibleSize} gray={gray} palette={palette}/>);
83
+ }
84
+ // Native implementation with Gesture Handler for proper scroll view negotiation
85
+ return (<NativeSlider {...{
86
+ currentValue,
87
+ min,
88
+ max,
89
+ step,
90
+ disabled,
91
+ updateValue,
92
+ trackHeight,
93
+ thumbVisibleSize,
94
+ gray,
95
+ rangeColor,
96
+ trackStyle,
97
+ rangeStyle,
98
+ containerStyle,
99
+ }}/>);
100
+ }
101
+ // Separate web component to track focus state with hooks
102
+ function WebSlider({ currentValue, min, max, step, disabled, handlePrimitiveValueChange, containerStyle, trackStyle, rangeStyle, thumbVisibleSize, gray, palette, }) {
103
+ const [isFocused, setIsFocused] = React.useState(false);
104
+ // Base box-shadow (always visible)
105
+ const baseBoxShadow = disabled
106
+ ? `0 0 0 1px ${gray['5']}`
107
+ : `0 0 0 1px ${gray.a3}, 0 1px 2px ${gray.a4}, 0 1px 3px -0.5px ${gray.a3}`;
108
+ // Focus box-shadow adds the light accent buffer ring
109
+ const focusBoxShadow = `${baseBoxShadow}, 0 0 0 3px ${palette['3']}`;
110
+ const webThumbStyle = {
111
+ width: thumbVisibleSize,
112
+ height: thumbVisibleSize,
113
+ borderRadius: thumbVisibleSize / 2,
114
+ backgroundColor: disabled ? gray['1'] : 'white',
115
+ boxShadow: isFocused && !disabled ? focusBoxShadow : baseBoxShadow,
116
+ cursor: disabled ? 'not-allowed' : 'grab',
117
+ // Focus outline - only show when focused
118
+ outlineStyle: isFocused && !disabled ? 'solid' : 'none',
119
+ outlineWidth: 2,
120
+ outlineOffset: 3,
121
+ outlineColor: palette['8'],
122
+ };
123
+ return (<SliderPrimitive.Root value={currentValue} min={min} max={max} step={step} onValueChange={handlePrimitiveValueChange} disabled={disabled} style={containerStyle}>
124
+ <SliderPrimitive.Track style={trackStyle}>
125
+ <SliderPrimitive.Range style={rangeStyle}/>
126
+ </SliderPrimitive.Track>
127
+ <SliderPrimitive.Thumb style={webThumbStyle} onFocus={() => setIsFocused(true)} onBlur={() => setIsFocused(false)}>
128
+ <View />
129
+ </SliderPrimitive.Thumb>
130
+ </SliderPrimitive.Root>);
131
+ }
132
+ // Separate native component to avoid hook issues with conditional rendering
133
+ function NativeSlider({ currentValue, min, max, step, disabled, updateValue, trackHeight, thumbVisibleSize, gray, rangeColor, trackStyle, rangeStyle, containerStyle, }) {
134
+ // Track dimensions
135
+ const trackWidth = useSharedValue(0);
136
+ // Animated thumb position (as percentage 0-1)
137
+ const thumbPosition = useSharedValue((currentValue - min) / (max - min));
138
+ // Update thumb position when controlled value changes
139
+ React.useEffect(() => {
140
+ thumbPosition.value = (currentValue - min) / (max - min);
141
+ }, [currentValue, min, max, thumbPosition]);
142
+ // Convert position to stepped value
143
+ const positionToValue = React.useCallback((position) => {
144
+ 'worklet';
145
+ const percent = Math.max(0, Math.min(1, position));
146
+ const rawValue = min + percent * (max - min);
147
+ // Round to step
148
+ const steppedValue = Math.round(rawValue / step) * step;
149
+ return Math.max(min, Math.min(max, steppedValue));
150
+ }, [min, max, step]);
151
+ // Handle track layout to get dimensions
152
+ const handleTrackLayout = React.useCallback((event) => {
153
+ trackWidth.value = event.nativeEvent.layout.width;
154
+ // We'll measure pageX on gesture start
155
+ }, [trackWidth]);
156
+ // Track ref for measuring
157
+ const trackRef = React.useRef(null);
158
+ // Pan gesture with proper scroll view handling
159
+ const panGesture = React.useMemo(() => Gesture.Pan()
160
+ .enabled(!disabled)
161
+ // Small horizontal threshold to claim gesture before scroll view
162
+ .activeOffsetX([-5, 5])
163
+ // Large vertical threshold - let scroll view handle vertical
164
+ .failOffsetY([-20, 20])
165
+ .onStart((event) => {
166
+ // Calculate position from touch
167
+ if (trackWidth.value > 0) {
168
+ // Use the locationX which is relative to the component
169
+ const percent = Math.max(0, Math.min(1, event.x / trackWidth.value));
170
+ thumbPosition.value = percent;
171
+ const newValue = positionToValue(percent);
172
+ runOnJS(updateValue)(newValue);
173
+ }
174
+ })
175
+ .onUpdate((event) => {
176
+ if (trackWidth.value > 0) {
177
+ const percent = Math.max(0, Math.min(1, event.x / trackWidth.value));
178
+ thumbPosition.value = percent;
179
+ const newValue = positionToValue(percent);
180
+ runOnJS(updateValue)(newValue);
181
+ }
182
+ }), [disabled, trackWidth, thumbPosition, positionToValue, updateValue]);
183
+ // Tap gesture for clicking on track
184
+ const tapGesture = React.useMemo(() => Gesture.Tap()
185
+ .enabled(!disabled)
186
+ .onStart((event) => {
187
+ if (trackWidth.value > 0) {
188
+ const percent = Math.max(0, Math.min(1, event.x / trackWidth.value));
189
+ thumbPosition.value = percent;
190
+ const newValue = positionToValue(percent);
191
+ runOnJS(updateValue)(newValue);
192
+ }
193
+ }), [disabled, trackWidth, thumbPosition, positionToValue, updateValue]);
194
+ // Combine gestures - tap and pan work together
195
+ const composedGesture = Gesture.Race(panGesture, tapGesture);
196
+ // Outer ring size (the outline effect from web's box-shadow)
197
+ const outerRingSize = thumbVisibleSize + 2;
198
+ // Animated styles for range fill
199
+ const animatedRangeStyle = useAnimatedStyle(() => {
200
+ return {
201
+ width: `${thumbPosition.value * 100}%`,
202
+ };
203
+ });
204
+ // Animated styles for thumb position
205
+ const animatedThumbStyle = useAnimatedStyle(() => {
206
+ const left = thumbPosition.value * trackWidth.value - outerRingSize / 2;
207
+ return {
208
+ transform: [{ translateX: left }],
209
+ };
210
+ });
211
+ // Outer ring style - creates the dark outline effect
212
+ const thumbOuterStyle = {
213
+ width: outerRingSize,
214
+ height: outerRingSize,
215
+ borderRadius: outerRingSize / 2,
216
+ backgroundColor: disabled ? gray['5'] : gray.a5,
217
+ position: 'absolute',
218
+ top: (trackHeight - outerRingSize) / 2,
219
+ left: 0,
220
+ alignItems: 'center',
221
+ justifyContent: 'center',
222
+ // Drop shadow
223
+ shadowColor: '#000',
224
+ shadowOpacity: disabled ? 0.08 : 0.15,
225
+ shadowOffset: { width: 0, height: 1 },
226
+ shadowRadius: 2,
227
+ elevation: disabled ? 1 : 2,
228
+ };
229
+ // Inner thumb style - the white center
230
+ const thumbInnerStyle = {
231
+ width: thumbVisibleSize,
232
+ height: thumbVisibleSize,
233
+ borderRadius: thumbVisibleSize / 2,
234
+ backgroundColor: disabled ? gray['1'] : 'white',
235
+ };
236
+ return (<GestureHandlerRootView style={containerStyle}>
237
+ <GestureDetector gesture={composedGesture}>
238
+ <View ref={trackRef} style={trackStyle} onLayout={handleTrackLayout}>
239
+ <Animated.View style={[rangeStyle, animatedRangeStyle, { backgroundColor: rangeColor }]}/>
240
+ <Animated.View style={[thumbOuterStyle, animatedThumbStyle]}>
241
+ <View style={thumbInnerStyle}/>
242
+ </Animated.View>
243
+ </View>
244
+ </GestureDetector>
245
+ </GestureHandlerRootView>);
246
+ }
247
+ export { Slider };
248
+ //# sourceMappingURL=slider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slider.js","sourceRoot":"","sources":["../../src/components/slider.tsx"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@
3
3
  > **Critical**: Always import components from `@frosted-ui/react-native`, never from React Native directly for UI elements.
4
4
 
5
5
  ```tsx
6
- import { Button, Text, Card, Dialog } from '@frosted-ui/react-native';
6
+ import { Button, Text, Card, Dialog, Slider, CircularProgress } from '@frosted-ui/react-native';
7
7
  ```
8
8
 
9
9
  ---
@@ -499,6 +499,128 @@ Progress bar indicator.
499
499
 
500
500
  ---
501
501
 
502
+ ### CircularProgress
503
+
504
+ Circular progress indicator with SVG rendering.
505
+
506
+ ```tsx
507
+ <CircularProgress value={75} max={100} size="5" color="accent" />
508
+ ```
509
+
510
+ | Prop | Type | Default | Description |
511
+ | ------- | --------- | ---------- | ---------------------------- |
512
+ | `value` | `number` | `0` | Current progress |
513
+ | `max` | `number` | `100` | Maximum value |
514
+ | `size` | `'1'-'9'` | `'3'` | Ring size (16px to 72px) |
515
+ | `color` | `Color` | `'accent'` | Progress indicator color |
516
+
517
+ #### Size Reference
518
+
519
+ | Size | Diameter | Stroke Width | Use Case |
520
+ | ----- | -------- | ------------ | ------------------------------ |
521
+ | `'1'` | 16px | 3px | Inline indicators |
522
+ | `'2'` | 20px | 4px | Compact UI |
523
+ | `'3'` | 24px | 5px | **Default** — small indicators |
524
+ | `'4'` | 32px | 5px | List items, stats |
525
+ | `'5'` | 40px | 6px | Card displays |
526
+ | `'6'` | 48px | 7px | Prominent indicators |
527
+ | `'7'` | 56px | 8px | Dashboard widgets |
528
+ | `'8'` | 64px | 9px | Large displays |
529
+ | `'9'` | 72px | 10px | Hero/featured metrics |
530
+
531
+ #### Common Patterns
532
+
533
+ **With value inside:**
534
+
535
+ ```tsx
536
+ <View style={{ position: 'relative', alignItems: 'center', justifyContent: 'center' }}>
537
+ <CircularProgress size="6" value={75} color="cyan" />
538
+ <View style={{ position: 'absolute' }}>
539
+ <Text size="2" weight="bold">75%</Text>
540
+ </View>
541
+ </View>
542
+ ```
543
+
544
+ **System health dashboard:**
545
+
546
+ ```tsx
547
+ <View style={{ flexDirection: 'row', gap: 16 }}>
548
+ <View style={{ alignItems: 'center', gap: 4 }}>
549
+ <CircularProgress size="5" value={42} color="cyan" />
550
+ <Text size="1" color="gray">CPU</Text>
551
+ </View>
552
+ <View style={{ alignItems: 'center', gap: 4 }}>
553
+ <CircularProgress size="5" value={68} color="violet" />
554
+ <Text size="1" color="gray">Memory</Text>
555
+ </View>
556
+ <View style={{ alignItems: 'center', gap: 4 }}>
557
+ <CircularProgress size="5" value={85} color="orange" />
558
+ <Text size="1" color="gray">Disk</Text>
559
+ </View>
560
+ </View>
561
+ ```
562
+
563
+ ---
564
+
565
+ ### Slider
566
+
567
+ Draggable slider for selecting a value from a range.
568
+
569
+ ```tsx
570
+ const [volume, setVolume] = React.useState(50);
571
+
572
+ <Slider value={volume} onValueChange={setVolume} min={0} max={100} />;
573
+ ```
574
+
575
+ | Prop | Type | Default | Description |
576
+ | --------------- | ------------------------- | ---------- | ---------------------------- |
577
+ | `value` | `number` | — | Controlled value |
578
+ | `defaultValue` | `number` | `50` | Initial value (uncontrolled) |
579
+ | `min` | `number` | `0` | Minimum value |
580
+ | `max` | `number` | `100` | Maximum value |
581
+ | `step` | `number` | `1` | Step increment |
582
+ | `onValueChange` | `(value: number) => void` | — | Change handler |
583
+ | `size` | `'1' \| '2' \| '3'` | `'2'` | Track and thumb size |
584
+ | `color` | `Color` | `'accent'` | Range fill color |
585
+ | `disabled` | `boolean` | `false` | Disabled state |
586
+
587
+ #### Slider with Label Pattern
588
+
589
+ ```tsx
590
+ function VolumeSlider() {
591
+ const [value, setValue] = React.useState(75);
592
+ return (
593
+ <View style={{ gap: 8 }}>
594
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
595
+ <Text size="2">Volume</Text>
596
+ <Text size="2" color="gray">
597
+ {value}%
598
+ </Text>
599
+ </View>
600
+ <Slider value={value} onValueChange={setValue} />
601
+ </View>
602
+ );
603
+ }
604
+ ```
605
+
606
+ #### Custom Range Example
607
+
608
+ ```tsx
609
+ {
610
+ /* Playback speed: 0.5x to 2.0x */
611
+ }
612
+ <Slider
613
+ value={playbackSpeed}
614
+ onValueChange={setPlaybackSpeed}
615
+ min={50}
616
+ max={200}
617
+ step={25}
618
+ color="purple"
619
+ />;
620
+ ```
621
+
622
+ ---
623
+
502
624
  ### Spinner
503
625
 
504
626
  Loading indicator.
@@ -1020,7 +1142,9 @@ Card shown on hover (web) or press (mobile).
1020
1142
  | Avatar | `'0'` - `'9'` |
1021
1143
  | Checkbox, Switch, RadioGroup | `'1'`, `'2'`, `'3'` |
1022
1144
  | TextField, TextArea, Select | `'1'`, `'2'`, `'3'`, `'4'` |
1145
+ | Slider | `'1'`, `'2'`, `'3'` |
1023
1146
  | Progress, Spinner | `'1'` - `'6'` |
1147
+ | CircularProgress | `'1'` - `'9'` |
1024
1148
  | Tabs | `'1'`, `'2'` |
1025
1149
  | Callout | `'1'`, `'2'`, `'3'` |
1026
1150
  | Dialog | `'1'`, `'2'`, `'3'`, `'4'` |
@@ -1080,6 +1204,14 @@ All share the same height scale. IconButton is square (width = height).
1080
1204
  | `'2'` | 42×24px | **Default** — standard toggles |
1081
1205
  | `'3'` | 56×32px | Touch-friendly, prominent toggles |
1082
1206
 
1207
+ ### Slider
1208
+
1209
+ | Size | Track Height | Thumb Size | Use Case |
1210
+ | ----- | ------------ | ---------- | --------------------------------- |
1211
+ | `'1'` | 6px | ~14px | Compact controls, dense UI |
1212
+ | `'2'` | 8px | ~16px | **Default** — standard sliders |
1213
+ | `'3'` | 10px | ~18px | Touch-friendly, prominent sliders |
1214
+
1083
1215
  ### Spinner
1084
1216
 
1085
1217
  | Size | Dimensions | Use Case |
@@ -1091,6 +1223,20 @@ All share the same height scale. IconButton is square (width = height).
1091
1223
  | `'5'` | 32×32px | Section loading |
1092
1224
  | `'6'` | 40×40px | Page loading |
1093
1225
 
1226
+ ### CircularProgress
1227
+
1228
+ | Size | Diameter | Stroke | Use Case |
1229
+ | ----- | -------- | ------ | ------------------------------ |
1230
+ | `'1'` | 16px | 3px | Inline indicators |
1231
+ | `'2'` | 20px | 4px | Compact UI |
1232
+ | `'3'` | 24px | 5px | **Default** — small indicators |
1233
+ | `'4'` | 32px | 5px | List items, stats |
1234
+ | `'5'` | 40px | 6px | Card displays |
1235
+ | `'6'` | 48px | 7px | Prominent indicators |
1236
+ | `'7'` | 56px | 8px | Dashboard widgets |
1237
+ | `'8'` | 64px | 9px | Large displays |
1238
+ | `'9'` | 72px | 10px | Hero/featured metrics |
1239
+
1094
1240
  ---
1095
1241
 
1096
1242
  ## Common Patterns
@@ -500,6 +500,58 @@ Group related fields together:
500
500
  </List.Root>
501
501
  ```
502
502
 
503
+ ### Settings with Slider Controls
504
+
505
+ For settings that require a value selection (volume, brightness, text size):
506
+
507
+ ```tsx
508
+ const [brightness, setBrightness] = React.useState(75);
509
+ const [volume, setVolume] = React.useState(80);
510
+
511
+ <Card>
512
+ <View style={{ gap: 20 }}>
513
+ <Heading size="3">Display Settings</Heading>
514
+
515
+ {/* Brightness */}
516
+ <View style={{ gap: 8 }}>
517
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
518
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
519
+ <Icon as={Sun} size={18} color={colors.palettes.amber.a11} />
520
+ <Text weight="medium">Brightness</Text>
521
+ </View>
522
+ <Text size="2" color="gray">
523
+ {brightness}%
524
+ </Text>
525
+ </View>
526
+ <Slider value={brightness} onValueChange={setBrightness} color="amber" />
527
+ </View>
528
+
529
+ <Separator size="4" />
530
+
531
+ {/* Volume */}
532
+ <View style={{ gap: 8 }}>
533
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
534
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
535
+ <Icon as={Volume2} size={18} color={colors.palettes.blue.a11} />
536
+ <Text weight="medium">Volume</Text>
537
+ </View>
538
+ <Text size="2" color="gray">
539
+ {volume}%
540
+ </Text>
541
+ </View>
542
+ <Slider value={volume} onValueChange={setVolume} color="blue" />
543
+ </View>
544
+ </View>
545
+ </Card>;
546
+ ```
547
+
548
+ **Key patterns:**
549
+
550
+ - Show current value as percentage or label on the right
551
+ - Use colored icons that match the slider's `color` prop
552
+ - Use `Separator` between slider groups
553
+ - Label + value row above, slider below
554
+
503
555
  ### List with RadioGroup (Shipping Options)
504
556
 
505
557
  ```tsx
@@ -2277,6 +2329,45 @@ const entries = [
2277
2329
  </Card>
2278
2330
  ```
2279
2331
 
2332
+ ### System Health (CircularProgress)
2333
+
2334
+ Use `CircularProgress` for dashboard-style metrics:
2335
+
2336
+ ```tsx
2337
+ <Card>
2338
+ <View style={{ gap: 16 }}>
2339
+ <View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
2340
+ <Heading size="3">System Health</Heading>
2341
+ <Badge color="success" size="1">
2342
+ <Text>All Systems Normal</Text>
2343
+ </Badge>
2344
+ </View>
2345
+
2346
+ {/* Circular progress indicators in a row */}
2347
+ <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
2348
+ {[
2349
+ { label: 'CPU', value: 42, color: 'cyan' },
2350
+ { label: 'Memory', value: 68, color: 'violet' },
2351
+ { label: 'Disk', value: 85, color: 'orange' },
2352
+ { label: 'Network', value: 23, color: 'lime' },
2353
+ ].map((metric) => (
2354
+ <View key={metric.label} style={{ alignItems: 'center', gap: 8 }}>
2355
+ <View style={{ position: 'relative', alignItems: 'center', justifyContent: 'center' }}>
2356
+ <CircularProgress size="6" value={metric.value} color={metric.color} />
2357
+ <View style={{ position: 'absolute' }}>
2358
+ <Text size="1" weight="bold">{metric.value}</Text>
2359
+ </View>
2360
+ </View>
2361
+ <Text size="1" color="gray">{metric.label}</Text>
2362
+ </View>
2363
+ ))}
2364
+ </View>
2365
+ </View>
2366
+ </Card>
2367
+ ```
2368
+
2369
+ > **Tip**: Place text inside circular progress using absolute positioning. Use size `"5"` or larger when displaying values inside.
2370
+
2280
2371
  ### Daily Challenge
2281
2372
 
2282
2373
  ```tsx
@@ -2332,6 +2423,14 @@ const entries = [
2332
2423
 
2333
2424
  ```tsx
2334
2425
  const [isPlaying, setIsPlaying] = React.useState(true);
2426
+ const [position, setPosition] = React.useState(84); // seconds
2427
+ const duration = 225; // 3:45 in seconds
2428
+
2429
+ const formatTime = (seconds: number) => {
2430
+ const mins = Math.floor(seconds / 60);
2431
+ const secs = seconds % 60;
2432
+ return `${mins}:${secs.toString().padStart(2, '0')}`;
2433
+ };
2335
2434
 
2336
2435
  <Card>
2337
2436
  <View style={{ gap: 16 }}>
@@ -2364,15 +2463,15 @@ const [isPlaying, setIsPlaying] = React.useState(true);
2364
2463
  </IconButton>
2365
2464
  </View>
2366
2465
 
2367
- {/* Progress */}
2368
- <View style={{ gap: 8 }}>
2369
- <Progress value={35} size="1" />
2466
+ {/* Playback Position - Interactive Slider */}
2467
+ <View style={{ gap: 4 }}>
2468
+ <Slider value={position} onValueChange={setPosition} min={0} max={duration} size="1" />
2370
2469
  <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
2371
2470
  <Text size="0" color="gray">
2372
- 1:24
2471
+ {formatTime(position)}
2373
2472
  </Text>
2374
2473
  <Text size="0" color="gray">
2375
- 3:45
2474
+ {formatTime(duration)}
2376
2475
  </Text>
2377
2476
  </View>
2378
2477
  </View>
@@ -2393,6 +2492,8 @@ const [isPlaying, setIsPlaying] = React.useState(true);
2393
2492
  </Card>;
2394
2493
  ```
2395
2494
 
2495
+ > **Tip**: Use `Slider` for interactive playback control (user can seek). Use `Progress` for read-only progress display.
2496
+
2396
2497
  ### Poll Card
2397
2498
 
2398
2499
  ```tsx
@@ -46,6 +46,7 @@ import {
46
46
  Callout,
47
47
  Card,
48
48
  Checkbox,
49
+ CircularProgress,
49
50
  Dialog,
50
51
  Heading,
51
52
  IconButton,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@frosted-ui/react-native",
3
- "version": "0.0.1-canary.94",
3
+ "version": "0.0.1-canary.95",
4
4
  "private": false,
5
5
  "main": "expo-router/entry",
6
6
  "types": "./dist/index.d.ts",
@@ -23,6 +23,7 @@
23
23
  "lucide-react-native": ">=0.300.0",
24
24
  "react": ">=18.0.0",
25
25
  "react-native": ">=0.70.0",
26
+ "react-native-gesture-handler": ">=2.0.0",
26
27
  "react-native-reanimated": ">=3.0.0",
27
28
  "react-native-safe-area-context": ">=4.0.0",
28
29
  "react-native-screens": ">=3.0.0",
@@ -40,6 +41,7 @@
40
41
  },
41
42
  "dependencies": {
42
43
  "@frosted-ui/colors": "workspace:*",
44
+ "@rn-primitives/slider": "^1.2.0",
43
45
  "@rn-primitives/accordion": "^1.2.0",
44
46
  "@rn-primitives/alert-dialog": "^1.2.0",
45
47
  "@rn-primitives/aspect-ratio": "^1.2.0",
@@ -81,6 +83,7 @@
81
83
  "react": "19.1.0",
82
84
  "react-dom": "19.1.0",
83
85
  "react-native": "0.81.5",
86
+ "react-native-gesture-handler": "~2.24.0",
84
87
  "react-native-reanimated": "~4.1.1",
85
88
  "react-native-safe-area-context": "~5.6.0",
86
89
  "react-native-screens": "~4.16.0",