panelui-native 0.40.0 → 0.43.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 +4 -2
- package/lib/module/components/card/index.js +172 -3
- package/lib/module/components/card/index.js.map +1 -1
- package/lib/module/components/color-picker/index.js +1395 -0
- package/lib/module/components/color-picker/index.js.map +1 -0
- package/lib/module/components/combobox/index.js +87 -19
- package/lib/module/components/combobox/index.js.map +1 -1
- package/lib/module/components/drawer/index.js +13 -4
- package/lib/module/components/drawer/index.js.map +1 -1
- package/lib/module/components/kpi-chart/index.js +648 -0
- package/lib/module/components/kpi-chart/index.js.map +1 -0
- package/lib/module/components/map/index.js +72 -12
- package/lib/module/components/map/index.js.map +1 -1
- package/lib/module/components/menu/index.js +40 -10
- package/lib/module/components/menu/index.js.map +1 -1
- package/lib/module/components/pagination/index.js +19 -9
- package/lib/module/components/pagination/index.js.map +1 -1
- package/lib/module/components/panelside/index.js +68 -18
- package/lib/module/components/panelside/index.js.map +1 -1
- package/lib/module/components/radar-chart/index.js +704 -0
- package/lib/module/components/radar-chart/index.js.map +1 -0
- package/lib/module/components/section-rail/index.js +32 -7
- package/lib/module/components/section-rail/index.js.map +1 -1
- package/lib/module/components/slider/index.js +240 -39
- package/lib/module/components/slider/index.js.map +1 -1
- package/lib/module/components/tabs/index.js +194 -10
- package/lib/module/components/tabs/index.js.map +1 -1
- package/lib/module/components/text-animation/index.js +857 -0
- package/lib/module/components/text-animation/index.js.map +1 -0
- package/lib/module/icons/index.js +25 -7
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +5 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/theme/use-theme.js +1 -1
- package/lib/module/utils/chart.js +44 -0
- package/lib/module/utils/chart.js.map +1 -1
- package/lib/module/utils/color.js +268 -0
- package/lib/module/utils/color.js.map +1 -0
- package/lib/typescript/src/components/card/index.d.ts +20 -0
- package/lib/typescript/src/components/card/index.d.ts.map +1 -1
- package/lib/typescript/src/components/color-picker/index.d.ts +258 -0
- package/lib/typescript/src/components/color-picker/index.d.ts.map +1 -0
- package/lib/typescript/src/components/combobox/index.d.ts.map +1 -1
- package/lib/typescript/src/components/drawer/index.d.ts +13 -1
- package/lib/typescript/src/components/drawer/index.d.ts.map +1 -1
- package/lib/typescript/src/components/kpi-chart/index.d.ts +490 -0
- package/lib/typescript/src/components/kpi-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/map/index.d.ts +37 -2
- package/lib/typescript/src/components/map/index.d.ts.map +1 -1
- package/lib/typescript/src/components/menu/index.d.ts.map +1 -1
- package/lib/typescript/src/components/pagination/index.d.ts.map +1 -1
- package/lib/typescript/src/components/panelside/index.d.ts +50 -4
- package/lib/typescript/src/components/panelside/index.d.ts.map +1 -1
- package/lib/typescript/src/components/radar-chart/index.d.ts +214 -0
- package/lib/typescript/src/components/radar-chart/index.d.ts.map +1 -0
- package/lib/typescript/src/components/section-rail/index.d.ts +8 -1
- package/lib/typescript/src/components/section-rail/index.d.ts.map +1 -1
- package/lib/typescript/src/components/slider/index.d.ts +19 -0
- package/lib/typescript/src/components/slider/index.d.ts.map +1 -1
- package/lib/typescript/src/components/tabs/index.d.ts +11 -1
- package/lib/typescript/src/components/tabs/index.d.ts.map +1 -1
- package/lib/typescript/src/components/text-animation/index.d.ts +268 -0
- package/lib/typescript/src/components/text-animation/index.d.ts.map +1 -0
- package/lib/typescript/src/icons/index.d.ts +6 -0
- package/lib/typescript/src/icons/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +8 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/utils/chart.d.ts +21 -0
- package/lib/typescript/src/utils/chart.d.ts.map +1 -1
- package/lib/typescript/src/utils/color.d.ts +74 -0
- package/lib/typescript/src/utils/color.d.ts.map +1 -0
- package/package.json +2 -1
- package/src/components/card/index.tsx +227 -2
- package/src/components/color-picker/index.tsx +1618 -0
- package/src/components/combobox/index.tsx +89 -19
- package/src/components/drawer/index.tsx +31 -9
- package/src/components/kpi-chart/index.tsx +719 -0
- package/src/components/map/index.tsx +158 -14
- package/src/components/menu/index.tsx +51 -6
- package/src/components/pagination/index.tsx +18 -6
- package/src/components/panelside/index.tsx +134 -19
- package/src/components/radar-chart/index.tsx +910 -0
- package/src/components/section-rail/index.tsx +42 -8
- package/src/components/slider/index.tsx +283 -41
- package/src/components/tabs/index.tsx +263 -8
- package/src/components/text-animation/index.tsx +1093 -0
- package/src/icons/index.tsx +23 -4
- package/src/index.ts +73 -1
- package/src/theme/use-theme.ts +1 -1
- package/src/utils/chart.ts +52 -0
- package/src/utils/color.ts +246 -0
- package/theme.css +125 -112
|
@@ -128,6 +128,43 @@ function useToken(name: string, fallback: string): string {
|
|
|
128
128
|
return typeof value === 'string' && value.length > 0 ? value : fallback;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
/** True for a theme token name, as opposed to a literal colour. */
|
|
132
|
+
function isToken(value: string | undefined): value is string {
|
|
133
|
+
return typeof value === 'string' && value.startsWith('--');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* The same colour at a given alpha, for a ramp built from one hue.
|
|
138
|
+
*
|
|
139
|
+
* Style expressions are handed to the renderer as strings, so this produces
|
|
140
|
+
* `rgba()` rather than reaching for a colour type the layer would not accept.
|
|
141
|
+
*/
|
|
142
|
+
function withAlpha(color: string, alpha: number): string {
|
|
143
|
+
if (color.startsWith('#')) {
|
|
144
|
+
const hex = color.slice(1);
|
|
145
|
+
const full =
|
|
146
|
+
hex.length === 3
|
|
147
|
+
? hex
|
|
148
|
+
.split('')
|
|
149
|
+
.map((c) => c + c)
|
|
150
|
+
.join('')
|
|
151
|
+
: hex.slice(0, 6);
|
|
152
|
+
const r = parseInt(full.slice(0, 2), 16);
|
|
153
|
+
const g = parseInt(full.slice(2, 4), 16);
|
|
154
|
+
const b = parseInt(full.slice(4, 6), 16);
|
|
155
|
+
if (Number.isNaN(r + g + b)) return color;
|
|
156
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const channels = color.match(/rgba?\(([^)]+)\)/)?.[1];
|
|
160
|
+
if (channels) {
|
|
161
|
+
const [r, g, b] = channels.split(',').map((part) => part.trim());
|
|
162
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return color;
|
|
166
|
+
}
|
|
167
|
+
|
|
131
168
|
interface MapContextValue {
|
|
132
169
|
mapRef: React.RefObject<MapRef | null>;
|
|
133
170
|
cameraRef: React.RefObject<CameraRef | null>;
|
|
@@ -1025,6 +1062,28 @@ export interface MapHeatmapProps {
|
|
|
1025
1062
|
data: unknown;
|
|
1026
1063
|
/** Feature property to weight each point by. Unweighted when omitted. */
|
|
1027
1064
|
weight?: string;
|
|
1065
|
+
/**
|
|
1066
|
+
* Base colour of the field — a theme token by name, or a literal. The ramp
|
|
1067
|
+
* is this colour at rising opacity, so density reads as *more of the same
|
|
1068
|
+
* thing* rather than as a change of subject.
|
|
1069
|
+
*
|
|
1070
|
+
* Defaults to `--color-chart-2`, which is a saturated accent in every theme.
|
|
1071
|
+
* It is deliberately not `--color-chart-1`: that is the series colour a chart
|
|
1072
|
+
* is about, and every theme starts it on something close to the foreground —
|
|
1073
|
+
* near-black in a light theme, near-white in a dark one — which over a
|
|
1074
|
+
* basemap is a smudge rather than a measurement.
|
|
1075
|
+
*/
|
|
1076
|
+
color?: string;
|
|
1077
|
+
/**
|
|
1078
|
+
* Replace the derived ramp outright, coolest first. For the conventional
|
|
1079
|
+
* heat ramp, where the hue carries the reading as well as the opacity —
|
|
1080
|
+
* worth it when the field sits over varied terrain and one hue at five
|
|
1081
|
+
* opacities stops being separable from what is underneath it.
|
|
1082
|
+
*
|
|
1083
|
+
* The first stop is drawn at the lowest density, the last at the highest.
|
|
1084
|
+
* Density zero stays fully transparent either way.
|
|
1085
|
+
*/
|
|
1086
|
+
colors?: string[];
|
|
1028
1087
|
/**
|
|
1029
1088
|
* Spread of a single point, in points, at street zoom. Larger blurs more.
|
|
1030
1089
|
* The drawn radius shrinks as the map zooms out, so a point keeps covering
|
|
@@ -1037,6 +1096,12 @@ export interface MapHeatmapProps {
|
|
|
1037
1096
|
opacity?: number;
|
|
1038
1097
|
/** Above this zoom the layer fades out — see the note on the component. */
|
|
1039
1098
|
maxZoom?: number;
|
|
1099
|
+
/**
|
|
1100
|
+
* Draw the points themselves as the field fades out, coloured from the same
|
|
1101
|
+
* ramp by weight. Without them, zooming past `maxZoom` leaves an empty map:
|
|
1102
|
+
* the layer gets out of the way, and nothing takes its place.
|
|
1103
|
+
*/
|
|
1104
|
+
points?: boolean;
|
|
1040
1105
|
id?: string;
|
|
1041
1106
|
}
|
|
1042
1107
|
|
|
@@ -1050,30 +1115,63 @@ export interface MapHeatmapProps {
|
|
|
1050
1115
|
*
|
|
1051
1116
|
* It fades out past `maxZoom` on purpose. Zoomed far enough in, every point is
|
|
1052
1117
|
* its own island and the blur says less than the points would — so the layer
|
|
1053
|
-
* gets out of the way rather than smearing five records across a street.
|
|
1118
|
+
* gets out of the way rather than smearing five records across a street. Set
|
|
1119
|
+
* `points` and the records themselves fade in as it goes, which is the whole
|
|
1120
|
+
* handover: a field while the question is where, marks once it is which.
|
|
1054
1121
|
*
|
|
1055
1122
|
* The radius is tied to zoom for the mirror-image reason. Left as a fixed
|
|
1056
1123
|
* number of screen points it would mean a different distance at every zoom:
|
|
1057
1124
|
* a blur that reads as a city at street level covers half a continent once
|
|
1058
1125
|
* the map is pulled out, and a field measured over land ends up sitting in
|
|
1059
1126
|
* the sea. Scaling it with the projection keeps the claim the same one.
|
|
1127
|
+
*
|
|
1128
|
+
* Intensity is tied to zoom too, and in the other direction. The same points
|
|
1129
|
+
* are packed into fewer pixels the further out the map goes, so a constant
|
|
1130
|
+
* intensity saturates the whole field at world zoom and shows nothing but its
|
|
1131
|
+
* own ceiling.
|
|
1060
1132
|
*/
|
|
1061
1133
|
function MapHeatmap({
|
|
1062
1134
|
data,
|
|
1063
1135
|
weight,
|
|
1136
|
+
color,
|
|
1137
|
+
colors,
|
|
1064
1138
|
radius = 24,
|
|
1065
1139
|
intensity = 1,
|
|
1066
1140
|
opacity = 0.85,
|
|
1067
1141
|
maxZoom = 15,
|
|
1142
|
+
points = false,
|
|
1068
1143
|
id = 'heatmap',
|
|
1069
1144
|
}: MapHeatmapProps) {
|
|
1070
|
-
const
|
|
1071
|
-
const
|
|
1072
|
-
|
|
1145
|
+
const base = useToken(isToken(color) ? color : '--color-chart-2', '#3b82f6');
|
|
1146
|
+
const resolved = (isToken(color) ? base : color) ?? base;
|
|
1147
|
+
|
|
1148
|
+
/*
|
|
1149
|
+
* One colour at rising opacity rather than five colours, which is how every
|
|
1150
|
+
* other ramp in the library is built: a sequential scale is one quantity
|
|
1151
|
+
* getting larger, and five hues say five categories. `colors` is there for
|
|
1152
|
+
* the case where that is not enough.
|
|
1153
|
+
*/
|
|
1154
|
+
const ramp = colors?.length
|
|
1155
|
+
? colors
|
|
1156
|
+
: [
|
|
1157
|
+
withAlpha(resolved, 0.25),
|
|
1158
|
+
withAlpha(resolved, 0.45),
|
|
1159
|
+
withAlpha(resolved, 0.7),
|
|
1160
|
+
withAlpha(resolved, 0.9),
|
|
1161
|
+
resolved,
|
|
1162
|
+
];
|
|
1073
1163
|
|
|
1074
1164
|
if (!MapLibre) return null;
|
|
1075
1165
|
const { GeoJSONSource, Layer } = MapLibre;
|
|
1076
1166
|
|
|
1167
|
+
// Density zero is transparent rather than the coolest colour, so the map
|
|
1168
|
+
// shows through everywhere nothing was measured instead of the whole
|
|
1169
|
+
// viewport being tinted by the absence of data.
|
|
1170
|
+
const stops = ramp.flatMap((entry, index) => [
|
|
1171
|
+
0.15 + (0.85 * index) / Math.max(1, ramp.length - 1),
|
|
1172
|
+
entry,
|
|
1173
|
+
]);
|
|
1174
|
+
|
|
1077
1175
|
return (
|
|
1078
1176
|
<GeoJSONSource id={`${id}-source`} data={data}>
|
|
1079
1177
|
<Layer
|
|
@@ -1084,7 +1182,15 @@ function MapHeatmap({
|
|
|
1084
1182
|
heatmapWeight: weight
|
|
1085
1183
|
? ['interpolate', ['linear'], ['get', weight], 0, 0, 1, 1]
|
|
1086
1184
|
: 1,
|
|
1087
|
-
heatmapIntensity:
|
|
1185
|
+
heatmapIntensity: [
|
|
1186
|
+
'interpolate',
|
|
1187
|
+
['linear'],
|
|
1188
|
+
['zoom'],
|
|
1189
|
+
0,
|
|
1190
|
+
intensity * 0.6,
|
|
1191
|
+
maxZoom,
|
|
1192
|
+
intensity * 1.2,
|
|
1193
|
+
],
|
|
1088
1194
|
// `radius` is the spread at street zoom; below that it is scaled
|
|
1089
1195
|
// down so it keeps covering the same ground rather than the same
|
|
1090
1196
|
// number of pixels. The stops are the projection: each zoom level
|
|
@@ -1101,21 +1207,13 @@ function MapHeatmap({
|
|
|
1101
1207
|
14,
|
|
1102
1208
|
radius,
|
|
1103
1209
|
],
|
|
1104
|
-
// Transparent at zero rather than the coolest colour, so the map
|
|
1105
|
-
// shows through everywhere nothing was measured instead of the whole
|
|
1106
|
-
// viewport being tinted by the absence of data.
|
|
1107
1210
|
heatmapColor: [
|
|
1108
1211
|
'interpolate',
|
|
1109
1212
|
['linear'],
|
|
1110
1213
|
['heatmap-density'],
|
|
1111
1214
|
0,
|
|
1112
1215
|
'rgba(0,0,0,0)',
|
|
1113
|
-
|
|
1114
|
-
cool,
|
|
1115
|
-
0.6,
|
|
1116
|
-
warm,
|
|
1117
|
-
1,
|
|
1118
|
-
hot,
|
|
1216
|
+
...stops,
|
|
1119
1217
|
],
|
|
1120
1218
|
heatmapOpacity: [
|
|
1121
1219
|
'interpolate',
|
|
@@ -1128,6 +1226,52 @@ function MapHeatmap({
|
|
|
1128
1226
|
],
|
|
1129
1227
|
}}
|
|
1130
1228
|
/>
|
|
1229
|
+
|
|
1230
|
+
{/* The handover, in the two zoom levels the field spends fading: the
|
|
1231
|
+
marks arrive as it leaves, so there is never a zoom with neither. */}
|
|
1232
|
+
{points ? (
|
|
1233
|
+
<Layer
|
|
1234
|
+
id={`${id}-points`}
|
|
1235
|
+
type="circle"
|
|
1236
|
+
minzoom={maxZoom - 2}
|
|
1237
|
+
style={{
|
|
1238
|
+
circleRadius: weight
|
|
1239
|
+
? ['interpolate', ['linear'], ['get', weight], 0, 3, 1, 9]
|
|
1240
|
+
: 5,
|
|
1241
|
+
circleColor: weight
|
|
1242
|
+
? [
|
|
1243
|
+
'interpolate',
|
|
1244
|
+
['linear'],
|
|
1245
|
+
['get', weight],
|
|
1246
|
+
0,
|
|
1247
|
+
ramp[0] as string,
|
|
1248
|
+
1,
|
|
1249
|
+
ramp[ramp.length - 1] as string,
|
|
1250
|
+
]
|
|
1251
|
+
: (ramp[ramp.length - 1] as string),
|
|
1252
|
+
circleStrokeWidth: 1,
|
|
1253
|
+
circleStrokeColor: 'rgba(255,255,255,0.75)',
|
|
1254
|
+
circleOpacity: [
|
|
1255
|
+
'interpolate',
|
|
1256
|
+
['linear'],
|
|
1257
|
+
['zoom'],
|
|
1258
|
+
maxZoom - 2,
|
|
1259
|
+
0,
|
|
1260
|
+
maxZoom,
|
|
1261
|
+
0.85,
|
|
1262
|
+
],
|
|
1263
|
+
circleStrokeOpacity: [
|
|
1264
|
+
'interpolate',
|
|
1265
|
+
['linear'],
|
|
1266
|
+
['zoom'],
|
|
1267
|
+
maxZoom - 2,
|
|
1268
|
+
0,
|
|
1269
|
+
maxZoom,
|
|
1270
|
+
0.6,
|
|
1271
|
+
],
|
|
1272
|
+
}}
|
|
1273
|
+
/>
|
|
1274
|
+
) : null}
|
|
1131
1275
|
</GeoJSONSource>
|
|
1132
1276
|
);
|
|
1133
1277
|
}
|
|
@@ -57,9 +57,9 @@ import Animated, {
|
|
|
57
57
|
} from 'react-native-reanimated';
|
|
58
58
|
import { tv } from 'tailwind-variants';
|
|
59
59
|
import { useCSSVariable } from 'uniwind';
|
|
60
|
-
import {
|
|
60
|
+
import { Check, ChevronLeft, ChevronRight, Circle } from 'lucide-react-native';
|
|
61
61
|
import { Text, textChildren } from '../../primitives/text';
|
|
62
|
-
import { useDirectionSign } from '../../hooks/use-direction';
|
|
62
|
+
import { useDirection, useDirectionSign } from '../../hooks/use-direction';
|
|
63
63
|
import { selectionTick } from '../../utils/haptics';
|
|
64
64
|
import { cn } from '../../utils/cn';
|
|
65
65
|
import { Popover, type PopoverContentProps, type PopoverProps } from '../popover';
|
|
@@ -79,6 +79,19 @@ function useTint(variable: string): string | undefined {
|
|
|
79
79
|
return typeof raw === 'string' ? raw : undefined;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
/**
|
|
83
|
+
* The colour an indicator falls back to before the stylesheet has been read.
|
|
84
|
+
*
|
|
85
|
+
* The glyphs here are drawn by a general-purpose icon set rather than by this
|
|
86
|
+
* library's own, and that set defaults an unset colour to `currentColor` —
|
|
87
|
+
* which React Native cannot resolve and refuses to paint. A neutral mid grey
|
|
88
|
+
* is legible on either a light or a dark panel for the frame or two it lasts.
|
|
89
|
+
*/
|
|
90
|
+
const INDICATOR_FALLBACK = '#737373';
|
|
91
|
+
|
|
92
|
+
/** Icon stroke, matched to the weight this library's own glyphs are drawn at. */
|
|
93
|
+
const INDICATOR_STROKE = 2;
|
|
94
|
+
|
|
82
95
|
/** How long a row takes to light up under a finger, and to let go again. */
|
|
83
96
|
const PRESS_IN_DURATION = 90;
|
|
84
97
|
const PRESS_OUT_DURATION = 160;
|
|
@@ -544,7 +557,17 @@ function MenuCheckboxItem({
|
|
|
544
557
|
// An empty column rather than no column: the mark comes and goes as the
|
|
545
558
|
// row is toggled, and a row whose label steps sideways each time reads
|
|
546
559
|
// as a different row rather than the same one in a new state.
|
|
547
|
-
icon={
|
|
560
|
+
icon={
|
|
561
|
+
checked ? (
|
|
562
|
+
<Check
|
|
563
|
+
size={16}
|
|
564
|
+
strokeWidth={INDICATOR_STROKE}
|
|
565
|
+
color={tint ?? INDICATOR_FALLBACK}
|
|
566
|
+
/>
|
|
567
|
+
) : (
|
|
568
|
+
<MenuIndicatorSpacer />
|
|
569
|
+
)
|
|
570
|
+
}
|
|
548
571
|
onSelect={() => {
|
|
549
572
|
onCheckedChange?.(!checked);
|
|
550
573
|
onSelect?.();
|
|
@@ -616,9 +639,22 @@ function MenuRadioItem({
|
|
|
616
639
|
icon={
|
|
617
640
|
selected ? (
|
|
618
641
|
indicator === 'dot' ? (
|
|
619
|
-
|
|
642
|
+
// A filled circle, not a bare View: the dot is an indicator like
|
|
643
|
+
// the tick beside it, and drawing one of the two as a rounded box
|
|
644
|
+
// is what makes them optically different sizes at the same nominal
|
|
645
|
+
// one.
|
|
646
|
+
<Circle
|
|
647
|
+
size={8}
|
|
648
|
+
strokeWidth={INDICATOR_STROKE}
|
|
649
|
+
color={tint ?? INDICATOR_FALLBACK}
|
|
650
|
+
fill={tint ?? INDICATOR_FALLBACK}
|
|
651
|
+
/>
|
|
620
652
|
) : (
|
|
621
|
-
<
|
|
653
|
+
<Check
|
|
654
|
+
size={16}
|
|
655
|
+
strokeWidth={INDICATOR_STROKE}
|
|
656
|
+
color={tint ?? INDICATOR_FALLBACK}
|
|
657
|
+
/>
|
|
622
658
|
)
|
|
623
659
|
) : (
|
|
624
660
|
// Held open, so the options stay in one column as the choice moves
|
|
@@ -690,8 +726,13 @@ export interface MenuSubTriggerProps
|
|
|
690
726
|
function MenuSubTrigger({ className, children, icon, onSelect, ...props }: MenuSubTriggerProps) {
|
|
691
727
|
const { open, toggle } = useMenuSub('Menu.SubTrigger');
|
|
692
728
|
const sign = useDirectionSign();
|
|
729
|
+
const direction = useDirection();
|
|
693
730
|
const reducedMotion = useReducedMotion();
|
|
694
731
|
const chevronTint = useTint('--color-muted-foreground');
|
|
732
|
+
// The glyph mirrors by being the other glyph. A `scaleX` flip would work on
|
|
733
|
+
// a chevron, but it also flips the rotation below with it — and this one is
|
|
734
|
+
// already being rotated.
|
|
735
|
+
const Chevron = direction === 'rtl' ? ChevronLeft : ChevronRight;
|
|
695
736
|
const progress = useSharedValue(open ? 1 : 0);
|
|
696
737
|
|
|
697
738
|
useEffect(() => {
|
|
@@ -717,7 +758,11 @@ function MenuSubTrigger({ className, children, icon, onSelect, ...props }: MenuS
|
|
|
717
758
|
className={className}
|
|
718
759
|
trailing={
|
|
719
760
|
<Animated.View style={chevronStyle}>
|
|
720
|
-
<
|
|
761
|
+
<Chevron
|
|
762
|
+
size={16}
|
|
763
|
+
strokeWidth={INDICATOR_STROKE}
|
|
764
|
+
color={chevronTint ?? INDICATOR_FALLBACK}
|
|
765
|
+
/>
|
|
721
766
|
</Animated.View>
|
|
722
767
|
}
|
|
723
768
|
onSelect={() => {
|
|
@@ -65,9 +65,10 @@ export type PaginationSize = 'sm' | 'default';
|
|
|
65
65
|
/**
|
|
66
66
|
* What the small size gives back as padding. 44pt is the smallest target a
|
|
67
67
|
* finger reliably hits, and the row is allowed to get tighter than that only
|
|
68
|
-
* because the reach is restored outside the paint
|
|
68
|
+
* because the reach is restored outside the paint — so this is exactly the
|
|
69
|
+
* difference between the small target's 32pt and that 44.
|
|
69
70
|
*/
|
|
70
|
-
const SMALL_HIT_SLOP = { top:
|
|
71
|
+
const SMALL_HIT_SLOP = { top: 6, bottom: 6, left: 6, right: 6 } as const;
|
|
71
72
|
|
|
72
73
|
const paginationVariants = tv({
|
|
73
74
|
slots: {
|
|
@@ -91,9 +92,9 @@ const paginationVariants = tv({
|
|
|
91
92
|
},
|
|
92
93
|
sm: {
|
|
93
94
|
list: 'gap-0.5',
|
|
94
|
-
item: 'h-
|
|
95
|
+
item: 'h-8 min-w-8 px-1',
|
|
95
96
|
itemLabel: 'text-xs',
|
|
96
|
-
ellipsis: 'h-
|
|
97
|
+
ellipsis: 'h-8 w-8',
|
|
97
98
|
status: 'text-xs',
|
|
98
99
|
summary: 'text-xs',
|
|
99
100
|
},
|
|
@@ -304,7 +305,18 @@ const PaginationRoot = forwardRef<View, PaginationProps>(
|
|
|
304
305
|
// With nothing on the leading edge the controls are the whole row
|
|
305
306
|
// and centre in it; with something there they part to the two ends,
|
|
306
307
|
// which is the shape a table footer wants.
|
|
307
|
-
|
|
308
|
+
//
|
|
309
|
+
// Clipped, because the run is a fixed number of targets and a
|
|
310
|
+
// narrow enough container cannot hold it. Overflowing, a centred
|
|
311
|
+
// row hangs the same distance past both edges, and the leading
|
|
312
|
+
// number ends up half off the screen with nothing to say why.
|
|
313
|
+
// Inside its own bounds the shortfall at least looks deliberate,
|
|
314
|
+
// and `siblings`/`boundaries` are the knobs that fix it.
|
|
315
|
+
className: cn(
|
|
316
|
+
'overflow-hidden',
|
|
317
|
+
children ? 'justify-between gap-3' : 'justify-center',
|
|
318
|
+
className
|
|
319
|
+
),
|
|
308
320
|
})}
|
|
309
321
|
{...props}
|
|
310
322
|
>
|
|
@@ -312,7 +324,7 @@ const PaginationRoot = forwardRef<View, PaginationProps>(
|
|
|
312
324
|
<PaginationStatus>{text}</PaginationStatus>
|
|
313
325
|
))}
|
|
314
326
|
|
|
315
|
-
<View className={list()}>
|
|
327
|
+
<View className={list({ className: 'max-w-full' })}>
|
|
316
328
|
{controls ? <PaginationPrevious label={variant === 'simple'} /> : null}
|
|
317
329
|
|
|
318
330
|
{variant === 'numbers'
|