@pallasoft/ps-mobile-components 1.11.0 → 1.13.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.
Files changed (118) hide show
  1. package/dist/components/ps-action-sheet/ps-action-sheet.js +18 -2
  2. package/dist/components/ps-barcode-scanner-sheet/ps-barcode-scanner-sheet.js +2 -1
  3. package/dist/components/ps-document-highlight-layer/index.d.ts +2 -0
  4. package/dist/components/ps-document-highlight-layer/index.js +2 -0
  5. package/dist/components/ps-document-highlight-layer/ps-document-highlight-layer-props.d.ts +8 -0
  6. package/dist/components/ps-document-highlight-layer/ps-document-highlight-layer-props.js +1 -0
  7. package/dist/components/ps-document-highlight-layer/ps-document-highlight-layer.d.ts +2 -0
  8. package/dist/components/ps-document-highlight-layer/ps-document-highlight-layer.js +19 -0
  9. package/dist/components/ps-document-page/ps-document-page-props.d.ts +2 -0
  10. package/dist/components/ps-document-page/ps-document-page.d.ts +1 -1
  11. package/dist/components/ps-document-page/ps-document-page.js +3 -3
  12. package/dist/components/ps-document-search-bar/index.d.ts +2 -0
  13. package/dist/components/ps-document-search-bar/index.js +2 -0
  14. package/dist/components/ps-document-search-bar/ps-document-search-bar-props.d.ts +11 -0
  15. package/dist/components/ps-document-search-bar/ps-document-search-bar-props.js +1 -0
  16. package/dist/components/ps-document-search-bar/ps-document-search-bar.d.ts +2 -0
  17. package/dist/components/ps-document-search-bar/ps-document-search-bar.js +46 -0
  18. package/dist/components/ps-document-search-step/index.d.ts +2 -0
  19. package/dist/components/ps-document-search-step/index.js +2 -0
  20. package/dist/components/ps-document-search-step/ps-document-search-step-props.d.ts +7 -0
  21. package/dist/components/ps-document-search-step/ps-document-search-step-props.js +1 -0
  22. package/dist/components/ps-document-search-step/ps-document-search-step.d.ts +2 -0
  23. package/dist/components/ps-document-search-step/ps-document-search-step.js +30 -0
  24. package/dist/components/ps-document-text-page/ps-document-text-page-props.d.ts +2 -0
  25. package/dist/components/ps-document-text-page/ps-document-text-page.d.ts +1 -1
  26. package/dist/components/ps-document-text-page/ps-document-text-page.js +27 -3
  27. package/dist/components/ps-document-viewer/ps-document-viewer.js +53 -3
  28. package/dist/components/ps-document-zoom-image/ps-document-zoom-image-props.d.ts +4 -0
  29. package/dist/components/ps-document-zoom-image/ps-document-zoom-image.d.ts +1 -1
  30. package/dist/components/ps-document-zoom-image/ps-document-zoom-image.js +30 -3
  31. package/dist/components/ps-infinite-list/ps-infinite-list-props.d.ts +2 -0
  32. package/dist/components/ps-infinite-list/ps-infinite-list.d.ts +1 -1
  33. package/dist/components/ps-infinite-list/ps-infinite-list.js +12 -5
  34. package/dist/components/ps-list/ps-list-props.d.ts +2 -0
  35. package/dist/components/ps-list/ps-list.d.ts +1 -1
  36. package/dist/components/ps-list/ps-list.js +1 -1
  37. package/dist/components/ps-menu-popup/ps-menu-popup.js +3 -2
  38. package/dist/components/ps-screen/ps-screen-props.d.ts +2 -0
  39. package/dist/components/ps-screen/ps-screen.d.ts +1 -1
  40. package/dist/components/ps-screen/ps-screen.js +12 -5
  41. package/dist/components/ps-sheet-content/ps-sheet-content.js +4 -2
  42. package/dist/components/ps-sheet-presenter/ps-sheet-presenter.ios.js +15 -5
  43. package/dist/components/ps-sheet-presenter/ps-sheet-presenter.js +16 -3
  44. package/dist/components/ps-sortable-grid/ps-sortable-grid.js +4 -1
  45. package/dist/components/ps-text/ps-text-props.d.ts +1 -0
  46. package/dist/components/ps-text/ps-text.d.ts +1 -1
  47. package/dist/components/ps-text/ps-text.js +2 -2
  48. package/dist/components/ps-widget-list/ps-widget-grid.js +16 -7
  49. package/dist/components/ps-widget-list/ps-widget-list-props.d.ts +2 -0
  50. package/dist/components/ps-widget-list/ps-widget-list.d.ts +1 -1
  51. package/dist/components/ps-widget-list/ps-widget-list.js +12 -5
  52. package/dist/constants/ps-content-width.d.ts +6 -0
  53. package/dist/constants/ps-content-width.js +5 -0
  54. package/dist/constants/ps-document-search-config.d.ts +16 -0
  55. package/dist/constants/ps-document-search-config.js +16 -0
  56. package/dist/constants/ps-layout-class-config.d.ts +12 -0
  57. package/dist/constants/ps-layout-class-config.js +12 -0
  58. package/dist/constants/ps-layout-class.d.ts +5 -0
  59. package/dist/constants/ps-layout-class.js +4 -0
  60. package/dist/constants/ps-menu-popup-config.d.ts +1 -0
  61. package/dist/constants/ps-menu-popup-config.js +1 -0
  62. package/dist/constants/ps-orientation-config.d.ts +3 -0
  63. package/dist/constants/ps-orientation-config.js +3 -0
  64. package/dist/constants/ps-sheet-config.d.ts +1 -0
  65. package/dist/constants/ps-sheet-config.js +1 -0
  66. package/dist/constants/ps-sortable-grid-config.d.ts +2 -0
  67. package/dist/constants/ps-sortable-grid-config.js +2 -0
  68. package/dist/hooks/use-ps-document-search-texts.d.ts +2 -0
  69. package/dist/hooks/use-ps-document-search-texts.js +26 -0
  70. package/dist/hooks/use-ps-layout-class.d.ts +2 -0
  71. package/dist/hooks/use-ps-layout-class.js +6 -0
  72. package/dist/hooks/use-ps-menu-anchor.d.ts +1 -1
  73. package/dist/hooks/use-ps-menu-anchor.js +14 -2
  74. package/dist/index.d.ts +9 -0
  75. package/dist/index.js +9 -0
  76. package/dist/interfaces/ps-document-highlight-rect.d.ts +5 -0
  77. package/dist/interfaces/ps-document-highlight-rect.js +1 -0
  78. package/dist/interfaces/ps-document-item.d.ts +3 -0
  79. package/dist/interfaces/ps-document-labels.d.ts +7 -0
  80. package/dist/interfaces/ps-document-point.d.ts +4 -0
  81. package/dist/interfaces/ps-document-point.js +1 -0
  82. package/dist/interfaces/ps-document-search-labels.d.ts +9 -0
  83. package/dist/interfaces/ps-document-search-labels.js +1 -0
  84. package/dist/interfaces/ps-document-search-location.d.ts +4 -0
  85. package/dist/interfaces/ps-document-search-location.js +1 -0
  86. package/dist/interfaces/ps-document-search-match.d.ts +2 -0
  87. package/dist/interfaces/ps-document-search-match.js +1 -0
  88. package/dist/interfaces/ps-document-search-state.d.ts +4 -0
  89. package/dist/interfaces/ps-document-search-state.js +1 -0
  90. package/dist/interfaces/ps-document-text-box.d.ts +2 -0
  91. package/dist/interfaces/ps-document-text-box.js +1 -0
  92. package/dist/interfaces/ps-document-text-layer-word.d.ts +2 -0
  93. package/dist/interfaces/ps-document-text-layer-word.js +1 -0
  94. package/dist/interfaces/ps-document-text-layer.d.ts +2 -0
  95. package/dist/interfaces/ps-document-text-layer.js +1 -0
  96. package/dist/interfaces/ps-document-text-line.d.ts +4 -0
  97. package/dist/interfaces/ps-document-text-line.js +1 -0
  98. package/dist/interfaces/ps-document-text-segment.d.ts +2 -0
  99. package/dist/interfaces/ps-document-text-segment.js +1 -0
  100. package/dist/interfaces/ps-document-word-match.d.ts +3 -0
  101. package/dist/interfaces/ps-document-word-match.js +1 -0
  102. package/dist/interfaces/ps-menu-popup-insets.d.ts +2 -0
  103. package/dist/interfaces/ps-menu-popup-layout.d.ts +1 -0
  104. package/dist/services/ps-document-search-service.d.ts +36 -0
  105. package/dist/services/ps-document-search-service.js +114 -0
  106. package/dist/services/ps-document-search-style-service.d.ts +7 -0
  107. package/dist/services/ps-document-search-style-service.js +22 -0
  108. package/dist/services/ps-document-viewer-entry-service.js +1 -0
  109. package/dist/services/ps-document-zoom-service.d.ts +1 -0
  110. package/dist/services/ps-document-zoom-service.js +3 -0
  111. package/dist/services/ps-layout-service.d.ts +12 -0
  112. package/dist/services/ps-layout-service.js +41 -0
  113. package/dist/services/ps-menu-popup-service.js +8 -4
  114. package/dist/services/ps-sheet-service.d.ts +5 -2
  115. package/dist/services/ps-sheet-service.js +17 -4
  116. package/dist/services/ps-sortable-grid-service.d.ts +3 -2
  117. package/dist/services/ps-sortable-grid-service.js +26 -22
  118. package/package.json +2 -2
