@webority-technologies/mobile-ui 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commonjs/components/DocumentViewer/DocumentViewer.js +74 -60
- package/lib/module/components/DocumentViewer/DocumentViewer.js +75 -61
- package/lib/typescript/commonjs/components/DocumentViewer/DocumentViewer.d.ts +10 -3
- package/lib/typescript/module/components/DocumentViewer/DocumentViewer.d.ts +10 -3
- package/package.json +1 -1
|
@@ -14,6 +14,8 @@ var _jsxRuntime = require("react/jsx-runtime");
|
|
|
14
14
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
15
|
const HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
|
|
16
16
|
const MAX_RENDER_SCALE = 3;
|
|
17
|
+
/** How many pages beyond the current one stay mounted, each direction. */
|
|
18
|
+
const RENDER_WINDOW = 1;
|
|
17
19
|
const toError = value => value instanceof Error ? value : new Error(String(value));
|
|
18
20
|
|
|
19
21
|
/** The renderPage scale is capped so a very wide view never asks the native
|
|
@@ -38,11 +40,19 @@ const localPathFromSource = async source => {
|
|
|
38
40
|
});
|
|
39
41
|
return result.path;
|
|
40
42
|
};
|
|
43
|
+
|
|
41
44
|
/**
|
|
42
45
|
* Renders a PDF via our own native rasterizer (PDFKit on iOS, PdfRenderer on
|
|
43
|
-
* Android) — no third-party PDF dependency.
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
+
* Android) — no third-party PDF dependency. Pages are paged through a plain
|
|
47
|
+
* `ScrollView` with manual windowed mounting (render the visible page ±
|
|
48
|
+
* `RENDER_WINDOW`), not a `FlatList` — a `VirtualizedList`-based component
|
|
49
|
+
* would trip React Native's "VirtualizedLists should never be nested inside
|
|
50
|
+
* plain ScrollViews" the moment a consumer embeds DocumentViewer in their own
|
|
51
|
+
* scrolling screen, which is a completely ordinary way to use it. Avoiding the
|
|
52
|
+
* VirtualizedList primitive entirely removes that whole class of warning
|
|
53
|
+
* rather than working around one instance of it. The WebView fallback
|
|
54
|
+
* consumer apps use for non-PDF office documents is a distinct rendering
|
|
55
|
+
* strategy and stays app-side.
|
|
46
56
|
*/
|
|
47
57
|
const DocumentViewer = ({
|
|
48
58
|
source,
|
|
@@ -64,11 +74,14 @@ const DocumentViewer = ({
|
|
|
64
74
|
}); // US Letter fallback
|
|
65
75
|
const pageAspect = pageSizePt.height / pageSizePt.width;
|
|
66
76
|
const [renderedPages, setRenderedPages] = (0, _react.useState)({});
|
|
77
|
+
const [currentPage, setCurrentPage] = (0, _react.useState)(0);
|
|
67
78
|
const handleRef = (0, _react.useRef)(null);
|
|
68
79
|
const onErrorRef = (0, _react.useRef)(onError);
|
|
69
80
|
onErrorRef.current = onError;
|
|
70
81
|
const onLoadCompleteRef = (0, _react.useRef)(onLoadComplete);
|
|
71
82
|
onLoadCompleteRef.current = onLoadComplete;
|
|
83
|
+
const onPageChangedRef = (0, _react.useRef)(onPageChanged);
|
|
84
|
+
onPageChangedRef.current = onPageChanged;
|
|
72
85
|
const documentSource = (0, _react.useMemo)(() => ({
|
|
73
86
|
uri: source.uri,
|
|
74
87
|
headers: source.headers,
|
|
@@ -93,6 +106,8 @@ const DocumentViewer = ({
|
|
|
93
106
|
}
|
|
94
107
|
handleRef.current = opened.handle;
|
|
95
108
|
setPageCount(opened.pageCount);
|
|
109
|
+
setCurrentPage(0);
|
|
110
|
+
setRenderedPages({});
|
|
96
111
|
if (opened.pageWidth > 0 && opened.pageHeight > 0) {
|
|
97
112
|
setPageSizePt({
|
|
98
113
|
width: opened.pageWidth,
|
|
@@ -135,56 +150,37 @@ const DocumentViewer = ({
|
|
|
135
150
|
_mobileCore.Logger.error(`[@webority-technologies/mobile-ui] DocumentViewer failed to render page ${pageIndex}.`, toError(error));
|
|
136
151
|
}
|
|
137
152
|
}, [pageSizePt.width, windowWidth]);
|
|
138
|
-
const
|
|
139
|
-
length: pageCount
|
|
140
|
-
}, (_unused, index) => ({
|
|
141
|
-
index
|
|
142
|
-
})), [pageCount]);
|
|
143
|
-
const onPageChangedRef = (0, _react.useRef)(onPageChanged);
|
|
144
|
-
onPageChangedRef.current = onPageChanged;
|
|
145
|
-
const pageCountRef = (0, _react.useRef)(pageCount);
|
|
146
|
-
pageCountRef.current = pageCount;
|
|
147
|
-
const renderPageImageRef = (0, _react.useRef)(renderPageImage);
|
|
148
|
-
renderPageImageRef.current = renderPageImage;
|
|
153
|
+
const pageHeight = windowWidth * pageAspect;
|
|
149
154
|
|
|
150
|
-
//
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}) => {
|
|
156
|
-
const first = viewableItems[0]?.item;
|
|
157
|
-
if (first) {
|
|
158
|
-
onPageChangedRef.current?.(first.index + 1, pageCountRef.current);
|
|
159
|
-
viewableItems.forEach(v => void renderPageImageRef.current(v.item.index));
|
|
155
|
+
// Mount and rasterize the current page plus a small window around it;
|
|
156
|
+
// everything else stays an empty placeholder slot until scrolled near.
|
|
157
|
+
(0, _react.useEffect)(() => {
|
|
158
|
+
if (pageCount === 0) {
|
|
159
|
+
return;
|
|
160
160
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
style: styles.pageImage,
|
|
178
|
-
resizeMode: "contain",
|
|
179
|
-
accessible: false
|
|
180
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
181
|
-
style: styles.pagePlaceholder,
|
|
182
|
-
children: loadingIndicator ? loadingIndicator() : /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.Spinner, {
|
|
183
|
-
size: "lg"
|
|
184
|
-
})
|
|
185
|
-
})
|
|
161
|
+
const start = Math.max(0, currentPage - RENDER_WINDOW);
|
|
162
|
+
const end = Math.min(pageCount - 1, currentPage + RENDER_WINDOW);
|
|
163
|
+
for (let index = start; index <= end; index += 1) {
|
|
164
|
+
void renderPageImage(index);
|
|
165
|
+
}
|
|
166
|
+
}, [currentPage, pageCount, renderPageImage]);
|
|
167
|
+
const handleScroll = (0, _react.useCallback)(event => {
|
|
168
|
+
if (pageHeight <= 0) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const page = Math.min(pageCount - 1, Math.max(0, Math.round(event.nativeEvent.contentOffset.y / pageHeight)));
|
|
172
|
+
setCurrentPage(prev => {
|
|
173
|
+
if (prev !== page) {
|
|
174
|
+
onPageChangedRef.current?.(page + 1, pageCount);
|
|
175
|
+
}
|
|
176
|
+
return page;
|
|
186
177
|
});
|
|
187
|
-
}, [
|
|
178
|
+
}, [pageCount, pageHeight]);
|
|
179
|
+
const pages = (0, _react.useMemo)(() => Array.from({
|
|
180
|
+
length: pageCount
|
|
181
|
+
}, (_unused, i) => i), [pageCount]);
|
|
182
|
+
const renderWindowStart = Math.max(0, currentPage - RENDER_WINDOW);
|
|
183
|
+
const renderWindowEnd = Math.min(pageCount - 1, currentPage + RENDER_WINDOW);
|
|
188
184
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
189
185
|
style: [styles.root, style],
|
|
190
186
|
testID: testID,
|
|
@@ -196,16 +192,34 @@ const DocumentViewer = ({
|
|
|
196
192
|
children: loadingIndicator ? loadingIndicator() : /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.Spinner, {
|
|
197
193
|
size: "lg"
|
|
198
194
|
})
|
|
199
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
195
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
|
|
196
|
+
onScroll: handleScroll,
|
|
197
|
+
scrollEventThrottle: 32,
|
|
198
|
+
showsVerticalScrollIndicator: true,
|
|
199
|
+
removeClippedSubviews: true,
|
|
200
|
+
children: pages.map(index => {
|
|
201
|
+
const withinWindow = index >= renderWindowStart && index <= renderWindowEnd;
|
|
202
|
+
const uri = withinWindow ? renderedPages[index] : undefined;
|
|
203
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
204
|
+
style: [styles.page, {
|
|
205
|
+
width: windowWidth,
|
|
206
|
+
height: pageHeight
|
|
207
|
+
}],
|
|
208
|
+
children: uri ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Image, {
|
|
209
|
+
source: {
|
|
210
|
+
uri
|
|
211
|
+
},
|
|
212
|
+
style: styles.pageImage,
|
|
213
|
+
resizeMode: "contain",
|
|
214
|
+
accessible: false
|
|
215
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
216
|
+
style: styles.pagePlaceholder,
|
|
217
|
+
children: withinWindow ? loadingIndicator?.() ?? /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.Spinner, {
|
|
218
|
+
size: "lg"
|
|
219
|
+
}) : null
|
|
220
|
+
})
|
|
221
|
+
}, index);
|
|
222
|
+
})
|
|
209
223
|
})
|
|
210
224
|
});
|
|
211
225
|
};
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
import { Logger } from '@webority-technologies/mobile-core';
|
|
4
4
|
import { downloadFile } from '@webority-technologies/mobile-core/download';
|
|
5
5
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
6
|
-
import {
|
|
6
|
+
import { Image, PixelRatio, ScrollView, StyleSheet, useWindowDimensions, View } from 'react-native';
|
|
7
7
|
import PdfRasterizer from "../../specs/NativePdfRasterizer.js";
|
|
8
8
|
import { Spinner } from "../Spinner/index.js";
|
|
9
9
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
10
10
|
const HAS_SCHEME = /^[a-z][a-z0-9+.-]*:/i;
|
|
11
11
|
const MAX_RENDER_SCALE = 3;
|
|
12
|
+
/** How many pages beyond the current one stay mounted, each direction. */
|
|
13
|
+
const RENDER_WINDOW = 1;
|
|
12
14
|
const toError = value => value instanceof Error ? value : new Error(String(value));
|
|
13
15
|
|
|
14
16
|
/** The renderPage scale is capped so a very wide view never asks the native
|
|
@@ -33,11 +35,19 @@ const localPathFromSource = async source => {
|
|
|
33
35
|
});
|
|
34
36
|
return result.path;
|
|
35
37
|
};
|
|
38
|
+
|
|
36
39
|
/**
|
|
37
40
|
* Renders a PDF via our own native rasterizer (PDFKit on iOS, PdfRenderer on
|
|
38
|
-
* Android) — no third-party PDF dependency.
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
+
* Android) — no third-party PDF dependency. Pages are paged through a plain
|
|
42
|
+
* `ScrollView` with manual windowed mounting (render the visible page ±
|
|
43
|
+
* `RENDER_WINDOW`), not a `FlatList` — a `VirtualizedList`-based component
|
|
44
|
+
* would trip React Native's "VirtualizedLists should never be nested inside
|
|
45
|
+
* plain ScrollViews" the moment a consumer embeds DocumentViewer in their own
|
|
46
|
+
* scrolling screen, which is a completely ordinary way to use it. Avoiding the
|
|
47
|
+
* VirtualizedList primitive entirely removes that whole class of warning
|
|
48
|
+
* rather than working around one instance of it. The WebView fallback
|
|
49
|
+
* consumer apps use for non-PDF office documents is a distinct rendering
|
|
50
|
+
* strategy and stays app-side.
|
|
41
51
|
*/
|
|
42
52
|
export const DocumentViewer = ({
|
|
43
53
|
source,
|
|
@@ -59,11 +69,14 @@ export const DocumentViewer = ({
|
|
|
59
69
|
}); // US Letter fallback
|
|
60
70
|
const pageAspect = pageSizePt.height / pageSizePt.width;
|
|
61
71
|
const [renderedPages, setRenderedPages] = useState({});
|
|
72
|
+
const [currentPage, setCurrentPage] = useState(0);
|
|
62
73
|
const handleRef = useRef(null);
|
|
63
74
|
const onErrorRef = useRef(onError);
|
|
64
75
|
onErrorRef.current = onError;
|
|
65
76
|
const onLoadCompleteRef = useRef(onLoadComplete);
|
|
66
77
|
onLoadCompleteRef.current = onLoadComplete;
|
|
78
|
+
const onPageChangedRef = useRef(onPageChanged);
|
|
79
|
+
onPageChangedRef.current = onPageChanged;
|
|
67
80
|
const documentSource = useMemo(() => ({
|
|
68
81
|
uri: source.uri,
|
|
69
82
|
headers: source.headers,
|
|
@@ -88,6 +101,8 @@ export const DocumentViewer = ({
|
|
|
88
101
|
}
|
|
89
102
|
handleRef.current = opened.handle;
|
|
90
103
|
setPageCount(opened.pageCount);
|
|
104
|
+
setCurrentPage(0);
|
|
105
|
+
setRenderedPages({});
|
|
91
106
|
if (opened.pageWidth > 0 && opened.pageHeight > 0) {
|
|
92
107
|
setPageSizePt({
|
|
93
108
|
width: opened.pageWidth,
|
|
@@ -130,56 +145,37 @@ export const DocumentViewer = ({
|
|
|
130
145
|
Logger.error(`[@webority-technologies/mobile-ui] DocumentViewer failed to render page ${pageIndex}.`, toError(error));
|
|
131
146
|
}
|
|
132
147
|
}, [pageSizePt.width, windowWidth]);
|
|
133
|
-
const
|
|
134
|
-
length: pageCount
|
|
135
|
-
}, (_unused, index) => ({
|
|
136
|
-
index
|
|
137
|
-
})), [pageCount]);
|
|
138
|
-
const onPageChangedRef = useRef(onPageChanged);
|
|
139
|
-
onPageChangedRef.current = onPageChanged;
|
|
140
|
-
const pageCountRef = useRef(pageCount);
|
|
141
|
-
pageCountRef.current = pageCount;
|
|
142
|
-
const renderPageImageRef = useRef(renderPageImage);
|
|
143
|
-
renderPageImageRef.current = renderPageImage;
|
|
148
|
+
const pageHeight = windowWidth * pageAspect;
|
|
144
149
|
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}) => {
|
|
151
|
-
const first = viewableItems[0]?.item;
|
|
152
|
-
if (first) {
|
|
153
|
-
onPageChangedRef.current?.(first.index + 1, pageCountRef.current);
|
|
154
|
-
viewableItems.forEach(v => void renderPageImageRef.current(v.item.index));
|
|
150
|
+
// Mount and rasterize the current page plus a small window around it;
|
|
151
|
+
// everything else stays an empty placeholder slot until scrolled near.
|
|
152
|
+
useEffect(() => {
|
|
153
|
+
if (pageCount === 0) {
|
|
154
|
+
return;
|
|
155
155
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
style: styles.pageImage,
|
|
173
|
-
resizeMode: "contain",
|
|
174
|
-
accessible: false
|
|
175
|
-
}) : /*#__PURE__*/_jsx(View, {
|
|
176
|
-
style: styles.pagePlaceholder,
|
|
177
|
-
children: loadingIndicator ? loadingIndicator() : /*#__PURE__*/_jsx(Spinner, {
|
|
178
|
-
size: "lg"
|
|
179
|
-
})
|
|
180
|
-
})
|
|
156
|
+
const start = Math.max(0, currentPage - RENDER_WINDOW);
|
|
157
|
+
const end = Math.min(pageCount - 1, currentPage + RENDER_WINDOW);
|
|
158
|
+
for (let index = start; index <= end; index += 1) {
|
|
159
|
+
void renderPageImage(index);
|
|
160
|
+
}
|
|
161
|
+
}, [currentPage, pageCount, renderPageImage]);
|
|
162
|
+
const handleScroll = useCallback(event => {
|
|
163
|
+
if (pageHeight <= 0) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const page = Math.min(pageCount - 1, Math.max(0, Math.round(event.nativeEvent.contentOffset.y / pageHeight)));
|
|
167
|
+
setCurrentPage(prev => {
|
|
168
|
+
if (prev !== page) {
|
|
169
|
+
onPageChangedRef.current?.(page + 1, pageCount);
|
|
170
|
+
}
|
|
171
|
+
return page;
|
|
181
172
|
});
|
|
182
|
-
}, [
|
|
173
|
+
}, [pageCount, pageHeight]);
|
|
174
|
+
const pages = useMemo(() => Array.from({
|
|
175
|
+
length: pageCount
|
|
176
|
+
}, (_unused, i) => i), [pageCount]);
|
|
177
|
+
const renderWindowStart = Math.max(0, currentPage - RENDER_WINDOW);
|
|
178
|
+
const renderWindowEnd = Math.min(pageCount - 1, currentPage + RENDER_WINDOW);
|
|
183
179
|
return /*#__PURE__*/_jsx(View, {
|
|
184
180
|
style: [styles.root, style],
|
|
185
181
|
testID: testID,
|
|
@@ -191,16 +187,34 @@ export const DocumentViewer = ({
|
|
|
191
187
|
children: loadingIndicator ? loadingIndicator() : /*#__PURE__*/_jsx(Spinner, {
|
|
192
188
|
size: "lg"
|
|
193
189
|
})
|
|
194
|
-
}) : /*#__PURE__*/_jsx(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
190
|
+
}) : /*#__PURE__*/_jsx(ScrollView, {
|
|
191
|
+
onScroll: handleScroll,
|
|
192
|
+
scrollEventThrottle: 32,
|
|
193
|
+
showsVerticalScrollIndicator: true,
|
|
194
|
+
removeClippedSubviews: true,
|
|
195
|
+
children: pages.map(index => {
|
|
196
|
+
const withinWindow = index >= renderWindowStart && index <= renderWindowEnd;
|
|
197
|
+
const uri = withinWindow ? renderedPages[index] : undefined;
|
|
198
|
+
return /*#__PURE__*/_jsx(View, {
|
|
199
|
+
style: [styles.page, {
|
|
200
|
+
width: windowWidth,
|
|
201
|
+
height: pageHeight
|
|
202
|
+
}],
|
|
203
|
+
children: uri ? /*#__PURE__*/_jsx(Image, {
|
|
204
|
+
source: {
|
|
205
|
+
uri
|
|
206
|
+
},
|
|
207
|
+
style: styles.pageImage,
|
|
208
|
+
resizeMode: "contain",
|
|
209
|
+
accessible: false
|
|
210
|
+
}) : /*#__PURE__*/_jsx(View, {
|
|
211
|
+
style: styles.pagePlaceholder,
|
|
212
|
+
children: withinWindow ? loadingIndicator?.() ?? /*#__PURE__*/_jsx(Spinner, {
|
|
213
|
+
size: "lg"
|
|
214
|
+
}) : null
|
|
215
|
+
})
|
|
216
|
+
}, index);
|
|
217
|
+
})
|
|
204
218
|
})
|
|
205
219
|
});
|
|
206
220
|
};
|
|
@@ -19,9 +19,16 @@ export interface DocumentViewerProps {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Renders a PDF via our own native rasterizer (PDFKit on iOS, PdfRenderer on
|
|
22
|
-
* Android) — no third-party PDF dependency.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Android) — no third-party PDF dependency. Pages are paged through a plain
|
|
23
|
+
* `ScrollView` with manual windowed mounting (render the visible page ±
|
|
24
|
+
* `RENDER_WINDOW`), not a `FlatList` — a `VirtualizedList`-based component
|
|
25
|
+
* would trip React Native's "VirtualizedLists should never be nested inside
|
|
26
|
+
* plain ScrollViews" the moment a consumer embeds DocumentViewer in their own
|
|
27
|
+
* scrolling screen, which is a completely ordinary way to use it. Avoiding the
|
|
28
|
+
* VirtualizedList primitive entirely removes that whole class of warning
|
|
29
|
+
* rather than working around one instance of it. The WebView fallback
|
|
30
|
+
* consumer apps use for non-PDF office documents is a distinct rendering
|
|
31
|
+
* strategy and stays app-side.
|
|
25
32
|
*/
|
|
26
33
|
export declare const DocumentViewer: React.FC<DocumentViewerProps>;
|
|
27
34
|
export default DocumentViewer;
|
|
@@ -19,9 +19,16 @@ export interface DocumentViewerProps {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* Renders a PDF via our own native rasterizer (PDFKit on iOS, PdfRenderer on
|
|
22
|
-
* Android) — no third-party PDF dependency.
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Android) — no third-party PDF dependency. Pages are paged through a plain
|
|
23
|
+
* `ScrollView` with manual windowed mounting (render the visible page ±
|
|
24
|
+
* `RENDER_WINDOW`), not a `FlatList` — a `VirtualizedList`-based component
|
|
25
|
+
* would trip React Native's "VirtualizedLists should never be nested inside
|
|
26
|
+
* plain ScrollViews" the moment a consumer embeds DocumentViewer in their own
|
|
27
|
+
* scrolling screen, which is a completely ordinary way to use it. Avoiding the
|
|
28
|
+
* VirtualizedList primitive entirely removes that whole class of warning
|
|
29
|
+
* rather than working around one instance of it. The WebView fallback
|
|
30
|
+
* consumer apps use for non-PDF office documents is a distinct rendering
|
|
31
|
+
* strategy and stays app-side.
|
|
25
32
|
*/
|
|
26
33
|
export declare const DocumentViewer: React.FC<DocumentViewerProps>;
|
|
27
34
|
export default DocumentViewer;
|
package/package.json
CHANGED