@pallasoft/ps-mobile-components 1.10.2 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ps-cartesian-chart/ps-cartesian-chart-props.d.ts +1 -0
- package/dist/components/ps-cartesian-chart/ps-cartesian-chart.d.ts +1 -1
- package/dist/components/ps-cartesian-chart/ps-cartesian-chart.js +6 -5
- package/dist/components/ps-chart-frame/ps-chart-frame.js +5 -1
- package/dist/components/ps-document-highlight-layer/index.d.ts +2 -0
- package/dist/components/ps-document-highlight-layer/index.js +2 -0
- package/dist/components/ps-document-highlight-layer/ps-document-highlight-layer-props.d.ts +8 -0
- package/dist/components/ps-document-highlight-layer/ps-document-highlight-layer-props.js +1 -0
- package/dist/components/ps-document-highlight-layer/ps-document-highlight-layer.d.ts +2 -0
- package/dist/components/ps-document-highlight-layer/ps-document-highlight-layer.js +19 -0
- package/dist/components/ps-document-page/ps-document-page-props.d.ts +2 -0
- package/dist/components/ps-document-page/ps-document-page.d.ts +1 -1
- package/dist/components/ps-document-page/ps-document-page.js +3 -3
- package/dist/components/ps-document-search-bar/index.d.ts +2 -0
- package/dist/components/ps-document-search-bar/index.js +2 -0
- package/dist/components/ps-document-search-bar/ps-document-search-bar-props.d.ts +11 -0
- package/dist/components/ps-document-search-bar/ps-document-search-bar-props.js +1 -0
- package/dist/components/ps-document-search-bar/ps-document-search-bar.d.ts +2 -0
- package/dist/components/ps-document-search-bar/ps-document-search-bar.js +46 -0
- package/dist/components/ps-document-search-step/index.d.ts +2 -0
- package/dist/components/ps-document-search-step/index.js +2 -0
- package/dist/components/ps-document-search-step/ps-document-search-step-props.d.ts +7 -0
- package/dist/components/ps-document-search-step/ps-document-search-step-props.js +1 -0
- package/dist/components/ps-document-search-step/ps-document-search-step.d.ts +2 -0
- package/dist/components/ps-document-search-step/ps-document-search-step.js +30 -0
- package/dist/components/ps-document-text-page/ps-document-text-page-props.d.ts +2 -0
- package/dist/components/ps-document-text-page/ps-document-text-page.d.ts +1 -1
- package/dist/components/ps-document-text-page/ps-document-text-page.js +27 -3
- package/dist/components/ps-document-viewer/ps-document-viewer.js +51 -2
- package/dist/components/ps-document-zoom-image/ps-document-zoom-image-props.d.ts +4 -0
- package/dist/components/ps-document-zoom-image/ps-document-zoom-image.d.ts +1 -1
- package/dist/components/ps-document-zoom-image/ps-document-zoom-image.js +20 -3
- package/dist/components/ps-donut-chart/ps-donut-chart-props.d.ts +1 -0
- package/dist/components/ps-donut-chart/ps-donut-chart.d.ts +1 -1
- package/dist/components/ps-donut-chart/ps-donut-chart.js +2 -2
- package/dist/components/ps-menu-popup/ps-menu-popup.js +10 -8
- package/dist/components/ps-sheet-presenter/ps-sheet-presenter.ios.js +8 -1
- package/dist/components/ps-sparkline/ps-sparkline-props.d.ts +1 -0
- package/dist/components/ps-sparkline/ps-sparkline.d.ts +1 -1
- package/dist/components/ps-sparkline/ps-sparkline.js +2 -2
- package/dist/components/ps-text/ps-text-props.d.ts +1 -0
- package/dist/components/ps-text/ps-text.d.ts +1 -1
- package/dist/components/ps-text/ps-text.js +2 -2
- package/dist/components/ps-waterfall-chart/ps-waterfall-chart-props.d.ts +1 -0
- package/dist/components/ps-waterfall-chart/ps-waterfall-chart.d.ts +1 -1
- package/dist/components/ps-waterfall-chart/ps-waterfall-chart.js +6 -5
- package/dist/constants/ps-chart-config.d.ts +3 -0
- package/dist/constants/ps-chart-config.js +3 -0
- package/dist/constants/ps-document-search-config.d.ts +19 -0
- package/dist/constants/ps-document-search-config.js +19 -0
- package/dist/hooks/use-ps-chart-reveal.d.ts +1 -1
- package/dist/hooks/use-ps-chart-reveal.js +4 -2
- package/dist/hooks/use-ps-chart-scrub.js +17 -18
- package/dist/hooks/use-ps-document-search-texts.d.ts +2 -0
- package/dist/hooks/use-ps-document-search-texts.js +26 -0
- package/dist/hooks/use-ps-infinite-data.d.ts +1 -1
- package/dist/hooks/use-ps-infinite-data.js +23 -7
- package/dist/hooks/use-ps-keyboard-height.d.ts +1 -0
- package/dist/hooks/use-ps-keyboard-height.js +14 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/interfaces/ps-chart-scrub-result.d.ts +2 -2
- package/dist/interfaces/ps-document-highlight-rect.d.ts +5 -0
- package/dist/interfaces/ps-document-highlight-rect.js +1 -0
- package/dist/interfaces/ps-document-item.d.ts +3 -0
- package/dist/interfaces/ps-document-labels.d.ts +7 -0
- package/dist/interfaces/ps-document-normalized-text.d.ts +5 -0
- package/dist/interfaces/ps-document-normalized-text.js +1 -0
- package/dist/interfaces/ps-document-point.d.ts +4 -0
- package/dist/interfaces/ps-document-point.js +1 -0
- package/dist/interfaces/ps-document-search-labels.d.ts +9 -0
- package/dist/interfaces/ps-document-search-labels.js +1 -0
- package/dist/interfaces/ps-document-search-location.d.ts +4 -0
- package/dist/interfaces/ps-document-search-location.js +1 -0
- package/dist/interfaces/ps-document-search-match.d.ts +4 -0
- package/dist/interfaces/ps-document-search-match.js +1 -0
- package/dist/interfaces/ps-document-search-state.d.ts +4 -0
- package/dist/interfaces/ps-document-search-state.js +1 -0
- package/dist/interfaces/ps-document-text-box.d.ts +6 -0
- package/dist/interfaces/ps-document-text-box.js +1 -0
- package/dist/interfaces/ps-document-text-layer-word.d.ts +5 -0
- package/dist/interfaces/ps-document-text-layer-word.js +1 -0
- package/dist/interfaces/ps-document-text-layer.d.ts +6 -0
- package/dist/interfaces/ps-document-text-layer.js +1 -0
- package/dist/interfaces/ps-document-text-line.d.ts +4 -0
- package/dist/interfaces/ps-document-text-line.js +1 -0
- package/dist/interfaces/ps-document-text-segment.d.ts +4 -0
- package/dist/interfaces/ps-document-text-segment.js +1 -0
- package/dist/interfaces/ps-document-word-match.d.ts +3 -0
- package/dist/interfaces/ps-document-word-match.js +1 -0
- package/dist/interfaces/ps-infinite-data-options.d.ts +1 -0
- package/dist/interfaces/ps-infinite-data-result.d.ts +1 -0
- package/dist/interfaces/ps-menu-popup-insets.d.ts +4 -0
- package/dist/interfaces/ps-menu-popup-insets.js +1 -0
- package/dist/services/ps-chart-series-service.d.ts +0 -1
- package/dist/services/ps-chart-series-service.js +0 -3
- package/dist/services/ps-document-search-service.d.ts +40 -0
- package/dist/services/ps-document-search-service.js +201 -0
- package/dist/services/ps-document-search-style-service.d.ts +7 -0
- package/dist/services/ps-document-search-style-service.js +22 -0
- package/dist/services/ps-document-viewer-entry-service.js +1 -0
- package/dist/services/ps-document-zoom-service.d.ts +1 -0
- package/dist/services/ps-document-zoom-service.js +3 -0
- package/dist/services/ps-infinite-data-service.d.ts +1 -0
- package/dist/services/ps-infinite-data-service.js +3 -0
- package/dist/services/ps-menu-popup-service.d.ts +2 -1
- package/dist/services/ps-menu-popup-service.js +3 -3
- package/dist/services/ps-sheet-service.d.ts +1 -0
- package/dist/services/ps-sheet-service.js +3 -0
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PsCartesianChartProps } from './ps-cartesian-chart-props';
|
|
2
|
-
export declare const PsCartesianChart: ({ data, emptyLabel, formatTick, formatValue, height: baseHeight, isLoading, kind, series, showLegend, }: PsCartesianChartProps) => import("react").JSX.Element;
|
|
2
|
+
export declare const PsCartesianChart: ({ data, emptyLabel, formatTick, formatValue, height: baseHeight, isLoading, kind, revealKey, series, showLegend, }: PsCartesianChartProps) => import("react").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { StyleSheet, View } from 'react-native';
|
|
3
|
+
import { GestureDetector } from 'react-native-gesture-handler';
|
|
3
4
|
import Svg, { Circle, G, Line, Text as SvgText } from 'react-native-svg';
|
|
4
5
|
import { PsChartConfig } from '../../constants/ps-chart-config';
|
|
5
6
|
import { PsCartesianChartKind } from '../../constants/ps-chart-kind';
|
|
@@ -22,7 +23,7 @@ import { PsChartLegend } from '../ps-chart-legend/ps-chart-legend';
|
|
|
22
23
|
import { PsChartLine } from '../ps-chart-line/ps-chart-line';
|
|
23
24
|
import { PsChartReadout } from '../ps-chart-readout/ps-chart-readout';
|
|
24
25
|
import { PsChartSkeleton } from '../ps-chart-skeleton/ps-chart-skeleton';
|
|
25
|
-
export const PsCartesianChart = ({ data, emptyLabel, formatTick, formatValue, height: baseHeight = PsChartConfig.chartHeight, isLoading = false, kind, series, showLegend = true, }) => {
|
|
26
|
+
export const PsCartesianChart = ({ data, emptyLabel, formatTick, formatValue, height: baseHeight = PsChartConfig.chartHeight, isLoading = false, kind, revealKey, series, showLegend = true, }) => {
|
|
26
27
|
const theme = usePsMobileTheme();
|
|
27
28
|
const { onLayout, width } = usePsChartWidth();
|
|
28
29
|
const height = baseHeight + usePsWidgetFill();
|
|
@@ -41,8 +42,8 @@ export const PsCartesianChart = ({ data, emptyLabel, formatTick, formatValue, he
|
|
|
41
42
|
const tickLabels = PsChartScaleService.ticks(domain).map((tick) => formatTick(tick));
|
|
42
43
|
const yAxisWidth = PsChartAxisService.yAxisWidth(tickLabels, width);
|
|
43
44
|
const plot = PsChartScaleService.plot(width, height, yAxisWidth);
|
|
44
|
-
const {
|
|
45
|
-
const progress = usePsChartReveal(
|
|
45
|
+
const { gesture, index } = usePsChartScrub(data.length, isBars, plot);
|
|
46
|
+
const progress = usePsChartReveal(!isLoading && width > 0, revealKey);
|
|
46
47
|
if (isLoading)
|
|
47
48
|
return (_jsx(PsChartSkeleton, { height: baseHeight, variant: PsChartKindService.skeletonVariant(kind) }));
|
|
48
49
|
if (data.length === 0 || PsChartSeriesService.isEmpty(data, series))
|
|
@@ -65,7 +66,7 @@ export const PsCartesianChart = ({ data, emptyLabel, formatTick, formatValue, he
|
|
|
65
66
|
: isStacked
|
|
66
67
|
? PsChartBarService.stacked(data, barSeries, barColors, domain, plot)
|
|
67
68
|
: PsChartBarService.grouped(data, barSeries, barColors, domain, plot);
|
|
68
|
-
return (_jsxs(View, { style: { gap: 8 }, children: [_jsx(PsChartReadout, { items: items, lines: readoutLines, title: datum.label }), _jsx(View, { accessible: true, accessibilityLabel: PsChartReadoutService.summary(datum.label, items), accessibilityRole: 'image', onLayout: onLayout, style: { height }, children: width === 0 ?
|
|
69
|
+
return (_jsxs(View, { style: { gap: 8 }, children: [_jsx(PsChartReadout, { items: items, lines: readoutLines, title: datum.label }), _jsx(View, { accessible: true, accessibilityLabel: PsChartReadoutService.summary(datum.label, items), accessibilityRole: 'image', onLayout: onLayout, style: { height }, children: width === 0 ? (_jsx(PsChartSkeleton, { height: baseHeight, variant: PsChartKindService.skeletonVariant(kind) })) : (_jsxs(_Fragment, { children: [_jsxs(Svg, { height: height, pointerEvents: 'none', width: width, children: [PsChartScaleService.ticks(domain).map((tick, tickIndex) => {
|
|
69
70
|
const y = PsChartScaleService.y(tick, domain, plot);
|
|
70
71
|
return (_jsxs(G, { children: [_jsx(Line, { stroke: theme.line, strokeWidth: PsChartConfig.gridLineWidth, x1: plot.left, x2: plot.right, y1: y, y2: y }), _jsx(SvgText, { fill: theme.muted, fontFamily: theme.fonts.medium, fontSize: PsChartConfig.axisLabelSize, textAnchor: 'end', x: plot.left - PsChartConfig.axisTickGap, y: y + PsChartConfig.axisLabelSize / 3, children: PsChartTextService.fit(tickLabels[tickIndex], plot.left - PsChartConfig.axisTickGap, PsChartConfig.axisLabelSize) })] }, tick));
|
|
71
72
|
}), xLabels.indexes.map((position) => (_jsx(SvgText, { fill: theme.muted, fontFamily: theme.fonts.medium, fontSize: PsChartConfig.axisLabelSize, textAnchor: PsChartScaleService.labelAnchor(position, data.length, isBars), x: xAt(position), y: height - 6, children: PsChartTextService.fit(data[position].label, xLabels.maxWidth, PsChartConfig.axisLabelSize) }, position))), rects.map((rect) => (_jsx(PsChartBar, { progress: progress, rect: rect }, rect.id))), lineSeries.map((entry, lineIndex) => {
|
|
@@ -77,7 +78,7 @@ export const PsCartesianChart = ({ data, emptyLabel, formatTick, formatValue, he
|
|
|
77
78
|
return (_jsx(PsChartLine, { areaBaseline: kind === PsCartesianChartKind.Area
|
|
78
79
|
? PsChartScaleService.y(0, domain, plot)
|
|
79
80
|
: undefined, color: colors[position], points: points, progress: progress }, entry.dataKey));
|
|
80
|
-
}), index === null ? null : (_jsx(Line, { stroke: theme.muted, strokeWidth: PsChartConfig.scrubLineWidth, x1: xAt(selected), x2: xAt(selected), y1: plot.top, y2: plot.bottom })), lineSeries.map((entry, lineIndex) => (_jsx(Circle, { cx: xAt(selected), cy: PsChartScaleService.y(PsChartSeriesService.value(datum, entry.dataKey), domain, plot), fill: theme.surface, r: PsChartConfig.markerRadius, stroke: colors[lineIndexes[lineIndex]], strokeWidth: 2 }, entry.dataKey)))] }), _jsx(
|
|
81
|
+
}), index === null ? null : (_jsx(Line, { stroke: theme.muted, strokeWidth: PsChartConfig.scrubLineWidth, x1: xAt(selected), x2: xAt(selected), y1: plot.top, y2: plot.bottom })), lineSeries.map((entry, lineIndex) => (_jsx(Circle, { cx: xAt(selected), cy: PsChartScaleService.y(PsChartSeriesService.value(datum, entry.dataKey), domain, plot), fill: theme.surface, r: PsChartConfig.markerRadius, stroke: colors[lineIndexes[lineIndex]], strokeWidth: 2 }, entry.dataKey)))] }), _jsx(GestureDetector, { gesture: gesture, children: _jsx(View, { style: StyleSheet.absoluteFill, testID: 'ps-chart-touch' }) })] })) }), showLegend && series.length > 1 ? (_jsx(PsChartLegend, { items: series.map((entry, position) => ({
|
|
81
82
|
color: colors[position],
|
|
82
83
|
label: entry.label,
|
|
83
84
|
})) })) : null] }));
|
|
@@ -11,5 +11,9 @@ export const PsChartFrame = ({ children, delta, period, title, value }) => {
|
|
|
11
11
|
const size = value === undefined
|
|
12
12
|
? PsChartConfig.kpiValueFontMax
|
|
13
13
|
: PsChartTextService.fontSize(value, width, PsChartConfig.kpiValueFontMax, PsChartConfig.kpiValueFontMin);
|
|
14
|
-
return (_jsx(PsCard, { style: { gap: 12 }, children: _jsxs(View, { onLayout: onLayout, style: { gap: 12 }, testID: 'ps-chart-frame', children: [title === undefined && value === undefined ? null : (_jsxs(View, { style: { gap: 4 }, children: [title === undefined ? null : (_jsx(PsText, { numberOfLines: 1, tone: 'muted', variant: 'label', children: title })), value === undefined ? null : (_jsx(PsText, { numberOfLines: 1, style: {
|
|
14
|
+
return (_jsx(PsCard, { style: { gap: 12 }, children: _jsxs(View, { onLayout: onLayout, style: { gap: 12 }, testID: 'ps-chart-frame', children: [title === undefined && value === undefined ? null : (_jsxs(View, { style: { gap: 4 }, children: [title === undefined ? null : (_jsx(PsText, { numberOfLines: 1, tone: 'muted', variant: 'label', children: title })), value === undefined ? null : (_jsx(PsText, { numberOfLines: 1, style: {
|
|
15
|
+
fontSize: size,
|
|
16
|
+
lineHeight: Math.round(size * 1.25),
|
|
17
|
+
opacity: width === 0 ? 0 : 1,
|
|
18
|
+
}, variant: 'numeric', weight: 'bold', children: value })), delta === undefined ? null : _jsx(PsChartDeltaBadge, { ...delta }), period === undefined ? null : (_jsx(PsText, { tone: 'muted', variant: 'caption', children: period }))] })), children] }) }));
|
|
15
19
|
};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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,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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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 @@
|
|
|
1
|
+
export {};
|
|
@@ -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:
|
|
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,17 @@ 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';
|
|
9
10
|
import { usePsDocumentPdfPages } from '../../hooks/use-ps-document-pdf-pages';
|
|
11
|
+
import { usePsDocumentSearchTexts } from '../../hooks/use-ps-document-search-texts';
|
|
10
12
|
import { usePsMobileTheme } from '../../hooks/use-ps-mobile-theme';
|
|
11
13
|
import { PsDocumentPagerService } from '../../services/ps-document-pager-service';
|
|
14
|
+
import { PsDocumentSearchService } from '../../services/ps-document-search-service';
|
|
12
15
|
import { PsDocumentViewerEntryService } from '../../services/ps-document-viewer-entry-service';
|
|
13
16
|
import { PsDocumentPageStrip } from '../ps-document-page-strip/ps-document-page-strip';
|
|
14
17
|
import { PsDocumentPage } from '../ps-document-page/ps-document-page';
|
|
18
|
+
import { PsDocumentSearchBar } from '../ps-document-search-bar/ps-document-search-bar';
|
|
15
19
|
import { PsIconButton } from '../ps-icon-button/ps-icon-button';
|
|
16
20
|
import { PsText } from '../ps-text/ps-text';
|
|
17
21
|
export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onClose, }) => {
|
|
@@ -27,6 +31,43 @@ export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onCl
|
|
|
27
31
|
? PsDocumentViewerEntryService.startIndex(items, entries, initialIndex)
|
|
28
32
|
: PsDocumentViewerEntryService.resolveIndex(currentEntry, entries, 0);
|
|
29
33
|
const current = entries[index];
|
|
34
|
+
const searchLabels = PsDocumentSearchService.labels(labels);
|
|
35
|
+
const [isSearching, setIsSearching] = useState(false);
|
|
36
|
+
const [query, setQuery] = useState('');
|
|
37
|
+
const [activeMatch, setActiveMatch] = useState(PsDocumentSearchConfig.noActive);
|
|
38
|
+
const searchTexts = usePsDocumentSearchTexts(items, isSearching);
|
|
39
|
+
const counts = PsDocumentSearchService.counts(entries, searchTexts, query);
|
|
40
|
+
const total = PsDocumentSearchService.total(counts);
|
|
41
|
+
const canSearch = searchLabels !== null && PsDocumentSearchService.isSearchable(items);
|
|
42
|
+
const showMatch = (match, nextCounts) => {
|
|
43
|
+
setActiveMatch(match);
|
|
44
|
+
const location = PsDocumentSearchService.locate(nextCounts, match);
|
|
45
|
+
if (location === null)
|
|
46
|
+
return;
|
|
47
|
+
const entry = entries[location.entryIndex];
|
|
48
|
+
if (entry !== undefined && location.entryIndex !== index)
|
|
49
|
+
setCurrentEntry(entry);
|
|
50
|
+
};
|
|
51
|
+
const closeSearch = () => {
|
|
52
|
+
setIsSearching(false);
|
|
53
|
+
setQuery('');
|
|
54
|
+
setActiveMatch(PsDocumentSearchConfig.noActive);
|
|
55
|
+
};
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!isSearching)
|
|
58
|
+
return;
|
|
59
|
+
if (total === 0) {
|
|
60
|
+
if (activeMatch !== PsDocumentSearchConfig.noActive)
|
|
61
|
+
setActiveMatch(PsDocumentSearchConfig.noActive);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (activeMatch < 0 || activeMatch >= total)
|
|
65
|
+
showMatch(PsDocumentSearchService.startIndex(counts, index), counts);
|
|
66
|
+
}, [isSearching, total, activeMatch]);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (!isOpen && isSearching)
|
|
69
|
+
closeSearch();
|
|
70
|
+
}, [isOpen]);
|
|
30
71
|
useEffect(() => {
|
|
31
72
|
if (width > 0 && entries.length > 0)
|
|
32
73
|
list.current?.scrollToIndex({ animated: false, index });
|
|
@@ -41,7 +82,10 @@ export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onCl
|
|
|
41
82
|
flexDirection: 'row',
|
|
42
83
|
paddingHorizontal: PsDocumentConfig.barPaddingHorizontal,
|
|
43
84
|
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(
|
|
85
|
+
}, 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) => {
|
|
86
|
+
setQuery(value);
|
|
87
|
+
setActiveMatch(PsDocumentSearchConfig.noActive);
|
|
88
|
+
}, 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
89
|
index: position,
|
|
46
90
|
length: width,
|
|
47
91
|
offset: PsDocumentPagerService.offset(position, width),
|
|
@@ -50,7 +94,12 @@ export const PsDocumentViewer = ({ initialIndex = 0, isOpen, items, labels, onCl
|
|
|
50
94
|
if (next !== undefined)
|
|
51
95
|
setCurrentEntry(next);
|
|
52
96
|
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,
|
|
97
|
+
}, 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
|
|
98
|
+
? {
|
|
99
|
+
activeIndex: PsDocumentSearchService.activeFor(counts, activeMatch, position),
|
|
100
|
+
query,
|
|
101
|
+
}
|
|
102
|
+
: 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
103
|
const entry = entries[position];
|
|
55
104
|
if (entry !== undefined)
|
|
56
105
|
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,21 @@ 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]);
|
|
86
103
|
const gesture = useSimultaneousGestures(pinch, move, dismiss, doubleTap);
|
|
87
104
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
88
105
|
transform: [
|
|
@@ -92,7 +109,7 @@ export const PsDocumentZoomImage = ({ name, onDismiss, onError, onZoomChange, so
|
|
|
92
109
|
{ scale: scale.value },
|
|
93
110
|
],
|
|
94
111
|
}));
|
|
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: [
|
|
112
|
+
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
113
|
alignItems: 'center',
|
|
97
114
|
bottom: 0,
|
|
98
115
|
justifyContent: 'center',
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { PsDonutChartProps } from './ps-donut-chart-props';
|
|
2
|
-
export declare const PsDonutChart: ({ centerLabel, centerValue, data, emptyLabel, formatShare, height, isLoading, }: PsDonutChartProps) => import("react").JSX.Element;
|
|
2
|
+
export declare const PsDonutChart: ({ centerLabel, centerValue, data, emptyLabel, formatShare, height, isLoading, revealKey, }: PsDonutChartProps) => import("react").JSX.Element;
|
|
@@ -14,12 +14,12 @@ import { PsChartLegend } from '../ps-chart-legend/ps-chart-legend';
|
|
|
14
14
|
import { PsChartSkeleton } from '../ps-chart-skeleton/ps-chart-skeleton';
|
|
15
15
|
import { PsDonutSlice } from '../ps-donut-slice/ps-donut-slice';
|
|
16
16
|
import { PsText } from '../ps-text/ps-text';
|
|
17
|
-
export const PsDonutChart = ({ centerLabel, centerValue, data, emptyLabel, formatShare, height = PsChartConfig.donutHeight, isLoading = false, }) => {
|
|
17
|
+
export const PsDonutChart = ({ centerLabel, centerValue, data, emptyLabel, formatShare, height = PsChartConfig.donutHeight, isLoading = false, revealKey, }) => {
|
|
18
18
|
const theme = usePsMobileTheme();
|
|
19
19
|
const { onLayout, width } = usePsChartWidth();
|
|
20
20
|
const fill = usePsWidgetFill();
|
|
21
21
|
const [selected, setSelected] = useState(null);
|
|
22
|
-
const progress = usePsChartReveal(
|
|
22
|
+
const progress = usePsChartReveal(!isLoading && width > 0, revealKey);
|
|
23
23
|
if (isLoading)
|
|
24
24
|
return _jsx(PsChartSkeleton, { height: height, variant: PsChartSkeletonVariant.Donut });
|
|
25
25
|
const layout = PsChartDonutService.layout(width, height);
|