@@ -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: { flex: 1, justifyContent: 'flex-end' }, children: _jsxs(Animated.View, { entering: FadeInDown, 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,
@@ -0,0 +1,2 @@
1
+ export * from './ps-document-highlight-layer';
2
+ export * from './ps-document-highlight-layer-props';
@@ -0,0 +1,2 @@
1
+ export * from './ps-document-highlight-layer';
2
+ export * from './ps-document-highlight-layer-props';
@@ -0,0 +1,8 @@
1
+ import type { PsDocumentSearchState } from '../../interfaces/ps-document-search-state';
2
+ import type { PsDocumentTextLayer } from '../../interfaces/ps-document-text-layer';
3
+ import type { PsSize } from '../../interfaces/ps-size';
4
+ export interface PsDocumentHighlightLayerProps {
5
+ layer: PsDocumentTextLayer;
6
+ search: PsDocumentSearchState;
7
+ size: PsSize;
8
+ }
@@ -0,0 +1,2 @@
1
+ import type { PsDocumentHighlightLayerProps } from './ps-document-highlight-layer-props';
2
+ export declare const PsDocumentHighlightLayer: ({ layer, search, size, }: PsDocumentHighlightLayerProps) => import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { View } from 'react-native';
3
+ import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
4
+ import { PsDocumentSearchService } from '../../services/ps-document-search-service';
5
+ import { PsDocumentSearchStyleService } from '../../services/ps-document-search-style-service';
6
+ export const PsDocumentHighlightLayer = ({ layer, search, size, }) => {
7
+ const theme = usePsMobileTheme();
8
+ const rects = PsDocumentSearchService.highlights(layer, search.query, size, search.activeIndex);
9
+ return (_jsx(View, { pointerEvents: 'none', style: { bottom: 0, left: 0, position: 'absolute', right: 0, top: 0 }, testID: 'ps-document-highlight-layer', children: rects.map((rect, index) => (_jsx(View, { style: [
10
+ PsDocumentSearchStyleService.rect(theme, rect.isActive),
11
+ {
12
+ height: rect.box.height,
13
+ left: rect.box.left,
14
+ position: 'absolute',
15
+ top: rect.box.top,
16
+ width: rect.box.width,
17
+ },
18
+ ], testID: rect.isActive ? 'ps-document-highlight-active' : 'ps-document-highlight' }, index))) }));
19
+ };
@@ -1,11 +1,13 @@
1
1
  import type { PsDocumentLoadStatus } from '../../constants/ps-document-load-status';
2
2
  import type { PsDocumentItem } from '../../interfaces/ps-document-item';
3
3
  import type { PsDocumentLabels } from '../../interfaces/ps-document-labels';
4
+ import type { PsDocumentSearchState } from '../../interfaces/ps-document-search-state';
4
5
  export interface PsDocumentPageProps {
5
6
  item: PsDocumentItem;
6
7
  labels: PsDocumentLabels;
7
8
  onDismiss: () => void;
8
9
  onRetry?: () => void;
9
10
  onZoomChange: (isZoomed: boolean) => void;
11
+ search?: PsDocumentSearchState;
10
12
  status?: PsDocumentLoadStatus;
11
13
  }
@@ -1,2 +1,2 @@
1
1
  import type { PsDocumentPageProps } from './ps-document-page-props';
2
- export declare const PsDocumentPage: ({ item, labels, onDismiss, onRetry, onZoomChange, status, }: PsDocumentPageProps) => import("react").JSX.Element;
2
+ export declare const PsDocumentPage: ({ item, labels, onDismiss, onRetry, onZoomChange, search, status, }: PsDocumentPageProps) => import("react").JSX.Element;
@@ -9,7 +9,7 @@ import { PsDocumentTextPage } from '../ps-document-text-page/ps-document-text-pa
9
9
  import { PsDocumentUnsupported } from '../ps-document-unsupported/ps-document-unsupported';
10
10
  import { PsDocumentZoomImage } from '../ps-document-zoom-image/ps-document-zoom-image';
11
11
  import { PsSpinner } from '../ps-spinner/ps-spinner';
12
- export const PsDocumentPage = ({ item, labels, onDismiss, onRetry, onZoomChange, status = PsDocumentLoadStatus.Ready, }) => {
12
+ export const PsDocumentPage = ({ item, labels, onDismiss, onRetry, onZoomChange, search, status = PsDocumentLoadStatus.Ready, }) => {
13
13
  const [attempt, setAttempt] = useState(0);
14
14
  const [hasFailed, setHasFailed] = useState(false);
15
15
  if (item.kind === PsDocumentKind.Pdf) {
@@ -23,9 +23,9 @@ export const PsDocumentPage = ({ item, labels, onDismiss, onRetry, onZoomChange,
23
23
  return hasFailed ? (_jsx(PsDocumentMessage, { actionLabel: labels.retry, iconKey: PsIconKey.Warning, isOnDark: true, onAction: () => {
24
24
  setHasFailed(false);
25
25
  setAttempt((current) => current + 1);
26
- }, title: labels.loadFailed })) : (_jsx(PsDocumentZoomImage, { name: item.name, onDismiss: onDismiss, onError: () => setHasFailed(true), onZoomChange: onZoomChange, source: item.source }, attempt));
26
+ }, title: labels.loadFailed })) : (_jsx(PsDocumentZoomImage, { name: item.name, onDismiss: onDismiss, onError: () => setHasFailed(true), onZoomChange: onZoomChange, search: search, source: item.source, textLayer: item.textLayer }, attempt));
27
27
  }
28
28
  if (item.kind === PsDocumentKind.Text)
29
- return _jsx(PsDocumentTextPage, { item: item, labels: labels });
29
+ return _jsx(PsDocumentTextPage, { item: item, labels: labels, search: search });
30
30
  return _jsx(PsDocumentUnsupported, { isOnDark: true, item: item, labels: labels });
31
31
  };
@@ -0,0 +1,2 @@
1
+ export * from './ps-document-search-bar';
2
+ export * from './ps-document-search-bar-props';
@@ -0,0 +1,2 @@
1
+ export * from './ps-document-search-bar';
2
+ export * from './ps-document-search-bar-props';
@@ -0,0 +1,11 @@
1
+ import type { PsDocumentSearchLabels } from '../../interfaces/ps-document-search-labels';
2
+ export interface PsDocumentSearchBarProps {
3
+ activeIndex: number;
4
+ labels: PsDocumentSearchLabels;
5
+ onChange: (query: string) => void;
6
+ onClose: () => void;
7
+ onNext: () => void;
8
+ onPrevious: () => void;
9
+ query: string;
10
+ total: number;
11
+ }
@@ -0,0 +1,2 @@
1
+ import type { PsDocumentSearchBarProps } from './ps-document-search-bar-props';
2
+ export declare const PsDocumentSearchBar: ({ activeIndex, labels, onChange, onClose, onNext, onPrevious, query, total, }: PsDocumentSearchBarProps) => import("react").JSX.Element;
@@ -0,0 +1,46 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PsIconKey } from '@pallasoft/ps-icons';
3
+ import { Platform, Pressable, TextInput, View } from 'react-native';
4
+ import { PsDocumentConfig } from '../../constants/ps-document-config';
5
+ import { PsDocumentSearchConfig } from '../../constants/ps-document-search-config';
6
+ import { PsLayoutConfig } from '../../constants/ps-layout-config';
7
+ import { PsMobileControlConfig } from '../../constants/ps-mobile-control-config';
8
+ import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
9
+ import { PsDocumentSearchService } from '../../services/ps-document-search-service';
10
+ import { PsDocumentSearchStyleService } from '../../services/ps-document-search-style-service';
11
+ import { PsMobileColorService } from '../../services/ps-mobile-color-service';
12
+ import { PsDocumentSearchStep } from '../ps-document-search-step/ps-document-search-step';
13
+ import { PsIconButton } from '../ps-icon-button/ps-icon-button';
14
+ import { PsIcon } from '../ps-icon/ps-icon';
15
+ import { PsText } from '../ps-text/ps-text';
16
+ export const PsDocumentSearchBar = ({ activeIndex, labels, onChange, onClose, onNext, onPrevious, query, total, }) => {
17
+ const theme = usePsMobileTheme();
18
+ const isMaterial = Platform.OS === 'android';
19
+ const hasQuery = PsDocumentSearchService.terms(query).length > 0;
20
+ const status = !hasQuery
21
+ ? null
22
+ : total === 0
23
+ ? labels.noMatches
24
+ : PsDocumentSearchService.countLabel(labels.matchCount, activeIndex + 1, total);
25
+ return (_jsxs(View, { style: {
26
+ alignItems: 'center',
27
+ flexDirection: 'row',
28
+ gap: PsDocumentSearchConfig.barGap,
29
+ paddingHorizontal: PsDocumentConfig.barPaddingHorizontal,
30
+ paddingVertical: PsDocumentConfig.barPaddingVertical,
31
+ }, testID: 'ps-document-search-bar', children: [_jsxs(View, { style: {
32
+ alignItems: 'center',
33
+ backgroundColor: PsMobileColorService.withAlpha(theme.white, PsDocumentSearchConfig.fieldAlpha),
34
+ borderRadius: PsDocumentSearchStyleService.fieldRadius(isMaterial),
35
+ flex: 1,
36
+ flexDirection: 'row',
37
+ gap: PsMobileControlConfig.buttonIconSpacing,
38
+ height: PsMobileControlConfig.controlHeights.compact,
39
+ paddingHorizontal: PsDocumentSearchConfig.fieldPaddingX,
40
+ }, children: [_jsx(PsIcon, { color: theme.white, iconKey: PsIconKey.Search, size: PsMobileControlConfig.iconSizeInline }), _jsx(TextInput, { accessibilityLabel: labels.searchPlaceholder, autoCapitalize: 'none', autoCorrect: false, autoFocus: true, clearButtonMode: 'while-editing', onChangeText: onChange, onSubmitEditing: onNext, placeholder: labels.searchPlaceholder, placeholderTextColor: PsMobileColorService.withAlpha(theme.white, PsDocumentConfig.chromeAlpha), returnKeyType: 'search', selectionColor: theme.primary, style: {
41
+ color: theme.white,
42
+ flex: 1,
43
+ fontSize: PsMobileControlConfig.controlFontSize,
44
+ padding: 0,
45
+ }, testID: 'ps-document-search-input', value: query }), status === null ? null : (_jsx(PsText, { tone: 'white', variant: 'caption', children: status }))] }), _jsx(PsDocumentSearchStep, { isDisabled: total === 0, isUp: true, label: labels.previousMatch, onPress: onPrevious, testID: 'ps-document-search-previous' }), _jsx(PsDocumentSearchStep, { isDisabled: total === 0, isUp: false, label: labels.nextMatch, onPress: onNext, testID: 'ps-document-search-next' }), isMaterial ? (_jsx(PsIconButton, { color: theme.white, iconKey: PsIconKey.Close, label: labels.closeSearch, onPress: onClose, size: 'compact', testID: 'ps-document-search-close' })) : (_jsx(Pressable, { accessibilityLabel: labels.closeSearch, accessibilityRole: 'button', hitSlop: PsLayoutConfig.hitSlop, onPress: onClose, testID: 'ps-document-search-close', children: _jsx(PsText, { tone: 'white', weight: 'semibold', children: labels.closeSearch }) }))] }));
46
+ };
@@ -0,0 +1,2 @@
1
+ export * from './ps-document-search-step';
2
+ export * from './ps-document-search-step-props';
@@ -0,0 +1,2 @@
1
+ export * from './ps-document-search-step';
2
+ export * from './ps-document-search-step-props';
@@ -0,0 +1,7 @@
1
+ export interface PsDocumentSearchStepProps {
2
+ isDisabled: boolean;
3
+ isUp: boolean;
4
+ label: string;
5
+ onPress: () => void;
6
+ testID: string;
7
+ }
@@ -0,0 +1,2 @@
1
+ import type { PsDocumentSearchStepProps } from './ps-document-search-step-props';
2
+ export declare const PsDocumentSearchStep: ({ isDisabled, isUp, label, onPress, testID, }: PsDocumentSearchStepProps) => import("react").JSX.Element;
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PsIconKey } from '@pallasoft/ps-icons';
3
+ import { Pressable, View } from 'react-native';
4
+ import { PsDocumentSearchConfig } from '../../constants/ps-document-search-config';
5
+ import { PsLayoutConfig } from '../../constants/ps-layout-config';
6
+ import { PsMobileControlConfig } from '../../constants/ps-mobile-control-config';
7
+ import { PsRippleKind } from '../../constants/ps-ripple-kind';
8
+ import { usePsHaptics } from '../../hooks/use-ps-haptics';
9
+ import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
10
+ import { PsRippleService } from '../../services/ps-ripple-service';
11
+ import { PsStateService } from '../../services/ps-state-service';
12
+ import { PsIcon } from '../ps-icon/ps-icon';
13
+ export const PsDocumentSearchStep = ({ isDisabled, isUp, label, onPress, testID, }) => {
14
+ const haptic = usePsHaptics();
15
+ const theme = usePsMobileTheme();
16
+ return (_jsx(Pressable, { android_ripple: PsRippleService.resolve(theme, PsRippleKind.Borderless), accessibilityLabel: label, accessibilityRole: 'button', accessibilityState: { disabled: isDisabled }, disabled: isDisabled, hitSlop: PsLayoutConfig.hitSlop, onPress: () => {
17
+ haptic('light');
18
+ onPress();
19
+ }, style: {
20
+ alignItems: 'center',
21
+ height: PsMobileControlConfig.controlHeights.compact,
22
+ justifyContent: 'center',
23
+ opacity: isDisabled ? PsStateService.disabledOpacity() : 1,
24
+ width: PsMobileControlConfig.controlHeights.compact,
25
+ }, testID: testID, children: _jsx(View, { style: {
26
+ transform: [
27
+ { rotate: isUp ? PsDocumentSearchConfig.rotateUp : PsDocumentSearchConfig.rotateDown },
28
+ ],
29
+ }, children: _jsx(PsIcon, { color: theme.white, iconKey: PsIconKey.Chevron }) }) }));
30
+ };
@@ -1,6 +1,8 @@
1
1
  import type { PsDocumentItem } from '../../interfaces/ps-document-item';
