panelui-native 0.25.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -1
- 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 +792 -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/code-block/highlight.js +363 -0
- package/lib/module/components/code-block/highlight.js.map +1 -0
- package/lib/module/components/code-block/index.js +313 -0
- package/lib/module/components/code-block/index.js.map +1 -0
- package/lib/module/components/date-picker/index.js +165 -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/menu/index.js +714 -0
- package/lib/module/components/menu/index.js.map +1 -0
- 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/plan/index.js +296 -0
- package/lib/module/components/plan/index.js.map +1 -0
- package/lib/module/components/popover/index.js +73 -10
- package/lib/module/components/popover/index.js.map +1 -1
- package/lib/module/components/radio-group/index.js +15 -10
- package/lib/module/components/radio-group/index.js.map +1 -1
- package/lib/module/components/reasoning/index.js +244 -0
- package/lib/module/components/reasoning/index.js.map +1 -0
- 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/sources/index.js +221 -0
- package/lib/module/components/sources/index.js.map +1 -0
- 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/task/index.js +300 -0
- package/lib/module/components/task/index.js.map +1 -0
- package/lib/module/components/textarea/index.js +295 -0
- package/lib/module/components/textarea/index.js.map +1 -0
- 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 +648 -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 +202 -0
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +13 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/primitives/collapse.js +112 -0
- package/lib/module/primitives/collapse.js.map +1 -0
- 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 +173 -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/code-block/highlight.d.ts +39 -0
- package/lib/typescript/src/components/code-block/highlight.d.ts.map +1 -0
- package/lib/typescript/src/components/code-block/index.d.ts +113 -0
- package/lib/typescript/src/components/code-block/index.d.ts.map +1 -0
- package/lib/typescript/src/components/date-picker/index.d.ts +97 -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/menu/index.d.ts +261 -0
- package/lib/typescript/src/components/menu/index.d.ts.map +1 -0
- 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/plan/index.d.ts +127 -0
- package/lib/typescript/src/components/plan/index.d.ts.map +1 -0
- package/lib/typescript/src/components/popover/index.d.ts +35 -1
- package/lib/typescript/src/components/popover/index.d.ts.map +1 -1
- package/lib/typescript/src/components/radio-group/index.d.ts.map +1 -1
- package/lib/typescript/src/components/reasoning/index.d.ts +97 -0
- package/lib/typescript/src/components/reasoning/index.d.ts.map +1 -0
- package/lib/typescript/src/components/select/index.d.ts.map +1 -1
- package/lib/typescript/src/components/sources/index.d.ts +85 -0
- package/lib/typescript/src/components/sources/index.d.ts.map +1 -0
- 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/task/index.d.ts +103 -0
- package/lib/typescript/src/components/task/index.d.ts.map +1 -0
- package/lib/typescript/src/components/textarea/index.d.ts +175 -0
- package/lib/typescript/src/components/textarea/index.d.ts.map +1 -0
- 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 +180 -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 +17 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +16 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/primitives/collapse.d.ts +42 -0
- package/lib/typescript/src/primitives/collapse.d.ts.map +1 -0
- 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 +970 -0
- package/src/components/carousel/index.tsx +788 -0
- package/src/components/chip/index.tsx +4 -6
- package/src/components/code-block/highlight.ts +278 -0
- package/src/components/code-block/index.tsx +341 -0
- package/src/components/date-picker/index.tsx +255 -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/menu/index.tsx +812 -0
- package/src/components/message/index.tsx +7 -7
- package/src/components/message-scroller/index.tsx +5 -4
- package/src/components/plan/index.tsx +325 -0
- package/src/components/popover/index.tsx +111 -8
- package/src/components/radio-group/index.tsx +13 -4
- package/src/components/reasoning/index.tsx +297 -0
- package/src/components/section-rail/index.tsx +4 -4
- package/src/components/select/index.tsx +10 -4
- package/src/components/sources/index.tsx +278 -0
- package/src/components/steps/index.tsx +4 -4
- package/src/components/tabs/index.tsx +7 -9
- package/src/components/task/index.tsx +329 -0
- package/src/components/textarea/index.tsx +381 -0
- 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 +793 -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 +147 -0
- package/src/index.ts +116 -0
- package/src/primitives/collapse.tsx +128 -0
- package/src/primitives/keyboard-avoider.tsx +2 -1
- package/src/primitives/text.tsx +28 -1
- package/src/utils/date.ts +446 -0
- package/theme.css +112 -0
|
@@ -64,6 +64,7 @@ import Svg, { G, Line as SvgLine, Path } from 'react-native-svg';
|
|
|
64
64
|
import { useCSSVariable } from 'uniwind';
|
|
65
65
|
import { Text } from '../../primitives/text';
|
|
66
66
|
import {
|
|
67
|
+
bandOf,
|
|
67
68
|
barPath,
|
|
68
69
|
columnValues,
|
|
69
70
|
compactNumber,
|
|
@@ -90,9 +91,15 @@ const PADDING_SIDEWAYS = { top: 6, right: 10, bottom: 6, left: 68 };
|
|
|
90
91
|
const LABEL_WIDTH = 132;
|
|
91
92
|
|
|
92
93
|
/** Left gutter reserved when a `YAxis` is present, for its labels to sit in. */
|
|
93
|
-
const Y_AXIS_WIDTH =
|
|
94
|
+
const Y_AXIS_WIDTH = 44;
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
/** Gap between the value labels and the plot they sit beside. */
|
|
97
|
+
const Y_AXIS_GUTTER = 6;
|
|
98
|
+
|
|
99
|
+
/** Line height of an `xs` label, for centring one on the grid line it names. */
|
|
100
|
+
const AXIS_LABEL_HEIGHT = 16;
|
|
101
|
+
|
|
102
|
+
type Layer = 'svg' | 'overlay' | 'header';
|
|
96
103
|
|
|
97
104
|
export type BarChartStatus = 'loading' | 'ready';
|
|
98
105
|
export type BarChartOrientation = 'vertical' | 'horizontal';
|
|
@@ -213,13 +220,14 @@ export interface BarChartHandle {
|
|
|
213
220
|
function partition(children: ReactNode) {
|
|
214
221
|
const svg: ReactNode[] = [];
|
|
215
222
|
const overlay: ReactNode[] = [];
|
|
223
|
+
const header: ReactNode[] = [];
|
|
216
224
|
Children.forEach(children, (child, index) => {
|
|
217
225
|
if (!isValidElement(child)) return;
|
|
218
226
|
const layer = (child.type as { layer?: Layer }).layer ?? 'svg';
|
|
219
227
|
const slot = <ChildSlot key={index}>{child}</ChildSlot>;
|
|
220
|
-
(layer === 'overlay' ? overlay : svg).push(slot);
|
|
228
|
+
(layer === 'header' ? header : layer === 'overlay' ? overlay : svg).push(slot);
|
|
221
229
|
});
|
|
222
|
-
return { svg, overlay };
|
|
230
|
+
return { svg, overlay, header };
|
|
223
231
|
}
|
|
224
232
|
|
|
225
233
|
function ChildSlot({ children }: { children: ReactNode }) {
|
|
@@ -450,24 +458,28 @@ const BarChartRoot = forwardRef<BarChartHandle, BarChartProps>(function BarChart
|
|
|
450
458
|
]
|
|
451
459
|
);
|
|
452
460
|
|
|
453
|
-
const { svg, overlay } = partition(children);
|
|
461
|
+
const { svg, overlay, header } = partition(children);
|
|
454
462
|
|
|
463
|
+
/*
|
|
464
|
+
* Two views, because the header is not part of the plot. `aspectRatio` and
|
|
465
|
+
* the layout measurement belong to the drawing area alone — measured on the
|
|
466
|
+
* outer view they would take in the header too, and the plot would lose as
|
|
467
|
+
* much height as the readout took while still claiming the shape asked for.
|
|
468
|
+
*/
|
|
455
469
|
return (
|
|
456
470
|
<BarChartContext.Provider value={context}>
|
|
457
|
-
<View
|
|
458
|
-
{
|
|
459
|
-
onLayout={onLayout}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
</>
|
|
470
|
-
) : null}
|
|
471
|
+
<View {...props} style={props.style} className={cn('w-full', className)}>
|
|
472
|
+
{header}
|
|
473
|
+
<View onLayout={onLayout} style={{ aspectRatio }} className="w-full">
|
|
474
|
+
{plot.width > 0 ? (
|
|
475
|
+
<>
|
|
476
|
+
<Svg width="100%" height="100%" style={StyleSheet.absoluteFill}>
|
|
477
|
+
{svg}
|
|
478
|
+
</Svg>
|
|
479
|
+
{overlay}
|
|
480
|
+
</>
|
|
481
|
+
) : null}
|
|
482
|
+
</View>
|
|
471
483
|
</View>
|
|
472
484
|
</BarChartContext.Provider>
|
|
473
485
|
);
|
|
@@ -730,8 +742,18 @@ BarChartBar.layer = 'svg' as Layer;
|
|
|
730
742
|
/* Overlay layer */
|
|
731
743
|
/* -------------------------------------------------------------------------- */
|
|
732
744
|
|
|
745
|
+
/**
|
|
746
|
+
* Narrowest a category label may be drawn before the axis starts dropping
|
|
747
|
+
* some. Roughly three characters at `xs`, which is what a month abbreviation
|
|
748
|
+
* or a short name needs.
|
|
749
|
+
*/
|
|
750
|
+
const MIN_BAND_LABEL = 34;
|
|
751
|
+
|
|
733
752
|
export interface BarChartXAxisProps {
|
|
734
|
-
/**
|
|
753
|
+
/**
|
|
754
|
+
* How many labels to show. Every category by default, thinned only when the
|
|
755
|
+
* bands get too narrow to read — pass a number to force it lower.
|
|
756
|
+
*/
|
|
735
757
|
ticks?: number;
|
|
736
758
|
/** Turn a row into its label. Defaults to the value at `xDataKey`. */
|
|
737
759
|
format?: (datum: BarChartDatum, index: number) => string;
|
|
@@ -743,40 +765,77 @@ export interface BarChartXAxisProps {
|
|
|
743
765
|
* than SVG text, so they follow the theme's font and the platform's text
|
|
744
766
|
* scaling — SVG text does neither.
|
|
745
767
|
*/
|
|
746
|
-
function BarChartXAxis({ ticks
|
|
768
|
+
function BarChartXAxis({ ticks, format, className }: BarChartXAxisProps) {
|
|
747
769
|
const { data, xDataKey, plot, orientation } = useChart('BarChart.XAxis');
|
|
748
770
|
|
|
749
771
|
const labels = useMemo(() => {
|
|
750
772
|
if (!data.length) return [];
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
773
|
+
|
|
774
|
+
/*
|
|
775
|
+
* Every category, unless they will not fit. A fixed tick count dropped
|
|
776
|
+
* names that had room to be drawn — eight months at six ticks lost March
|
|
777
|
+
* and June for no reason anyone looking at the chart could see. The axis
|
|
778
|
+
* asks the plot how much room there is instead, and only thins when the
|
|
779
|
+
* answer is not enough.
|
|
780
|
+
*/
|
|
781
|
+
const room = Math.max(1, Math.floor(plot.width / MIN_BAND_LABEL));
|
|
782
|
+
const count = Math.max(1, Math.min(ticks ?? room, data.length));
|
|
783
|
+
|
|
784
|
+
// Every nth band, rather than a fractional step rounded to the nearest
|
|
785
|
+
// index — rounding lands on the same band twice and skips its neighbour.
|
|
786
|
+
const stride = Math.ceil(data.length / count);
|
|
787
|
+
const picked: { key: number; text: string }[] = [];
|
|
788
|
+
for (let index = 0; index < data.length; index += stride) {
|
|
789
|
+
const datum = data[index];
|
|
790
|
+
if (!datum) continue;
|
|
791
|
+
picked.push({
|
|
792
|
+
key: index,
|
|
793
|
+
text: format ? format(datum, index) : String(datum[xDataKey] ?? ''),
|
|
794
|
+
});
|
|
795
|
+
}
|
|
796
|
+
return picked;
|
|
797
|
+
}, [data, ticks, format, xDataKey, plot.width]);
|
|
763
798
|
|
|
764
799
|
if (orientation === 'horizontal') return null;
|
|
765
800
|
|
|
801
|
+
/*
|
|
802
|
+
* Each label is placed on its own band's centre, not spaced evenly along the
|
|
803
|
+
* axis. Two things went wrong when they were spread with `justify-between`:
|
|
804
|
+
* a bar owns a *band* rather than sitting on a point, so the first and last
|
|
805
|
+
* labels were half a band out at the edges; and the indices `ticks` picks
|
|
806
|
+
* are not evenly spaced (eight months shown six at a time gives 0,1,3,4,6,7),
|
|
807
|
+
* so the ones between were spread evenly over gaps that are not.
|
|
808
|
+
*
|
|
809
|
+
* The box is backed off by half its own width rather than translated by
|
|
810
|
+
* `-50%`, which is not reliable across React Native versions.
|
|
811
|
+
*/
|
|
812
|
+
/*
|
|
813
|
+
* One box per band, exactly the band's width. Tiling them rather than giving
|
|
814
|
+
* each a fixed width means they can never overlap each other and the first
|
|
815
|
+
* and last can never hang off the ends of the plot — the row of labels
|
|
816
|
+
* occupies precisely the space the bars do.
|
|
817
|
+
*/
|
|
818
|
+
const bandWidth = data.length > 0 ? plot.width / data.length : 0;
|
|
819
|
+
|
|
766
820
|
return (
|
|
767
821
|
<View
|
|
768
|
-
pointerEvents
|
|
769
|
-
|
|
770
|
-
position: 'absolute',
|
|
771
|
-
left: plot.left,
|
|
772
|
-
right: PADDING.right,
|
|
773
|
-
bottom: 0,
|
|
774
|
-
height: PADDING.bottom,
|
|
775
|
-
}}
|
|
776
|
-
className={cn('flex-row items-center justify-between', className)}
|
|
822
|
+
style={{ position: 'absolute', inset: 0, pointerEvents: 'none' }}
|
|
823
|
+
className={cn(className)}
|
|
777
824
|
>
|
|
778
825
|
{labels.map((label) => (
|
|
779
|
-
<Text
|
|
826
|
+
<Text
|
|
827
|
+
key={label.key}
|
|
828
|
+
size="xs"
|
|
829
|
+
muted
|
|
830
|
+
numberOfLines={1}
|
|
831
|
+
style={{
|
|
832
|
+
position: 'absolute',
|
|
833
|
+
bottom: 0,
|
|
834
|
+
left: bandOf(label.key, data.length, plot) - bandWidth / 2,
|
|
835
|
+
width: bandWidth,
|
|
836
|
+
textAlign: 'center',
|
|
837
|
+
}}
|
|
838
|
+
>
|
|
780
839
|
{label.text}
|
|
781
840
|
</Text>
|
|
782
841
|
))}
|
|
@@ -834,8 +893,12 @@ function BarChartYAxis({ ticks = 4, format, className }: BarChartYAxisProps) {
|
|
|
834
893
|
style={{
|
|
835
894
|
position: 'absolute',
|
|
836
895
|
left: 0,
|
|
837
|
-
|
|
838
|
-
|
|
896
|
+
// Upright, each label is centred on the grid line it names: the strip
|
|
897
|
+
// is lifted half a label and grown by a whole one, so `justify-between`
|
|
898
|
+
// lands the text's middle on the line rather than its top edge on the
|
|
899
|
+
// first and its bottom edge on the last.
|
|
900
|
+
top: horizontal ? plot.top : plot.top - AXIS_LABEL_HEIGHT / 2,
|
|
901
|
+
height: horizontal ? plot.height : plot.height + AXIS_LABEL_HEIGHT,
|
|
839
902
|
width: horizontal ? Math.max(plot.left - 8, 0) : undefined,
|
|
840
903
|
}}
|
|
841
904
|
className={cn(horizontal ? 'items-end' : 'justify-between', className)}
|
|
@@ -1011,6 +1074,18 @@ export interface BarChartLegendProps extends ViewProps {
|
|
|
1011
1074
|
labels?: Record<string, string>;
|
|
1012
1075
|
}
|
|
1013
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
|
+
|
|
1014
1089
|
/** A swatch and a name per series, in the order the series were declared. */
|
|
1015
1090
|
function BarChartLegend({ className, labels, ...props }: BarChartLegendProps) {
|
|
1016
1091
|
const { series } = useChart('BarChart.Legend');
|
|
@@ -1019,18 +1094,11 @@ function BarChartLegend({ className, labels, ...props }: BarChartLegendProps) {
|
|
|
1019
1094
|
return (
|
|
1020
1095
|
<View
|
|
1021
1096
|
{...props}
|
|
1022
|
-
pointerEvents
|
|
1097
|
+
style={[{ pointerEvents: 'none' }, props.style]}
|
|
1023
1098
|
className={cn('absolute right-2 top-1 flex-row gap-3', className)}
|
|
1024
1099
|
>
|
|
1025
1100
|
{series.map(([key, color]) => (
|
|
1026
|
-
<
|
|
1027
|
-
<View
|
|
1028
|
-
style={{ width: 8, height: 8, borderRadius: 2, backgroundColor: color }}
|
|
1029
|
-
/>
|
|
1030
|
-
<Text size="xs" muted>
|
|
1031
|
-
{labels?.[key] ?? key}
|
|
1032
|
-
</Text>
|
|
1033
|
-
</View>
|
|
1101
|
+
<SeriesSwatch key={key} color={color} label={labels?.[key] ?? key} />
|
|
1034
1102
|
))}
|
|
1035
1103
|
</View>
|
|
1036
1104
|
);
|
|
@@ -1038,7 +1106,99 @@ function BarChartLegend({ className, labels, ...props }: BarChartLegendProps) {
|
|
|
1038
1106
|
BarChartLegend.displayName = 'BarChart.Legend';
|
|
1039
1107
|
BarChartLegend.layer = 'overlay' as Layer;
|
|
1040
1108
|
|
|
1109
|
+
/* -------------------------------------------------------------------------- */
|
|
1110
|
+
/* Header layer */
|
|
1111
|
+
/* -------------------------------------------------------------------------- */
|
|
1112
|
+
|
|
1113
|
+
export interface BarChartHeaderProps extends ViewProps {
|
|
1114
|
+
className?: string;
|
|
1115
|
+
/** Small line above the value — what the chart is of. */
|
|
1116
|
+
title?: string;
|
|
1117
|
+
/** The readout. The largest thing on the card, and the first thing read. */
|
|
1118
|
+
value?: string;
|
|
1119
|
+
/** One muted line under the value — a period, a comparison, a total. */
|
|
1120
|
+
caption?: string;
|
|
1121
|
+
/** Prettier names for the series keys, as the legend takes. */
|
|
1122
|
+
labels?: Record<string, string>;
|
|
1123
|
+
/**
|
|
1124
|
+
* Draw a swatch and a name per series along the trailing edge. Prefer this to
|
|
1125
|
+
* `BarChart.Legend` on a chart that has a header: the legend floats over the
|
|
1126
|
+
* plot, where it competes with the bars for the same corner.
|
|
1127
|
+
*/
|
|
1128
|
+
legend?: boolean;
|
|
1129
|
+
/** Trailing slot — a control, a badge, a range picker. Wins over `legend`. */
|
|
1130
|
+
children?: ReactNode;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* The strip above the plot: what the chart is of, what it currently reads, and
|
|
1135
|
+
* what the colours mean.
|
|
1136
|
+
*
|
|
1137
|
+
* It belongs to the chart rather than to the card around it because it is about
|
|
1138
|
+
* the *plot* — the number changes as a finger moves along the bars, and the
|
|
1139
|
+
* legend is the series list the chart itself is holding. The card's header is a
|
|
1140
|
+
* caption on the tray the chart sits in; this is the chart introducing itself.
|
|
1141
|
+
*
|
|
1142
|
+
* The value is not derived here. A readout that follows the finger belongs to
|
|
1143
|
+
* whoever owns the data — take it from `onActiveIndexChange` and pass the
|
|
1144
|
+
* formatted string down, so one header can show a total when nothing is pressed
|
|
1145
|
+
* and a band's value when something is.
|
|
1146
|
+
*/
|
|
1147
|
+
function BarChartHeader({
|
|
1148
|
+
className,
|
|
1149
|
+
title,
|
|
1150
|
+
value,
|
|
1151
|
+
caption,
|
|
1152
|
+
labels,
|
|
1153
|
+
legend = false,
|
|
1154
|
+
children,
|
|
1155
|
+
...props
|
|
1156
|
+
}: BarChartHeaderProps) {
|
|
1157
|
+
const { series } = useChart('BarChart.Header');
|
|
1158
|
+
const trailing =
|
|
1159
|
+
children ??
|
|
1160
|
+
(legend && series.length ? (
|
|
1161
|
+
<View className="flex-row flex-wrap items-center justify-end gap-x-3 gap-y-1">
|
|
1162
|
+
{series.map(([key, color]) => (
|
|
1163
|
+
<SeriesSwatch key={key} color={color} label={labels?.[key] ?? key} />
|
|
1164
|
+
))}
|
|
1165
|
+
</View>
|
|
1166
|
+
) : null);
|
|
1167
|
+
|
|
1168
|
+
return (
|
|
1169
|
+
<View
|
|
1170
|
+
{...props}
|
|
1171
|
+
className={cn('flex-row items-start justify-between gap-3 pb-3', className)}
|
|
1172
|
+
>
|
|
1173
|
+
<View className="flex-1 gap-0.5">
|
|
1174
|
+
{title ? (
|
|
1175
|
+
<Text size="xs" muted>
|
|
1176
|
+
{title}
|
|
1177
|
+
</Text>
|
|
1178
|
+
) : null}
|
|
1179
|
+
{value ? (
|
|
1180
|
+
<Text size="xl" weight="bold">
|
|
1181
|
+
{value}
|
|
1182
|
+
</Text>
|
|
1183
|
+
) : null}
|
|
1184
|
+
{caption ? (
|
|
1185
|
+
<Text size="xs" muted>
|
|
1186
|
+
{caption}
|
|
1187
|
+
</Text>
|
|
1188
|
+
) : null}
|
|
1189
|
+
</View>
|
|
1190
|
+
{/* Shrinkable, unlike a view's default in React Native. Held rigid, a
|
|
1191
|
+
three-series key takes the width it wants and the caption underneath
|
|
1192
|
+
the value wraps to two lines to make room for it. */}
|
|
1193
|
+
{trailing ? <View className="shrink pt-1">{trailing}</View> : null}
|
|
1194
|
+
</View>
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
BarChartHeader.displayName = 'BarChart.Header';
|
|
1198
|
+
BarChartHeader.layer = 'header' as Layer;
|
|
1199
|
+
|
|
1041
1200
|
export const BarChart = Object.assign(BarChartRoot, {
|
|
1201
|
+
Header: BarChartHeader,
|
|
1042
1202
|
Grid: BarChartGrid,
|
|
1043
1203
|
Bar: BarChartBar,
|
|
1044
1204
|
XAxis: BarChartXAxis,
|
|
@@ -33,7 +33,8 @@ import { getNativeUI } from '../../native';
|
|
|
33
33
|
import { XIcon } from '../../icons';
|
|
34
34
|
import { Portal } from '../../primitives/portal';
|
|
35
35
|
import { Scrim } from '../../primitives/scrim';
|
|
36
|
-
import { Text } from '../../primitives/text';
|
|
36
|
+
import { Text, textChildren } from '../../primitives/text';
|
|
37
|
+
import { useBackHandler } from '../../hooks/use-back-handler';
|
|
37
38
|
import { cn } from '../../utils/cn';
|
|
38
39
|
|
|
39
40
|
const SPRING = { damping: 22, stiffness: 280, mass: 0.7 } as const;
|
|
@@ -290,6 +291,10 @@ function BottomSheetContent({
|
|
|
290
291
|
|
|
291
292
|
const close = useCallback(() => setOpen(false), [setOpen]);
|
|
292
293
|
|
|
294
|
+
// The sheet closes on the Android back button while it is up, the same as a
|
|
295
|
+
// backdrop tap — but only when it is dismissible.
|
|
296
|
+
useBackHandler(open && dismissible, close);
|
|
297
|
+
|
|
293
298
|
/*
|
|
294
299
|
* The offset survives a close — the early return below sits after every
|
|
295
300
|
* hook, so this component keeps its state while the sheet is hidden. A
|
|
@@ -418,7 +423,7 @@ function BottomSheetContent({
|
|
|
418
423
|
paddingBottom: Math.max(insets.bottom, 16),
|
|
419
424
|
}}
|
|
420
425
|
>
|
|
421
|
-
{children}
|
|
426
|
+
{textChildren(children)}
|
|
422
427
|
</View>
|
|
423
428
|
</BottomSheetContext.Provider>
|
|
424
429
|
</RNHostView>
|
|
@@ -470,7 +475,7 @@ function BottomSheetContent({
|
|
|
470
475
|
<View className="mb-3 self-center">
|
|
471
476
|
<View className="h-1 w-10 rounded-full bg-muted-foreground/30" />
|
|
472
477
|
</View>
|
|
473
|
-
{children}
|
|
478
|
+
{textChildren(children)}
|
|
474
479
|
{/*
|
|
475
480
|
* Last, and lifted above the content.
|
|
476
481
|
*
|
|
@@ -534,21 +539,17 @@ function BottomSheetHeader({
|
|
|
534
539
|
}: BottomSheetHeaderProps) {
|
|
535
540
|
return (
|
|
536
541
|
<View className={cn('gap-1 pb-3 pe-12', className)} {...props}>
|
|
537
|
-
{
|
|
542
|
+
{textChildren(title, (text) => (
|
|
538
543
|
<Text size="lg" weight="semibold">
|
|
539
|
-
{
|
|
544
|
+
{text}
|
|
540
545
|
</Text>
|
|
541
|
-
)
|
|
542
|
-
|
|
543
|
-
)}
|
|
544
|
-
{typeof description === 'string' ? (
|
|
546
|
+
))}
|
|
547
|
+
{textChildren(description, (text) => (
|
|
545
548
|
<Text size="sm" muted>
|
|
546
|
-
{
|
|
549
|
+
{text}
|
|
547
550
|
</Text>
|
|
548
|
-
)
|
|
549
|
-
|
|
550
|
-
)}
|
|
551
|
-
{children}
|
|
551
|
+
))}
|
|
552
|
+
{textChildren(children)}
|
|
552
553
|
</View>
|
|
553
554
|
);
|
|
554
555
|
}
|
|
@@ -607,7 +608,7 @@ function BottomSheetBody({
|
|
|
607
608
|
className={cn('flex-1', className)}
|
|
608
609
|
{...props}
|
|
609
610
|
>
|
|
610
|
-
{children}
|
|
611
|
+
{textChildren(children)}
|
|
611
612
|
</Animated.ScrollView>
|
|
612
613
|
);
|
|
613
614
|
|
|
@@ -641,7 +642,7 @@ function BottomSheetFooter({
|
|
|
641
642
|
className={cn('gap-2 border-t border-border pt-3', className)}
|
|
642
643
|
{...props}
|
|
643
644
|
>
|
|
644
|
-
{children}
|
|
645
|
+
{textChildren(children)}
|
|
645
646
|
</View>
|
|
646
647
|
);
|
|
647
648
|
}
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
AnimatedPressable,
|
|
48
48
|
type AnimatedPressableProps,
|
|
49
49
|
} from '../../primitives/animated-pressable';
|
|
50
|
-
import { Text, type TextProps } from '../../primitives/text';
|
|
50
|
+
import { Text, type TextProps, textChildren } from '../../primitives/text';
|
|
51
51
|
import { cn } from '../../utils/cn';
|
|
52
52
|
|
|
53
53
|
type BreadcrumbSize = 'sm' | 'default';
|
|
@@ -102,7 +102,7 @@ const BreadcrumbRoot = forwardRef<View, BreadcrumbProps>(
|
|
|
102
102
|
className={cn('w-full', className)}
|
|
103
103
|
{...props}
|
|
104
104
|
>
|
|
105
|
-
{children}
|
|
105
|
+
{textChildren(children)}
|
|
106
106
|
</View>
|
|
107
107
|
</BreadcrumbContext.Provider>
|
|
108
108
|
)
|
|
@@ -202,7 +202,7 @@ const BreadcrumbItem = forwardRef<View, BreadcrumbItemProps>(
|
|
|
202
202
|
className={cn('flex-row items-center', className)}
|
|
203
203
|
{...props}
|
|
204
204
|
>
|
|
205
|
-
{children}
|
|
205
|
+
{textChildren(children)}
|
|
206
206
|
</View>
|
|
207
207
|
)
|
|
208
208
|
);
|
|
@@ -235,13 +235,11 @@ const BreadcrumbLink = forwardRef<View, BreadcrumbLinkProps>(
|
|
|
235
235
|
className={cn('flex-row items-center', className)}
|
|
236
236
|
{...props}
|
|
237
237
|
>
|
|
238
|
-
{
|
|
238
|
+
{textChildren(children, (text) => (
|
|
239
239
|
<Text className={crumbText({ size, className: cn('text-muted-foreground', textClassName) })}>
|
|
240
|
-
{
|
|
240
|
+
{text}
|
|
241
241
|
</Text>
|
|
242
|
-
)
|
|
243
|
-
children
|
|
244
|
-
)}
|
|
242
|
+
))}
|
|
245
243
|
</AnimatedPressable>
|
|
246
244
|
);
|
|
247
245
|
}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
AnimatedPressable,
|
|
7
7
|
type AnimatedPressableProps,
|
|
8
8
|
} from '../../primitives/animated-pressable';
|
|
9
|
-
import { Text } from '../../primitives/text';
|
|
9
|
+
import { Text, textChildren } from '../../primitives/text';
|
|
10
10
|
import { IconColorProvider } from '../../icons';
|
|
11
11
|
import { getNativeUI } from '../../native';
|
|
12
12
|
import { Spinner } from '../spinner';
|
|
@@ -210,10 +210,16 @@ export const Button = forwardRef<View, ButtonProps>(
|
|
|
210
210
|
>
|
|
211
211
|
{/* Non-string children are React Native views, and the native
|
|
212
212
|
button cannot measure those directly — they have to be hosted
|
|
213
|
-
or they render outside the button's bounds.
|
|
213
|
+
or they render outside the button's bounds. An icon beside a
|
|
214
|
+
label is the common case, and the label half of it is still
|
|
215
|
+
bare text once it is in there. */}
|
|
214
216
|
{isStringLabel ? undefined : (
|
|
215
217
|
<RNHostView matchContents>
|
|
216
|
-
<>
|
|
218
|
+
<>
|
|
219
|
+
{textChildren(children, (text) => (
|
|
220
|
+
<Text className={label({ className: labelClassName })}>{text}</Text>
|
|
221
|
+
))}
|
|
222
|
+
</>
|
|
217
223
|
</RNHostView>
|
|
218
224
|
)}
|
|
219
225
|
</NativeButton>
|
|
@@ -236,11 +242,9 @@ export const Button = forwardRef<View, ButtonProps>(
|
|
|
236
242
|
) : (
|
|
237
243
|
startContent
|
|
238
244
|
)}
|
|
239
|
-
{
|
|
240
|
-
<Text className={label({ className: labelClassName })}>{
|
|
241
|
-
)
|
|
242
|
-
children
|
|
243
|
-
)}
|
|
245
|
+
{textChildren(children, (text) => (
|
|
246
|
+
<Text className={label({ className: labelClassName })}>{text}</Text>
|
|
247
|
+
))}
|
|
244
248
|
{endContent}
|
|
245
249
|
</AnimatedPressable>
|
|
246
250
|
</IconColorProvider>
|