@pallasoft/ps-mobile-components 1.12.0 → 1.13.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/dist/components/ps-action-sheet/ps-action-sheet.js +18 -2
- package/dist/components/ps-barcode-scanner-sheet/ps-barcode-scanner-sheet.js +2 -1
- package/dist/components/ps-chart-bar/ps-chart-bar.js +11 -4
- package/dist/components/ps-document-viewer/ps-document-viewer.js +2 -1
- package/dist/components/ps-document-zoom-image/ps-document-zoom-image.js +10 -0
- package/dist/components/ps-donut-chart/ps-donut-chart.js +5 -4
- package/dist/components/ps-donut-reveal/index.d.ts +1 -0
- package/dist/components/ps-donut-reveal/index.js +1 -0
- package/dist/components/ps-donut-reveal/ps-donut-reveal-props.d.ts +6 -0
- package/dist/components/ps-donut-reveal/ps-donut-reveal.d.ts +2 -0
- package/dist/components/ps-donut-reveal/ps-donut-reveal.js +14 -0
- package/dist/components/ps-donut-slice/ps-donut-slice-props.d.ts +0 -4
- package/dist/components/ps-donut-slice/ps-donut-slice.d.ts +1 -1
- package/dist/components/ps-donut-slice/ps-donut-slice.js +2 -14
- package/dist/components/ps-infinite-list/ps-infinite-list-props.d.ts +2 -0
- package/dist/components/ps-infinite-list/ps-infinite-list.d.ts +1 -1
- package/dist/components/ps-infinite-list/ps-infinite-list.js +12 -5
- package/dist/components/ps-list/ps-list-props.d.ts +2 -0
- package/dist/components/ps-list/ps-list.d.ts +1 -1
- package/dist/components/ps-list/ps-list.js +1 -1
- package/dist/components/ps-menu-popup/ps-menu-popup.js +3 -2
- package/dist/components/ps-screen/ps-screen-props.d.ts +2 -0
- package/dist/components/ps-screen/ps-screen.d.ts +1 -1
- package/dist/components/ps-screen/ps-screen.js +12 -5
- package/dist/components/ps-sheet-content/ps-sheet-content.js +4 -2
- package/dist/components/ps-sheet-presenter/ps-sheet-presenter.ios.js +15 -5
- package/dist/components/ps-sheet-presenter/ps-sheet-presenter.js +16 -3
- package/dist/components/ps-sortable-grid/ps-sortable-grid.js +7 -4
- package/dist/components/ps-sortable-grid/ps-sortable-item-props.d.ts +1 -1
- package/dist/components/ps-sortable-grid/ps-sortable-item.js +19 -5
- package/dist/components/ps-widget-list/ps-widget-grid.js +16 -7
- package/dist/components/ps-widget-list/ps-widget-list-props.d.ts +2 -0
- package/dist/components/ps-widget-list/ps-widget-list.d.ts +1 -1
- package/dist/components/ps-widget-list/ps-widget-list.js +12 -5
- package/dist/constants/ps-chart-bar-corner.d.ts +6 -0
- package/dist/constants/ps-chart-bar-corner.js +5 -0
- package/dist/constants/ps-chart-config.d.ts +4 -1
- package/dist/constants/ps-chart-config.js +4 -1
- package/dist/constants/ps-content-width.d.ts +6 -0
- package/dist/constants/ps-content-width.js +5 -0
- package/dist/constants/ps-document-search-config.d.ts +0 -3
- package/dist/constants/ps-document-search-config.js +0 -3
- package/dist/constants/ps-layout-class-config.d.ts +12 -0
- package/dist/constants/ps-layout-class-config.js +12 -0
- package/dist/constants/ps-layout-class.d.ts +5 -0
- package/dist/constants/ps-layout-class.js +4 -0
- package/dist/constants/ps-menu-popup-config.d.ts +1 -0
- package/dist/constants/ps-menu-popup-config.js +1 -0
- package/dist/constants/ps-orientation-config.d.ts +3 -0
- package/dist/constants/ps-orientation-config.js +3 -0
- package/dist/constants/ps-sheet-config.d.ts +1 -0
- package/dist/constants/ps-sheet-config.js +1 -0
- package/dist/constants/ps-sortable-grid-config.d.ts +4 -0
- package/dist/constants/ps-sortable-grid-config.js +4 -0
- package/dist/hooks/use-ps-layout-class.d.ts +2 -0
- package/dist/hooks/use-ps-layout-class.js +6 -0
- package/dist/hooks/use-ps-menu-anchor.d.ts +1 -1
- package/dist/hooks/use-ps-menu-anchor.js +14 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/interfaces/ps-chart-arc-data.d.ts +9 -0
- package/dist/interfaces/ps-chart-arc-data.js +1 -0
- package/dist/interfaces/ps-chart-bar-rect.d.ts +2 -0
- package/dist/interfaces/ps-document-search-match.d.ts +2 -4
- package/dist/interfaces/ps-document-text-box.d.ts +2 -6
- package/dist/interfaces/ps-document-text-layer-word.d.ts +2 -5
- package/dist/interfaces/ps-document-text-layer.d.ts +2 -6
- package/dist/interfaces/ps-document-text-segment.d.ts +2 -4
- package/dist/interfaces/ps-donut-slice-data.d.ts +1 -3
- package/dist/interfaces/ps-menu-popup-insets.d.ts +2 -0
- package/dist/interfaces/ps-menu-popup-layout.d.ts +1 -0
- package/dist/interfaces/ps-sortable-measure-data.d.ts +4 -0
- package/dist/interfaces/ps-sortable-measure-data.js +1 -0
- package/dist/services/ps-chart-arc-service.d.ts +14 -0
- package/dist/services/ps-chart-arc-service.js +83 -0
- package/dist/services/ps-chart-bar-service.d.ts +2 -0
- package/dist/services/ps-chart-bar-service.js +18 -3
- package/dist/services/ps-chart-donut-service.d.ts +2 -0
- package/dist/services/ps-chart-donut-service.js +42 -12
- package/dist/services/ps-document-search-service.d.ts +0 -4
- package/dist/services/ps-document-search-service.js +9 -96
- package/dist/services/ps-layout-service.d.ts +12 -0
- package/dist/services/ps-layout-service.js +41 -0
- package/dist/services/ps-menu-popup-service.js +8 -4
- package/dist/services/ps-sheet-service.d.ts +5 -2
- package/dist/services/ps-sheet-service.js +17 -4
- package/dist/services/ps-sortable-grid-service.d.ts +3 -2
- package/dist/services/ps-sortable-grid-service.js +26 -22
- package/dist/services/ps-waterfall-service.js +2 -0
- package/package.json +2 -2
- package/dist/interfaces/ps-document-normalized-text.d.ts +0 -5
- /package/dist/{interfaces/ps-document-normalized-text.js → components/ps-donut-reveal/ps-donut-reveal-props.js} +0 -0
|
@@ -1,35 +1,51 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useRef } from 'react';
|
|
3
3
|
import { PsIconKey } from '@pallasoft/ps-icons';
|
|
4
|
-
import { Modal, Pressable, StyleSheet, View } from 'react-native';
|
|
4
|
+
import { Modal, Pressable, StyleSheet, View, useWindowDimensions } from 'react-native';
|
|
5
5
|
import Animated, { FadeInDown } from 'react-native-reanimated';
|
|
6
6
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
7
|
+
import { PsLayoutClass } from '../../constants/ps-layout-class';
|
|
7
8
|
import { PsLayoutConfig } from '../../constants/ps-layout-config';
|
|
8
9
|
import { PsMobileControlConfig } from '../../constants/ps-mobile-control-config';
|
|
10
|
+
import { PsOrientationConfig } from '../../constants/ps-orientation-config';
|
|
9
11
|
import { PsRippleKind } from '../../constants/ps-ripple-kind';
|
|
12
|
+
import { usePsLayoutClass } from '../../hooks/use-ps-layout-class';
|
|
10
13
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
11
14
|
import { PsActionSheetService } from '../../services/ps-action-sheet-service';
|
|
12
15
|
import { PsRippleService } from '../../services/ps-ripple-service';
|
|
16
|
+
import { PsSheetService } from '../../services/ps-sheet-service';
|
|
13
17
|
import { PsStateService } from '../../services/ps-state-service';
|
|
14
18
|
import { PsIcon } from '../ps-icon/ps-icon';
|
|
15
19
|
import { PsText } from '../ps-text/ps-text';
|
|
16
20
|
export const PsActionSheet = ({ cancelLabel, isOpen, items, onClose, title, }) => {
|
|
17
21
|
const theme = usePsMobileTheme();
|
|
18
22
|
const insets = useSafeAreaInsets();
|
|
23
|
+
const layoutClass = usePsLayoutClass();
|
|
24
|
+
const { width: windowWidth } = useWindowDimensions();
|
|
25
|
+
const isRegular = layoutClass === PsLayoutClass.regular;
|
|
19
26
|
const pending = useRef(undefined);
|
|
20
27
|
const runPending = () => {
|
|
21
28
|
const action = pending.current;
|
|
22
29
|
pending.current = undefined;
|
|
23
30
|
action?.();
|
|
24
31
|
};
|
|
25
|
-
return (_jsxs(Modal, { animationType: 'fade', onDismiss: runPending, onRequestClose: onClose, statusBarTranslucent: true, transparent: true, visible: isOpen, children: [_jsx(Pressable, { accessibilityElementsHidden: true, onPress: onClose, style: [StyleSheet.absoluteFill, { backgroundColor: theme.overlay }] }), _jsx(View, { pointerEvents: 'box-none', style: {
|
|
32
|
+
return (_jsxs(Modal, { animationType: 'fade', onDismiss: runPending, onRequestClose: onClose, statusBarTranslucent: true, supportedOrientations: PsOrientationConfig.all, transparent: true, visible: isOpen, children: [_jsx(Pressable, { accessibilityElementsHidden: true, onPress: onClose, style: [StyleSheet.absoluteFill, { backgroundColor: theme.overlay }] }), _jsx(View, { pointerEvents: 'box-none', style: {
|
|
33
|
+
alignItems: isRegular ? 'center' : undefined,
|
|
34
|
+
flex: 1,
|
|
35
|
+
justifyContent: 'flex-end',
|
|
36
|
+
}, children: _jsxs(Animated.View, { entering: FadeInDown, style: {
|
|
26
37
|
backgroundColor: theme.surface,
|
|
27
38
|
borderColor: theme.line,
|
|
39
|
+
borderBottomLeftRadius: isRegular ? PsLayoutConfig.actionSheetRadius : 0,
|
|
40
|
+
borderBottomRightRadius: isRegular ? PsLayoutConfig.actionSheetRadius : 0,
|
|
28
41
|
borderTopLeftRadius: PsLayoutConfig.actionSheetRadius,
|
|
29
42
|
borderTopRightRadius: PsLayoutConfig.actionSheetRadius,
|
|
30
43
|
borderWidth: 1,
|
|
44
|
+
marginBottom: isRegular ? PsLayoutConfig.gutter : 0,
|
|
45
|
+
maxWidth: PsSheetService.fittedMaxWidth(windowWidth, layoutClass),
|
|
31
46
|
paddingBottom: insets.bottom + PsLayoutConfig.sheetFooterGap,
|
|
32
47
|
paddingTop: PsLayoutConfig.sheetFooterGap,
|
|
48
|
+
width: isRegular ? '100%' : undefined,
|
|
33
49
|
}, testID: 'ps-action-sheet', children: [title === undefined ? null : (_jsx(View, { style: { paddingHorizontal: PsLayoutConfig.gutter, paddingVertical: 8 }, children: _jsx(PsText, { tone: 'muted', variant: 'label', children: title }) })), items.map((item) => (_jsxs(Pressable, { android_ripple: PsRippleService.resolve(theme, PsRippleKind.Surface), accessibilityRole: 'menuitem', accessibilityState: { disabled: item.isDisabled === true }, disabled: item.isDisabled, onPress: () => {
|
|
34
50
|
pending.current = item.onSelect;
|
|
35
51
|
onClose();
|
|
@@ -6,6 +6,7 @@ import { Linking, Modal, StatusBar, StyleSheet, View, useWindowDimensions } from
|
|
|
6
6
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
7
7
|
import { PsBarcodePermission } from '../../constants/ps-barcode-permission';
|
|
8
8
|
import { PsBarcodeScannerConfig } from '../../constants/ps-barcode-scanner-config';
|
|
9
|
+
import { PsOrientationConfig } from '../../constants/ps-orientation-config';
|
|
9
10
|
import { usePsHaptics } from '../../hooks/use-ps-haptics';
|
|
10
11
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
11
12
|
import { PsBarcodeScannerService } from '../../services/ps-barcode-scanner-service';
|
|
@@ -41,7 +42,7 @@ export const PsBarcodeScannerSheet = ({ barcodeTypes, isContinuous = false, isOp
|
|
|
41
42
|
if (!isContinuous)
|
|
42
43
|
onClose();
|
|
43
44
|
};
|
|
44
|
-
return (_jsxs(Modal, { animationType: 'fade', onRequestClose: onClose, presentationStyle: 'fullScreen', visible: isOpen, children: [_jsx(StatusBar, { barStyle: 'light-content' }), _jsxs(View, { style: { backgroundColor: PsBarcodeScannerConfig.backdropColor, flex: 1 }, testID: 'ps-barcode-scanner', children: [Camera !== null && permission === PsBarcodePermission.granted ? (_jsx(Camera, { barcodeScannerSettings: {
|
|
45
|
+
return (_jsxs(Modal, { animationType: 'fade', onRequestClose: onClose, presentationStyle: 'fullScreen', supportedOrientations: PsOrientationConfig.all, visible: isOpen, children: [_jsx(StatusBar, { barStyle: 'light-content' }), _jsxs(View, { style: { backgroundColor: PsBarcodeScannerConfig.backdropColor, flex: 1 }, testID: 'ps-barcode-scanner', children: [Camera !== null && permission === PsBarcodePermission.granted ? (_jsx(Camera, { barcodeScannerSettings: {
|
|
45
46
|
barcodeTypes: PsBarcodeScannerService.types(barcodeTypes),
|
|
46
47
|
}, enableTorch: isTorchOn, facing: PsBarcodeScannerConfig.facing, onBarcodeScanned: read, style: StyleSheet.absoluteFill })) : null, permission === PsBarcodePermission.granted ? (_jsx(View, { pointerEvents: 'none', style: [
|
|
47
48
|
StyleSheet.absoluteFill,
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Animated, { useAnimatedProps } from 'react-native-reanimated';
|
|
3
|
-
import { Rect } from 'react-native-svg';
|
|
4
|
-
import {
|
|
3
|
+
import { G, Rect } from 'react-native-svg';
|
|
4
|
+
import { PsChartBarCorner } from '../../constants/ps-chart-bar-corner';
|
|
5
|
+
import { PsChartBarService } from '../../services/ps-chart-bar-service';
|
|
5
6
|
const AnimatedRect = Animated.createAnimatedComponent(Rect);
|
|
6
7
|
export const PsChartBar = ({ progress, rect }) => {
|
|
8
|
+
const radius = PsChartBarService.radius(rect);
|
|
9
|
+
const hasFlatBase = rect.corner === PsChartBarCorner.Value && radius > 0;
|
|
7
10
|
const animatedProps = useAnimatedProps(() => ({
|
|
8
11
|
height: rect.height * progress.value,
|
|
9
12
|
y: rect.isNegative ? rect.y : rect.y + rect.height * (1 - progress.value),
|
|
10
13
|
}));
|
|
11
|
-
|
|
14
|
+
const baseProps = useAnimatedProps(() => {
|
|
15
|
+
const height = Math.min(radius, rect.height * progress.value);
|
|
16
|
+
return { height, y: rect.isNegative ? rect.y : rect.y + rect.height - height };
|
|
17
|
+
});
|
|
18
|
+
return (_jsxs(G, { children: [_jsx(AnimatedRect, { animatedProps: animatedProps, fill: rect.color, height: rect.height, rx: radius, width: rect.width, x: rect.x, y: rect.y }), hasFlatBase ? (_jsx(AnimatedRect, { animatedProps: baseProps, fill: rect.color, height: Math.min(radius, rect.height), width: rect.width, x: rect.x, y: rect.isNegative ? rect.y : rect.y + rect.height - Math.min(radius, rect.height) })) : null] }));
|
|
12
19
|
};
|
|
@@ -7,6 +7,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
7
7
|
import { PsDocumentConfig } from '../../constants/ps-document-config';
|
|
8
8
|
import { PsDocumentSearchConfig } from '../../constants/ps-document-search-config';
|
|
9
9
|
import { PsMobileControlConfig } from '../../constants/ps-mobile-control-config';
|
|
10
|
+
import { PsOrientationConfig } from '../../constants/ps-orientation-config';
|
|
10
11
|
import { usePsDocumentPdfPages } from '../../hooks/use-ps-document-pdf-pages';
|
|
11
12
|
import { usePsDocumentSearchTexts } from '../../hooks/use-ps-document-search-texts';
|
|
12
13
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
@@ -72,7 +73,7 @@ export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onCl
|
|
|
72
73
|
if (width > 0 && entries.length > 0)
|
|
73
74
|
list.current?.scrollToIndex({ animated: false, index });
|
|
74
75
|
}, [entries.length, index, width]);
|
|
75
|
-
return (_jsxs(Modal, { animationType: 'fade', onRequestClose: onClose, presentationStyle: 'fullScreen', visible: isOpen, children: [_jsx(StatusBar, { barStyle: 'light-content' }), _jsxs(GestureHandlerRootView, { style: {
|
|
76
|
+
return (_jsxs(Modal, { animationType: 'fade', onRequestClose: onClose, presentationStyle: 'fullScreen', supportedOrientations: PsOrientationConfig.all, visible: isOpen, children: [_jsx(StatusBar, { barStyle: 'light-content' }), _jsxs(GestureHandlerRootView, { style: {
|
|
76
77
|
backgroundColor: PsDocumentConfig.backdropColor,
|
|
77
78
|
flex: 1,
|
|
78
79
|
paddingBottom: insets.bottom,
|
|
@@ -100,6 +100,16 @@ export const PsDocumentZoomImage = ({ name, onDismiss, onError, onZoomChange, se
|
|
|
100
100
|
baseX.value = nextX;
|
|
101
101
|
baseY.value = nextY;
|
|
102
102
|
}, [search?.activeIndex, search?.query]);
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
scale.value = PsDocumentConfig.minZoom;
|
|
105
|
+
baseScale.value = PsDocumentConfig.minZoom;
|
|
106
|
+
x.value = 0;
|
|
107
|
+
y.value = 0;
|
|
108
|
+
baseX.value = 0;
|
|
109
|
+
baseY.value = 0;
|
|
110
|
+
setIsZoomed(false);
|
|
111
|
+
onZoomChange(false);
|
|
112
|
+
}, [size.height, size.width]);
|
|
103
113
|
const gesture = useSimultaneousGestures(pinch, move, dismiss, doubleTap);
|
|
104
114
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
105
115
|
transform: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from 'react';
|
|
2
|
+
import { useId, useState } from 'react';
|
|
3
3
|
import { View } from 'react-native';
|
|
4
|
-
import Svg from 'react-native-svg';
|
|
4
|
+
import Svg, { G } from 'react-native-svg';
|
|
5
5
|
import { PsChartConfig } from '../../constants/ps-chart-config';
|
|
6
6
|
import { PsChartSkeletonVariant } from '../../constants/ps-chart-skeleton-variant';
|
|
7
7
|
import { usePsChartReveal } from '../../hooks/use-ps-chart-reveal';
|
|
@@ -12,6 +12,7 @@ import { PsChartDonutService } from '../../services/ps-chart-donut-service';
|
|
|
12
12
|
import { PsChartEmptyState } from '../ps-chart-empty-state/ps-chart-empty-state';
|
|
13
13
|
import { PsChartLegend } from '../ps-chart-legend/ps-chart-legend';
|
|
14
14
|
import { PsChartSkeleton } from '../ps-chart-skeleton/ps-chart-skeleton';
|
|
15
|
+
import { PsDonutReveal } from '../ps-donut-reveal/ps-donut-reveal';
|
|
15
16
|
import { PsDonutSlice } from '../ps-donut-slice/ps-donut-slice';
|
|
16
17
|
import { PsText } from '../ps-text/ps-text';
|
|
17
18
|
export const PsDonutChart = ({ centerLabel, centerValue, data, emptyLabel, formatShare, height = PsChartConfig.donutHeight, isLoading = false, revealKey, }) => {
|
|
@@ -19,6 +20,7 @@ export const PsDonutChart = ({ centerLabel, centerValue, data, emptyLabel, forma
|
|
|
19
20
|
const { onLayout, width } = usePsChartWidth();
|
|
20
21
|
const fill = usePsWidgetFill();
|
|
21
22
|
const [selected, setSelected] = useState(null);
|
|
23
|
+
const maskId = `donut${useId().replace(/[^a-zA-Z0-9]/g, '')}`;
|
|
22
24
|
const progress = usePsChartReveal(!isLoading && width > 0, revealKey);
|
|
23
25
|
if (isLoading)
|
|
24
26
|
return _jsx(PsChartSkeleton, { height: height, variant: PsChartSkeletonVariant.Donut });
|
|
@@ -27,7 +29,6 @@ export const PsDonutChart = ({ centerLabel, centerValue, data, emptyLabel, forma
|
|
|
27
29
|
const slices = PsChartDonutService.slices(data, theme.chart, size);
|
|
28
30
|
if (slices.length === 0)
|
|
29
31
|
return _jsx(PsChartEmptyState, { height: height, label: emptyLabel });
|
|
30
|
-
const circumference = PsChartDonutService.circumference(size);
|
|
31
32
|
const chosen = selected === null ? null : data[selected];
|
|
32
33
|
const readValue = chosen === null
|
|
33
34
|
? centerValue
|
|
@@ -47,7 +48,7 @@ export const PsDonutChart = ({ centerLabel, centerValue, data, emptyLabel, forma
|
|
|
47
48
|
justifyContent: 'center',
|
|
48
49
|
minHeight: height + fill,
|
|
49
50
|
rowGap: PsChartConfig.donutGap,
|
|
50
|
-
}, testID: 'ps-donut-chart', children: [_jsxs(View, { style: { height: size, width: size }, children: [
|
|
51
|
+
}, testID: 'ps-donut-chart', children: [_jsxs(View, { style: { height: size, width: size }, children: [_jsxs(Svg, { height: size, width: size, children: [_jsx(PsDonutReveal, { id: maskId, progress: progress, size: size }), _jsx(G, { mask: `url(#${maskId})`, children: slices.map((slice, index) => slice.path === '' ? null : (_jsx(PsDonutSlice, { isDimmed: selected !== null && selected !== index, onPress: () => setSelected(selected === index ? null : index), slice: slice }, slice.id))) })] }), _jsxs(View, { pointerEvents: 'none', style: {
|
|
51
52
|
alignItems: 'center',
|
|
52
53
|
bottom: 0,
|
|
53
54
|
justifyContent: 'center',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ps-donut-reveal';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ps-donut-reveal';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import Animated, { useAnimatedProps } from 'react-native-reanimated';
|
|
3
|
+
import { Circle, Defs, Mask } from 'react-native-svg';
|
|
4
|
+
import { PsChartConfig } from '../../constants/ps-chart-config';
|
|
5
|
+
import { PsChartDonutService } from '../../services/ps-chart-donut-service';
|
|
6
|
+
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
|
7
|
+
export const PsDonutReveal = ({ id, progress, size }) => {
|
|
8
|
+
const centre = size / 2;
|
|
9
|
+
const circumference = PsChartDonutService.circumference(size);
|
|
10
|
+
const animatedProps = useAnimatedProps(() => ({
|
|
11
|
+
strokeDasharray: [progress.value * circumference, circumference],
|
|
12
|
+
}));
|
|
13
|
+
return (_jsx(Defs, { children: _jsx(Mask, { height: size, id: id, maskUnits: 'userSpaceOnUse', width: size, x: 0, y: 0, children: _jsx(AnimatedCircle, { animatedProps: animatedProps, cx: centre, cy: centre, fill: 'none', origin: `${centre}, ${centre}`, r: PsChartDonutService.radius(size), rotation: -90, stroke: 'white', strokeDasharray: [0, circumference], strokeWidth: PsChartConfig.donutThickness + PsChartConfig.donutRevealOverlap }) }) }));
|
|
14
|
+
};
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
import type { SharedValue } from 'react-native-reanimated';
|
|
2
1
|
import type { PsDonutSliceData } from '../../interfaces/ps-donut-slice-data';
|
|
3
2
|
export interface PsDonutSliceProps {
|
|
4
|
-
circumference: number;
|
|
5
3
|
isDimmed: boolean;
|
|
6
4
|
onPress: () => void;
|
|
7
|
-
progress: SharedValue<number>;
|
|
8
|
-
size: number;
|
|
9
5
|
slice: PsDonutSliceData;
|
|
10
6
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PsDonutSliceProps } from './ps-donut-slice-props';
|
|
2
|
-
export declare const PsDonutSlice: ({
|
|
2
|
+
export declare const PsDonutSlice: ({ isDimmed, onPress, slice }: PsDonutSliceProps) => import("react").JSX.Element;
|
|
@@ -1,16 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
3
|
-
import { Circle } from 'react-native-svg';
|
|
2
|
+
import { Path } from 'react-native-svg';
|
|
4
3
|
import { PsChartConfig } from '../../constants/ps-chart-config';
|
|
5
|
-
|
|
6
|
-
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
|
7
|
-
export const PsDonutSlice = ({ circumference, isDimmed, onPress, progress, size, slice, }) => {
|
|
8
|
-
const centre = size / 2;
|
|
9
|
-
const animatedProps = useAnimatedProps(() => ({
|
|
10
|
-
strokeDasharray: [
|
|
11
|
-
Math.max(0, Math.min(slice.dashLength, progress.value * circumference - slice.start)),
|
|
12
|
-
circumference,
|
|
13
|
-
],
|
|
14
|
-
}));
|
|
15
|
-
return (_jsx(AnimatedCircle, { animatedProps: animatedProps, cx: centre, cy: centre, fill: 'none', onPress: onPress, opacity: isDimmed ? 0.4 : 1, origin: `${centre}, ${centre}`, r: PsChartDonutService.radius(size), rotation: -90, stroke: slice.color, strokeDasharray: [slice.dashLength, circumference], strokeDashoffset: slice.dashOffset, strokeWidth: PsChartConfig.donutThickness }));
|
|
16
|
-
};
|
|
4
|
+
export const PsDonutSlice = ({ isDimmed, onPress, slice }) => (_jsx(Path, { d: slice.path, fill: slice.color, fillRule: 'evenodd', onPress: onPress, opacity: isDimmed ? PsChartConfig.donutDimmedOpacity : 1 }));
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactElement, ReactNode } from 'react';
|
|
2
2
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import type { PsContentWidth } from '../../constants/ps-content-width';
|
|
3
4
|
import type { PsListVariant } from '../../services/ps-list-service';
|
|
4
5
|
import type { PsListSkeletonLayout } from '../ps-list/ps-list-props';
|
|
5
6
|
export interface PsInfiniteSection<T> {
|
|
@@ -9,6 +10,7 @@ export interface PsInfiniteSection<T> {
|
|
|
9
10
|
title?: string;
|
|
10
11
|
}
|
|
11
12
|
export interface PsInfiniteListProps<T> {
|
|
13
|
+
contentWidth?: PsContentWidth;
|
|
12
14
|
empty?: ReactNode;
|
|
13
15
|
hasMore: boolean;
|
|
14
16
|
header?: ReactNode;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PsInfiniteListProps } from './ps-infinite-list-props';
|
|
2
|
-
export declare const PsInfiniteList: <T>({ empty, hasMore, header, isLoading, isLoadingMore, items, keyExtractor, onEndReached, onRefresh, renderItem, sections, skeleton, style, variant, }: PsInfiniteListProps<T>) => import("react").JSX.Element;
|
|
2
|
+
export declare const PsInfiniteList: <T>({ contentWidth, empty, hasMore, header, isLoading, isLoadingMore, items, keyExtractor, onEndReached, onRefresh, renderItem, sections, skeleton, style, variant, }: PsInfiniteListProps<T>) => import("react").JSX.Element;
|
|
@@ -1,34 +1,41 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Platform, RefreshControl, SectionList, View } from 'react-native';
|
|
3
3
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
|
+
import { PsContentWidth } from '../../constants/ps-content-width';
|
|
4
5
|
import { PsInfiniteConfig } from '../../constants/ps-infinite-config';
|
|
5
6
|
import { PsLayoutConfig } from '../../constants/ps-layout-config';
|
|
6
7
|
import { PsSelectionBarConfig } from '../../constants/ps-selection-bar-config';
|
|
7
8
|
import { PsScrollContext } from '../../contexts/ps-scroll-context';
|
|
9
|
+
import { usePsLayoutClass } from '../../hooks/use-ps-layout-class';
|
|
8
10
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
9
11
|
import { usePsRefresh } from '../../hooks/use-ps-refresh';
|
|
10
12
|
import { usePsScrollHost } from '../../hooks/use-ps-scroll-host';
|
|
11
13
|
import { usePsTabBar } from '../../hooks/use-ps-tab-bar';
|
|
12
14
|
import { usePsTopInset } from '../../hooks/use-ps-top-inset';
|
|
13
15
|
import { PsInfiniteListService } from '../../services/ps-infinite-list-service';
|
|
16
|
+
import { PsLayoutService } from '../../services/ps-layout-service';
|
|
14
17
|
import { PsListService } from '../../services/ps-list-service';
|
|
15
18
|
import { PsScreenService } from '../../services/ps-screen-service';
|
|
16
19
|
import { PsSkeletonList } from '../ps-skeleton/ps-skeleton-list';
|
|
17
20
|
import { PsText } from '../ps-text/ps-text';
|
|
18
21
|
import { PsInfiniteListFooter } from './ps-infinite-list-footer';
|
|
19
22
|
import { PsInfiniteListItem } from './ps-infinite-list-item';
|
|
20
|
-
export const PsInfiniteList = ({ empty, hasMore, header, isLoading = false, isLoadingMore = false, items, keyExtractor, onEndReached, onRefresh, renderItem, sections, skeleton, style, variant = 'grouped', }) => {
|
|
23
|
+
export const PsInfiniteList = ({ contentWidth = PsContentWidth.readable, empty, hasMore, header, isLoading = false, isLoadingMore = false, items, keyExtractor, onEndReached, onRefresh, renderItem, sections, skeleton, style, variant = 'grouped', }) => {
|
|
21
24
|
const theme = usePsMobileTheme();
|
|
22
25
|
const insets = useSafeAreaInsets();
|
|
23
26
|
const topInset = usePsTopInset();
|
|
24
27
|
const { hasTabBar, isHidden: isTabBarHidden } = usePsTabBar();
|
|
25
28
|
const { isRefreshing, refresh } = usePsRefresh(onRefresh);
|
|
26
29
|
const host = usePsScrollHost();
|
|
30
|
+
const layoutClass = usePsLayoutClass();
|
|
27
31
|
const shown = isLoading ? [] : PsInfiniteListService.sections(items, sections);
|
|
28
|
-
return (_jsxs(View, { style: { flex: 1 }, children: [_jsx(PsScrollContext, { value: host.context, children: _jsx(SectionList, { ListEmptyComponent: isLoading ? _jsx(PsSkeletonList, { layout: skeleton }) : _jsx(_Fragment, { children: empty }), ListFooterComponent: _jsx(PsInfiniteListFooter, { isLoadingMore: isLoadingMore }), ListHeaderComponent: header === undefined ? undefined : (_jsx(View, { style: { marginBottom: PsLayoutConfig.listGap }, children: header })), contentContainerStyle:
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
+
return (_jsxs(View, { style: { flex: 1 }, children: [_jsx(PsScrollContext, { value: host.context, children: _jsx(SectionList, { ListEmptyComponent: isLoading ? _jsx(PsSkeletonList, { layout: skeleton }) : _jsx(_Fragment, { children: empty }), ListFooterComponent: _jsx(PsInfiniteListFooter, { isLoadingMore: isLoadingMore }), ListHeaderComponent: header === undefined ? undefined : (_jsx(View, { style: { marginBottom: PsLayoutConfig.listGap }, children: header })), contentContainerStyle: [
|
|
33
|
+
PsScreenService.content({
|
|
34
|
+
bottom: PsScreenService.bottomInset(insets.bottom, hasTabBar, isTabBarHidden),
|
|
35
|
+
top: topInset,
|
|
36
|
+
}, Platform.OS === 'ios', PsListService.hasGutter(variant), 0, isTabBarHidden ? PsSelectionBarConfig.height : 0),
|
|
37
|
+
PsLayoutService.frame(layoutClass, contentWidth),
|
|
38
|
+
], contentInsetAdjustmentBehavior: 'automatic', initialNumToRender: PsInfiniteConfig.initialNumToRender, keyExtractor: keyExtractor, keyboardDismissMode: 'interactive', keyboardShouldPersistTaps: 'handled', maxToRenderPerBatch: PsInfiniteConfig.maxToRenderPerBatch, onContentSizeChange: host.onContentSizeChange, onEndReached: () => {
|
|
32
39
|
if (PsInfiniteListService.shouldLoadMore(hasMore, isLoading, isLoadingMore))
|
|
33
40
|
onEndReached();
|
|
34
41
|
}, onEndReachedThreshold: PsInfiniteConfig.endReachedThreshold, onLayout: host.onLayout, onScroll: host.onScroll, refreshControl: onRefresh === undefined ? undefined : (_jsx(RefreshControl, { colors: [theme.primaryText], onRefresh: () => void refresh(), progressBackgroundColor: theme.surface, refreshing: isRefreshing, tintColor: theme.primary })), renderItem: ({ index, item, section }) => (_jsx(PsInfiniteListItem, { count: section.data.length, index: index, children: renderItem(item) })), renderSectionFooter: ({ section }) => (_jsx(View, { style: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { ReactElement, ReactNode } from 'react';
|
|
2
2
|
import type { PsIconKey } from '@pallasoft/ps-icons';
|
|
3
3
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
4
|
+
import type { PsContentWidth } from '../../constants/ps-content-width';
|
|
4
5
|
import type { PsMenuItem } from '../../interfaces/ps-menu-item';
|
|
5
6
|
import type { PsBadgeTone } from '../../services/ps-badge-tone-service';
|
|
6
7
|
import type { PsListVariant } from '../../services/ps-list-service';
|
|
@@ -26,6 +27,7 @@ export interface PsListSkeletonResolved {
|
|
|
26
27
|
}
|
|
27
28
|
export interface PsListProps {
|
|
28
29
|
children: ReactNode;
|
|
30
|
+
contentWidth?: PsContentWidth;
|
|
29
31
|
header?: ReactNode;
|
|
30
32
|
isLoading?: boolean;
|
|
31
33
|
onRefresh?: () => Promise<void>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PsListProps } from './ps-list-props';
|
|
2
|
-
export declare const PsList: ({ children, header, isLoading, onRefresh, skeleton, style, variant, }: PsListProps) => import("react").JSX.Element;
|
|
2
|
+
export declare const PsList: ({ children, contentWidth, header, isLoading, onRefresh, skeleton, style, variant, }: PsListProps) => import("react").JSX.Element;
|
|
@@ -3,4 +3,4 @@ import { PsLayoutConfig } from '../../constants/ps-layout-config';
|
|
|
3
3
|
import { PsListService } from '../../services/ps-list-service';
|
|
4
4
|
import { PsScreen } from '../ps-screen/ps-screen';
|
|
5
5
|
import { PsSkeletonList } from '../ps-skeleton/ps-skeleton-list';
|
|
6
|
-
export const PsList = ({ children, header, isLoading = false, onRefresh, skeleton, style, variant = 'grouped', }) => (_jsx(PsScreen, { gap: PsLayoutConfig.listGap, hasGutter: PsListService.hasGutter(variant), header: header, onRefresh: onRefresh, style: style, children: isLoading ? _jsx(PsSkeletonList, { layout: skeleton }) : children }));
|
|
6
|
+
export const PsList = ({ children, contentWidth, header, isLoading = false, onRefresh, skeleton, style, variant = 'grouped', }) => (_jsx(PsScreen, { contentWidth: contentWidth, gap: PsLayoutConfig.listGap, hasGutter: PsListService.hasGutter(variant), header: header, onRefresh: onRefresh, style: style, children: isLoading ? _jsx(PsSkeletonList, { layout: skeleton }) : children }));
|
|
@@ -4,6 +4,7 @@ import { Modal, Pressable, ScrollView, StyleSheet, useWindowDimensions } from 'r
|
|
|
4
4
|
import Animated from 'react-native-reanimated';
|
|
5
5
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
6
6
|
import { PsMenuPopupConfig } from '../../constants/ps-menu-popup-config';
|
|
7
|
+
import { PsOrientationConfig } from '../../constants/ps-orientation-config';
|
|
7
8
|
import { usePsMaterialScheme } from '../../hooks/use-ps-material-scheme';
|
|
8
9
|
import { usePsMenuPopupReveal } from '../../hooks/use-ps-menu-popup-reveal';
|
|
9
10
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
@@ -21,7 +22,7 @@ export const PsMenuPopup = ({ anchor, children, isFullWidth = false, onClose, })
|
|
|
21
22
|
: PsMenuPopupService.layout(anchor, window, insets, size.height, size.width, isFullWidth);
|
|
22
23
|
const container = PsMenuPopupStyleService.container(theme, scheme, isMaterial);
|
|
23
24
|
const reveal = usePsMenuPopupReveal(size !== undefined, layout.isBelow, isMaterial);
|
|
24
|
-
return (_jsxs(Modal, { animationType: isMaterial ? 'none' : 'fade', navigationBarTranslucent: true, onRequestClose: onClose, statusBarTranslucent: true, transparent: true, visible: true, children: [_jsx(Pressable, { accessibilityElementsHidden: true, onPress: onClose, style: StyleSheet.absoluteFill, testID: 'ps-menu-popup-backdrop' }), _jsx(Animated.View, { onLayout: (event) => {
|
|
25
|
+
return (_jsxs(Modal, { animationType: isMaterial ? 'none' : 'fade', navigationBarTranslucent: true, onRequestClose: onClose, statusBarTranslucent: true, supportedOrientations: PsOrientationConfig.all, transparent: true, visible: true, children: [_jsx(Pressable, { accessibilityElementsHidden: true, onPress: onClose, style: StyleSheet.absoluteFill, testID: 'ps-menu-popup-backdrop' }), _jsx(Animated.View, { onLayout: (event) => {
|
|
25
26
|
if (size === undefined)
|
|
26
27
|
setSize({
|
|
27
28
|
height: event.nativeEvent.layout.height,
|
|
@@ -36,7 +37,7 @@ export const PsMenuPopup = ({ anchor, children, isFullWidth = false, onClose, })
|
|
|
36
37
|
elevation: container.elevation,
|
|
37
38
|
left: layout.left,
|
|
38
39
|
maxHeight: layout.maxHeight,
|
|
39
|
-
maxWidth: PsMenuPopupConfig.maxWidth,
|
|
40
|
+
maxWidth: Math.min(PsMenuPopupConfig.maxWidth, layout.maxWidth),
|
|
40
41
|
minWidth: isFullWidth ? undefined : PsMenuPopupConfig.minWidth,
|
|
41
42
|
overflow: 'hidden',
|
|
42
43
|
position: 'absolute',
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { StyleProp, ViewStyle } from 'react-native';
|
|
3
|
+
import type { PsContentWidth } from '../../constants/ps-content-width';
|
|
3
4
|
export interface PsScreenProps {
|
|
4
5
|
children: ReactNode;
|
|
6
|
+
contentWidth?: PsContentWidth;
|
|
5
7
|
gap?: number;
|
|
6
8
|
hasGutter?: boolean;
|
|
7
9
|
header?: ReactNode;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PsScreenProps } from './ps-screen-props';
|
|
2
|
-
export declare const PsScreen: ({ children, gap, hasGutter, header, onRefresh, style, }: PsScreenProps) => import("react").JSX.Element;
|
|
2
|
+
export declare const PsScreen: ({ children, contentWidth, gap, hasGutter, header, onRefresh, style, }: PsScreenProps) => import("react").JSX.Element;
|
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Platform, RefreshControl, ScrollView, View } from 'react-native';
|
|
3
3
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
4
|
+
import { PsContentWidth } from '../../constants/ps-content-width';
|
|
4
5
|
import { PsLayoutConfig } from '../../constants/ps-layout-config';
|
|
5
6
|
import { PsSelectionBarConfig } from '../../constants/ps-selection-bar-config';
|
|
6
7
|
import { PsScrollContext } from '../../contexts/ps-scroll-context';
|
|
8
|
+
import { usePsLayoutClass } from '../../hooks/use-ps-layout-class';
|
|
7
9
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
8
10
|
import { usePsRefresh } from '../../hooks/use-ps-refresh';
|
|
9
11
|
import { usePsScrollHost } from '../../hooks/use-ps-scroll-host';
|
|
10
12
|
import { usePsTabBar } from '../../hooks/use-ps-tab-bar';
|
|
11
13
|
import { usePsTopInset } from '../../hooks/use-ps-top-inset';
|
|
14
|
+
import { PsLayoutService } from '../../services/ps-layout-service';
|
|
12
15
|
import { PsScreenService } from '../../services/ps-screen-service';
|
|
13
|
-
export const PsScreen = ({ children, gap = PsLayoutConfig.listGap, hasGutter = true, header, onRefresh, style, }) => {
|
|
16
|
+
export const PsScreen = ({ children, contentWidth = PsContentWidth.readable, gap = PsLayoutConfig.listGap, hasGutter = true, header, onRefresh, style, }) => {
|
|
14
17
|
const theme = usePsMobileTheme();
|
|
15
18
|
const insets = useSafeAreaInsets();
|
|
16
19
|
const topInset = usePsTopInset();
|
|
17
20
|
const { hasTabBar, isHidden: isTabBarHidden } = usePsTabBar();
|
|
18
21
|
const { isRefreshing, refresh } = usePsRefresh(onRefresh);
|
|
19
22
|
const host = usePsScrollHost();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
const layoutClass = usePsLayoutClass();
|
|
24
|
+
return (_jsxs(View, { style: { flex: 1 }, children: [_jsx(ScrollView, { contentContainerStyle: [
|
|
25
|
+
PsScreenService.content({
|
|
26
|
+
bottom: PsScreenService.bottomInset(insets.bottom, hasTabBar, isTabBarHidden),
|
|
27
|
+
top: topInset,
|
|
28
|
+
}, Platform.OS === 'ios', hasGutter, gap, isTabBarHidden ? PsSelectionBarConfig.height : 0),
|
|
29
|
+
PsLayoutService.frame(layoutClass, contentWidth),
|
|
30
|
+
], contentInsetAdjustmentBehavior: 'automatic', keyboardDismissMode: 'interactive', onContentSizeChange: host.onContentSizeChange, onLayout: host.onLayout, onScroll: host.onScroll, keyboardShouldPersistTaps: 'handled', refreshControl: onRefresh === undefined ? undefined : (_jsx(RefreshControl, { colors: [theme.primaryText], progressBackgroundColor: theme.surface, onRefresh: () => void refresh(), refreshing: isRefreshing, tintColor: theme.primary })), ref: host.scrollRef, scrollEnabled: !host.isLocked, scrollEventThrottle: PsLayoutConfig.scrollEventThrottle, showsVerticalScrollIndicator: false, style: [{ backgroundColor: theme.background, flex: 1 }, style], testID: 'ps-screen', children: _jsxs(PsScrollContext, { value: host.context, children: [header, children] }) }), header === undefined ? null : (_jsx(View, { pointerEvents: 'none', style: [PsScreenService.statusBarScrim(topInset), { backgroundColor: theme.background }], testID: 'ps-screen-status-bar-scrim' }))] }));
|
|
24
31
|
};
|
|
@@ -4,6 +4,7 @@ import { Platform, ScrollView, View, useWindowDimensions } from 'react-native';
|
|
|
4
4
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
5
5
|
import { PsLayoutConfig } from '../../constants/ps-layout-config';
|
|
6
6
|
import { PsSheetMeasureContext } from '../../contexts/ps-sheet-measure-context';
|
|
7
|
+
import { usePsLayoutClass } from '../../hooks/use-ps-layout-class';
|
|
7
8
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
8
9
|
import { PsSheetService } from '../../services/ps-sheet-service';
|
|
9
10
|
import { PsSheetHeader } from '../ps-sheet-header/ps-sheet-header';
|
|
@@ -11,11 +12,12 @@ export const PsSheetContent = ({ children, footer, header, isScrollable }) => {
|
|
|
11
12
|
const theme = usePsMobileTheme();
|
|
12
13
|
const insets = useSafeAreaInsets();
|
|
13
14
|
const { height } = useWindowDimensions();
|
|
15
|
+
const layoutClass = usePsLayoutClass();
|
|
14
16
|
const report = useContext(PsSheetMeasureContext);
|
|
15
17
|
const [headerHeight, setHeaderHeight] = useState(0);
|
|
16
18
|
const [bodyHeight, setBodyHeight] = useState(0);
|
|
17
19
|
const fitted = headerHeight > 0 && bodyHeight > 0
|
|
18
|
-
? PsSheetService.fittedHeight(headerHeight, bodyHeight, height)
|
|
20
|
+
? PsSheetService.fittedHeight(headerHeight, bodyHeight, height, layoutClass)
|
|
19
21
|
: null;
|
|
20
22
|
useEffect(() => {
|
|
21
23
|
if (fitted !== null)
|
|
@@ -35,6 +37,6 @@ export const PsSheetContent = ({ children, footer, header, isScrollable }) => {
|
|
|
35
37
|
return (_jsxs(View, { style: {
|
|
36
38
|
backgroundColor: theme.background,
|
|
37
39
|
height: fitted === null ? undefined : fitted,
|
|
38
|
-
maxHeight: PsSheetService.maxHeight(height),
|
|
40
|
+
maxHeight: PsSheetService.maxHeight(height, layoutClass),
|
|
39
41
|
}, testID: 'ps-sheet', children: [_jsx(View, { onLayout: (event) => setHeaderHeight(event.nativeEvent.layout.height), children: _jsx(PsSheetHeader, { ...header }) }), isScrollable ? (_jsx(ScrollView, { automaticallyAdjustKeyboardInsets: true, contentContainerStyle: contentStyle, keyboardDismissMode: 'interactive', keyboardShouldPersistTaps: 'handled', onContentSizeChange: (_width, contentHeight) => setBodyHeight(contentHeight), style: { flexGrow: 0 }, children: body })) : (_jsx(View, { onLayout: (event) => setBodyHeight(event.nativeEvent.layout.height), style: contentStyle, children: body }))] }));
|
|
40
42
|
};
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { BottomSheet, Group, RNHostView } from '@expo/ui/swift-ui';
|
|
4
|
-
import { frame, interactiveDismissDisabled, presentationBackground, presentationDetents, presentationDragIndicator, } from '@expo/ui/swift-ui/modifiers';
|
|
5
|
-
import { useWindowDimensions } from 'react-native';
|
|
4
|
+
import { frame, interactiveDismissDisabled, presentationBackground, presentationDetents, presentationDragIndicator, presentationSizing, } from '@expo/ui/swift-ui/modifiers';
|
|
5
|
+
import { Platform, useWindowDimensions } from 'react-native';
|
|
6
6
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
7
|
+
import { PsLayoutClass } from '../../constants/ps-layout-class';
|
|
7
8
|
import { PsNativeTreeContext } from '../../contexts/ps-native-tree-context';
|
|
8
9
|
import { PsSheetMeasureContext } from '../../contexts/ps-sheet-measure-context';
|
|
9
10
|
import { usePsKeyboardHeight } from '../../hooks/use-ps-keyboard-height';
|
|
11
|
+
import { usePsLayoutClass } from '../../hooks/use-ps-layout-class';
|
|
10
12
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
11
13
|
import { PsSheetService } from '../../services/ps-sheet-service';
|
|
12
14
|
import { PsHost } from '../ps-host/ps-host';
|
|
@@ -18,6 +20,8 @@ export const PsSheetPresenter = ({ children, isDismissBlocked, isOpen, onClose,
|
|
|
18
20
|
const keyboardHeight = usePsKeyboardHeight();
|
|
19
21
|
const window = useWindowDimensions();
|
|
20
22
|
const insets = useSafeAreaInsets();
|
|
23
|
+
const isForm = usePsLayoutClass() === PsLayoutClass.regular &&
|
|
24
|
+
PsSheetService.supportsFormSizing(Platform.Version);
|
|
21
25
|
const detentHeight = height > 0 ? PsSheetService.raisedHeight(height, keyboardHeight, window.height, insets.top) : 0;
|
|
22
26
|
isOpenRef.current = isOpen;
|
|
23
27
|
isBlockedRef.current = isDismissBlocked;
|
|
@@ -33,9 +37,15 @@ export const PsSheetPresenter = ({ children, isDismissBlocked, isOpen, onClose,
|
|
|
33
37
|
onClose();
|
|
34
38
|
}
|
|
35
39
|
}, children: _jsx(Group, { modifiers: [
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
isForm
|
|
41
|
+
? frame({ alignment: 'top', maxWidth: Infinity })
|
|
42
|
+
: frame({ alignment: 'top', maxHeight: Infinity, maxWidth: Infinity }),
|
|
43
|
+
...(isForm
|
|
44
|
+
? [presentationSizing('form', { fitted: { horizontal: false, vertical: true } })]
|
|
45
|
+
: [
|
|
46
|
+
presentationDetents(detentHeight > 0 ? [{ height: detentHeight }] : ['medium']),
|
|
47
|
+
presentationDragIndicator('visible'),
|
|
48
|
+
]),
|
|
39
49
|
presentationBackground(theme.background),
|
|
40
50
|
interactiveDismissDisabled(isDismissBlocked),
|
|
41
51
|
], children: _jsx(RNHostView, { matchContents: { vertical: true }, children: _jsx(PsNativeTreeContext.Provider, { value: false, children: _jsx(PsSheetMeasureContext.Provider, { value: measure, children: children }) }) }) }) }) }));
|
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Modal, Pressable, StyleSheet, View } from 'react-native';
|
|
2
|
+
import { Modal, Pressable, StyleSheet, View, useWindowDimensions } from 'react-native';
|
|
3
|
+
import { PsLayoutClass } from '../../constants/ps-layout-class';
|
|
4
|
+
import { PsOrientationConfig } from '../../constants/ps-orientation-config';
|
|
3
5
|
import { PsSheetConfig } from '../../constants/ps-sheet-config';
|
|
6
|
+
import { usePsLayoutClass } from '../../hooks/use-ps-layout-class';
|
|
4
7
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
8
|
+
import { PsSheetService } from '../../services/ps-sheet-service';
|
|
5
9
|
export const PsSheetPresenter = ({ children, isDismissBlocked, isOpen, onClose, }) => {
|
|
6
10
|
const theme = usePsMobileTheme();
|
|
7
|
-
|
|
11
|
+
const layoutClass = usePsLayoutClass();
|
|
12
|
+
const window = useWindowDimensions();
|
|
13
|
+
const isRegular = layoutClass === PsLayoutClass.regular;
|
|
14
|
+
const maxWidth = PsSheetService.fittedMaxWidth(window.width, layoutClass);
|
|
15
|
+
return (_jsx(Modal, { animationType: 'slide', onRequestClose: isDismissBlocked ? undefined : onClose, statusBarTranslucent: true, supportedOrientations: PsOrientationConfig.all, transparent: true, visible: isOpen, children: _jsxs(View, { style: {
|
|
8
16
|
backgroundColor: theme.overlay,
|
|
17
|
+
alignItems: isRegular ? 'center' : undefined,
|
|
9
18
|
flex: 1,
|
|
10
|
-
justifyContent: 'flex-end',
|
|
19
|
+
justifyContent: isRegular ? 'center' : 'flex-end',
|
|
11
20
|
}, children: [_jsx(Pressable, { onPress: isDismissBlocked ? undefined : onClose, style: StyleSheet.absoluteFill, testID: 'ps-sheet-scrim' }), _jsx(View, { style: {
|
|
12
21
|
backgroundColor: theme.background,
|
|
22
|
+
borderBottomLeftRadius: isRegular ? PsSheetConfig.cornerRadius : 0,
|
|
23
|
+
borderBottomRightRadius: isRegular ? PsSheetConfig.cornerRadius : 0,
|
|
13
24
|
borderTopLeftRadius: PsSheetConfig.cornerRadius,
|
|
14
25
|
borderTopRightRadius: PsSheetConfig.cornerRadius,
|
|
26
|
+
maxWidth,
|
|
15
27
|
overflow: 'hidden',
|
|
28
|
+
width: isRegular ? '100%' : undefined,
|
|
16
29
|
}, children: children })] }) }));
|
|
17
30
|
};
|
|
@@ -5,14 +5,17 @@ import { useSharedValue } from 'react-native-reanimated';
|
|
|
5
5
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
6
6
|
import { PsSortableGridConfig } from '../../constants/ps-sortable-grid-config';
|
|
7
7
|
import { PsScrollContext } from '../../contexts/ps-scroll-context';
|
|
8
|
+
import { usePsLayoutClass } from '../../hooks/use-ps-layout-class';
|
|
8
9
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
9
10
|
import { PsHapticService } from '../../services/ps-haptic-service';
|
|
11
|
+
import { PsLayoutService } from '../../services/ps-layout-service';
|
|
10
12
|
import { PsSortableGridService } from '../../services/ps-sortable-grid-service';
|
|
11
13
|
import { PsSortableItem } from './ps-sortable-item';
|
|
12
14
|
export const PsSortableGrid = ({ getItemSpan, isDisabled = false, items, labels, onReorder, renderItem, }) => {
|
|
13
15
|
const scroll = useContext(PsScrollContext);
|
|
14
16
|
const { hasHaptics } = usePsMobileTheme();
|
|
15
17
|
const insets = useSafeAreaInsets();
|
|
18
|
+
const capacity = PsLayoutService.gridUnits(usePsLayoutClass());
|
|
16
19
|
const { height: windowHeight } = useWindowDimensions();
|
|
17
20
|
const [order, setOrder] = useState(items);
|
|
18
21
|
const [activeId, setActiveId] = useState(null);
|
|
@@ -30,7 +33,7 @@ export const PsSortableGrid = ({ getItemSpan, isDisabled = false, items, labels,
|
|
|
30
33
|
translationY: 0,
|
|
31
34
|
});
|
|
32
35
|
const ids = useMemo(() => PsSortableGridService.ids(order), [order]);
|
|
33
|
-
const rects = useMemo(() => PsSortableGridService.layout(order.map((item) => getItemSpan(item)), PsSortableGridService.heights(ids, measured), width), [getItemSpan, ids, measured, order, width]);
|
|
36
|
+
const rects = useMemo(() => PsSortableGridService.layout(order.map((item) => getItemSpan(item)), PsSortableGridService.heights(ids, measured), width, capacity), [capacity, getItemSpan, ids, measured, order, width]);
|
|
34
37
|
const extras = useMemo(() => PsSortableGridService.extras(rects, PsSortableGridService.heights(ids, measured)), [ids, measured, rects]);
|
|
35
38
|
const isReady = PsSortableGridService.isMeasured(ids, measured, width);
|
|
36
39
|
const latest = useRef({ items, onReorder, order, rects, scroll, windowHeight, insets });
|
|
@@ -132,12 +135,12 @@ export const PsSortableGrid = ({ getItemSpan, isDisabled = false, items, labels,
|
|
|
132
135
|
notify(next);
|
|
133
136
|
PsHapticService.play('selection', hasHaptics);
|
|
134
137
|
}, [hasHaptics]);
|
|
135
|
-
const measure = useCallback((id, total,
|
|
136
|
-
const natural = PsSortableGridService.natural(total,
|
|
138
|
+
const measure = useCallback((id, total, fill) => {
|
|
139
|
+
const natural = PsSortableGridService.natural(total, fill);
|
|
137
140
|
setMeasured((current) => current[id] !== undefined &&
|
|
138
141
|
Math.abs(current[id] - natural) < PsSortableGridConfig.measureTolerance
|
|
139
142
|
? current
|
|
140
143
|
: { ...current, [id]: natural });
|
|
141
144
|
}, []);
|
|
142
|
-
return (_jsx(View, { onLayout: (event) => setWidth(event.nativeEvent.layout.width), style: { height: PsSortableGridService.contentHeight(rects) }, children: order.map((item, index) => (_jsx(PsSortableItem, { canMoveDown: index < order.length - 1, canMoveUp: index > 0, dragX: dragX, dragY: dragY, extra: extras[index], id: item.id, isActive: item.id === activeId, isDisabled: isDisabled, isReady: isReady, label: item.label, labels: labels, onEnd: end, onMeasure: measure, onMove: moveBy, onStart: start, onUpdate: update, rect: rects[index], children: renderItem({ isActive: item.id === activeId, item }) }, item.id))) }));
|
|
145
|
+
return (_jsx(View, { onLayout: (event) => setWidth(event.nativeEvent.layout.width), style: { height: PsSortableGridService.contentHeight(rects) }, testID: PsSortableGridConfig.testId, children: order.map((item, index) => (_jsx(PsSortableItem, { canMoveDown: index < order.length - 1, canMoveUp: index > 0, dragX: dragX, dragY: dragY, extra: extras[index], id: item.id, isActive: item.id === activeId, isDisabled: isDisabled, isReady: isReady, label: item.label, labels: labels, onEnd: end, onMeasure: measure, onMove: moveBy, onStart: start, onUpdate: update, rect: rects[index], children: renderItem({ isActive: item.id === activeId, item }) }, item.id))) }));
|
|
143
146
|
};
|