2
2
  import type { PsDocumentLabels } from '../../interfaces/ps-document-labels';
3
+ import type { PsDocumentSearchState } from '../../interfaces/ps-document-search-state';
3
4
  export interface PsDocumentTextPageProps {
4
5
  item: PsDocumentItem;
5
6
  labels: PsDocumentLabels;
7
+ search?: PsDocumentSearchState;
6
8
  }
@@ -1,2 +1,2 @@
1
1
  import type { PsDocumentTextPageProps } from './ps-document-text-page-props';
2
- export declare const PsDocumentTextPage: ({ item, labels }: PsDocumentTextPageProps) => import("react").JSX.Element;
2
+ export declare const PsDocumentTextPage: ({ item, labels, search }: PsDocumentTextPageProps) => import("react").JSX.Element;
@@ -1,18 +1,42 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
2
3
  import { PsIconKey } from '@pallasoft/ps-icons';
3
- import { ScrollView, View } from 'react-native';
4
+ import { ScrollView, Text, View } from 'react-native';
4
5
  import { PsDocumentConfig } from '../../constants/ps-document-config';
5
6
  import { PsDocumentLoadStatus } from '../../constants/ps-document-load-status';
7
+ import { PsDocumentSearchConfig } from '../../constants/ps-document-search-config';
6
8
  import { usePsDocumentText } from '../../hooks/use-ps-document-text';
