panelui-native 0.22.6 → 0.28.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.
- package/README.md +1 -0
- package/lib/module/components/accordion/index.js +8 -8
- package/lib/module/components/accordion/index.js.map +1 -1
- package/lib/module/components/alert/index.js +2 -2
- package/lib/module/components/alert/index.js.map +1 -1
- package/lib/module/components/area-chart/index.js +958 -0
- package/lib/module/components/area-chart/index.js.map +1 -0
- package/lib/module/components/attachment/index.js +2 -1
- package/lib/module/components/attachment/index.js.map +1 -1
- package/lib/module/components/avatar/index.js +4 -4
- package/lib/module/components/avatar/index.js.map +1 -1
- package/lib/module/components/badge/index.js +4 -4
- package/lib/module/components/badge/index.js.map +1 -1
- package/lib/module/components/bar-chart/index.js +994 -0
- package/lib/module/components/bar-chart/index.js.map +1 -0
- package/lib/module/components/bottom-sheet/index.js +213 -24
- package/lib/module/components/bottom-sheet/index.js.map +1 -1
- package/lib/module/components/breadcrumb/index.js +275 -0
- package/lib/module/components/breadcrumb/index.js.map +1 -0
- package/lib/module/components/button/index.js +11 -6
- package/lib/module/components/button/index.js.map +1 -1
- package/lib/module/components/calendar/index.js +557 -0
- package/lib/module/components/calendar/index.js.map +1 -0
- package/lib/module/components/carousel/index.js +680 -0
- package/lib/module/components/carousel/index.js.map +1 -0
- package/lib/module/components/chip/index.js +6 -6
- package/lib/module/components/chip/index.js.map +1 -1
- package/lib/module/components/date-picker/index.js +158 -0
- package/lib/module/components/date-picker/index.js.map +1 -0
- package/lib/module/components/dialog/index.js +7 -2
- package/lib/module/components/dialog/index.js.map +1 -1
- package/lib/module/components/direction/index.js +15 -20
- package/lib/module/components/direction/index.js.map +1 -1
- package/lib/module/components/empty-state/index.js +2 -2
- package/lib/module/components/empty-state/index.js.map +1 -1
- package/lib/module/components/field/index.js +5 -5
- package/lib/module/components/field/index.js.map +1 -1
- package/lib/module/components/flow/index.js +3 -3
- package/lib/module/components/flow/index.js.map +1 -1
- package/lib/module/components/frame/index.js +22 -5
- package/lib/module/components/frame/index.js.map +1 -1
- package/lib/module/components/heatmap-chart/index.js +28 -8
- package/lib/module/components/heatmap-chart/index.js.map +1 -1
- package/lib/module/components/input-group/index.js +5 -4
- package/lib/module/components/input-group/index.js.map +1 -1
- package/lib/module/components/item/index.js +9 -9
- package/lib/module/components/item/index.js.map +1 -1
- package/lib/module/components/label/index.js +4 -4
- package/lib/module/components/label/index.js.map +1 -1
- package/lib/module/components/line-chart/index.js +165 -184
- package/lib/module/components/line-chart/index.js.map +1 -1
- package/lib/module/components/loader/index.js +758 -0
- package/lib/module/components/loader/index.js.map +1 -0
- package/lib/module/components/map/basemap.js +265 -0
- package/lib/module/components/map/basemap.js.map +1 -0
- package/lib/module/components/map/index.js +850 -0
- package/lib/module/components/map/index.js.map +1 -0
- package/lib/module/components/map/maplibre.js +87 -0
- package/lib/module/components/map/maplibre.js.map +1 -0
- package/lib/module/components/marker/index.js +3 -3
- package/lib/module/components/marker/index.js.map +1 -1
- package/lib/module/components/message/index.js +15 -14
- package/lib/module/components/message/index.js.map +1 -1
- package/lib/module/components/message-scroller/index.js +5 -4
- package/lib/module/components/message-scroller/index.js.map +1 -1
- package/lib/module/components/otp-input/index.js +2 -2
- package/lib/module/components/popover/index.js +39 -7
- package/lib/module/components/popover/index.js.map +1 -1
- package/lib/module/components/progress/index.js +8 -2
- package/lib/module/components/progress/index.js.map +1 -1
- package/lib/module/components/radio-group/index.js +2 -2
- package/lib/module/components/radio-group/index.js.map +1 -1
- package/lib/module/components/ring-chart/index.js +423 -0
- package/lib/module/components/ring-chart/index.js.map +1 -0
- package/lib/module/components/section-rail/index.js +6 -6
- package/lib/module/components/section-rail/index.js.map +1 -1
- package/lib/module/components/select/index.js +10 -4
- package/lib/module/components/select/index.js.map +1 -1
- package/lib/module/components/separator/index.js +76 -22
- package/lib/module/components/separator/index.js.map +1 -1
- package/lib/module/components/shimmer/index.js +10 -1
- package/lib/module/components/shimmer/index.js.map +1 -1
- package/lib/module/components/slider/index.js +19 -5
- package/lib/module/components/slider/index.js.map +1 -1
- package/lib/module/components/steps/index.js +5 -5
- package/lib/module/components/steps/index.js.map +1 -1
- package/lib/module/components/switch/index.js +6 -1
- package/lib/module/components/switch/index.js.map +1 -1
- package/lib/module/components/tabs/index.js +7 -7
- package/lib/module/components/tabs/index.js.map +1 -1
- package/lib/module/components/timeline/index.js +4 -4
- package/lib/module/components/timeline/index.js.map +1 -1
- package/lib/module/components/toast/index.js +2 -2
- package/lib/module/components/toast/index.js.map +1 -1
- package/lib/module/components/toggle-button/index.js +5 -5
- package/lib/module/components/toggle-button/index.js.map +1 -1
- package/lib/module/components/tooltip/index.js +492 -0
- package/lib/module/components/tooltip/index.js.map +1 -0
- package/lib/module/components/typography/index.js +7 -2
- package/lib/module/components/typography/index.js.map +1 -1
- package/lib/module/hooks/index.js +1 -0
- package/lib/module/hooks/index.js.map +1 -1
- package/lib/module/hooks/use-back-handler.js +37 -0
- package/lib/module/hooks/use-back-handler.js.map +1 -0
- package/lib/module/hooks/use-direction.js +43 -0
- package/lib/module/hooks/use-direction.js.map +1 -0
- package/lib/module/icons/index.js +180 -2
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +12 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/primitives/keyboard-avoider.js +2 -1
- package/lib/module/primitives/keyboard-avoider.js.map +1 -1
- package/lib/module/primitives/text.js +55 -11
- package/lib/module/primitives/text.js.map +1 -1
- package/lib/module/utils/chart.js +279 -0
- package/lib/module/utils/chart.js.map +1 -0
- package/lib/module/utils/date.js +386 -0
- package/lib/module/utils/date.js.map +1 -0
- package/lib/typescript/src/components/accordion/index.d.ts.map +1 -1
- package/lib/typescript/src/components/alert/index.d.ts.map +1 -1
- package/lib/typescript/src/components/area-chart/index.d.ts +237 -0
- package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/attachment/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bar-chart/index.d.ts +270 -0
- package/lib/typescript/src/components/bar-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/bottom-sheet/index.d.ts +75 -4
- package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/src/components/breadcrumb/index.d.ts +100 -0
- package/lib/typescript/src/components/breadcrumb/index.d.ts.map +1 -0
- package/lib/typescript/src/components/button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/calendar/index.d.ts +108 -0
- package/lib/typescript/src/components/calendar/index.d.ts.map +1 -0
- package/lib/typescript/src/components/carousel/index.d.ts +179 -0
- package/lib/typescript/src/components/carousel/index.d.ts.map +1 -0
- package/lib/typescript/src/components/chip/index.d.ts.map +1 -1
- package/lib/typescript/src/components/date-picker/index.d.ts +91 -0
- package/lib/typescript/src/components/date-picker/index.d.ts.map +1 -0
- package/lib/typescript/src/components/dialog/index.d.ts.map +1 -1
- package/lib/typescript/src/components/direction/index.d.ts +11 -10
- package/lib/typescript/src/components/direction/index.d.ts.map +1 -1
- package/lib/typescript/src/components/empty-state/index.d.ts.map +1 -1
- package/lib/typescript/src/components/field/index.d.ts.map +1 -1
- package/lib/typescript/src/components/frame/index.d.ts +17 -0
- package/lib/typescript/src/components/frame/index.d.ts.map +1 -1
- package/lib/typescript/src/components/heatmap-chart/index.d.ts +22 -3
- package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/input-group/index.d.ts.map +1 -1
- package/lib/typescript/src/components/item/index.d.ts.map +1 -1
- package/lib/typescript/src/components/label/index.d.ts.map +1 -1
- package/lib/typescript/src/components/line-chart/index.d.ts +42 -2
- package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/loader/index.d.ts +38 -0
- package/lib/typescript/src/components/loader/index.d.ts.map +1 -0
- package/lib/typescript/src/components/map/basemap.d.ts +76 -0
- package/lib/typescript/src/components/map/basemap.d.ts.map +1 -0
- package/lib/typescript/src/components/map/index.d.ts +367 -0
- package/lib/typescript/src/components/map/index.d.ts.map +1 -0
- package/lib/typescript/src/components/map/maplibre.d.ts +193 -0
- package/lib/typescript/src/components/map/maplibre.d.ts.map +1 -0
- package/lib/typescript/src/components/marker/index.d.ts.map +1 -1
- package/lib/typescript/src/components/message/index.d.ts.map +1 -1
- package/lib/typescript/src/components/message-scroller/index.d.ts.map +1 -1
- package/lib/typescript/src/components/popover/index.d.ts.map +1 -1
- package/lib/typescript/src/components/progress/index.d.ts.map +1 -1
- package/lib/typescript/src/components/ring-chart/index.d.ts +156 -0
- package/lib/typescript/src/components/ring-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/select/index.d.ts.map +1 -1
- package/lib/typescript/src/components/separator/index.d.ts +36 -1
- package/lib/typescript/src/components/separator/index.d.ts.map +1 -1
- package/lib/typescript/src/components/shimmer/index.d.ts.map +1 -1
- package/lib/typescript/src/components/slider/index.d.ts.map +1 -1
- package/lib/typescript/src/components/steps/index.d.ts.map +1 -1
- package/lib/typescript/src/components/switch/index.d.ts.map +1 -1
- package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
- package/lib/typescript/src/components/timeline/index.d.ts.map +1 -1
- package/lib/typescript/src/components/toast/index.d.ts.map +1 -1
- package/lib/typescript/src/components/toggle-button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/tooltip/index.d.ts +125 -0
- package/lib/typescript/src/components/tooltip/index.d.ts.map +1 -0
- package/lib/typescript/src/components/typography/index.d.ts +6 -0
- package/lib/typescript/src/components/typography/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/index.d.ts +1 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -1
- package/lib/typescript/src/hooks/use-back-handler.d.ts +19 -0
- package/lib/typescript/src/hooks/use-back-handler.d.ts.map +1 -0
- package/lib/typescript/src/hooks/use-direction.d.ts +20 -0
- package/lib/typescript/src/hooks/use-direction.d.ts.map +1 -0
- package/lib/typescript/src/icons/index.d.ts +8 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +14 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/keyboard-avoider.d.ts.map +1 -1
- package/lib/typescript/src/primitives/text.d.ts +20 -0
- package/lib/typescript/src/primitives/text.d.ts.map +1 -1
- package/lib/typescript/src/utils/chart.d.ts +96 -0
- package/lib/typescript/src/utils/chart.d.ts.map +1 -0
- package/lib/typescript/src/utils/date.d.ts +116 -0
- package/lib/typescript/src/utils/date.d.ts.map +1 -0
- package/package.json +9 -1
- package/src/components/accordion/index.tsx +8 -12
- package/src/components/alert/index.tsx +2 -2
- package/src/components/area-chart/index.tsx +1147 -0
- package/src/components/attachment/index.tsx +2 -2
- package/src/components/avatar/index.tsx +4 -4
- package/src/components/badge/index.tsx +6 -6
- package/src/components/bar-chart/index.tsx +1208 -0
- package/src/components/bottom-sheet/index.tsx +282 -21
- package/src/components/breadcrumb/index.tsx +363 -0
- package/src/components/button/index.tsx +12 -8
- package/src/components/calendar/index.tsx +703 -0
- package/src/components/carousel/index.tsx +788 -0
- package/src/components/chip/index.tsx +6 -8
- package/src/components/date-picker/index.tsx +237 -0
- package/src/components/dialog/index.tsx +7 -2
- package/src/components/direction/index.tsx +22 -22
- package/src/components/empty-state/index.tsx +2 -2
- package/src/components/field/index.tsx +3 -5
- package/src/components/flow/index.tsx +3 -3
- package/src/components/frame/index.tsx +22 -7
- package/src/components/heatmap-chart/index.tsx +58 -11
- package/src/components/input-group/index.tsx +5 -4
- package/src/components/item/index.tsx +9 -9
- package/src/components/label/index.tsx +2 -2
- package/src/components/line-chart/index.tsx +194 -223
- package/src/components/loader/index.tsx +812 -0
- package/src/components/map/basemap.ts +304 -0
- package/src/components/map/index.tsx +1116 -0
- package/src/components/map/maplibre.ts +201 -0
- package/src/components/marker/index.tsx +3 -3
- package/src/components/message/index.tsx +15 -14
- package/src/components/message-scroller/index.tsx +5 -4
- package/src/components/otp-input/index.tsx +2 -2
- package/src/components/popover/index.tsx +43 -7
- package/src/components/progress/index.tsx +10 -2
- package/src/components/radio-group/index.tsx +2 -2
- package/src/components/ring-chart/index.tsx +543 -0
- package/src/components/section-rail/index.tsx +6 -6
- package/src/components/select/index.tsx +10 -4
- package/src/components/separator/index.tsx +77 -19
- package/src/components/shimmer/index.tsx +10 -1
- package/src/components/slider/index.tsx +20 -5
- package/src/components/steps/index.tsx +5 -5
- package/src/components/switch/index.tsx +6 -1
- package/src/components/tabs/index.tsx +7 -9
- package/src/components/timeline/index.tsx +4 -4
- package/src/components/toast/index.tsx +2 -2
- package/src/components/toggle-button/index.tsx +5 -7
- package/src/components/tooltip/index.tsx +610 -0
- package/src/components/typography/index.tsx +7 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-back-handler.ts +37 -0
- package/src/hooks/use-direction.ts +45 -0
- package/src/icons/index.tsx +111 -0
- package/src/index.ts +129 -0
- package/src/primitives/keyboard-avoider.tsx +2 -1
- package/src/primitives/text.tsx +53 -8
- package/src/utils/chart.ts +355 -0
- package/src/utils/date.ts +446 -0
|
@@ -0,0 +1,543 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RingChart — progress towards several targets, as concentric arcs.
|
|
3
|
+
*
|
|
4
|
+
* ```tsx
|
|
5
|
+
* <RingChart data={goals}>
|
|
6
|
+
* <RingChart.Ring index={0} />
|
|
7
|
+
* <RingChart.Ring index={1} />
|
|
8
|
+
* <RingChart.Center />
|
|
9
|
+
* <RingChart.Legend />
|
|
10
|
+
* </RingChart>
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* ## What it is not
|
|
14
|
+
*
|
|
15
|
+
* It is not a pie or a donut, and the difference matters. A pie divides one
|
|
16
|
+
* whole between its slices, so its parts are only meaningful against each
|
|
17
|
+
* other and the angles must add to a full turn. A ring here is a value against
|
|
18
|
+
* *its own* target — three rings can all be at ninety percent of three
|
|
19
|
+
* unrelated numbers, and that is the reading. Nothing is normalised across
|
|
20
|
+
* rings, and nothing has to add up.
|
|
21
|
+
*
|
|
22
|
+
* That is also why each ring gets a track. An arc drawn on nothing shows how
|
|
23
|
+
* far something went; an arc drawn on a full circle shows how far it went *of
|
|
24
|
+
* what it was aiming at*, which is the entire question.
|
|
25
|
+
*
|
|
26
|
+
* ## Drawing
|
|
27
|
+
*
|
|
28
|
+
* Each ring is two arcs — a full-circle track and the progress over it — with
|
|
29
|
+
* only the progress animated, through `strokeDasharray`. Sweeping the arc by
|
|
30
|
+
* rebuilding its path would work, but a dash offset is two numbers moving on
|
|
31
|
+
* an unchanged path, and it keeps the rounded cap pinned to the moving end for
|
|
32
|
+
* free.
|
|
33
|
+
*
|
|
34
|
+
* Touch, not hover: a ring is selected by pressing it, and pressing the same
|
|
35
|
+
* one again clears the selection. There is no equivalent of a pointer resting
|
|
36
|
+
* somewhere without committing, so a chart that only revealed its numbers on
|
|
37
|
+
* hover would never reveal them at all.
|
|
38
|
+
*/
|
|
39
|
+
import {
|
|
40
|
+
Children,
|
|
41
|
+
createContext,
|
|
42
|
+
forwardRef,
|
|
43
|
+
isValidElement,
|
|
44
|
+
useContext,
|
|
45
|
+
useEffect,
|
|
46
|
+
useImperativeHandle,
|
|
47
|
+
useMemo,
|
|
48
|
+
useRef,
|
|
49
|
+
useState,
|
|
50
|
+
type ReactNode,
|
|
51
|
+
} from 'react';
|
|
52
|
+
import { Pressable, View, type LayoutChangeEvent, type ViewProps } from 'react-native';
|
|
53
|
+
import Animated, {
|
|
54
|
+
Easing,
|
|
55
|
+
useAnimatedProps,
|
|
56
|
+
useReducedMotion,
|
|
57
|
+
useSharedValue,
|
|
58
|
+
withTiming,
|
|
59
|
+
type SharedValue,
|
|
60
|
+
} from 'react-native-reanimated';
|
|
61
|
+
import Svg, { Circle, G } from 'react-native-svg';
|
|
62
|
+
import { Text } from '../../primitives/text';
|
|
63
|
+
import { compactNumber, useSeriesColor, type SeriesColorIndex } from '../../utils/chart';
|
|
64
|
+
import { cn } from '../../utils/cn';
|
|
65
|
+
|
|
66
|
+
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
|
67
|
+
|
|
68
|
+
/** One ring per datum, and the datum is the whole of its contract. */
|
|
69
|
+
export interface RingDatum {
|
|
70
|
+
/** Name for the legend and the centre readout. */
|
|
71
|
+
label: string;
|
|
72
|
+
/** Where this ring has got to. */
|
|
73
|
+
value: number;
|
|
74
|
+
/** What it is aiming at. The ring is full when `value` reaches it. */
|
|
75
|
+
maxValue: number;
|
|
76
|
+
/** Explicit colour, overriding the `--color-chart-*` token. */
|
|
77
|
+
color?: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
interface RingChartContextValue {
|
|
81
|
+
data: RingDatum[];
|
|
82
|
+
size: number;
|
|
83
|
+
strokeWidth: number;
|
|
84
|
+
ringGap: number;
|
|
85
|
+
colors: string[];
|
|
86
|
+
/** 0 to 1 as the arcs sweep in. */
|
|
87
|
+
reveal: SharedValue<number>;
|
|
88
|
+
activeIndex: number;
|
|
89
|
+
setActiveIndex: (index: number) => void;
|
|
90
|
+
radiusOf: (index: number) => number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const RingChartContext = createContext<RingChartContextValue | null>(null);
|
|
94
|
+
|
|
95
|
+
function useChart(component: string): RingChartContextValue {
|
|
96
|
+
const context = useContext(RingChartContext);
|
|
97
|
+
if (!context) {
|
|
98
|
+
throw new Error(`${component} must be used within a <RingChart>`);
|
|
99
|
+
}
|
|
100
|
+
return context;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The selected ring, for something rendered inside the chart. */
|
|
104
|
+
export function useRingChart() {
|
|
105
|
+
const { data, activeIndex } = useChart('useRingChart');
|
|
106
|
+
return {
|
|
107
|
+
activeIndex,
|
|
108
|
+
activeRing: activeIndex >= 0 ? (data[activeIndex] ?? null) : null,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface RingChartProps extends ViewProps {
|
|
113
|
+
className?: string;
|
|
114
|
+
/** One entry per ring, outermost first. */
|
|
115
|
+
data: RingDatum[];
|
|
116
|
+
/** Fixed diameter in points. Measured from the container when omitted. */
|
|
117
|
+
size?: number;
|
|
118
|
+
/** Thickness of each ring. */
|
|
119
|
+
strokeWidth?: number;
|
|
120
|
+
/** Gap between one ring and the next. */
|
|
121
|
+
ringGap?: number;
|
|
122
|
+
/** Milliseconds for the arcs to sweep in. */
|
|
123
|
+
animationDuration?: number;
|
|
124
|
+
/** Selected ring. Leave unset to let the chart track it. */
|
|
125
|
+
activeIndex?: number;
|
|
126
|
+
/** Fires with the selected ring, or `-1` when the selection is cleared. */
|
|
127
|
+
onActiveIndexChange?: (index: number) => void;
|
|
128
|
+
children?: ReactNode;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Imperative handle: re-run the sweep, for a "replay" control. */
|
|
132
|
+
export interface RingChartHandle {
|
|
133
|
+
replay: () => void;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const RingChartRoot = forwardRef<RingChartHandle, RingChartProps>(function RingChartRoot(
|
|
137
|
+
{
|
|
138
|
+
className,
|
|
139
|
+
data,
|
|
140
|
+
size,
|
|
141
|
+
strokeWidth = 12,
|
|
142
|
+
ringGap = 6,
|
|
143
|
+
animationDuration = 1100,
|
|
144
|
+
activeIndex: activeIndexProp,
|
|
145
|
+
onActiveIndexChange,
|
|
146
|
+
children,
|
|
147
|
+
...props
|
|
148
|
+
},
|
|
149
|
+
ref
|
|
150
|
+
) {
|
|
151
|
+
const [measured, setMeasured] = useState(0);
|
|
152
|
+
const [internalActive, setInternalActive] = useState(-1);
|
|
153
|
+
const reveal = useSharedValue(0);
|
|
154
|
+
const reducedMotion = useReducedMotion();
|
|
155
|
+
|
|
156
|
+
const controlled = activeIndexProp !== undefined;
|
|
157
|
+
const activeIndex = controlled ? activeIndexProp : internalActive;
|
|
158
|
+
|
|
159
|
+
const setActiveIndex = useMemo(
|
|
160
|
+
() => (index: number) => {
|
|
161
|
+
if (!controlled) setInternalActive(index);
|
|
162
|
+
onActiveIndexChange?.(index);
|
|
163
|
+
},
|
|
164
|
+
[controlled, onActiveIndexChange]
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const box = size ?? measured;
|
|
168
|
+
|
|
169
|
+
/*
|
|
170
|
+
* Outermost ring first, so `data[0]` is the one the eye lands on. Each ring
|
|
171
|
+
* inside it steps in by its own thickness plus the gap.
|
|
172
|
+
*/
|
|
173
|
+
const radiusOf = useMemo(
|
|
174
|
+
() => (index: number) =>
|
|
175
|
+
Math.max(box / 2 - strokeWidth / 2 - index * (strokeWidth + ringGap), strokeWidth / 2),
|
|
176
|
+
[box, strokeWidth, ringGap]
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const playReveal = useMemo(
|
|
180
|
+
() => () => {
|
|
181
|
+
if (reducedMotion) {
|
|
182
|
+
reveal.value = 1;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
reveal.value = 0;
|
|
186
|
+
reveal.value = withTiming(1, {
|
|
187
|
+
duration: animationDuration,
|
|
188
|
+
easing: Easing.bezier(0.85, 0, 0.15, 1),
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
[reducedMotion, animationDuration, reveal]
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
const revealed = useRef(false);
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
if (revealed.current || box <= 0 || !data.length) return;
|
|
197
|
+
revealed.current = true;
|
|
198
|
+
playReveal();
|
|
199
|
+
}, [box, data.length, playReveal]);
|
|
200
|
+
|
|
201
|
+
useImperativeHandle(ref, () => ({ replay: playReveal }), [playReveal]);
|
|
202
|
+
|
|
203
|
+
// Resolved here rather than inside each ring, so the legend and the centre
|
|
204
|
+
// readout can name a ring's colour without rendering one.
|
|
205
|
+
const c1 = useSeriesColor(undefined, 1);
|
|
206
|
+
const c2 = useSeriesColor(undefined, 2);
|
|
207
|
+
const c3 = useSeriesColor(undefined, 3);
|
|
208
|
+
const c4 = useSeriesColor(undefined, 4);
|
|
209
|
+
const c5 = useSeriesColor(undefined, 5);
|
|
210
|
+
const palette = useMemo(() => [c1, c2, c3, c4, c5], [c1, c2, c3, c4, c5]);
|
|
211
|
+
const colors = useMemo(
|
|
212
|
+
() => data.map((ring, index) => ring.color ?? palette[index % palette.length]!),
|
|
213
|
+
[data, palette]
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const onLayout = (event: LayoutChangeEvent) => {
|
|
217
|
+
const { width, height } = event.nativeEvent.layout;
|
|
218
|
+
const next = Math.round(Math.min(width, height));
|
|
219
|
+
if (next !== measured) setMeasured(next);
|
|
220
|
+
props.onLayout?.(event);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
const context = useMemo<RingChartContextValue>(
|
|
224
|
+
() => ({
|
|
225
|
+
data,
|
|
226
|
+
size: box,
|
|
227
|
+
strokeWidth,
|
|
228
|
+
ringGap,
|
|
229
|
+
colors,
|
|
230
|
+
reveal,
|
|
231
|
+
activeIndex,
|
|
232
|
+
setActiveIndex,
|
|
233
|
+
radiusOf,
|
|
234
|
+
}),
|
|
235
|
+
[data, box, strokeWidth, ringGap, colors, reveal, activeIndex, setActiveIndex, radiusOf]
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
const rings: ReactNode[] = [];
|
|
239
|
+
const overlay: ReactNode[] = [];
|
|
240
|
+
Children.forEach(children, (child, index) => {
|
|
241
|
+
if (!isValidElement(child)) return;
|
|
242
|
+
const slot = (child.type as { slot?: 'ring' | 'overlay' }).slot ?? 'overlay';
|
|
243
|
+
(slot === 'ring' ? rings : overlay).push(
|
|
244
|
+
<ChildSlot key={index}>{child}</ChildSlot>
|
|
245
|
+
);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<RingChartContext.Provider value={context}>
|
|
250
|
+
<View
|
|
251
|
+
{...props}
|
|
252
|
+
onLayout={onLayout}
|
|
253
|
+
style={[size ? { width: size, height: size } : { aspectRatio: 1 }, props.style]}
|
|
254
|
+
className={cn('w-full items-center justify-center', className)}
|
|
255
|
+
>
|
|
256
|
+
{box > 0 ? (
|
|
257
|
+
<>
|
|
258
|
+
<Svg width={box} height={box}>
|
|
259
|
+
{rings}
|
|
260
|
+
</Svg>
|
|
261
|
+
{/*
|
|
262
|
+
* The centre and the legend sit over the SVG rather than inside
|
|
263
|
+
* it: both are text, and SVG text ignores the platform's text
|
|
264
|
+
* scaling and the theme's font.
|
|
265
|
+
*/}
|
|
266
|
+
<View
|
|
267
|
+
pointerEvents="box-none"
|
|
268
|
+
style={{ position: 'absolute', width: box, height: box }}
|
|
269
|
+
className="items-center justify-center"
|
|
270
|
+
>
|
|
271
|
+
{overlay}
|
|
272
|
+
</View>
|
|
273
|
+
</>
|
|
274
|
+
) : null}
|
|
275
|
+
</View>
|
|
276
|
+
</RingChartContext.Provider>
|
|
277
|
+
);
|
|
278
|
+
});
|
|
279
|
+
RingChartRoot.displayName = 'RingChart';
|
|
280
|
+
|
|
281
|
+
function ChildSlot({ children }: { children: ReactNode }) {
|
|
282
|
+
return <>{children}</>;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface RingChartRingProps {
|
|
286
|
+
/** Which entry in `data` this ring draws. */
|
|
287
|
+
index: number;
|
|
288
|
+
/** Explicit colour, overriding the datum's and the token. */
|
|
289
|
+
color?: string;
|
|
290
|
+
/** Which of the five chart tokens to take, when the datum names no colour. */
|
|
291
|
+
colorIndex?: SeriesColorIndex;
|
|
292
|
+
/** Rounded ends, or square ones. */
|
|
293
|
+
lineCap?: 'round' | 'butt';
|
|
294
|
+
/** Opacity of the track behind the arc. */
|
|
295
|
+
trackOpacity?: number;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* One ring: a full-circle track, and the arc showing how far along it the
|
|
300
|
+
* value has got.
|
|
301
|
+
*
|
|
302
|
+
* The arc is swept with `strokeDasharray` rather than by rebuilding its path.
|
|
303
|
+
* Both work, but a dash offset moves two numbers on a path that never changes
|
|
304
|
+
* — and it keeps the rounded cap pinned to the moving end without any extra
|
|
305
|
+
* geometry.
|
|
306
|
+
*/
|
|
307
|
+
function RingChartRing({
|
|
308
|
+
index,
|
|
309
|
+
color,
|
|
310
|
+
colorIndex,
|
|
311
|
+
lineCap = 'round',
|
|
312
|
+
trackOpacity = 0.15,
|
|
313
|
+
}: RingChartRingProps) {
|
|
314
|
+
const { data, size, strokeWidth, colors, reveal, activeIndex, setActiveIndex, radiusOf } =
|
|
315
|
+
useChart('RingChart.Ring');
|
|
316
|
+
|
|
317
|
+
const datum = data[index];
|
|
318
|
+
const tokenColor = useSeriesColor(undefined, colorIndex ?? 1);
|
|
319
|
+
const stroke = color ?? datum?.color ?? (colorIndex ? tokenColor : colors[index]) ?? tokenColor;
|
|
320
|
+
|
|
321
|
+
const radius = radiusOf(index);
|
|
322
|
+
const circumference = 2 * Math.PI * radius;
|
|
323
|
+
const centre = size / 2;
|
|
324
|
+
|
|
325
|
+
const fraction = datum && datum.maxValue > 0 ? datum.value / datum.maxValue : 0;
|
|
326
|
+
// A value past its target fills the ring and stops. Going round twice would
|
|
327
|
+
// draw 110% as 10%, which is the wrong answer told confidently.
|
|
328
|
+
const clamped = Math.max(0, Math.min(1, fraction));
|
|
329
|
+
|
|
330
|
+
/*
|
|
331
|
+
* Staggered outward-in, so the rings arrive as a sequence rather than all at
|
|
332
|
+
* once. The window each gets is what is left after the stagger, so a chart
|
|
333
|
+
* of five rings still finishes inside the one duration.
|
|
334
|
+
*/
|
|
335
|
+
const count = Math.max(1, data.length);
|
|
336
|
+
const start = (index / count) * 0.4;
|
|
337
|
+
|
|
338
|
+
const props = useAnimatedProps(() => {
|
|
339
|
+
const progress = Math.max(0, Math.min(1, (reveal.value - start) / 0.6));
|
|
340
|
+
const drawn = circumference * clamped * progress;
|
|
341
|
+
return {
|
|
342
|
+
strokeDasharray: [drawn, circumference],
|
|
343
|
+
};
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const dimmed = activeIndex >= 0 && activeIndex !== index;
|
|
347
|
+
|
|
348
|
+
if (!datum || radius <= 0) return null;
|
|
349
|
+
|
|
350
|
+
return (
|
|
351
|
+
<G opacity={dimmed ? 0.35 : 1}>
|
|
352
|
+
<Circle
|
|
353
|
+
cx={centre}
|
|
354
|
+
cy={centre}
|
|
355
|
+
r={radius}
|
|
356
|
+
stroke={stroke}
|
|
357
|
+
strokeOpacity={trackOpacity}
|
|
358
|
+
strokeWidth={strokeWidth}
|
|
359
|
+
fill="none"
|
|
360
|
+
/>
|
|
361
|
+
<AnimatedCircle
|
|
362
|
+
animatedProps={props}
|
|
363
|
+
cx={centre}
|
|
364
|
+
cy={centre}
|
|
365
|
+
r={radius}
|
|
366
|
+
stroke={stroke}
|
|
367
|
+
strokeWidth={strokeWidth}
|
|
368
|
+
strokeLinecap={lineCap}
|
|
369
|
+
fill="none"
|
|
370
|
+
// Rotated so the arc starts at twelve o'clock. An arc starting at
|
|
371
|
+
// three reads as a gauge that has already been running.
|
|
372
|
+
transform={`rotate(-90 ${centre} ${centre})`}
|
|
373
|
+
/>
|
|
374
|
+
{/*
|
|
375
|
+
* The touch target is the ring itself, drawn as a transparent stroke
|
|
376
|
+
* over it and made wider than the ring — a twelve-point band is below
|
|
377
|
+
* the size a finger can reliably hit.
|
|
378
|
+
*/}
|
|
379
|
+
<Circle
|
|
380
|
+
cx={centre}
|
|
381
|
+
cy={centre}
|
|
382
|
+
r={radius}
|
|
383
|
+
stroke="transparent"
|
|
384
|
+
strokeWidth={Math.max(strokeWidth, 28)}
|
|
385
|
+
fill="none"
|
|
386
|
+
onPress={() => setActiveIndex(activeIndex === index ? -1 : index)}
|
|
387
|
+
/>
|
|
388
|
+
</G>
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
RingChartRing.displayName = 'RingChart.Ring';
|
|
392
|
+
RingChartRing.slot = 'ring' as const;
|
|
393
|
+
|
|
394
|
+
export interface RingChartCenterProps {
|
|
395
|
+
/**
|
|
396
|
+
* Heading shown when no ring is selected. Defaults to the outermost ring's
|
|
397
|
+
* own name, which is what the centre shows when nothing has been picked.
|
|
398
|
+
*/
|
|
399
|
+
defaultLabel?: string;
|
|
400
|
+
/** Format the number under the label. Defaults to a compact number. */
|
|
401
|
+
formatValue?: (value: number, ring: RingDatum | null) => string;
|
|
402
|
+
/**
|
|
403
|
+
* Draw the middle yourself. Given the selected ring, or `null` when nothing
|
|
404
|
+
* is selected.
|
|
405
|
+
*/
|
|
406
|
+
children?: (ring: RingDatum | null) => ReactNode;
|
|
407
|
+
className?: string;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* The readout in the hole.
|
|
412
|
+
*
|
|
413
|
+
* With nothing selected it shows the outermost ring — the one the eye lands on
|
|
414
|
+
* first. Not a total: the rings measure different things against different
|
|
415
|
+
* targets, so their values do not add up and their percentages do not average,
|
|
416
|
+
* and a total here would be a confident number about nothing. Selecting a ring
|
|
417
|
+
* swaps it for that ring's own figures.
|
|
418
|
+
*/
|
|
419
|
+
function RingChartCenter({
|
|
420
|
+
defaultLabel,
|
|
421
|
+
formatValue,
|
|
422
|
+
children,
|
|
423
|
+
className,
|
|
424
|
+
}: RingChartCenterProps) {
|
|
425
|
+
const { data, activeIndex, strokeWidth, radiusOf } = useChart('RingChart.Center');
|
|
426
|
+
|
|
427
|
+
/*
|
|
428
|
+
* With nothing selected the centre shows the outermost ring — the one the
|
|
429
|
+
* eye lands on — rather than an aggregate. There is no aggregate to show:
|
|
430
|
+
* the rings measure different things against different targets, so their
|
|
431
|
+
* values do not add up and their percentages do not average. A total here
|
|
432
|
+
* would be a confident number about nothing.
|
|
433
|
+
*/
|
|
434
|
+
const ring = (activeIndex >= 0 ? data[activeIndex] : data[0]) ?? null;
|
|
435
|
+
const selected = activeIndex >= 0;
|
|
436
|
+
const format = formatValue ?? ((amount: number) => compactNumber(amount));
|
|
437
|
+
|
|
438
|
+
/*
|
|
439
|
+
* The hole is what is left inside the innermost ring, measured off the same
|
|
440
|
+
* function that places the rings so the two cannot disagree. Text wider than
|
|
441
|
+
* it would sit on the arcs rather than inside them.
|
|
442
|
+
*/
|
|
443
|
+
const inner = Math.max(radiusOf(Math.max(data.length - 1, 0)) - strokeWidth / 2, 0);
|
|
444
|
+
// A square inside a circle, not across it: the corners of a box as wide as
|
|
445
|
+
// the diameter fall outside the hole.
|
|
446
|
+
const hole = inner * Math.SQRT2;
|
|
447
|
+
|
|
448
|
+
return (
|
|
449
|
+
<View
|
|
450
|
+
pointerEvents="none"
|
|
451
|
+
style={{ maxWidth: hole }}
|
|
452
|
+
className={cn('items-center', className)}
|
|
453
|
+
>
|
|
454
|
+
{children ? (
|
|
455
|
+
children(selected ? ring : null)
|
|
456
|
+
) : ring ? (
|
|
457
|
+
<>
|
|
458
|
+
<Text size="xs" muted numberOfLines={1}>
|
|
459
|
+
{selected ? ring.label : (defaultLabel ?? ring.label)}
|
|
460
|
+
</Text>
|
|
461
|
+
{/* Below about ninety points there is no room for two lines and a
|
|
462
|
+
headline, so the number gets the space and the rest is dropped. */}
|
|
463
|
+
<Text size={hole < 90 ? 'lg' : 'xl'} weight="semibold" numberOfLines={1}>
|
|
464
|
+
{format(ring.value, ring)}
|
|
465
|
+
</Text>
|
|
466
|
+
{hole >= 90 ? (
|
|
467
|
+
<Text size="xs" muted numberOfLines={1}>
|
|
468
|
+
{`of ${format(ring.maxValue, ring)}`}
|
|
469
|
+
</Text>
|
|
470
|
+
) : null}
|
|
471
|
+
</>
|
|
472
|
+
) : null}
|
|
473
|
+
</View>
|
|
474
|
+
);
|
|
475
|
+
}
|
|
476
|
+
RingChartCenter.displayName = 'RingChart.Center';
|
|
477
|
+
RingChartCenter.slot = 'overlay' as const;
|
|
478
|
+
|
|
479
|
+
export interface RingChartLegendProps extends ViewProps {
|
|
480
|
+
className?: string;
|
|
481
|
+
/** Show each ring's percentage of its own target beside its name. */
|
|
482
|
+
showValue?: boolean;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* A swatch and a name per ring, pressable in the same way the rings are — the
|
|
487
|
+
* legend is usually the easier target of the two, and on a small chart it is
|
|
488
|
+
* the only comfortable one.
|
|
489
|
+
*/
|
|
490
|
+
function RingChartLegend({ className, showValue = true, ...props }: RingChartLegendProps) {
|
|
491
|
+
const { data, colors, activeIndex, setActiveIndex } = useChart('RingChart.Legend');
|
|
492
|
+
|
|
493
|
+
if (!data.length) return null;
|
|
494
|
+
|
|
495
|
+
return (
|
|
496
|
+
<View
|
|
497
|
+
{...props}
|
|
498
|
+
pointerEvents="box-none"
|
|
499
|
+
className={cn('absolute -bottom-2 w-full gap-1', className)}
|
|
500
|
+
>
|
|
501
|
+
{data.map((ring, index) => {
|
|
502
|
+
const percent =
|
|
503
|
+
ring.maxValue > 0 ? Math.round((ring.value / ring.maxValue) * 100) : 0;
|
|
504
|
+
const dimmed = activeIndex >= 0 && activeIndex !== index;
|
|
505
|
+
return (
|
|
506
|
+
<Pressable
|
|
507
|
+
key={ring.label}
|
|
508
|
+
accessibilityRole="button"
|
|
509
|
+
accessibilityLabel={`${ring.label}, ${percent} percent`}
|
|
510
|
+
onPress={() => setActiveIndex(activeIndex === index ? -1 : index)}
|
|
511
|
+
style={{ opacity: dimmed ? 0.4 : 1 }}
|
|
512
|
+
className="flex-row items-center gap-1.5"
|
|
513
|
+
>
|
|
514
|
+
<View
|
|
515
|
+
style={{
|
|
516
|
+
width: 8,
|
|
517
|
+
height: 8,
|
|
518
|
+
borderRadius: 4,
|
|
519
|
+
backgroundColor: colors[index],
|
|
520
|
+
}}
|
|
521
|
+
/>
|
|
522
|
+
<Text size="xs" muted numberOfLines={1} className="flex-1">
|
|
523
|
+
{ring.label}
|
|
524
|
+
</Text>
|
|
525
|
+
{showValue ? (
|
|
526
|
+
<Text size="xs" weight="medium">
|
|
527
|
+
{percent}%
|
|
528
|
+
</Text>
|
|
529
|
+
) : null}
|
|
530
|
+
</Pressable>
|
|
531
|
+
);
|
|
532
|
+
})}
|
|
533
|
+
</View>
|
|
534
|
+
);
|
|
535
|
+
}
|
|
536
|
+
RingChartLegend.displayName = 'RingChart.Legend';
|
|
537
|
+
RingChartLegend.slot = 'overlay' as const;
|
|
538
|
+
|
|
539
|
+
export const RingChart = Object.assign(RingChartRoot, {
|
|
540
|
+
Ring: RingChartRing,
|
|
541
|
+
Center: RingChartCenter,
|
|
542
|
+
Legend: RingChartLegend,
|
|
543
|
+
});
|
|
@@ -50,7 +50,7 @@ import Animated, {
|
|
|
50
50
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
51
51
|
import { useCSSVariable } from 'uniwind';
|
|
52
52
|
import { Portal } from '../../primitives/portal';
|
|
53
|
-
import { Text } from '../../primitives/text';
|
|
53
|
+
import { Text, textChildren } from '../../primitives/text';
|
|
54
54
|
import { cn } from '../../utils/cn';
|
|
55
55
|
import { selectionTick } from '../../utils/haptics';
|
|
56
56
|
|
|
@@ -242,7 +242,7 @@ function SectionRailRoot({
|
|
|
242
242
|
}}
|
|
243
243
|
{...props}
|
|
244
244
|
>
|
|
245
|
-
{children}
|
|
245
|
+
{textChildren(children)}
|
|
246
246
|
</View>
|
|
247
247
|
</SectionRailContext.Provider>
|
|
248
248
|
);
|
|
@@ -271,12 +271,12 @@ function SectionRailTrigger({ className, children, ...props }: SectionRailTrigge
|
|
|
271
271
|
hitSlop={8}
|
|
272
272
|
className={cn(
|
|
273
273
|
'gap-2 py-3',
|
|
274
|
-
placement === 'right' ? 'items-end
|
|
274
|
+
placement === 'right' ? 'items-end ps-6 pe-2' : 'items-start ps-2 pe-6',
|
|
275
275
|
className
|
|
276
276
|
)}
|
|
277
277
|
{...props}
|
|
278
278
|
>
|
|
279
|
-
{children}
|
|
279
|
+
{textChildren(children)}
|
|
280
280
|
</Pressable>
|
|
281
281
|
);
|
|
282
282
|
}
|
|
@@ -407,7 +407,7 @@ function SectionRailPanel({ className, children, ...props }: SectionRailContentP
|
|
|
407
407
|
{...props}
|
|
408
408
|
>
|
|
409
409
|
<ScrollView bounces={false} showsVerticalScrollIndicator={false}>
|
|
410
|
-
{children}
|
|
410
|
+
{textChildren(children)}
|
|
411
411
|
</ScrollView>
|
|
412
412
|
</Animated.View>
|
|
413
413
|
);
|
|
@@ -434,7 +434,7 @@ function SectionRailItem({ className, value, level = 0, children }: SectionRailI
|
|
|
434
434
|
onPress={() => onValueChange?.(value)}
|
|
435
435
|
style={{ paddingLeft: 12 + level * ITEM_INDENT }}
|
|
436
436
|
className={cn(
|
|
437
|
-
'rounded-lg py-2
|
|
437
|
+
'rounded-lg py-2 pe-3 active:bg-accent',
|
|
438
438
|
selected && 'bg-accent',
|
|
439
439
|
className
|
|
440
440
|
)}
|
|
@@ -51,7 +51,8 @@ import { useCSSVariable } from 'uniwind';
|
|
|
51
51
|
import { CheckIcon, ChevronDownIcon } from '../../icons';
|
|
52
52
|
import { getNativeUI } from '../../native';
|
|
53
53
|
import { Portal } from '../../primitives/portal';
|
|
54
|
-
import { Text } from '../../primitives/text';
|
|
54
|
+
import { Text, textChildren } from '../../primitives/text';
|
|
55
|
+
import { useBackHandler } from '../../hooks/use-back-handler';
|
|
55
56
|
import { BottomSheet } from '../bottom-sheet';
|
|
56
57
|
|
|
57
58
|
const selectVariants = tv({
|
|
@@ -223,6 +224,11 @@ function SelectRoot({
|
|
|
223
224
|
onOpenChange?.(false);
|
|
224
225
|
}, [chevron, onOpenChange]);
|
|
225
226
|
|
|
227
|
+
// An open overlay list catches the Android back button, closing itself
|
|
228
|
+
// instead of popping the screen behind it. The `sheet` presentation gets the
|
|
229
|
+
// same behaviour from its BottomSheet; the native picker owns its own back.
|
|
230
|
+
useBackHandler(open && presentation === 'overlay' && !nativeUI, close);
|
|
231
|
+
|
|
226
232
|
const toggle = useCallback(() => {
|
|
227
233
|
if (open) {
|
|
228
234
|
close();
|
|
@@ -333,7 +339,7 @@ function SelectRoot({
|
|
|
333
339
|
</Text>
|
|
334
340
|
) : null}
|
|
335
341
|
<ScrollView bounces={false} className="max-h-96">
|
|
336
|
-
<View className="gap-1 pb-2">{children}</View>
|
|
342
|
+
<View className="gap-1 pb-2">{textChildren(children)}</View>
|
|
337
343
|
</ScrollView>
|
|
338
344
|
</SelectContext.Provider>
|
|
339
345
|
</BottomSheet.Content>
|
|
@@ -353,7 +359,7 @@ function SelectRoot({
|
|
|
353
359
|
exiting={FadeOut.duration(120)}
|
|
354
360
|
className={slots.list()}
|
|
355
361
|
>
|
|
356
|
-
{children}
|
|
362
|
+
{textChildren(children)}
|
|
357
363
|
</Animated.View>
|
|
358
364
|
) : null}
|
|
359
365
|
</View>
|
|
@@ -410,7 +416,7 @@ function SelectRoot({
|
|
|
410
416
|
className={slots.list()}
|
|
411
417
|
>
|
|
412
418
|
<ScrollView bounces={false} showsVerticalScrollIndicator={false}>
|
|
413
|
-
{children}
|
|
419
|
+
{textChildren(children)}
|
|
414
420
|
</ScrollView>
|
|
415
421
|
</Animated.View>
|
|
416
422
|
</SelectContext.Provider>
|