panelui-native 0.25.0 → 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/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 +182 -50
- package/lib/module/components/area-chart/index.js.map +1 -1
- 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 +3 -3
- 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 +197 -56
- package/lib/module/components/bar-chart/index.js.map +1 -1
- package/lib/module/components/bottom-sheet/index.js +15 -10
- package/lib/module/components/bottom-sheet/index.js.map +1 -1
- package/lib/module/components/breadcrumb/index.js +6 -6
- package/lib/module/components/breadcrumb/index.js.map +1 -1
- 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 +4 -4
- 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 +2 -1
- 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 +5 -5
- package/lib/module/components/frame/index.js.map +1 -1
- package/lib/module/components/input-group/index.js +3 -2
- 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 +167 -44
- package/lib/module/components/line-chart/index.js.map +1 -1
- package/lib/module/components/map/index.js +7 -7
- package/lib/module/components/map/index.js.map +1 -1
- 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 +7 -7
- 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/popover/index.js +39 -7
- package/lib/module/components/popover/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/section-rail/index.js +4 -4
- 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/steps/index.js +4 -4
- package/lib/module/components/steps/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 +2 -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/icons/index.js +63 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +5 -1
- 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 +25 -1
- package/lib/module/primitives/text.js.map +1 -1
- 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 +41 -1
- package/lib/typescript/src/components/area-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/attachment/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bar-chart/index.d.ts +44 -2
- package/lib/typescript/src/components/bar-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/src/components/breadcrumb/index.d.ts.map +1 -1
- 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.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.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 +41 -2
- package/lib/typescript/src/components/line-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/map/index.d.ts.map +1 -1
- 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/select/index.d.ts.map +1 -1
- package/lib/typescript/src/components/steps/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.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/icons/index.d.ts +3 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +8 -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/date.d.ts +116 -0
- package/lib/typescript/src/utils/date.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/components/accordion/index.tsx +8 -12
- package/src/components/alert/index.tsx +2 -2
- package/src/components/area-chart/index.tsx +208 -55
- package/src/components/attachment/index.tsx +2 -2
- package/src/components/avatar/index.tsx +3 -3
- package/src/components/badge/index.tsx +6 -6
- package/src/components/bar-chart/index.tsx +214 -54
- package/src/components/bottom-sheet/index.tsx +17 -16
- package/src/components/breadcrumb/index.tsx +6 -8
- 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 +4 -6
- package/src/components/date-picker/index.tsx +237 -0
- package/src/components/dialog/index.tsx +7 -2
- package/src/components/direction/index.tsx +2 -1
- 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 +5 -7
- package/src/components/input-group/index.tsx +3 -2
- package/src/components/item/index.tsx +9 -9
- package/src/components/label/index.tsx +2 -2
- package/src/components/line-chart/index.tsx +189 -50
- package/src/components/map/index.tsx +7 -9
- package/src/components/marker/index.tsx +3 -3
- package/src/components/message/index.tsx +7 -7
- package/src/components/message-scroller/index.tsx +5 -4
- package/src/components/popover/index.tsx +43 -7
- package/src/components/radio-group/index.tsx +2 -2
- package/src/components/section-rail/index.tsx +4 -4
- package/src/components/select/index.tsx +10 -4
- package/src/components/steps/index.tsx +4 -4
- 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 +2 -2
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use-back-handler.ts +37 -0
- package/src/icons/index.tsx +45 -0
- package/src/index.ts +45 -0
- package/src/primitives/keyboard-avoider.tsx +2 -1
- package/src/primitives/text.tsx +28 -1
- package/src/utils/date.ts +446 -0
|
@@ -106,7 +106,7 @@ const PADDING = { top: 12, right: 10, bottom: 22, left: 10 };
|
|
|
106
106
|
* stays a flat list of children instead of two nested slots the caller has to
|
|
107
107
|
* remember the order of.
|
|
108
108
|
*/
|
|
109
|
-
type Layer = 'svg' | 'overlay';
|
|
109
|
+
type Layer = 'svg' | 'overlay' | 'header';
|
|
110
110
|
|
|
111
111
|
export type LineChartStatus = 'loading' | 'ready';
|
|
112
112
|
export type LineChartCurve = 'monotone' | 'linear';
|
|
@@ -388,39 +388,43 @@ const LineChartRoot = forwardRef<LineChartHandle, LineChartProps>(function LineC
|
|
|
388
388
|
]
|
|
389
389
|
);
|
|
390
390
|
|
|
391
|
-
const { svg, overlay } = partition(children);
|
|
391
|
+
const { svg, overlay, header } = partition(children);
|
|
392
392
|
|
|
393
|
+
/*
|
|
394
|
+
* Two views, because the header is not part of the plot. `aspectRatio` and
|
|
395
|
+
* the layout measurement belong to the drawing area alone — measured on the
|
|
396
|
+
* outer view they would take in the header too, and the plot would lose as
|
|
397
|
+
* much height as the readout took while still claiming the shape asked for.
|
|
398
|
+
*/
|
|
393
399
|
return (
|
|
394
400
|
<LineChartContext.Provider value={context}>
|
|
395
|
-
<View
|
|
396
|
-
{
|
|
397
|
-
onLayout={onLayout}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
</>
|
|
423
|
-
) : null}
|
|
401
|
+
<View {...props} style={props.style} className={cn('w-full', className)}>
|
|
402
|
+
{header}
|
|
403
|
+
<View onLayout={onLayout} style={{ aspectRatio }} className="w-full">
|
|
404
|
+
{plot.width > 0 ? (
|
|
405
|
+
<>
|
|
406
|
+
<Svg width="100%" height="100%" style={StyleSheet.absoluteFill}>
|
|
407
|
+
<Defs>
|
|
408
|
+
{/*
|
|
409
|
+
* One clip for everything in the plot. Sharing it is what
|
|
410
|
+
* makes the reveal read as the chart arriving, rather than as
|
|
411
|
+
* three separate things animating in at once.
|
|
412
|
+
*/}
|
|
413
|
+
<ClipPath id={clipId}>
|
|
414
|
+
<AnimatedRect
|
|
415
|
+
x={plot.left}
|
|
416
|
+
y={0}
|
|
417
|
+
height={size.height}
|
|
418
|
+
animatedProps={clipProps}
|
|
419
|
+
/>
|
|
420
|
+
</ClipPath>
|
|
421
|
+
</Defs>
|
|
422
|
+
{svg}
|
|
423
|
+
</Svg>
|
|
424
|
+
{overlay}
|
|
425
|
+
</>
|
|
426
|
+
) : null}
|
|
427
|
+
</View>
|
|
424
428
|
</View>
|
|
425
429
|
</LineChartContext.Provider>
|
|
426
430
|
);
|
|
@@ -431,18 +435,19 @@ LineChartRoot.displayName = 'LineChart';
|
|
|
431
435
|
function partition(children: ReactNode) {
|
|
432
436
|
const svg: ReactNode[] = [];
|
|
433
437
|
const overlay: ReactNode[] = [];
|
|
438
|
+
const header: ReactNode[] = [];
|
|
434
439
|
|
|
435
440
|
Children.forEach(children, (child, index) => {
|
|
436
441
|
if (!isValidElement(child)) return;
|
|
437
442
|
const layer = (child.type as { layer?: Layer }).layer ?? 'svg';
|
|
438
|
-
(layer === 'overlay' ? overlay : svg).push(
|
|
443
|
+
(layer === 'header' ? header : layer === 'overlay' ? overlay : svg).push(
|
|
439
444
|
// Children of a `Children.forEach` need keys of their own once they are
|
|
440
445
|
// put into a new array.
|
|
441
446
|
<ChildSlot key={index}>{child}</ChildSlot>
|
|
442
447
|
);
|
|
443
448
|
});
|
|
444
449
|
|
|
445
|
-
return { svg, overlay };
|
|
450
|
+
return { svg, overlay, header };
|
|
446
451
|
}
|
|
447
452
|
|
|
448
453
|
/** Identity wrapper, purely so the partitioned arrays can carry keys. */
|
|
@@ -737,20 +742,44 @@ function LineChartXAxis({ ticks = 4, format, className }: LineChartXAxisProps) {
|
|
|
737
742
|
}).filter((label): label is { key: number; text: string } => label !== null);
|
|
738
743
|
}, [data, ticks, format, xDataKey]);
|
|
739
744
|
|
|
745
|
+
/*
|
|
746
|
+
* Each label sits on its own point rather than being spread along the axis.
|
|
747
|
+
* The indices `ticks` picks are not evenly spaced — twelve months shown five
|
|
748
|
+
* at a time gives 0,3,6,8,11 — so spreading them evenly put the ones in
|
|
749
|
+
* between over the wrong part of the line.
|
|
750
|
+
*
|
|
751
|
+
* The box is backed off by half its own width rather than translated by
|
|
752
|
+
* `-50%`, which is not reliable across React Native versions.
|
|
753
|
+
*/
|
|
740
754
|
return (
|
|
741
755
|
<View
|
|
742
|
-
pointerEvents
|
|
743
|
-
|
|
744
|
-
position: 'absolute',
|
|
745
|
-
left: plot.left,
|
|
746
|
-
right: PADDING.right,
|
|
747
|
-
bottom: 0,
|
|
748
|
-
height: PADDING.bottom,
|
|
749
|
-
}}
|
|
750
|
-
className={cn('flex-row items-center justify-between', className)}
|
|
756
|
+
style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}
|
|
757
|
+
className={cn(className)}
|
|
751
758
|
>
|
|
752
759
|
{labels.map((label) => (
|
|
753
|
-
<Text
|
|
760
|
+
<Text
|
|
761
|
+
key={label.key}
|
|
762
|
+
size="xs"
|
|
763
|
+
muted
|
|
764
|
+
numberOfLines={1}
|
|
765
|
+
style={{
|
|
766
|
+
position: 'absolute',
|
|
767
|
+
bottom: 0,
|
|
768
|
+
// Centred on its point, then held inside the chart. The first and
|
|
769
|
+
// last points sit on the plot's own edges, so a box centred on
|
|
770
|
+
// them hangs half its width off the side — the clamp slides those
|
|
771
|
+
// two back in rather than letting the numbers leave the frame.
|
|
772
|
+
left: Math.max(
|
|
773
|
+
0,
|
|
774
|
+
Math.min(
|
|
775
|
+
xOf(label.key, data.length, plot) - POINT_LABEL_WIDTH / 2,
|
|
776
|
+
plot.left + plot.width + PADDING.right - POINT_LABEL_WIDTH
|
|
777
|
+
)
|
|
778
|
+
),
|
|
779
|
+
width: POINT_LABEL_WIDTH,
|
|
780
|
+
textAlign: 'center',
|
|
781
|
+
}}
|
|
782
|
+
>
|
|
754
783
|
{label.text}
|
|
755
784
|
</Text>
|
|
756
785
|
))}
|
|
@@ -955,6 +984,16 @@ LineChartTooltip.layer = 'overlay' as Layer;
|
|
|
955
984
|
|
|
956
985
|
const LABEL_WIDTH = 112;
|
|
957
986
|
|
|
987
|
+
/**
|
|
988
|
+
* Box each x label is centred in. Wide enough for a short label to sit over
|
|
989
|
+
* its point without the neighbours colliding; a longer one is ellipsised
|
|
990
|
+
* rather than allowed to push the others out of place.
|
|
991
|
+
*/
|
|
992
|
+
const POINT_LABEL_WIDTH = 56;
|
|
993
|
+
|
|
994
|
+
/** Line height of an `xs` label, for centring one on the grid line it names. */
|
|
995
|
+
const AXIS_LABEL_HEIGHT = 16;
|
|
996
|
+
|
|
958
997
|
/** A compact number for the crosshair label: 1204 → "1.2k", 24801 → "24.8k". */
|
|
959
998
|
const DOT = 9;
|
|
960
999
|
|
|
@@ -1018,20 +1057,16 @@ export interface LineChartLegendProps extends ViewProps {
|
|
|
1018
1057
|
*/
|
|
1019
1058
|
function LineChartLegend({ className, labels, ...props }: LineChartLegendProps) {
|
|
1020
1059
|
const { series } = useChart('LineChart.Legend');
|
|
1060
|
+
if (!series.length) return null;
|
|
1021
1061
|
|
|
1022
1062
|
return (
|
|
1023
1063
|
<View
|
|
1024
|
-
pointerEvents="none"
|
|
1025
1064
|
className={cn('absolute left-2.5 top-0 flex-row flex-wrap items-center gap-4', className)}
|
|
1026
1065
|
{...props}
|
|
1066
|
+
style={[{ pointerEvents: 'none' }, props.style]}
|
|
1027
1067
|
>
|
|
1028
1068
|
{series.map(([key, color]) => (
|
|
1029
|
-
<
|
|
1030
|
-
<View style={{ backgroundColor: color }} className="h-2 w-2 rounded-full" />
|
|
1031
|
-
<Text size="xs" muted>
|
|
1032
|
-
{labels?.[key] ?? key}
|
|
1033
|
-
</Text>
|
|
1034
|
-
</View>
|
|
1069
|
+
<SeriesSwatch key={key} color={color} label={labels?.[key] ?? key} />
|
|
1035
1070
|
))}
|
|
1036
1071
|
</View>
|
|
1037
1072
|
);
|
|
@@ -1039,6 +1074,109 @@ function LineChartLegend({ className, labels, ...props }: LineChartLegendProps)
|
|
|
1039
1074
|
LineChartLegend.displayName = 'LineChart.Legend';
|
|
1040
1075
|
LineChartLegend.layer = 'overlay' as Layer;
|
|
1041
1076
|
|
|
1077
|
+
/** One series' colour and name. Shared by the legend and the header. */
|
|
1078
|
+
function SeriesSwatch({ color, label }: { color: string; label: string }) {
|
|
1079
|
+
return (
|
|
1080
|
+
<View className="flex-row items-center gap-1.5">
|
|
1081
|
+
<View style={{ backgroundColor: color }} className="h-2 w-2 rounded-full" />
|
|
1082
|
+
<Text size="xs" muted>
|
|
1083
|
+
{label}
|
|
1084
|
+
</Text>
|
|
1085
|
+
</View>
|
|
1086
|
+
);
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
/* -------------------------------------------------------------------------- */
|
|
1090
|
+
/* Header layer */
|
|
1091
|
+
/* -------------------------------------------------------------------------- */
|
|
1092
|
+
|
|
1093
|
+
export interface LineChartHeaderProps extends ViewProps {
|
|
1094
|
+
className?: string;
|
|
1095
|
+
/** Small line above the value — what the chart is of. */
|
|
1096
|
+
title?: string;
|
|
1097
|
+
/** The readout. The largest thing on the card, and the first thing read. */
|
|
1098
|
+
value?: string;
|
|
1099
|
+
/** One muted line under the value — a period, a comparison, a total. */
|
|
1100
|
+
caption?: string;
|
|
1101
|
+
/** Prettier names for the series keys, as the legend takes. */
|
|
1102
|
+
labels?: Record<string, string>;
|
|
1103
|
+
/**
|
|
1104
|
+
* Draw a swatch and a name per series along the trailing edge. Prefer this to
|
|
1105
|
+
* `LineChart.Legend` on a chart that has a header: the legend floats over the
|
|
1106
|
+
* plot, where it competes with the lines for the same corner.
|
|
1107
|
+
*/
|
|
1108
|
+
legend?: boolean;
|
|
1109
|
+
/** Trailing slot — a control, a badge, a range picker. Wins over `legend`. */
|
|
1110
|
+
children?: ReactNode;
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
/**
|
|
1114
|
+
* The strip above the plot: what the chart is of, what it currently reads, and
|
|
1115
|
+
* what the colours mean.
|
|
1116
|
+
*
|
|
1117
|
+
* It belongs to the chart rather than to the card around it because it is about
|
|
1118
|
+
* the *plot* — the number changes as a finger moves along the line, and the
|
|
1119
|
+
* legend is the series list the chart itself is holding. The card's header is a
|
|
1120
|
+
* caption on the tray the chart sits in; this is the chart introducing itself.
|
|
1121
|
+
*
|
|
1122
|
+
* The value is not derived here. A readout that follows the finger belongs to
|
|
1123
|
+
* whoever owns the data — take it from `onActiveIndexChange` and pass the
|
|
1124
|
+
* formatted string down, so one header can show a total when nothing is pressed
|
|
1125
|
+
* and a point's value when something is.
|
|
1126
|
+
*/
|
|
1127
|
+
function LineChartHeader({
|
|
1128
|
+
className,
|
|
1129
|
+
title,
|
|
1130
|
+
value,
|
|
1131
|
+
caption,
|
|
1132
|
+
labels,
|
|
1133
|
+
legend = false,
|
|
1134
|
+
children,
|
|
1135
|
+
...props
|
|
1136
|
+
}: LineChartHeaderProps) {
|
|
1137
|
+
const { series } = useChart('LineChart.Header');
|
|
1138
|
+
const trailing =
|
|
1139
|
+
children ??
|
|
1140
|
+
(legend && series.length ? (
|
|
1141
|
+
<View className="flex-row flex-wrap items-center justify-end gap-x-3 gap-y-1">
|
|
1142
|
+
{series.map(([key, color]) => (
|
|
1143
|
+
<SeriesSwatch key={key} color={color} label={labels?.[key] ?? key} />
|
|
1144
|
+
))}
|
|
1145
|
+
</View>
|
|
1146
|
+
) : null);
|
|
1147
|
+
|
|
1148
|
+
return (
|
|
1149
|
+
<View
|
|
1150
|
+
{...props}
|
|
1151
|
+
className={cn('flex-row items-start justify-between gap-3 pb-3', className)}
|
|
1152
|
+
>
|
|
1153
|
+
<View className="flex-1 gap-0.5">
|
|
1154
|
+
{title ? (
|
|
1155
|
+
<Text size="xs" muted>
|
|
1156
|
+
{title}
|
|
1157
|
+
</Text>
|
|
1158
|
+
) : null}
|
|
1159
|
+
{value ? (
|
|
1160
|
+
<Text size="xl" weight="bold">
|
|
1161
|
+
{value}
|
|
1162
|
+
</Text>
|
|
1163
|
+
) : null}
|
|
1164
|
+
{caption ? (
|
|
1165
|
+
<Text size="xs" muted>
|
|
1166
|
+
{caption}
|
|
1167
|
+
</Text>
|
|
1168
|
+
) : null}
|
|
1169
|
+
</View>
|
|
1170
|
+
{/* Shrinkable, unlike a view's default in React Native. Held rigid, a
|
|
1171
|
+
three-series key takes the width it wants and the caption underneath
|
|
1172
|
+
the value wraps to two lines to make room for it. */}
|
|
1173
|
+
{trailing ? <View className="shrink pt-1">{trailing}</View> : null}
|
|
1174
|
+
</View>
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
LineChartHeader.displayName = 'LineChart.Header';
|
|
1178
|
+
LineChartHeader.layer = 'header' as Layer;
|
|
1179
|
+
|
|
1042
1180
|
/* -------------------------------------------------------------------------- */
|
|
1043
1181
|
/* Scales and paths */
|
|
1044
1182
|
/* -------------------------------------------------------------------------- */
|
|
@@ -1046,6 +1184,7 @@ LineChartLegend.layer = 'overlay' as Layer;
|
|
|
1046
1184
|
/** Only reached if the theme CSS was never imported. */
|
|
1047
1185
|
|
|
1048
1186
|
export const LineChart = Object.assign(LineChartRoot, {
|
|
1187
|
+
Header: LineChartHeader,
|
|
1049
1188
|
Grid: LineChartGrid,
|
|
1050
1189
|
Area: LineChartArea,
|
|
1051
1190
|
Line: LineChartLine,
|
|
@@ -46,7 +46,7 @@ import { Pressable, View, type ViewProps } from 'react-native';
|
|
|
46
46
|
import { useCSSVariable } from 'uniwind';
|
|
47
47
|
import { tv } from 'tailwind-variants';
|
|
48
48
|
import { CompassIcon, CrosshairIcon, MinusIcon, PlusIcon } from '../../icons';
|
|
49
|
-
import { Text } from '../../primitives/text';
|
|
49
|
+
import { Text, textChildren } from '../../primitives/text';
|
|
50
50
|
import { cn } from '../../utils/cn';
|
|
51
51
|
import {
|
|
52
52
|
buildBasemapStyle,
|
|
@@ -334,7 +334,7 @@ const MapRoot = forwardRef<MapHandle, MapProps>(function MapRoot(
|
|
|
334
334
|
: { center: center ?? [0, 20], zoom, bearing, pitch }
|
|
335
335
|
}
|
|
336
336
|
/>
|
|
337
|
-
{children}
|
|
337
|
+
{textChildren(children)}
|
|
338
338
|
</MapLibreMap>
|
|
339
339
|
</MapContext.Provider>
|
|
340
340
|
</View>
|
|
@@ -471,13 +471,11 @@ function MapLabel({ children, className, side = 'bottom' }: MapLabelProps) {
|
|
|
471
471
|
style={{ left: -120, right: -120 }}
|
|
472
472
|
>
|
|
473
473
|
<View className={cn('rounded-md bg-background/85 px-1.5 py-0.5', className)}>
|
|
474
|
-
{
|
|
474
|
+
{textChildren(children, (text) => (
|
|
475
475
|
<Text size="xs" weight="medium" numberOfLines={1}>
|
|
476
|
-
{
|
|
476
|
+
{text}
|
|
477
477
|
</Text>
|
|
478
|
-
)
|
|
479
|
-
children
|
|
480
|
-
)}
|
|
478
|
+
))}
|
|
481
479
|
</View>
|
|
482
480
|
</View>
|
|
483
481
|
);
|
|
@@ -525,7 +523,7 @@ function MapPopup({ children, className, title, lngLat }: MapPopupProps) {
|
|
|
525
523
|
{title}
|
|
526
524
|
</Text>
|
|
527
525
|
) : null}
|
|
528
|
-
{children}
|
|
526
|
+
{textChildren(children)}
|
|
529
527
|
</View>
|
|
530
528
|
</Marker>
|
|
531
529
|
);
|
|
@@ -563,7 +561,7 @@ function ControlButton({
|
|
|
563
561
|
className={slots.control()}
|
|
564
562
|
onPress={onPress}
|
|
565
563
|
>
|
|
566
|
-
{children}
|
|
564
|
+
{textChildren(children)}
|
|
567
565
|
</Pressable>
|
|
568
566
|
);
|
|
569
567
|
}
|
|
@@ -25,7 +25,7 @@ import { tv, type VariantProps } from 'tailwind-variants';
|
|
|
25
25
|
import { useCSSVariable } from 'uniwind';
|
|
26
26
|
import { IconColorProvider } from '../../icons';
|
|
27
27
|
import { AnimatedPressable, type AnimatedPressableProps } from '../../primitives/animated-pressable';
|
|
28
|
-
import { Text, type TextProps } from '../../primitives/text';
|
|
28
|
+
import { Text, type TextProps, textChildren } from '../../primitives/text';
|
|
29
29
|
import { cn } from '../../utils/cn';
|
|
30
30
|
import { Separator } from '../separator';
|
|
31
31
|
import { Shimmer } from '../shimmer';
|
|
@@ -90,7 +90,7 @@ const MarkerRoot = forwardRef<View, MarkerProps>(
|
|
|
90
90
|
variant === 'separator' ? (
|
|
91
91
|
<>
|
|
92
92
|
<Separator className="flex-1" />
|
|
93
|
-
{children}
|
|
93
|
+
{textChildren(children)}
|
|
94
94
|
<Separator className="flex-1" />
|
|
95
95
|
</>
|
|
96
96
|
) : (
|
|
@@ -149,7 +149,7 @@ const MarkerIcon = forwardRef<View, MarkerIconProps>(
|
|
|
149
149
|
{...props}
|
|
150
150
|
>
|
|
151
151
|
<IconColorProvider color={typeof muted === 'string' ? muted : undefined}>
|
|
152
|
-
{children}
|
|
152
|
+
{textChildren(children)}
|
|
153
153
|
</IconColorProvider>
|
|
154
154
|
</View>
|
|
155
155
|
);
|
|
@@ -34,7 +34,7 @@ import { tv, type VariantProps } from 'tailwind-variants';
|
|
|
34
34
|
import { useCSSVariable } from 'uniwind';
|
|
35
35
|
import { IconColorProvider } from '../../icons';
|
|
36
36
|
import { AnimatedPressable } from '../../primitives/animated-pressable';
|
|
37
|
-
import { Text, type TextProps } from '../../primitives/text';
|
|
37
|
+
import { Text, type TextProps, textChildren } from '../../primitives/text';
|
|
38
38
|
import { cn } from '../../utils/cn';
|
|
39
39
|
|
|
40
40
|
const messageVariants = tv({
|
|
@@ -137,11 +137,11 @@ const MessageRoot = forwardRef<View, MessageProps>(
|
|
|
137
137
|
className={root({ className })}
|
|
138
138
|
{...props}
|
|
139
139
|
>
|
|
140
|
-
{children}
|
|
140
|
+
{textChildren(children)}
|
|
141
141
|
</AnimatedPressable>
|
|
142
142
|
) : (
|
|
143
143
|
<View ref={ref} className={root({ className })} {...props}>
|
|
144
|
-
{children}
|
|
144
|
+
{textChildren(children)}
|
|
145
145
|
</View>
|
|
146
146
|
);
|
|
147
147
|
|
|
@@ -207,7 +207,7 @@ const MessageAvatar = forwardRef<View, MessageAvatarProps>(
|
|
|
207
207
|
|
|
208
208
|
return (
|
|
209
209
|
<View ref={ref} className={avatar({ className })} {...props}>
|
|
210
|
-
{stacked ? <View className="opacity-0">{children}</View> : children}
|
|
210
|
+
{stacked ? <View className="opacity-0">{textChildren(children)}</View> : children}
|
|
211
211
|
</View>
|
|
212
212
|
);
|
|
213
213
|
}
|
|
@@ -227,7 +227,7 @@ const MessageContent = forwardRef<View, MessageContentProps>(
|
|
|
227
227
|
|
|
228
228
|
return (
|
|
229
229
|
<View ref={ref} className={content({ className })} {...props}>
|
|
230
|
-
{children}
|
|
230
|
+
{textChildren(children)}
|
|
231
231
|
</View>
|
|
232
232
|
);
|
|
233
233
|
}
|
|
@@ -275,7 +275,7 @@ const MessageBubble = forwardRef<View, MessageBubbleProps>(
|
|
|
275
275
|
return (
|
|
276
276
|
<View ref={ref} className={bubble({ className })} {...props}>
|
|
277
277
|
<IconColorProvider color={typeof foreground === 'string' ? foreground : undefined}>
|
|
278
|
-
{children}
|
|
278
|
+
{textChildren(children)}
|
|
279
279
|
</IconColorProvider>
|
|
280
280
|
</View>
|
|
281
281
|
);
|
|
@@ -334,7 +334,7 @@ const MessageActions = forwardRef<View, MessageActionsProps>(
|
|
|
334
334
|
)}
|
|
335
335
|
{...props}
|
|
336
336
|
>
|
|
337
|
-
{children}
|
|
337
|
+
{textChildren(children)}
|
|
338
338
|
</View>
|
|
339
339
|
);
|
|
340
340
|
}
|
|
@@ -56,6 +56,7 @@ import { useCSSVariable } from 'uniwind';
|
|
|
56
56
|
import { ChevronDownIcon } from '../../icons';
|
|
57
57
|
import { AnimatedPressable } from '../../primitives/animated-pressable';
|
|
58
58
|
import { cn } from '../../utils/cn';
|
|
59
|
+
import { textChildren } from '../../primitives/text';
|
|
59
60
|
|
|
60
61
|
/** Within this many pixels of the bottom still counts as being at the bottom. */
|
|
61
62
|
const END_THRESHOLD = 24;
|
|
@@ -233,7 +234,7 @@ function MessageScrollerRoot({
|
|
|
233
234
|
return (
|
|
234
235
|
<MessageScrollerContext.Provider value={context}>
|
|
235
236
|
<View className={cn('relative overflow-hidden', className)} {...props}>
|
|
236
|
-
{children}
|
|
237
|
+
{textChildren(children)}
|
|
237
238
|
</View>
|
|
238
239
|
</MessageScrollerContext.Provider>
|
|
239
240
|
);
|
|
@@ -404,7 +405,7 @@ function MessageScrollerViewport({
|
|
|
404
405
|
onMomentumScrollEnd={settleAnchor}
|
|
405
406
|
onContentSizeChange={onContentSizeChange}
|
|
406
407
|
>
|
|
407
|
-
{children}
|
|
408
|
+
{textChildren(children)}
|
|
408
409
|
</Animated.ScrollView>
|
|
409
410
|
);
|
|
410
411
|
}
|
|
@@ -445,7 +446,7 @@ function MessageScrollerContent({
|
|
|
445
446
|
className={cn('gap-3 p-4 pb-16', className)}
|
|
446
447
|
{...props}
|
|
447
448
|
>
|
|
448
|
-
{children}
|
|
449
|
+
{textChildren(children)}
|
|
449
450
|
</View>
|
|
450
451
|
);
|
|
451
452
|
}
|
|
@@ -487,7 +488,7 @@ function MessageScrollerItem({
|
|
|
487
488
|
|
|
488
489
|
return (
|
|
489
490
|
<View className={className} {...props} onLayout={onLayout}>
|
|
490
|
-
{children}
|
|
491
|
+
{textChildren(children)}
|
|
491
492
|
</View>
|
|
492
493
|
);
|
|
493
494
|
}
|
|
@@ -60,8 +60,9 @@ import Animated, {
|
|
|
60
60
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
61
61
|
import { Portal } from '../../primitives/portal';
|
|
62
62
|
import { Scrim } from '../../primitives/scrim';
|
|
63
|
+
import { useBackHandler } from '../../hooks/use-back-handler';
|
|
63
64
|
import { BottomSheet } from '../bottom-sheet';
|
|
64
|
-
import { Text, type TextProps } from '../../primitives/text';
|
|
65
|
+
import { Text, type TextProps, textChildren } from '../../primitives/text';
|
|
65
66
|
import { cn } from '../../utils/cn';
|
|
66
67
|
|
|
67
68
|
/** Gap between the trigger and the panel. */
|
|
@@ -255,6 +256,13 @@ function PopoverContent({
|
|
|
255
256
|
}: PopoverContentProps) {
|
|
256
257
|
const context = usePopover('Popover.Content');
|
|
257
258
|
const { open, setOpen, trigger, setPlacement, setArrowOffset, presentation } = context;
|
|
259
|
+
|
|
260
|
+
// The anchored panel owns the Android back button while it is up. The sheet
|
|
261
|
+
// presentation is left alone — BottomSheet installs its own handler.
|
|
262
|
+
useBackHandler(open && dismissible && presentation !== 'bottom-sheet', () =>
|
|
263
|
+
setOpen(false)
|
|
264
|
+
);
|
|
265
|
+
|
|
258
266
|
const { width: screenWidth, height: screenHeight } = useWindowDimensions();
|
|
259
267
|
const insets = useSafeAreaInsets();
|
|
260
268
|
const [size, setSize] = useState<{ width: number; height: number } | null>(null);
|
|
@@ -349,14 +357,42 @@ function PopoverContent({
|
|
|
349
357
|
],
|
|
350
358
|
}));
|
|
351
359
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
360
|
+
/*
|
|
361
|
+
* The sheet presentation hands off entirely to BottomSheet — it owns its own
|
|
362
|
+
* portal, backdrop and dismiss gesture, so there is nothing to anchor here.
|
|
363
|
+
* The context is re-provided inside so Popover.Close keeps closing it.
|
|
364
|
+
*
|
|
365
|
+
* `width` still means something, though. A sheet is the full width of the
|
|
366
|
+
* screen and lays its children out in a column, so a panel sized to its
|
|
367
|
+
* content takes the cross-axis *start* and ends up flush against one edge —
|
|
368
|
+
* the right-hand one under RTL, directly below the close button. Centring it
|
|
369
|
+
* is what makes `width="content-fit"` mean the same thing in both
|
|
370
|
+
* presentations.
|
|
371
|
+
*
|
|
372
|
+
* The className goes on an inner view rather than on the sheet: passed to
|
|
373
|
+
* the surface it is merged into the sheet's own padding classes and replaces
|
|
374
|
+
* them, so a panel asking for `p-3` silently strips the sheet's `px-5 pt-2`.
|
|
375
|
+
*/
|
|
355
376
|
if (presentation === 'bottom-sheet') {
|
|
356
377
|
return (
|
|
357
378
|
<BottomSheet open={open} onOpenChange={setOpen}>
|
|
358
|
-
<BottomSheet.Content dismissible={dismissible}
|
|
359
|
-
<PopoverContext.Provider value={context}>
|
|
379
|
+
<BottomSheet.Content dismissible={dismissible}>
|
|
380
|
+
<PopoverContext.Provider value={context}>
|
|
381
|
+
<View
|
|
382
|
+
className={cn(width === 'content-fit' && 'self-center', className)}
|
|
383
|
+
style={[
|
|
384
|
+
width === 'full' || width === 'trigger' ? { width: '100%' } : null,
|
|
385
|
+
typeof width === 'number' ? { width } : null,
|
|
386
|
+
minWidth === undefined ? null : { minWidth },
|
|
387
|
+
// Clear of the close button, which floats over the top-end
|
|
388
|
+
// corner of the sheet rather than sitting in the flow.
|
|
389
|
+
{ paddingTop: 8 },
|
|
390
|
+
style,
|
|
391
|
+
]}
|
|
392
|
+
>
|
|
393
|
+
{textChildren(children)}
|
|
394
|
+
</View>
|
|
395
|
+
</PopoverContext.Provider>
|
|
360
396
|
</BottomSheet.Content>
|
|
361
397
|
</BottomSheet>
|
|
362
398
|
);
|
|
@@ -410,7 +446,7 @@ function PopoverContent({
|
|
|
410
446
|
)}
|
|
411
447
|
{...props}
|
|
412
448
|
>
|
|
413
|
-
{children}
|
|
449
|
+
{textChildren(children)}
|
|
414
450
|
</Animated.View>
|
|
415
451
|
</Animated.View>
|
|
416
452
|
</View>
|
|
@@ -35,7 +35,7 @@ import Animated, {
|
|
|
35
35
|
} from 'react-native-reanimated';
|
|
36
36
|
import { tv, type VariantProps } from 'tailwind-variants';
|
|
37
37
|
import { cn } from '../../utils/cn';
|
|
38
|
-
import { Text } from '../../primitives/text';
|
|
38
|
+
import { Text, textChildren } from '../../primitives/text';
|
|
39
39
|
|
|
40
40
|
type RadioVariant = 'dot' | 'card';
|
|
41
41
|
type RadioOrientation = 'vertical' | 'horizontal';
|
|
@@ -152,7 +152,7 @@ const RadioGroupRoot = forwardRef<View, RadioGroupProps>(
|
|
|
152
152
|
)}
|
|
153
153
|
{...props}
|
|
154
154
|
>
|
|
155
|
-
{children}
|
|
155
|
+
{textChildren(children)}
|
|
156
156
|
</View>
|
|
157
157
|
</RadioGroupContext.Provider>
|
|
158
158
|
);
|
|
@@ -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
|
);
|
|
@@ -276,7 +276,7 @@ function SectionRailTrigger({ className, children, ...props }: SectionRailTrigge
|
|
|
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
|
);
|