9
+ import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
10
+ import { PsDocumentSearchService } from '../../services/ps-document-search-service';
11
+ import { PsDocumentSearchStyleService } from '../../services/ps-document-search-style-service';
7
12
  import { PsDocumentMessage } from '../ps-document-message/ps-document-message';
8
13
  import { PsDocumentUnsupported } from '../ps-document-unsupported/ps-document-unsupported';
9
14
  import { PsSpinner } from '../ps-spinner/ps-spinner';
10
15
  import { PsText } from '../ps-text/ps-text';
11
- export const PsDocumentTextPage = ({ item, labels }) => {
16
+ export const PsDocumentTextPage = ({ item, labels, search }) => {
12
17
  const loaded = usePsDocumentText(item);
18
+ const theme = usePsMobileTheme();
19
+ const scroll = useRef(null);
20
+ const [lines, setLines] = useState([]);
21
+ const matches = loaded.text === null || search === undefined
22
+ ? []
23
+ : PsDocumentSearchService.matches(loaded.text, search.query);
24
+ const active = search === undefined ? undefined : matches[search.activeIndex];
25
+ useEffect(() => {
26
+ if (active === undefined)
27
+ return;
28
+ scroll.current?.scrollTo({
29
+ animated: true,
30
+ y: Math.max(0, PsDocumentSearchService.scrollOffset(lines, active.start) +
31
+ PsDocumentConfig.pageGutter -
32
+ PsDocumentSearchConfig.scrollMargin),
33
+ });
34
+ }, [active?.start, lines, search?.query]);
13
35
  if (loaded.status === PsDocumentLoadStatus.Loading)
14
36
  return (_jsx(View, { style: { alignItems: 'center', flex: 1, justifyContent: 'center' }, children: _jsx(PsSpinner, {}) }));
15
37
  if (loaded.text === null)
16
38
  return item.source === null ? (_jsx(PsDocumentUnsupported, { isOnDark: true, item: item, labels: labels })) : (_jsx(PsDocumentMessage, { description: item.name, iconKey: PsIconKey.Warning, isOnDark: true, title: labels.loadFailed }));
17
- return (_jsx(View, { style: { flex: 1 }, testID: 'ps-document-text-page', children: _jsx(ScrollView, { contentContainerStyle: { padding: PsDocumentConfig.pageGutter }, showsVerticalScrollIndicator: true, children: _jsx(PsText, { isSelectable: true, tone: 'white', children: loaded.text }) }) }));
39
+ return (_jsx(View, { style: { flex: 1 }, testID: 'ps-document-text-page', children: _jsx(ScrollView, { contentContainerStyle: { padding: PsDocumentConfig.pageGutter }, ref: scroll, showsVerticalScrollIndicator: true, children: _jsx(PsText, { isSelectable: true, onTextLayout: (event) => setLines(event.nativeEvent.lines.map((line) => ({ text: line.text, y: line.y }))), tone: 'white', children: matches.length === 0
40
+ ? loaded.text
41
+ : PsDocumentSearchService.segments(loaded.text, matches).map((segment, index) => segment.matchIndex === null ? (segment.text) : (_jsx(Text, { style: PsDocumentSearchStyleService.span(theme, segment.matchIndex === search?.activeIndex), children: segment.text }, index))) }) }) }));
18
42
  };
@@ -5,13 +5,18 @@ import { FlatList, Modal, StatusBar, View } from 'react-native';
5
5
  import { GestureHandlerRootView } from 'react-native-gesture-handler';
6
6
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
7
7
  import { PsDocumentConfig } from '../../constants/ps-document-config';
8
+ import { PsDocumentSearchConfig } from '../../constants/ps-document-search-config';
8
9
  import { PsMobileControlConfig } from '../../constants/ps-mobile-control-config';
10
+ import { PsOrientationConfig } from '../../constants/ps-orientation-config';
9
11
  import { usePsDocumentPdfPages } from '../../hooks/use-ps-document-pdf-pages';
12
+ import { usePsDocumentSearchTexts } from '../../hooks/use-ps-document-search-texts';
10
13
  import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
11
14
  import { PsDocumentPagerService } from '../../services/ps-document-pager-service';
15
+ import { PsDocumentSearchService } from '../../services/ps-document-search-service';
12
16
  import { PsDocumentViewerEntryService } from '../../services/ps-document-viewer-entry-service';
13
17
  import { PsDocumentPageStrip } from '../ps-document-page-strip/ps-document-page-strip';
14
18
  import { PsDocumentPage } from '../ps-document-page/ps-document-page';
19
+ import { PsDocumentSearchBar } from '../ps-document-search-bar/ps-document-search-bar';
15
20
  import { PsIconButton } from '../ps-icon-button/ps-icon-button';
16
21
  import { PsText } from '../ps-text/ps-text';
17
22
  export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onClose, }) => {
@@ -27,11 +32,48 @@ export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onCl
27
32
  ? PsDocumentViewerEntryService.startIndex(items, entries, initialIndex)
28
33
  : PsDocumentViewerEntryService.resolveIndex(currentEntry, entries, 0);
29
34
  const current = entries[index];
35
+ const searchLabels = PsDocumentSearchService.labels(labels);
36
+ const [isSearching, setIsSearching] = useState(false);
37
+ const [query, setQuery] = useState('');
38
+ const [activeMatch, setActiveMatch] = useState(PsDocumentSearchConfig.noActive);
39
+ const searchTexts = usePsDocumentSearchTexts(items, isSearching);
40
+ const counts = PsDocumentSearchService.counts(entries, searchTexts, query);
41
+ const total = PsDocumentSearchService.total(counts);
42
+ const canSearch = searchLabels !== null && PsDocumentSearchService.isSearchable(items);
43
+ const showMatch = (match, nextCounts) => {
44
+ setActiveMatch(match);
45
+ const location = PsDocumentSearchService.locate(nextCounts, match);
46
+ if (location === null)
47
+ return;
48
+ const entry = entries[location.entryIndex];
49
+ if (entry !== undefined && location.entryIndex !== index)
50
+ setCurrentEntry(entry);
51
+ };
52
+ const closeSearch = () => {
53
+ setIsSearching(false);
54
+ setQuery('');
55
+ setActiveMatch(PsDocumentSearchConfig.noActive);
56
+ };
57
+ useEffect(() => {
58
+ if (!isSearching)
59
+ return;
60
+ if (total === 0) {
61
+ if (activeMatch !== PsDocumentSearchConfig.noActive)
62
+ setActiveMatch(PsDocumentSearchConfig.noActive);
63
+ return;
64
+ }
65
+ if (activeMatch < 0 || activeMatch >= total)
66
+ showMatch(PsDocumentSearchService.startIndex(counts, index), counts);
67
+ }, [isSearching, total, activeMatch]);
68
+ useEffect(() => {
69
+ if (!isOpen && isSearching)
70
+ closeSearch();
71
+ }, [isOpen]);
30
72
  useEffect(() => {
31
73
  if (width > 0 && entries.length > 0)
32
74
  list.current?.scrollToIndex({ animated: false, index });
33
75
  }, [entries.length, index, width]);
34
- 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: {
35
77
  backgroundColor: PsDocumentConfig.backdropColor,
36
78
  flex: 1,
37
79
  paddingBottom: insets.bottom,
@@ -41,7 +83,10 @@ export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onCl
41
83
  flexDirection: 'row',
42
84
  paddingHorizontal: PsDocumentConfig.barPaddingHorizontal,
43
85
  paddingVertical: PsDocumentConfig.barPaddingVertical,
44
- }, children: [_jsx(PsIconButton, { color: theme.white, iconKey: PsIconKey.Close, label: labels.close, onPress: onClose }), _jsxs(View, { style: { alignItems: 'center', flex: 1 }, children: [PsDocumentPagerService.hasMany(entries.length) ? (_jsx(PsText, { tone: 'white', weight: 'semibold', children: PsDocumentPagerService.counter(index, entries.length) })) : null, current === undefined ? null : (_jsx(PsText, { numberOfLines: 1, tone: 'white', variant: 'caption', children: current.item.name }))] }), _jsx(View, { style: { width: PsMobileControlConfig.controlHeights.default } })] }), _jsx(View, { onLayout: (event) => setWidth(event.nativeEvent.layout.width), style: { flex: 1 }, testID: 'ps-document-viewer-pager', children: width === 0 ? null : (_jsx(FlatList, { data: entries, getItemLayout: (_data, position) => ({
86
+ }, children: [_jsx(PsIconButton, { color: theme.white, iconKey: PsIconKey.Close, label: labels.close, onPress: onClose }), _jsxs(View, { style: { alignItems: 'center', flex: 1 }, children: [PsDocumentPagerService.hasMany(entries.length) ? (_jsx(PsText, { tone: 'white', weight: 'semibold', children: PsDocumentPagerService.counter(index, entries.length) })) : null, current === undefined ? null : (_jsx(PsText, { numberOfLines: 1, tone: 'white', variant: 'caption', children: current.item.name }))] }), canSearch && !isSearching ? (_jsx(PsIconButton, { color: theme.white, iconKey: PsIconKey.Search, label: searchLabels.search, onPress: () => setIsSearching(true), testID: 'ps-document-search-button' })) : (_jsx(View, { style: { width: PsMobileControlConfig.controlHeights.default } }))] }), canSearch && isSearching ? (_jsx(PsDocumentSearchBar, { activeIndex: activeMatch, labels: searchLabels, onChange: (value) => {
87
+ setQuery(value);
88
+ setActiveMatch(PsDocumentSearchConfig.noActive);
89
+ }, onClose: closeSearch, onNext: () => showMatch(PsDocumentSearchService.step(activeMatch, total, 1), counts), onPrevious: () => showMatch(PsDocumentSearchService.step(activeMatch, total, -1), counts), query: query, total: total })) : null, _jsx(View, { onLayout: (event) => setWidth(event.nativeEvent.layout.width), style: { flex: 1 }, testID: 'ps-document-viewer-pager', children: width === 0 ? null : (_jsx(FlatList, { data: entries, extraData: `${isSearching}|${query}|${activeMatch}|${total}`, getItemLayout: (_data, position) => ({
45
90
  index: position,
46
91
  length: width,
47
92
  offset: PsDocumentPagerService.offset(position, width),
@@ -50,7 +95,12 @@ export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onCl
50
95
  if (next !== undefined)
51
96
  setCurrentEntry(next);
52
97
  setIsZoomed(false);
53
- }, pagingEnabled: true, ref: list, renderItem: ({ item: entry }) => (_jsx(View, { style: { width }, children: _jsx(PsDocumentPage, { item: entry.item, labels: labels, onDismiss: onClose, onRetry: pdf.retry, onZoomChange: setIsZoomed, status: entry.status }) })), scrollEnabled: !isZoomed, showsHorizontalScrollIndicator: false, testID: 'ps-document-viewer-list' })) }), PsDocumentViewerEntryService.hasStrip(items, entries) ? (_jsx(PsDocumentPageStrip, { entries: entries, index: index, onSelect: (position) => {
98
+ }, pagingEnabled: true, ref: list, renderItem: ({ index: position, item: entry }) => (_jsx(View, { style: { width }, children: _jsx(PsDocumentPage, { item: entry.item, labels: labels, onDismiss: onClose, onRetry: pdf.retry, onZoomChange: setIsZoomed, search: isSearching
99
+ ? {
100
+ activeIndex: PsDocumentSearchService.activeFor(counts, activeMatch, position),
101
+ query,
102
+ }
103
+ : undefined, status: entry.status }) })), scrollEnabled: !isZoomed, showsHorizontalScrollIndicator: false, testID: 'ps-document-viewer-list' })) }), PsDocumentViewerEntryService.hasStrip(items, entries) ? (_jsx(PsDocumentPageStrip, { entries: entries, index: index, onSelect: (position) => {
54
104
  const entry = entries[position];
55
105
  if (entry !== undefined)
56
106
  setCurrentEntry(entry);
@@ -1,8 +1,12 @@
1
+ import type { PsDocumentSearchState } from '../../interfaces/ps-document-search-state';
1
2
  import type { PsDocumentSource } from '../../interfaces/ps-document-source';
3
+ import type { PsDocumentTextLayer } from '../../interfaces/ps-document-text-layer';
2
4
  export interface PsDocumentZoomImageProps {
3
5
  name: string;
4
6
  onDismiss: () => void;
5
7
  onError: () => void;
6
8
  onZoomChange: (isZoomed: boolean) => void;
9
+ search?: PsDocumentSearchState;
7
10
  source: PsDocumentSource;
11
+ textLayer?: PsDocumentTextLayer;
8
12
  }
@@ -1,2 +1,2 @@
1
1
  import type { PsDocumentZoomImageProps } from './ps-document-zoom-image-props';
2
- export declare const PsDocumentZoomImage: ({ name, onDismiss, onError, onZoomChange, source, }: PsDocumentZoomImageProps) => import("react").JSX.Element;
2
+ export declare const PsDocumentZoomImage: ({ name, onDismiss, onError, onZoomChange, search, source, textLayer, }: PsDocumentZoomImageProps) => import("react").JSX.Element;
@@ -1,12 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useState } from 'react';
2
+ import { useEffect, useState } from 'react';
3
3
  import { Image, View } from 'react-native';
4
4
  import { GestureDetector, usePanGesture, usePinchGesture, useSimultaneousGestures, useTapGesture, } from 'react-native-gesture-handler';
5
5
  import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
6
6
  import { PsDocumentConfig } from '../../constants/ps-document-config';
7
+ import { PsDocumentSearchService } from '../../services/ps-document-search-service';
7
8
  import { PsDocumentZoomService } from '../../services/ps-document-zoom-service';
9
+ import { PsDocumentHighlightLayer } from '../ps-document-highlight-layer/ps-document-highlight-layer';
8
10
  import { PsSpinner } from '../ps-spinner/ps-spinner';
9
- export const PsDocumentZoomImage = ({ name, onDismiss, onError, onZoomChange, source, }) => {
11
+ export const PsDocumentZoomImage = ({ name, onDismiss, onError, onZoomChange, search, source, textLayer, }) => {
10
12
  const [size, setSize] = useState({ height: 0, width: 0 });
11
13
  const [isZoomed, setIsZoomed] = useState(false);
12
14
  const [isLoaded, setIsLoaded] = useState(false);
@@ -83,6 +85,31 @@ export const PsDocumentZoomImage = ({ name, onDismiss, onError, onZoomChange, so
83
85
  },
84
86
  runOnJS: true,
85
87
  });
88
+ const hasSearch = search !== undefined && textLayer !== undefined && search.activeIndex >= 0;
89
+ useEffect(() => {
90
+ if (!hasSearch || !isZoomed || size.width === 0)
91
+ return;
92
+ const active = PsDocumentSearchService.highlights(textLayer, search.query, size, search.activeIndex).find((rect) => rect.isActive);
93
+ if (active === undefined)
94
+ return;
95
+ const center = PsDocumentSearchService.center(active.box);
96
+ const nextX = PsDocumentZoomService.centerOffset(center.x, size.width, scale.value);
97
+ const nextY = PsDocumentZoomService.centerOffset(center.y, size.height, scale.value);
98
+ x.value = withTiming(nextX, { duration: PsDocumentConfig.settleMs });
99
+ y.value = withTiming(nextY, { duration: PsDocumentConfig.settleMs });
100
+ baseX.value = nextX;
101
+ baseY.value = nextY;
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]);
86
113
  const gesture = useSimultaneousGestures(pinch, move, dismiss, doubleTap);
87
114
  const animatedStyle = useAnimatedStyle(() => ({
88
115
  transform: [
@@ -92,7 +119,7 @@ export const PsDocumentZoomImage = ({ name, onDismiss, onError, onZoomChange, so
92
119
  { scale: scale.value },
93
120
  ],
94
121
  }));
95
- return (_jsx(GestureDetector, { gesture: gesture, children: _jsxs(View, { onLayout: (event) => setSize(event.nativeEvent.layout), style: { flex: 1, overflow: 'hidden' }, testID: 'ps-document-zoom-image', children: [_jsx(Animated.View, { style: [{ flex: 1 }, animatedStyle], children: _jsx(Image, { accessibilityLabel: name, onError: onError, onLoad: () => setIsLoaded(true), resizeMode: 'contain', source: { headers: source.headers, uri: source.uri }, style: { flex: 1 } }) }), isLoaded ? null : (_jsx(View, { pointerEvents: 'none', style: {
122
+ return (_jsx(GestureDetector, { gesture: gesture, children: _jsxs(View, { onLayout: (event) => setSize(event.nativeEvent.layout), style: { flex: 1, overflow: 'hidden' }, testID: 'ps-document-zoom-image', children: [_jsxs(Animated.View, { style: [{ flex: 1 }, animatedStyle], children: [_jsx(Image, { accessibilityLabel: name, onError: onError, onLoad: () => setIsLoaded(true), resizeMode: 'contain', source: { headers: source.headers, uri: source.uri }, style: { flex: 1 } }), search === undefined || textLayer === undefined ? null : (_jsx(PsDocumentHighlightLayer, { layer: textLayer, search: search, size: size }))] }), isLoaded ? null : (_jsx(View, { pointerEvents: 'none', style: {
96
123
  alignItems: 'center',
97
124
  bottom: 0,
98
125
  justifyContent: 'center',
@@ -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;