panelui-native 0.38.0 → 0.41.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 +3 -1
- package/lib/module/components/card/index.js +172 -3
- package/lib/module/components/card/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/heatmap-chart/index.js +113 -6
- package/lib/module/components/heatmap-chart/index.js.map +1 -1
- package/lib/module/components/map/index.js +72 -12
- package/lib/module/components/map/index.js.map +1 -1
- package/lib/module/components/pagination/index.js +529 -0
- package/lib/module/components/pagination/index.js.map +1 -0
- package/lib/module/components/panelside/index.js +68 -18
- package/lib/module/components/panelside/index.js.map +1 -1
- package/lib/module/components/ring-chart/index.js +183 -45
- package/lib/module/components/ring-chart/index.js.map +1 -1
- package/lib/module/components/steps/index.js +8 -6
- package/lib/module/components/steps/index.js.map +1 -1
- package/lib/module/components/table/index.js +100 -26
- package/lib/module/components/table/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/components/timeline/index.js +8 -7
- package/lib/module/components/timeline/index.js.map +1 -1
- package/lib/module/icons/index.js +25 -7
- package/lib/module/icons/index.js.map +1 -1
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- 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/drawer/index.d.ts +13 -1
- package/lib/typescript/src/components/drawer/index.d.ts.map +1 -1
- package/lib/typescript/src/components/heatmap-chart/index.d.ts +51 -3
- package/lib/typescript/src/components/heatmap-chart/index.d.ts.map +1 -1
- 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/pagination/index.d.ts +285 -0
- package/lib/typescript/src/components/pagination/index.d.ts.map +1 -0
- 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/ring-chart/index.d.ts +75 -8
- package/lib/typescript/src/components/ring-chart/index.d.ts.map +1 -1
- package/lib/typescript/src/components/steps/index.d.ts +8 -6
- package/lib/typescript/src/components/steps/index.d.ts.map +1 -1
- package/lib/typescript/src/components/table/index.d.ts +59 -17
- package/lib/typescript/src/components/table/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/components/timeline/index.d.ts +8 -7
- package/lib/typescript/src/components/timeline/index.d.ts.map +1 -1
- 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 +6 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/card/index.tsx +227 -2
- package/src/components/drawer/index.tsx +31 -9
- package/src/components/heatmap-chart/index.tsx +147 -5
- package/src/components/map/index.tsx +158 -14
- package/src/components/pagination/index.tsx +603 -0
- package/src/components/panelside/index.tsx +134 -19
- package/src/components/ring-chart/index.tsx +269 -47
- package/src/components/steps/index.tsx +8 -6
- package/src/components/table/index.tsx +146 -30
- package/src/components/text-animation/index.tsx +1093 -0
- package/src/components/timeline/index.tsx +8 -7
- package/src/icons/index.tsx +23 -4
- package/src/index.ts +28 -1
|
@@ -123,6 +123,7 @@ import { Text, textChildren } from '../../primitives/text';
|
|
|
123
123
|
import { useBackHandler } from '../../hooks/use-back-handler';
|
|
124
124
|
import { useDirectionSign } from '../../hooks/use-direction';
|
|
125
125
|
import { cn } from '../../utils/cn';
|
|
126
|
+
import { selectionTick } from '../../utils/haptics';
|
|
126
127
|
|
|
127
128
|
const SPRING = { damping: 24, stiffness: 300, mass: 0.7 } as const;
|
|
128
129
|
|
|
@@ -245,6 +246,8 @@ const clamp = (value: number, min: number, max: number) => {
|
|
|
245
246
|
|
|
246
247
|
export type PanelsideMode = 'push' | 'overlay';
|
|
247
248
|
export type PanelsideSwipeFrom = 'anywhere' | 'edge';
|
|
249
|
+
export type PanelsideItemSize = 'default' | 'sm';
|
|
250
|
+
export type PanelsideCtaSize = 'default' | 'lg';
|
|
248
251
|
|
|
249
252
|
const itemVariants = tv({
|
|
250
253
|
// No width: in a group it stretches on its own, and pinning it to full width
|
|
@@ -252,26 +255,40 @@ const itemVariants = tv({
|
|
|
252
255
|
// React Native defaults `flexShrink` to 0 — in a footer beside a button, on a
|
|
253
256
|
// panel narrow enough for the two not to fit, nothing would give way and
|
|
254
257
|
// both would simply hang off the edge.
|
|
255
|
-
base: 'shrink flex-row items-center
|
|
258
|
+
base: 'shrink flex-row items-center rounded-xl',
|
|
256
259
|
variants: {
|
|
260
|
+
size: {
|
|
261
|
+
default: 'gap-3 px-3 py-2.5',
|
|
262
|
+
sm: 'gap-2.5 px-2.5 py-2',
|
|
263
|
+
},
|
|
257
264
|
active: { true: 'bg-secondary' },
|
|
258
265
|
disabled: { true: 'opacity-40' },
|
|
259
266
|
},
|
|
267
|
+
defaultVariants: {
|
|
268
|
+
size: 'default',
|
|
269
|
+
},
|
|
260
270
|
});
|
|
261
271
|
|
|
262
272
|
const ctaVariants = tv({
|
|
263
|
-
// Taller and wider than a list row's control
|
|
264
|
-
//
|
|
265
|
-
//
|
|
266
|
-
|
|
273
|
+
// Taller and wider than a list row's control. It is the one thing in the
|
|
274
|
+
// panel you are meant to reach for without reading, so it should not be the
|
|
275
|
+
// same size as the eight chat titles above it — but it shares its footer row
|
|
276
|
+
// with an account button, and a pill that stands a whole step above that row
|
|
277
|
+
// makes the footer taller than anything in the panel needs it to be.
|
|
278
|
+
base: 'shrink flex-row items-center justify-center rounded-full',
|
|
267
279
|
variants: {
|
|
268
280
|
variant: {
|
|
269
281
|
primary: 'bg-primary',
|
|
270
282
|
secondary: 'bg-secondary',
|
|
271
283
|
},
|
|
284
|
+
size: {
|
|
285
|
+
default: 'h-10 gap-2 px-5',
|
|
286
|
+
lg: 'h-12 gap-2 px-6',
|
|
287
|
+
},
|
|
272
288
|
},
|
|
273
289
|
defaultVariants: {
|
|
274
290
|
variant: 'primary',
|
|
291
|
+
size: 'default',
|
|
275
292
|
},
|
|
276
293
|
});
|
|
277
294
|
|
|
@@ -287,6 +304,10 @@ interface PanelsideContextValue {
|
|
|
287
304
|
/** True when the panel is laid out beside the scene rather than behind it. */
|
|
288
305
|
docked: boolean;
|
|
289
306
|
dismissible: boolean;
|
|
307
|
+
/** Scene defaults set on the root. A `Panelside.Scene` prop still wins. */
|
|
308
|
+
scale?: number;
|
|
309
|
+
radius?: number;
|
|
310
|
+
dim?: number;
|
|
290
311
|
}
|
|
291
312
|
|
|
292
313
|
const PanelsideContext = createContext<PanelsideContextValue | null>(null);
|
|
@@ -396,6 +417,26 @@ export interface PanelsideProps {
|
|
|
396
417
|
* Default true.
|
|
397
418
|
*/
|
|
398
419
|
dismissible?: boolean;
|
|
420
|
+
/**
|
|
421
|
+
* A tick under the finger when a swipe commits to opening or closing. Off by
|
|
422
|
+
* default — needs the optional `expo-haptics`, and is silent without it.
|
|
423
|
+
*
|
|
424
|
+
* It fires on the commit rather than during the drag: the panel following
|
|
425
|
+
* your thumb is already the feedback for the drag, and a tick per frame is
|
|
426
|
+
* what makes a gesture feel broken rather than responsive.
|
|
427
|
+
*/
|
|
428
|
+
haptics?: boolean;
|
|
429
|
+
/**
|
|
430
|
+
* How far the scene shrinks at full open, as a scale factor. Sets the
|
|
431
|
+
* default for every `Panelside.Scene` underneath; the scene's own prop still
|
|
432
|
+
* wins. Here so the three numbers that describe the curve can be set once
|
|
433
|
+
* where the panel is configured, rather than on a part further down.
|
|
434
|
+
*/
|
|
435
|
+
scale?: number;
|
|
436
|
+
/** The corner radius the scene reaches at full open, in points. */
|
|
437
|
+
radius?: number;
|
|
438
|
+
/** How far the scene is dimmed at full open, 0 to 1. */
|
|
439
|
+
dim?: number;
|
|
399
440
|
className?: string;
|
|
400
441
|
}
|
|
401
442
|
|
|
@@ -411,6 +452,10 @@ function PanelsideRoot({
|
|
|
411
452
|
swipeFrom = 'anywhere',
|
|
412
453
|
edgeWidth = EDGE_WIDTH,
|
|
413
454
|
dismissible = true,
|
|
455
|
+
haptics = false,
|
|
456
|
+
scale,
|
|
457
|
+
radius,
|
|
458
|
+
dim,
|
|
414
459
|
className,
|
|
415
460
|
}: PanelsideProps) {
|
|
416
461
|
const { width: windowWidth } = useWindowDimensions();
|
|
@@ -499,6 +544,15 @@ function PanelsideRoot({
|
|
|
499
544
|
const toggle = useCallback(() => setOpen(!open), [open, setOpen]);
|
|
500
545
|
const close = useCallback(() => setOpen(false), [setOpen]);
|
|
501
546
|
|
|
547
|
+
/*
|
|
548
|
+
* Wrapped so the gesture's worklet has one stable function to hand to
|
|
549
|
+
* `runOnJS` — a fresh closure each render would be re-serialised on every
|
|
550
|
+
* frame the pan is rebuilt.
|
|
551
|
+
*/
|
|
552
|
+
const tick = useCallback(() => {
|
|
553
|
+
if (haptics) selectionTick();
|
|
554
|
+
}, [haptics]);
|
|
555
|
+
|
|
502
556
|
useBackHandler(open && dismissible && !docked, close);
|
|
503
557
|
|
|
504
558
|
/*
|
|
@@ -539,6 +593,10 @@ function PanelsideRoot({
|
|
|
539
593
|
// `velocity` is already in travel space; the spring runs on the same
|
|
540
594
|
// axis, so it must not be converted back to screen space here.
|
|
541
595
|
settle(next, velocity);
|
|
596
|
+
// Only where the drag changed something. A swipe that fell short and
|
|
597
|
+
// sprang back did not open or close anything, and a tick that says it
|
|
598
|
+
// did is worse than no tick at all.
|
|
599
|
+
if (next !== open) runOnJS(tick)();
|
|
542
600
|
runOnJS(setOpen)(next);
|
|
543
601
|
});
|
|
544
602
|
|
|
@@ -565,12 +623,25 @@ function PanelsideRoot({
|
|
|
565
623
|
sign,
|
|
566
624
|
swipeEnabled,
|
|
567
625
|
swipeFrom,
|
|
626
|
+
tick,
|
|
568
627
|
translation,
|
|
569
628
|
]);
|
|
570
629
|
|
|
571
630
|
const context = useMemo<PanelsideContextValue>(
|
|
572
|
-
() => ({
|
|
573
|
-
|
|
631
|
+
() => ({
|
|
632
|
+
open,
|
|
633
|
+
setOpen,
|
|
634
|
+
toggle,
|
|
635
|
+
progress,
|
|
636
|
+
width,
|
|
637
|
+
mode,
|
|
638
|
+
docked,
|
|
639
|
+
dismissible,
|
|
640
|
+
scale,
|
|
641
|
+
radius,
|
|
642
|
+
dim,
|
|
643
|
+
}),
|
|
644
|
+
[dim, dismissible, docked, mode, open, progress, radius, scale, setOpen, toggle, width]
|
|
574
645
|
);
|
|
575
646
|
|
|
576
647
|
return (
|
|
@@ -831,6 +902,12 @@ export interface PanelsideItemProps extends Omit<PressableProps, 'children'> {
|
|
|
831
902
|
*/
|
|
832
903
|
badge?: ReactNode;
|
|
833
904
|
disabled?: boolean;
|
|
905
|
+
/**
|
|
906
|
+
* Row density. `sm` tightens the padding for a panel that has to show more
|
|
907
|
+
* history at once, without touching the type size — a list you can read is
|
|
908
|
+
* worth more than two extra rows.
|
|
909
|
+
*/
|
|
910
|
+
size?: PanelsideItemSize;
|
|
834
911
|
/** Trailing content — usually a `Panelside.Action`. */
|
|
835
912
|
children?: ReactNode;
|
|
836
913
|
}
|
|
@@ -842,6 +919,7 @@ function PanelsideItem({
|
|
|
842
919
|
active = false,
|
|
843
920
|
badge,
|
|
844
921
|
disabled = false,
|
|
922
|
+
size = 'default',
|
|
845
923
|
children,
|
|
846
924
|
...props
|
|
847
925
|
}: PanelsideItemProps) {
|
|
@@ -858,7 +936,7 @@ function PanelsideItem({
|
|
|
858
936
|
|
|
859
937
|
return (
|
|
860
938
|
<AnimatedPressable
|
|
861
|
-
className={itemVariants({ active, disabled, className })}
|
|
939
|
+
className={itemVariants({ active, disabled, size, className })}
|
|
862
940
|
disabled={disabled}
|
|
863
941
|
accessibilityRole="button"
|
|
864
942
|
accessibilityState={{ selected: active, disabled }}
|
|
@@ -1033,6 +1111,15 @@ export interface PanelsideCtaProps extends Omit<PressableProps, 'children'> {
|
|
|
1033
1111
|
icon?: ReactNode;
|
|
1034
1112
|
/** `primary` is the filled accent pill; `secondary` is the quiet one. */
|
|
1035
1113
|
variant?: 'primary' | 'secondary';
|
|
1114
|
+
/**
|
|
1115
|
+
* How tall the pill is. `default` is 40pt, which sits level with the account
|
|
1116
|
+
* button beside it in the footer; `lg` is the 48pt pill, for a panel where
|
|
1117
|
+
* the call to action is the only thing in the row.
|
|
1118
|
+
*
|
|
1119
|
+
* Ignored under `native` — the platform sizes its own button, and asks for a
|
|
1120
|
+
* control size rather than a height.
|
|
1121
|
+
*/
|
|
1122
|
+
size?: PanelsideCtaSize;
|
|
1036
1123
|
/**
|
|
1037
1124
|
* Render the platform's own button instead of the pill. Requires the
|
|
1038
1125
|
* optional `@expo/ui` package; without it this prop does nothing.
|
|
@@ -1054,6 +1141,7 @@ function PanelsideCta({
|
|
|
1054
1141
|
label,
|
|
1055
1142
|
icon,
|
|
1056
1143
|
variant = 'primary',
|
|
1144
|
+
size = 'default',
|
|
1057
1145
|
native = false,
|
|
1058
1146
|
glass = false,
|
|
1059
1147
|
disabled,
|
|
@@ -1076,9 +1164,9 @@ function PanelsideCta({
|
|
|
1076
1164
|
<Button
|
|
1077
1165
|
native
|
|
1078
1166
|
glass={glass}
|
|
1079
|
-
// The platform sizes a native button from its label, so
|
|
1080
|
-
//
|
|
1081
|
-
size=
|
|
1167
|
+
// The platform sizes a native button from its label, so a height means
|
|
1168
|
+
// nothing here — the step is asked for as a control size instead.
|
|
1169
|
+
size={size === 'lg' ? 'lg' : 'md'}
|
|
1082
1170
|
variant={variant}
|
|
1083
1171
|
accessibilityLabel={label}
|
|
1084
1172
|
// Pressable allows `null` for disabled; Button does not.
|
|
@@ -1107,7 +1195,7 @@ function PanelsideCta({
|
|
|
1107
1195
|
|
|
1108
1196
|
return (
|
|
1109
1197
|
<AnimatedPressable
|
|
1110
|
-
className={ctaVariants({ variant, className })}
|
|
1198
|
+
className={ctaVariants({ variant, size, className })}
|
|
1111
1199
|
accessibilityRole="button"
|
|
1112
1200
|
accessibilityLabel={label}
|
|
1113
1201
|
disabled={disabled}
|
|
@@ -1117,7 +1205,7 @@ function PanelsideCta({
|
|
|
1117
1205
|
{icon}
|
|
1118
1206
|
{label ? (
|
|
1119
1207
|
<Text
|
|
1120
|
-
size=
|
|
1208
|
+
size={size === 'lg' ? 'lg' : 'base'}
|
|
1121
1209
|
weight="medium"
|
|
1122
1210
|
// The pill gives way before the panel does, so the label has to be
|
|
1123
1211
|
// able to end somewhere rather than pushing the button off the edge.
|
|
@@ -1143,26 +1231,53 @@ export interface PanelsideSceneProps extends ViewProps {
|
|
|
1143
1231
|
* full height and stays behind the status bar, and the radius and dim do the
|
|
1144
1232
|
* work. Below one it shrinks about its centre, which insets it top and bottom
|
|
1145
1233
|
* as well as at the side.
|
|
1234
|
+
*
|
|
1235
|
+
* Falls back to the same prop on the `Panelside` root, so the three numbers
|
|
1236
|
+
* that describe the curve can be set once where the panel is configured.
|
|
1146
1237
|
*/
|
|
1147
1238
|
scale?: number;
|
|
1148
1239
|
/** The corner radius the scene reaches at full travel. Default 44. */
|
|
1149
1240
|
radius?: number;
|
|
1150
1241
|
/** How far the scene dims at full travel, 0 to 1. Default 0.45. */
|
|
1151
1242
|
dim?: number;
|
|
1243
|
+
/**
|
|
1244
|
+
* Styles the layer that dims the scene. Its opacity is `dim`'s to set, so
|
|
1245
|
+
* this is for the colour — a scrim that is not black, for a light theme
|
|
1246
|
+
* where black at 45% reads as a hole rather than as shade.
|
|
1247
|
+
*/
|
|
1248
|
+
scrimClassName?: string;
|
|
1152
1249
|
children?: ReactNode;
|
|
1153
1250
|
}
|
|
1154
1251
|
|
|
1155
1252
|
function PanelsideScene({
|
|
1156
1253
|
className,
|
|
1157
|
-
scale
|
|
1158
|
-
radius
|
|
1159
|
-
dim
|
|
1254
|
+
scale: scaleProp,
|
|
1255
|
+
radius: radiusProp,
|
|
1256
|
+
dim: dimProp,
|
|
1257
|
+
scrimClassName,
|
|
1160
1258
|
children,
|
|
1161
1259
|
style,
|
|
1162
1260
|
...props
|
|
1163
1261
|
}: PanelsideSceneProps) {
|
|
1164
|
-
const {
|
|
1165
|
-
|
|
1262
|
+
const {
|
|
1263
|
+
progress,
|
|
1264
|
+
width,
|
|
1265
|
+
mode,
|
|
1266
|
+
docked,
|
|
1267
|
+
dismissible,
|
|
1268
|
+
open,
|
|
1269
|
+
setOpen,
|
|
1270
|
+
scale: rootScale,
|
|
1271
|
+
radius: rootRadius,
|
|
1272
|
+
dim: rootDim,
|
|
1273
|
+
} = usePanelsideContext('Panelside.Scene');
|
|
1274
|
+
|
|
1275
|
+
// The part's own prop, then the root's, then the constant. Three levels
|
|
1276
|
+
// because the root's is a default for every scene under it and the part's is
|
|
1277
|
+
// a statement about this one.
|
|
1278
|
+
const scale = scaleProp ?? rootScale ?? SCENE_SCALE;
|
|
1279
|
+
const radius = radiusProp ?? rootRadius ?? SCENE_RADIUS;
|
|
1280
|
+
const dim = dimProp ?? rootDim ?? SCENE_DIM;
|
|
1166
1281
|
const [sceneWidth, setSceneWidth] = useState(0);
|
|
1167
1282
|
const sign = useDirectionSign();
|
|
1168
1283
|
/*
|
|
@@ -1251,7 +1366,7 @@ function PanelsideScene({
|
|
|
1251
1366
|
including the one on the button that opens the panel. */}
|
|
1252
1367
|
<Animated.View
|
|
1253
1368
|
pointerEvents={open && !docked ? 'auto' : 'none'}
|
|
1254
|
-
className=
|
|
1369
|
+
className={cn('absolute bottom-0 end-0 start-0 top-0 bg-black', scrimClassName)}
|
|
1255
1370
|
style={scrimStyle}
|
|
1256
1371
|
>
|
|
1257
1372
|
{dismissible ? (
|