@webority-technologies/mobile-ui 0.0.4 → 0.0.6

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.
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.DocumentViewer = void 0;
7
+ var _mobileCore = require("@webority-technologies/mobile-core");
8
+ var _react = require("react");
9
+ var _reactNative = require("react-native");
10
+ var _reactNativePdf = _interopRequireDefault(require("react-native-pdf"));
11
+ var _index = require("../Spinner/index.js");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ const toError = value => value instanceof Error ? value : new Error(String(value));
15
+
16
+ /**
17
+ * Renders a PDF only — the WebView fallback consumer apps use for non-PDF
18
+ * office documents is a distinct rendering strategy and stays app-side.
19
+ */
20
+ const DocumentViewer = ({
21
+ source,
22
+ trustAllCerts = false,
23
+ onLoadComplete,
24
+ onPageChanged,
25
+ onError,
26
+ loadingIndicator,
27
+ style,
28
+ testID,
29
+ accessibilityLabel
30
+ }) => {
31
+ const renderActivityIndicator = (0, _react.useCallback)(() => loadingIndicator ? loadingIndicator() : /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.Spinner, {
32
+ size: "lg"
33
+ }), [loadingIndicator]);
34
+ const handleError = (0, _react.useCallback)(error => {
35
+ const err = toError(error);
36
+ _mobileCore.Logger.error('[@webority-technologies/mobile-ui] DocumentViewer failed to load.', err);
37
+ onError?.(err);
38
+ }, [onError]);
39
+ const handleLoadComplete = (0, _react.useCallback)(numberOfPages => onLoadComplete?.(numberOfPages), [onLoadComplete]);
40
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
41
+ style: [styles.root, style],
42
+ testID: testID,
43
+ accessible: accessibilityLabel !== undefined,
44
+ accessibilityLabel: accessibilityLabel,
45
+ accessibilityRole: "none",
46
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativePdf.default, {
47
+ source: source,
48
+ trustAllCerts: trustAllCerts,
49
+ style: styles.pdf,
50
+ renderActivityIndicator: renderActivityIndicator,
51
+ onLoadComplete: handleLoadComplete,
52
+ onPageChanged: onPageChanged,
53
+ onError: handleError
54
+ })
55
+ });
56
+ };
57
+ exports.DocumentViewer = DocumentViewer;
58
+ DocumentViewer.displayName = 'DocumentViewer';
59
+ const styles = _reactNative.StyleSheet.create({
60
+ root: {
61
+ flex: 1
62
+ },
63
+ pdf: {
64
+ flex: 1,
65
+ width: '100%',
66
+ height: '100%'
67
+ }
68
+ });
69
+ var _default = exports.default = DocumentViewer;
70
+ //# sourceMappingURL=DocumentViewer.js.map
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "DocumentViewer", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _DocumentViewer.DocumentViewer;
10
+ }
11
+ });
12
+ var _DocumentViewer = require("./DocumentViewer.js");
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = exports.ZoomableImage = void 0;
7
+ var _react = _interopRequireWildcard(require("react"));
8
+ var _reactNative = require("react-native");
9
+ var _reactNativeGestureHandler = require("react-native-gesture-handler");
10
+ var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
11
+ var _index = require("../../utils/index.js");
12
+ var _jsxRuntime = require("react/jsx-runtime");
13
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
+ /**
15
+ * ZoomableImage — a standalone pinch-to-zoom / pan / double-tap-to-zoom
16
+ * wrapper for a single piece of content (typically one `<Image>`).
17
+ *
18
+ * Reuses the same Reanimated 3 gesture composition `ImageGallery`'s internal
19
+ * lightbox slide uses (pinch clamped and rubber-banded at its limits, pan
20
+ * gated to only engage once zoomed in, double-tap toggling between baseline
21
+ * and `doubleTapScale`), stripped of the carousel-slide concerns that
22
+ * component needs and this one does not — there is no `index`/`total`/
23
+ * `active` because a standalone image is always the one being viewed.
24
+ *
25
+ * USAGE:
26
+ *
27
+ * <ZoomableImage>
28
+ * <Image source={{ uri }} style={styles.image} resizeMode="contain" />
29
+ * </ZoomableImage>
30
+ *
31
+ * Takes `children` rather than a `source`/`uri` prop: every real consumer of
32
+ * this pattern in the fleet wraps an already-authenticated image component
33
+ * (headers, caching, its own loading state) rather than a bare `<Image>`, so
34
+ * a `source` prop would force re-implementing that per app. Wrapping keeps
35
+ * this component ignorant of how the image is fetched.
36
+ */
37
+
38
+ const DEFAULT_MAX_SCALE = 4;
39
+ const DEFAULT_MIN_SCALE = 1;
40
+ const DEFAULT_DOUBLE_TAP_SCALE = 2;
41
+ const SPRING_CONFIG = {
42
+ damping: 18,
43
+ stiffness: 220,
44
+ mass: 1
45
+ };
46
+ const ZoomableImage = ({
47
+ children,
48
+ maxScale = DEFAULT_MAX_SCALE,
49
+ minScale = DEFAULT_MIN_SCALE,
50
+ doubleTapScale = DEFAULT_DOUBLE_TAP_SCALE,
51
+ disabled = false,
52
+ haptic,
53
+ style,
54
+ accessibilityLabel,
55
+ testID
56
+ }) => {
57
+ const scale = (0, _reactNativeReanimated.useSharedValue)(1);
58
+ const savedScale = (0, _reactNativeReanimated.useSharedValue)(1);
59
+ const translateX = (0, _reactNativeReanimated.useSharedValue)(0);
60
+ const translateY = (0, _reactNativeReanimated.useSharedValue)(0);
61
+ const savedTranslateX = (0, _reactNativeReanimated.useSharedValue)(0);
62
+ const savedTranslateY = (0, _reactNativeReanimated.useSharedValue)(0);
63
+ const resetTransform = (0, _react.useCallback)(() => {
64
+ scale.value = (0, _reactNativeReanimated.withSpring)(1, SPRING_CONFIG);
65
+ savedScale.value = 1;
66
+ translateX.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
67
+ translateY.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
68
+ savedTranslateX.value = 0;
69
+ savedTranslateY.value = 0;
70
+ }, [scale, savedScale, translateX, translateY, savedTranslateX, savedTranslateY]);
71
+
72
+ // Disabling mid-zoom must not leave the content stranded scaled/panned —
73
+ // snap it back the same way ImageGallery's slide resets on losing focus.
74
+ (0, _react.useEffect)(() => {
75
+ if (disabled) {
76
+ resetTransform();
77
+ }
78
+ }, [disabled, resetTransform]);
79
+ const triggerImpact = (0, _react.useCallback)(() => {
80
+ const h = (0, _index.resolveHaptic)(haptic, 'impactLight');
81
+ if (h) {
82
+ (0, _index.triggerHaptic)(h);
83
+ }
84
+ }, [haptic]);
85
+ const pinch = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pinch().enabled(!disabled).onStart(() => {
86
+ 'worklet';
87
+
88
+ savedScale.value = scale.value;
89
+ }).onUpdate(e => {
90
+ 'worklet';
91
+
92
+ const next = savedScale.value * e.scale;
93
+ // Clamp minScale..maxScale on the UI thread so pinch feels rubbery at limits.
94
+ if (next < minScale) {
95
+ scale.value = minScale + (next - minScale) * 0.3;
96
+ } else if (next > maxScale) {
97
+ scale.value = maxScale + (next - maxScale) * 0.2;
98
+ } else {
99
+ scale.value = next;
100
+ }
101
+ }).onEnd(() => {
102
+ 'worklet';
103
+
104
+ if (scale.value < minScale) {
105
+ scale.value = (0, _reactNativeReanimated.withSpring)(minScale, SPRING_CONFIG);
106
+ translateX.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
107
+ translateY.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
108
+ savedScale.value = minScale;
109
+ savedTranslateX.value = 0;
110
+ savedTranslateY.value = 0;
111
+ return;
112
+ }
113
+ if (scale.value > maxScale) {
114
+ scale.value = (0, _reactNativeReanimated.withSpring)(maxScale, SPRING_CONFIG);
115
+ savedScale.value = maxScale;
116
+ return;
117
+ }
118
+ savedScale.value = scale.value;
119
+ }), [disabled, scale, savedScale, translateX, translateY, savedTranslateX, savedTranslateY, minScale, maxScale]);
120
+
121
+ // Pan only engages when zoomed in — otherwise a scroll view or carousel this
122
+ // is nested inside keeps owning the gesture.
123
+ const pan = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Pan().enabled(!disabled).minPointers(1).maxPointers(1).onStart(() => {
124
+ 'worklet';
125
+
126
+ savedTranslateX.value = translateX.value;
127
+ savedTranslateY.value = translateY.value;
128
+ }).onUpdate(e => {
129
+ 'worklet';
130
+
131
+ if (scale.value <= 1) {
132
+ return;
133
+ }
134
+ translateX.value = savedTranslateX.value + e.translationX;
135
+ translateY.value = savedTranslateY.value + e.translationY;
136
+ }).onEnd(() => {
137
+ 'worklet';
138
+
139
+ savedTranslateX.value = translateX.value;
140
+ savedTranslateY.value = translateY.value;
141
+ }), [disabled, scale, translateX, translateY, savedTranslateX, savedTranslateY]);
142
+ const doubleTap = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Tap().enabled(!disabled).numberOfTaps(2).onEnd(() => {
143
+ 'worklet';
144
+
145
+ (0, _reactNativeReanimated.runOnJS)(triggerImpact)();
146
+ if (scale.value > 1) {
147
+ scale.value = (0, _reactNativeReanimated.withSpring)(1, SPRING_CONFIG);
148
+ translateX.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
149
+ translateY.value = (0, _reactNativeReanimated.withSpring)(0, SPRING_CONFIG);
150
+ savedScale.value = 1;
151
+ savedTranslateX.value = 0;
152
+ savedTranslateY.value = 0;
153
+ } else {
154
+ scale.value = (0, _reactNativeReanimated.withSpring)(doubleTapScale, SPRING_CONFIG);
155
+ savedScale.value = doubleTapScale;
156
+ }
157
+ }), [disabled, scale, savedScale, translateX, translateY, savedTranslateX, savedTranslateY, triggerImpact, doubleTapScale]);
158
+
159
+ // Race the gestures so they coordinate cleanly: a tap won't be misread as a
160
+ // tiny pan, and pan won't fire when the user actually starts a pinch.
161
+ const composed = (0, _react.useMemo)(() => _reactNativeGestureHandler.Gesture.Race(pinch, pan, doubleTap), [pinch, pan, doubleTap]);
162
+ const animatedStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => ({
163
+ transform: [{
164
+ translateX: translateX.value
165
+ }, {
166
+ translateY: translateY.value
167
+ }, {
168
+ scale: scale.value
169
+ }]
170
+ }));
171
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeGestureHandler.GestureDetector, {
172
+ gesture: composed,
173
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
174
+ style: [styles.container, style],
175
+ testID: testID,
176
+ accessibilityLabel: accessibilityLabel,
177
+ accessibilityState: {
178
+ disabled
179
+ },
180
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
181
+ style: [styles.content, animatedStyle],
182
+ children: children
183
+ })
184
+ })
185
+ });
186
+ };
187
+ exports.ZoomableImage = ZoomableImage;
188
+ ZoomableImage.displayName = 'ZoomableImage';
189
+ const styles = _reactNative.StyleSheet.create({
190
+ container: {
191
+ flex: 1,
192
+ alignItems: 'center',
193
+ justifyContent: 'center',
194
+ overflow: 'hidden'
195
+ },
196
+ content: {
197
+ width: '100%',
198
+ height: '100%',
199
+ alignItems: 'center',
200
+ justifyContent: 'center'
201
+ }
202
+ });
203
+ var _default = exports.default = ZoomableImage;
204
+ //# sourceMappingURL=ZoomableImage.js.map
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "ZoomableImage", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _ZoomableImage.ZoomableImage;
10
+ }
11
+ });
12
+ var _ZoomableImage = require("./ZoomableImage.js");
13
+ //# sourceMappingURL=index.js.map