panelui-native 0.105.1 → 0.107.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/lib/module/components/bottom-sheet/index.js +63 -9
- package/lib/module/components/bottom-sheet/index.js.map +1 -1
- package/lib/module/components/button/index.js +11 -2
- package/lib/module/components/button/index.js.map +1 -1
- package/lib/module/components/select/index.js +73 -27
- package/lib/module/components/select/index.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/components/bottom-sheet/index.d.ts +7 -0
- package/lib/typescript/src/components/bottom-sheet/index.d.ts.map +1 -1
- package/lib/typescript/src/components/button/index.d.ts +17 -2
- package/lib/typescript/src/components/button/index.d.ts.map +1 -1
- package/lib/typescript/src/components/select/index.d.ts +45 -1
- package/lib/typescript/src/components/select/index.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/bottom-sheet/index.tsx +86 -7
- package/src/components/button/index.tsx +26 -4
- package/src/components/select/index.tsx +114 -19
- package/src/index.ts +1 -0
|
@@ -53,6 +53,7 @@ import {
|
|
|
53
53
|
View,
|
|
54
54
|
type LayoutChangeEvent,
|
|
55
55
|
} from 'react-native';
|
|
56
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
56
57
|
import Animated, {
|
|
57
58
|
FadeIn,
|
|
58
59
|
FadeOut,
|
|
@@ -68,7 +69,7 @@ import { Portal } from '../../primitives/portal';
|
|
|
68
69
|
import { Text, textChildren } from '../../primitives/text';
|
|
69
70
|
import { useBackHandler } from '../../hooks/use-back-handler';
|
|
70
71
|
import { cn } from '../../utils/cn';
|
|
71
|
-
import { BottomSheet } from '../bottom-sheet';
|
|
72
|
+
import { BottomSheet, bottomSheetDetentHeight } from '../bottom-sheet';
|
|
72
73
|
import { InputGroup } from '../input-group';
|
|
73
74
|
import { nativeSelectSupportsOptions } from './native-select-contract';
|
|
74
75
|
|
|
@@ -321,6 +322,50 @@ function filterOptions(children: ReactNode, needle: string): FilterResult {
|
|
|
321
322
|
return { kept, seen };
|
|
322
323
|
}
|
|
323
324
|
|
|
325
|
+
/**
|
|
326
|
+
* How the sheet is drawn in the `sheet` presentation. The other two
|
|
327
|
+
* presentations ignore it, and so does the `native` picker, which replaces the
|
|
328
|
+
* sheet altogether.
|
|
329
|
+
*/
|
|
330
|
+
export interface SelectSheetProps {
|
|
331
|
+
/**
|
|
332
|
+
* Present the platform's own sheet — SwiftUI on iOS, Jetpack Compose on
|
|
333
|
+
* Android — instead of the styled one. Requires the optional `@expo/ui`
|
|
334
|
+
* package; without it the styled sheet is shown.
|
|
335
|
+
*
|
|
336
|
+
* Only the container is the platform's. The options inside are still the
|
|
337
|
+
* select's own, so groups, disabled options and `searchable` all work.
|
|
338
|
+
*/
|
|
339
|
+
native?: boolean;
|
|
340
|
+
/**
|
|
341
|
+
* Heights the native sheet can rest at. Omit to size to the options. The
|
|
342
|
+
* list fills the first one and scrolls inside it. `{ fraction }` and
|
|
343
|
+
* `{ height }` are iOS-only. Native sheet only.
|
|
344
|
+
*/
|
|
345
|
+
snapPoints?: ('half' | 'full' | { fraction: number } | { height: number })[];
|
|
346
|
+
/**
|
|
347
|
+
* Paint the native sheet a solid colour instead of the platform's
|
|
348
|
+
* translucent material. `true` uses the theme's popover surface; a string
|
|
349
|
+
* paints that colour. Native sheet only.
|
|
350
|
+
*/
|
|
351
|
+
nativeBackground?: boolean | string;
|
|
352
|
+
/**
|
|
353
|
+
* How tall the sheet opens. `auto`, the default, sizes to the options and
|
|
354
|
+
* scrolls once they pass 384 points; `half` and `full` fix the height and
|
|
355
|
+
* the list fills it. On the native sheet these map onto the platform's
|
|
356
|
+
* detents, and `snapPoints` wins over them.
|
|
357
|
+
*/
|
|
358
|
+
size?: 'auto' | 'half' | 'full';
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* The native sheet's own top padding, which clears the platform's grabber —
|
|
363
|
+
* `pt-5` on `BottomSheet.Content`. A list that fills a detent has to be given
|
|
364
|
+
* the height left inside that padding, because the platform hosts the content
|
|
365
|
+
* at whatever size it reports.
|
|
366
|
+
*/
|
|
367
|
+
const NATIVE_SHEET_TOP_PADDING = 20;
|
|
368
|
+
|
|
324
369
|
/** Trigger frame in window coordinates, measured when the list opens. */
|
|
325
370
|
interface Anchor {
|
|
326
371
|
x: number;
|
|
@@ -384,6 +429,11 @@ export interface SelectProps {
|
|
|
384
429
|
presentation?: SelectPresentation;
|
|
385
430
|
/** Sheet title shown above the options. `sheet` presentation only. */
|
|
386
431
|
title?: string;
|
|
432
|
+
/**
|
|
433
|
+
* How the sheet is drawn — the platform's own sheet, its detents and
|
|
434
|
+
* surface, or a fixed height. `sheet` presentation only.
|
|
435
|
+
*/
|
|
436
|
+
sheetProps?: SelectSheetProps;
|
|
387
437
|
/**
|
|
388
438
|
* Width of the floating list. `trigger` matches the trigger, `content` sizes
|
|
389
439
|
* to the longest option, or pass a pixel value. `overlay` only.
|
|
@@ -441,6 +491,7 @@ function SelectRoot({
|
|
|
441
491
|
emptyClassName,
|
|
442
492
|
presentation = 'sheet',
|
|
443
493
|
title,
|
|
494
|
+
sheetProps,
|
|
444
495
|
contentWidth = 'trigger',
|
|
445
496
|
offset = 8,
|
|
446
497
|
onOpenChange,
|
|
@@ -458,6 +509,7 @@ function SelectRoot({
|
|
|
458
509
|
const triggerRef = useRef<View>(null);
|
|
459
510
|
const chevron = useSharedValue(0);
|
|
460
511
|
const { height: screenHeight } = useWindowDimensions();
|
|
512
|
+
const insets = useSafeAreaInsets();
|
|
461
513
|
|
|
462
514
|
const options = useMemo(() => {
|
|
463
515
|
const collected: SelectItemProps[] = [];
|
|
@@ -653,6 +705,58 @@ function SelectRoot({
|
|
|
653
705
|
);
|
|
654
706
|
|
|
655
707
|
if (presentation === 'sheet') {
|
|
708
|
+
const size = sheetProps?.size ?? 'auto';
|
|
709
|
+
const nativeSheet = !!sheetProps?.native && !!getNativeUI();
|
|
710
|
+
// The native sheet's resting heights — `snapPoints`, or `size` mapped onto
|
|
711
|
+
// the platform's detents. Undefined means it sizes to the options.
|
|
712
|
+
const detents = nativeSheet
|
|
713
|
+
? sheetProps?.snapPoints ?? (size === 'auto' ? undefined : [size])
|
|
714
|
+
: undefined;
|
|
715
|
+
const sized = nativeSheet ? detents !== undefined : size !== 'auto';
|
|
716
|
+
|
|
717
|
+
/*
|
|
718
|
+
* A list asked to fill a native sheet needs a definite height above it.
|
|
719
|
+
* The platform hosts the content at the size it reports, so a list left to
|
|
720
|
+
* fill reports every row and runs off the bottom of the detent.
|
|
721
|
+
*/
|
|
722
|
+
const detentHeight = bottomSheetDetentHeight(detents, screenHeight);
|
|
723
|
+
const nativeHeight =
|
|
724
|
+
detentHeight === undefined
|
|
725
|
+
? undefined
|
|
726
|
+
: detentHeight - NATIVE_SHEET_TOP_PADDING - Math.max(insets.bottom, 16);
|
|
727
|
+
|
|
728
|
+
const sheetBody = (
|
|
729
|
+
<>
|
|
730
|
+
{title ? (
|
|
731
|
+
<Text size="lg" weight="semibold" className="mb-2 px-3">
|
|
732
|
+
{title}
|
|
733
|
+
</Text>
|
|
734
|
+
) : null}
|
|
735
|
+
{search ? <View className="px-1">{search}</View> : null}
|
|
736
|
+
{/*
|
|
737
|
+
* The sheet's own scroller rather than a plain one, because the sheet
|
|
738
|
+
* and the list both want a vertical drag. Unrelated, whichever takes
|
|
739
|
+
* the touch first keeps it — on Android that was usually the sheet,
|
|
740
|
+
* so the options dragged the sheet instead of scrolling. This one
|
|
741
|
+
* scrolls until the list reaches its top and hands the drag over
|
|
742
|
+
* there.
|
|
743
|
+
*/}
|
|
744
|
+
<BottomSheet.Body
|
|
745
|
+
bounces={false}
|
|
746
|
+
// A sized sheet gives the list its height; an `auto` one stops it at
|
|
747
|
+
// 384 points so a long list scrolls instead of filling the screen.
|
|
748
|
+
className={sized ? undefined : 'max-h-96'}
|
|
749
|
+
// The filter is a text field above a scroller: dismissing the
|
|
750
|
+
// keyboard on a drag is what lets you look at what you filtered
|
|
751
|
+
// to without first tapping somewhere neutral.
|
|
752
|
+
keyboardDismissMode="on-drag"
|
|
753
|
+
keyboardShouldPersistTaps="handled"
|
|
754
|
+
>
|
|
755
|
+
<View className={slots.options({ className: listClassName })}>{optionList}</View>
|
|
756
|
+
</BottomSheet.Body>
|
|
757
|
+
</>
|
|
758
|
+
);
|
|
759
|
+
|
|
656
760
|
return (
|
|
657
761
|
<SelectContext.Provider value={context}>
|
|
658
762
|
<View className={className}>{trigger}</View>
|
|
@@ -663,28 +767,19 @@ function SelectRoot({
|
|
|
663
767
|
onOpenChange={(next) => {
|
|
664
768
|
if (!next) close();
|
|
665
769
|
}}
|
|
770
|
+
native={nativeSheet}
|
|
771
|
+
snapPoints={sheetProps?.snapPoints}
|
|
772
|
+
nativeBackground={sheetProps?.nativeBackground}
|
|
666
773
|
>
|
|
667
|
-
<BottomSheet.Content>
|
|
774
|
+
<BottomSheet.Content size={size}>
|
|
668
775
|
{/* BottomSheet.Content portals its children out of this subtree —
|
|
669
776
|
re-provide the select context so Select.Item keeps working. */}
|
|
670
777
|
<SelectContext.Provider value={context}>
|
|
671
|
-
{
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
</
|
|
675
|
-
)
|
|
676
|
-
{search ? <View className="px-1">{search}</View> : null}
|
|
677
|
-
<ScrollView
|
|
678
|
-
bounces={false}
|
|
679
|
-
className="max-h-96"
|
|
680
|
-
// The filter is a text field above a scroller: dismissing the
|
|
681
|
-
// keyboard on a drag is what lets you look at what you filtered
|
|
682
|
-
// to without first tapping somewhere neutral.
|
|
683
|
-
keyboardDismissMode="on-drag"
|
|
684
|
-
keyboardShouldPersistTaps="handled"
|
|
685
|
-
>
|
|
686
|
-
<View className={slots.options({ className: listClassName })}>{optionList}</View>
|
|
687
|
-
</ScrollView>
|
|
778
|
+
{nativeHeight === undefined ? (
|
|
779
|
+
sheetBody
|
|
780
|
+
) : (
|
|
781
|
+
<View style={{ height: nativeHeight }}>{sheetBody}</View>
|
|
782
|
+
)}
|
|
688
783
|
</SelectContext.Provider>
|
|
689
784
|
</BottomSheet.Content>
|
|
690
785
|
</BottomSheet>
|