@atlaskit/media-document-viewer 0.4.3 → 0.5.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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @atlaskit/media-document-viewer
2
2
 
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`3a4089c3a27b3`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/3a4089c3a27b3) -
8
+ Improve handling of zoom to take into account device DPI to prevent blurry images. Also update
9
+ form handling to show default pdfium rendered forms, and only show HTML input elements on focus.
10
+
11
+ ## 0.4.4
12
+
13
+ ### Patch Changes
14
+
15
+ - Updated dependencies
16
+
3
17
  ## 0.4.3
4
18
 
5
19
  ### Patch Changes
@@ -1,15 +1,25 @@
1
1
 
2
2
  ._19itglyw{border:none}._14zgglyw{resize:none}
3
+ ._18m915vq{overflow-y:hidden}
3
4
  ._19bvidpf{padding-left:0}
4
5
  ._1bah1yb4{justify-content:space-between}
5
6
  ._1bsb1osq{width:100%}
6
7
  ._1e0c11p5{display:grid}
8
+ ._1reo15vq{overflow-x:hidden}
7
9
  ._4cvr1h6o{align-items:center}
8
10
  ._4t3i1osq{height:100%}
11
+ ._bfhk1j28{background-color:transparent}
9
12
  ._ca0qidpf{padding-top:0}
13
+ ._ect41ttw{font-family:Arial}
10
14
  ._kqswstnw{position:absolute}
11
15
  ._n3tdidpf{padding-bottom:0}
12
16
  ._r06hglyw{-webkit-appearance:none;appearance:none}
17
+ ._syaz1j28{color:transparent}
13
18
  ._u5f3idpf{padding-right:0}
14
19
  ._vchhusvi{box-sizing:border-box}
15
- ._yv0e1ghl{grid-template-columns:1fr auto}
20
+ ._vwz410nf{line-height:1.25}
21
+ ._yv0e1ghl{grid-template-columns:1fr auto}
22
+ ._1chs1wug:focus{overflow-y:auto}
23
+ ._f8pjr3uz:focus{color:#000}
24
+ ._jomru67f:focus{background-color:#fff}
25
+ ._p6m71wug:focus{overflow-x:auto}
@@ -12,8 +12,16 @@ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/de
12
12
  var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
13
13
  var _react = _interopRequireDefault(require("react"));
14
14
  var _chevronDown = _interopRequireDefault(require("@atlaskit/icon/core/chevron-down"));
15
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
15
16
  /* eslint-disable @atlaskit/ui-styling-standard/enforce-style-prop */
16
17
  var formInputBaseStyles = null;
18
+
19
+ /**
20
+ * By default, the visual pdf form elements are rendered by pdfium server side. Therefore we only
21
+ * show visibility of the html input if the user interacts with it. This allows us to show visually
22
+ * accurate PDF form elements while still allowing the user to interact with the input.
23
+ */
24
+ var invisibleInputStyles = null;
17
25
  var textInputStyles = null;
18
26
  var foreignObjectProps = {
19
27
  xmlns: 'http://www.w3.org/1999/xhtml'
@@ -33,7 +41,7 @@ var TextInput = function TextInput(_ref) {
33
41
  value: value,
34
42
  type: "text",
35
43
  readOnly: true,
36
- className: (0, _runtime.ax)(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _r06hglyw _14zgglyw", "_kqswstnw _4t3i1osq _vchhusvi _1bsb1osq"])
44
+ className: (0, _runtime.ax)(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _ect41ttw _vwz410nf _r06hglyw _14zgglyw", "_kqswstnw _4t3i1osq _vchhusvi _1bsb1osq", (0, _platformFeatureFlags.fg)('media-document-viewer-annotations') && "_1reo15vq _18m915vq _bfhk1j28 _syaz1j28 _p6m71wug _1chs1wug _jomru67f _f8pjr3uz"])
37
45
  }));
38
46
  };
39
47
  var TextInputFormField = exports.TextInputFormField = function TextInputFormField(_ref2) {
@@ -77,8 +85,8 @@ var ComboBoxFormField = exports.ComboBoxFormField = function ComboBoxFormField(_
77
85
  }
78
86
  },
79
87
  readOnly: true,
80
- className: (0, _runtime.ax)(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _r06hglyw _14zgglyw", "_1bsb1osq"])
81
- }), /*#__PURE__*/_react.default.createElement(_chevronDown.default, {
88
+ className: (0, _runtime.ax)(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _ect41ttw _vwz410nf _r06hglyw _14zgglyw", "_1bsb1osq", (0, _platformFeatureFlags.fg)('media-document-viewer-annotations') && "_1reo15vq _18m915vq _bfhk1j28 _syaz1j28 _p6m71wug _1chs1wug _jomru67f _f8pjr3uz"])
89
+ }), !(0, _platformFeatureFlags.fg)('media-document-viewer-annotations') && /*#__PURE__*/_react.default.createElement(_chevronDown.default, {
82
90
  label: "",
83
91
  size: "small"
84
92
  })));
@@ -19,6 +19,7 @@ var _useCachedGetImage = require("./utils/useCachedGetImage");
19
19
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(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 (var _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); }
20
20
  var documentViewerStyles = null;
21
21
  var DEFAULT_PAGINATION_SIZE = 50;
22
+ var DEFAULT_MAX_PAGE_IMAGE_ZOOM = 6;
22
23
  var DocumentViewer = exports.DocumentViewer = function DocumentViewer(_ref) {
23
24
  var _documentMetadata$pag;
24
25
  var onSuccess = _ref.onSuccess,
@@ -26,12 +27,14 @@ var DocumentViewer = exports.DocumentViewer = function DocumentViewer(_ref) {
26
27
  getPageImageUrl = _ref.getPageImageUrl,
27
28
  _ref$paginationSize = _ref.paginationSize,
28
29
  paginationSize = _ref$paginationSize === void 0 ? DEFAULT_PAGINATION_SIZE : _ref$paginationSize,
30
+ _ref$maxPageImageZoom = _ref.maxPageImageZoom,
31
+ maxPageImageZoom = _ref$maxPageImageZoom === void 0 ? DEFAULT_MAX_PAGE_IMAGE_ZOOM : _ref$maxPageImageZoom,
29
32
  zoom = _ref.zoom;
30
33
  var _usePageContent = (0, _usePageContent2.usePageContent)(getContent, paginationSize),
31
34
  getPageContent = _usePageContent.getPageContent,
32
35
  loadPageContent = _usePageContent.loadPageContent,
33
36
  documentMetadata = _usePageContent.documentMetadata;
34
- var getImageUrl = (0, _useCachedGetImage.useCachedGetImage)(getPageImageUrl);
37
+ var getImageUrl = (0, _useCachedGetImage.useCachedGetImage)(getPageImageUrl, maxPageImageZoom);
35
38
  var style = {
36
39
  '--document-viewer-zoom': zoom
37
40
  };
@@ -75,6 +78,7 @@ var DocumentViewer = exports.DocumentViewer = function DocumentViewer(_ref) {
75
78
  return /*#__PURE__*/React.createElement(_page.Page, {
76
79
  key: i,
77
80
  getPageSrc: getImageUrl,
81
+ maxPageImageZoom: maxPageImageZoom,
78
82
  pageIndex: i,
79
83
  zoom: zoom,
80
84
  defaultDimensions: documentMetadata.defaultDimensions,
package/dist/cjs/page.js CHANGED
@@ -14,10 +14,12 @@ var _runtime = require("@compiled/react/runtime");
14
14
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
15
15
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
16
16
  var _mediaCommon = require("@atlaskit/media-common");
17
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
17
18
  var _spinner = _interopRequireDefault(require("@atlaskit/spinner"));
18
19
  var _annotations = require("./annotations");
19
20
  var _documentLinks = require("./documentLinks");
20
21
  var _getDocumentRoot = require("./utils/getDocumentRoot");
22
+ var _useCachedGetImage = require("./utils/useCachedGetImage");
21
23
  var _useIntersectionObserver = require("./utils/useIntersectionObserver");
22
24
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function _interopRequireWildcard(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 (var _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); }
23
25
  var Span = function Span(_ref) {
@@ -67,6 +69,7 @@ var Line = function Line() {
67
69
  };
68
70
  var pageSvgStyles = null;
69
71
  var pageImageStyles = null;
72
+ var pixelatedImageRendering = null;
70
73
  var pageSpinnerStyles = null;
71
74
  var pageWrapperStyles = null;
72
75
  var a4Dimensions = {
@@ -112,7 +115,7 @@ var PageView = /*#__PURE__*/(0, _react.forwardRef)(function (_ref4, ref) {
112
115
  src: imageSrc,
113
116
  alt: "",
114
117
  onLoad: onImageLoad,
115
- className: (0, _runtime.ax)(["_kqswstnw _154iidpf _1ltvidpf _uiztglyw _1kemd8h4"])
118
+ className: (0, _runtime.ax)(["_kqswstnw _154iidpf _1ltvidpf _uiztglyw", !(0, _platformFeatureFlags.fg)('media-document-viewer-clear-render') && "_1kemd8h4"])
116
119
  }), content && /*#__PURE__*/React.createElement("svg", {
117
120
  "data-testid": "page-".concat(pageIndex, "-text-layer"),
118
121
  style: style,
@@ -135,6 +138,7 @@ var PageView = /*#__PURE__*/(0, _react.forwardRef)(function (_ref4, ref) {
135
138
  var Page = exports.Page = function Page(_ref5) {
136
139
  var _ref6;
137
140
  var getPageSrc = _ref5.getPageSrc,
141
+ maxPageImageZoom = _ref5.maxPageImageZoom,
138
142
  content = _ref5.content,
139
143
  fonts = _ref5.fonts,
140
144
  pageIndex = _ref5.pageIndex,
@@ -167,9 +171,12 @@ var Page = exports.Page = function Page(_ref5) {
167
171
  onLoad === null || onLoad === void 0 || onLoad();
168
172
  if (!content) {
169
173
  var _zoom = image.dataset.zoom ? Number(image.dataset.zoom) : 1;
174
+ var imageZoom = (0, _useCachedGetImage.getImageZoom)(_zoom, maxPageImageZoom);
175
+ var contentWidth = image.naturalWidth / imageZoom;
176
+ var contentHeight = image.naturalHeight / imageZoom;
170
177
  setDimensions({
171
- width: image.width / _zoom,
172
- height: image.height / _zoom
178
+ width: contentWidth,
179
+ height: contentHeight
173
180
  });
174
181
  }
175
182
  });
@@ -4,12 +4,14 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
+ exports.getImageZoom = getImageZoom;
7
8
  exports.useCachedGetImage = void 0;
8
9
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
9
10
  var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
10
11
  var _react = require("react");
11
12
  var _mediaCommon = require("@atlaskit/media-common");
12
- var useCachedGetImage = exports.useCachedGetImage = function useCachedGetImage(getPageImageUrl) {
13
+ var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
14
+ var useCachedGetImage = exports.useCachedGetImage = function useCachedGetImage(getPageImageUrl, maxPageImageZoom) {
13
15
  var imageUrlRefs = (0, _react.useRef)({});
14
16
  (0, _react.useEffect)(function () {
15
17
  return function () {
@@ -22,37 +24,38 @@ var useCachedGetImage = exports.useCachedGetImage = function useCachedGetImage(g
22
24
  }, []);
23
25
  var getImageUrl = (0, _mediaCommon.useStaticCallback)( /*#__PURE__*/function () {
24
26
  var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(pageNumber, zoom) {
25
- var key, url, isBlobUrl, blob;
27
+ var imageZoom, key, url, isBlobUrl, blob;
26
28
  return _regenerator.default.wrap(function _callee$(_context) {
27
29
  while (1) switch (_context.prev = _context.next) {
28
30
  case 0:
29
- key = "".concat(pageNumber, "-").concat(zoom);
31
+ imageZoom = getImageZoom(zoom, maxPageImageZoom);
32
+ key = "".concat(pageNumber, "-").concat(imageZoom);
30
33
  if (!imageUrlRefs.current[key]) {
31
- _context.next = 3;
34
+ _context.next = 4;
32
35
  break;
33
36
  }
34
37
  return _context.abrupt("return", imageUrlRefs.current[key]);
35
- case 3:
36
- _context.next = 5;
37
- return getPageImageUrl(pageNumber, zoom);
38
- case 5:
38
+ case 4:
39
+ _context.next = 6;
40
+ return getPageImageUrl(pageNumber, imageZoom);
41
+ case 6:
39
42
  url = _context.sent;
40
43
  isBlobUrl = url.startsWith('blob:');
41
44
  if (isBlobUrl) {
42
- _context.next = 12;
45
+ _context.next = 13;
43
46
  break;
44
47
  }
45
- _context.next = 10;
48
+ _context.next = 11;
46
49
  return fetch(url).then(function (res) {
47
50
  return res.blob();
48
51
  });
49
- case 10:
52
+ case 11:
50
53
  blob = _context.sent;
51
54
  url = URL.createObjectURL(blob);
52
- case 12:
55
+ case 13:
53
56
  imageUrlRefs.current[key] = url;
54
57
  return _context.abrupt("return", url);
55
- case 14:
58
+ case 15:
56
59
  case "end":
57
60
  return _context.stop();
58
61
  }
@@ -63,4 +66,21 @@ var useCachedGetImage = exports.useCachedGetImage = function useCachedGetImage(g
63
66
  };
64
67
  }());
65
68
  return getImageUrl;
66
- };
69
+ };
70
+
71
+ /**
72
+ * The actual zoom that will be requested from the image service.
73
+ *
74
+ * This is different from the 'zoom' prop because it is adjusted for the device pixel ratio.
75
+ * We're achieving the same result as a srcset, crisp images for high DPI screens.
76
+ *
77
+ * We also reduce impact of excessively slow rendering by setting a max zoom level.
78
+ * If the user is zoomed past this level, the image will just be scaled-up client side.
79
+ */
80
+ function getImageZoom(zoom, maxPageImageZoom) {
81
+ if (!(0, _platformFeatureFlags.fg)('media-document-viewer-clear-render')) {
82
+ return zoom;
83
+ }
84
+ var dpiAdjustedZoom = zoom * (window.devicePixelRatio || 1);
85
+ return Math.min(dpiAdjustedZoom, maxPageImageZoom);
86
+ }
@@ -1,15 +1,25 @@
1
1
 
2
2
  ._19itglyw{border:none}._14zgglyw{resize:none}
3
+ ._18m915vq{overflow-y:hidden}
3
4
  ._19bvidpf{padding-left:0}
4
5
  ._1bah1yb4{justify-content:space-between}
5
6
  ._1bsb1osq{width:100%}
6
7
  ._1e0c11p5{display:grid}
8
+ ._1reo15vq{overflow-x:hidden}
7
9
  ._4cvr1h6o{align-items:center}
8
10
  ._4t3i1osq{height:100%}
11
+ ._bfhk1j28{background-color:transparent}
9
12
  ._ca0qidpf{padding-top:0}
13
+ ._ect41ttw{font-family:Arial}
10
14
  ._kqswstnw{position:absolute}
11
15
  ._n3tdidpf{padding-bottom:0}
12
16
  ._r06hglyw{-webkit-appearance:none;appearance:none}
17
+ ._syaz1j28{color:transparent}
13
18
  ._u5f3idpf{padding-right:0}
14
19
  ._vchhusvi{box-sizing:border-box}
15
- ._yv0e1ghl{grid-template-columns:1fr auto}
20
+ ._vwz410nf{line-height:1.25}
21
+ ._yv0e1ghl{grid-template-columns:1fr auto}
22
+ ._1chs1wug:focus{overflow-y:auto}
23
+ ._f8pjr3uz:focus{color:#000}
24
+ ._jomru67f:focus{background-color:#fff}
25
+ ._p6m71wug:focus{overflow-x:auto}
@@ -6,7 +6,15 @@ import { ax, ix } from "@compiled/react/runtime";
6
6
 
7
7
  import React from 'react';
8
8
  import ChevronDownIcon from '@atlaskit/icon/core/chevron-down';
9
+ import { fg } from '@atlaskit/platform-feature-flags';
9
10
  const formInputBaseStyles = null;
11
+
12
+ /**
13
+ * By default, the visual pdf form elements are rendered by pdfium server side. Therefore we only
14
+ * show visibility of the html input if the user interacts with it. This allows us to show visually
15
+ * accurate PDF form elements while still allowing the user to interact with the input.
16
+ */
17
+ const invisibleInputStyles = null;
10
18
  const textInputStyles = null;
11
19
  const foreignObjectProps = {
12
20
  xmlns: 'http://www.w3.org/1999/xhtml'
@@ -26,7 +34,7 @@ const TextInput = ({
26
34
  value: value,
27
35
  type: "text",
28
36
  readOnly: true,
29
- className: ax(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _r06hglyw _14zgglyw", "_kqswstnw _4t3i1osq _vchhusvi _1bsb1osq"])
37
+ className: ax(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _ect41ttw _vwz410nf _r06hglyw _14zgglyw", "_kqswstnw _4t3i1osq _vchhusvi _1bsb1osq", fg('media-document-viewer-annotations') && "_1reo15vq _18m915vq _bfhk1j28 _syaz1j28 _p6m71wug _1chs1wug _jomru67f _f8pjr3uz"])
30
38
  }));
31
39
  export const TextInputFormField = ({
32
40
  field,
@@ -75,8 +83,8 @@ export const ComboBoxFormField = ({
75
83
  }
76
84
  },
77
85
  readOnly: true,
78
- className: ax(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _r06hglyw _14zgglyw", "_1bsb1osq"])
79
- }), /*#__PURE__*/React.createElement(ChevronDownIcon, {
86
+ className: ax(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _ect41ttw _vwz410nf _r06hglyw _14zgglyw", "_1bsb1osq", fg('media-document-viewer-annotations') && "_1reo15vq _18m915vq _bfhk1j28 _syaz1j28 _p6m71wug _1chs1wug _jomru67f _f8pjr3uz"])
87
+ }), !fg('media-document-viewer-annotations') && /*#__PURE__*/React.createElement(ChevronDownIcon, {
80
88
  label: "",
81
89
  size: "small"
82
90
  })));
@@ -9,11 +9,13 @@ import { getScrollElement } from './utils/getDocumentRoot';
9
9
  import { useCachedGetImage } from './utils/useCachedGetImage';
10
10
  const documentViewerStyles = null;
11
11
  const DEFAULT_PAGINATION_SIZE = 50;
12
+ const DEFAULT_MAX_PAGE_IMAGE_ZOOM = 6;
12
13
  export const DocumentViewer = ({
13
14
  onSuccess,
14
15
  getContent,
15
16
  getPageImageUrl,
16
17
  paginationSize = DEFAULT_PAGINATION_SIZE,
18
+ maxPageImageZoom = DEFAULT_MAX_PAGE_IMAGE_ZOOM,
17
19
  zoom
18
20
  }) => {
19
21
  var _documentMetadata$pag;
@@ -22,7 +24,7 @@ export const DocumentViewer = ({
22
24
  loadPageContent,
23
25
  documentMetadata
24
26
  } = usePageContent(getContent, paginationSize);
25
- const getImageUrl = useCachedGetImage(getPageImageUrl);
27
+ const getImageUrl = useCachedGetImage(getPageImageUrl, maxPageImageZoom);
26
28
  const style = {
27
29
  '--document-viewer-zoom': zoom
28
30
  };
@@ -67,6 +69,7 @@ export const DocumentViewer = ({
67
69
  return /*#__PURE__*/React.createElement(Page, {
68
70
  key: i,
69
71
  getPageSrc: getImageUrl,
72
+ maxPageImageZoom: maxPageImageZoom,
70
73
  pageIndex: i,
71
74
  zoom: zoom,
72
75
  defaultDimensions: documentMetadata.defaultDimensions,
@@ -4,10 +4,12 @@ import * as React from 'react';
4
4
  import { ax, ix } from "@compiled/react/runtime";
5
5
  import { forwardRef, useEffect, useState } from 'react';
6
6
  import { useStaticCallback } from '@atlaskit/media-common';
7
+ import { fg } from '@atlaskit/platform-feature-flags';
7
8
  import Spinner from '@atlaskit/spinner';
8
9
  import { Annotations } from './annotations';
9
10
  import { DocumentLinks } from './documentLinks';
10
11
  import { getDocumentRoot } from './utils/getDocumentRoot';
12
+ import { getImageZoom } from './utils/useCachedGetImage';
11
13
  import { useIntersectionObserver } from './utils/useIntersectionObserver';
12
14
  const Span = ({
13
15
  span,
@@ -56,6 +58,7 @@ const Line = ({
56
58
  })));
57
59
  const pageSvgStyles = null;
58
60
  const pageImageStyles = null;
61
+ const pixelatedImageRendering = null;
59
62
  const pageSpinnerStyles = null;
60
63
  const pageWrapperStyles = null;
61
64
  const a4Dimensions = {
@@ -102,7 +105,7 @@ const PageView = /*#__PURE__*/forwardRef(({
102
105
  src: imageSrc,
103
106
  alt: "",
104
107
  onLoad: onImageLoad,
105
- className: ax(["_kqswstnw _154iidpf _1ltvidpf _uiztglyw _1kemd8h4"])
108
+ className: ax(["_kqswstnw _154iidpf _1ltvidpf _uiztglyw", !fg('media-document-viewer-clear-render') && "_1kemd8h4"])
106
109
  }), content && /*#__PURE__*/React.createElement("svg", {
107
110
  "data-testid": `page-${pageIndex}-text-layer`,
108
111
  style: style,
@@ -122,6 +125,7 @@ const PageView = /*#__PURE__*/forwardRef(({
122
125
  });
123
126
  export const Page = ({
124
127
  getPageSrc,
128
+ maxPageImageZoom,
125
129
  content,
126
130
  fonts,
127
131
  pageIndex,
@@ -151,9 +155,12 @@ export const Page = ({
151
155
  onLoad === null || onLoad === void 0 ? void 0 : onLoad();
152
156
  if (!content) {
153
157
  const zoom = image.dataset.zoom ? Number(image.dataset.zoom) : 1;
158
+ const imageZoom = getImageZoom(zoom, maxPageImageZoom);
159
+ const contentWidth = image.naturalWidth / imageZoom;
160
+ const contentHeight = image.naturalHeight / imageZoom;
154
161
  setDimensions({
155
- width: image.width / zoom,
156
- height: image.height / zoom
162
+ width: contentWidth,
163
+ height: contentHeight
157
164
  });
158
165
  }
159
166
  });
@@ -1,6 +1,7 @@
1
1
  import { useEffect, useRef } from 'react';
2
2
  import { useStaticCallback } from '@atlaskit/media-common';
3
- export const useCachedGetImage = getPageImageUrl => {
3
+ import { fg } from '@atlaskit/platform-feature-flags';
4
+ export const useCachedGetImage = (getPageImageUrl, maxPageImageZoom) => {
4
5
  const imageUrlRefs = useRef({});
5
6
  useEffect(() => {
6
7
  return () => {
@@ -11,11 +12,12 @@ export const useCachedGetImage = getPageImageUrl => {
11
12
  };
12
13
  }, []);
13
14
  const getImageUrl = useStaticCallback(async (pageNumber, zoom) => {
14
- const key = `${pageNumber}-${zoom}`;
15
+ const imageZoom = getImageZoom(zoom, maxPageImageZoom);
16
+ const key = `${pageNumber}-${imageZoom}`;
15
17
  if (imageUrlRefs.current[key]) {
16
18
  return imageUrlRefs.current[key];
17
19
  }
18
- let url = await getPageImageUrl(pageNumber, zoom);
20
+ let url = await getPageImageUrl(pageNumber, imageZoom);
19
21
  const isBlobUrl = url.startsWith('blob:');
20
22
  if (!isBlobUrl) {
21
23
  const blob = await fetch(url).then(res => res.blob());
@@ -25,4 +27,21 @@ export const useCachedGetImage = getPageImageUrl => {
25
27
  return url;
26
28
  });
27
29
  return getImageUrl;
28
- };
30
+ };
31
+
32
+ /**
33
+ * The actual zoom that will be requested from the image service.
34
+ *
35
+ * This is different from the 'zoom' prop because it is adjusted for the device pixel ratio.
36
+ * We're achieving the same result as a srcset, crisp images for high DPI screens.
37
+ *
38
+ * We also reduce impact of excessively slow rendering by setting a max zoom level.
39
+ * If the user is zoomed past this level, the image will just be scaled-up client side.
40
+ */
41
+ export function getImageZoom(zoom, maxPageImageZoom) {
42
+ if (!fg('media-document-viewer-clear-render')) {
43
+ return zoom;
44
+ }
45
+ const dpiAdjustedZoom = zoom * (window.devicePixelRatio || 1);
46
+ return Math.min(dpiAdjustedZoom, maxPageImageZoom);
47
+ }
@@ -1,15 +1,25 @@
1
1
 
2
2
  ._19itglyw{border:none}._14zgglyw{resize:none}
3
+ ._18m915vq{overflow-y:hidden}
3
4
  ._19bvidpf{padding-left:0}
4
5
  ._1bah1yb4{justify-content:space-between}
5
6
  ._1bsb1osq{width:100%}
6
7
  ._1e0c11p5{display:grid}
8
+ ._1reo15vq{overflow-x:hidden}
7
9
  ._4cvr1h6o{align-items:center}
8
10
  ._4t3i1osq{height:100%}
11
+ ._bfhk1j28{background-color:transparent}
9
12
  ._ca0qidpf{padding-top:0}
13
+ ._ect41ttw{font-family:Arial}
10
14
  ._kqswstnw{position:absolute}
11
15
  ._n3tdidpf{padding-bottom:0}
12
16
  ._r06hglyw{-webkit-appearance:none;appearance:none}
17
+ ._syaz1j28{color:transparent}
13
18
  ._u5f3idpf{padding-right:0}
14
19
  ._vchhusvi{box-sizing:border-box}
15
- ._yv0e1ghl{grid-template-columns:1fr auto}
20
+ ._vwz410nf{line-height:1.25}
21
+ ._yv0e1ghl{grid-template-columns:1fr auto}
22
+ ._1chs1wug:focus{overflow-y:auto}
23
+ ._f8pjr3uz:focus{color:#000}
24
+ ._jomru67f:focus{background-color:#fff}
25
+ ._p6m71wug:focus{overflow-x:auto}
@@ -7,7 +7,15 @@ import { ax, ix } from "@compiled/react/runtime";
7
7
 
8
8
  import React from 'react';
9
9
  import ChevronDownIcon from '@atlaskit/icon/core/chevron-down';
10
+ import { fg } from '@atlaskit/platform-feature-flags';
10
11
  var formInputBaseStyles = null;
12
+
13
+ /**
14
+ * By default, the visual pdf form elements are rendered by pdfium server side. Therefore we only
15
+ * show visibility of the html input if the user interacts with it. This allows us to show visually
16
+ * accurate PDF form elements while still allowing the user to interact with the input.
17
+ */
18
+ var invisibleInputStyles = null;
11
19
  var textInputStyles = null;
12
20
  var foreignObjectProps = {
13
21
  xmlns: 'http://www.w3.org/1999/xhtml'
@@ -27,7 +35,7 @@ var TextInput = function TextInput(_ref) {
27
35
  value: value,
28
36
  type: "text",
29
37
  readOnly: true,
30
- className: ax(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _r06hglyw _14zgglyw", "_kqswstnw _4t3i1osq _vchhusvi _1bsb1osq"])
38
+ className: ax(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _ect41ttw _vwz410nf _r06hglyw _14zgglyw", "_kqswstnw _4t3i1osq _vchhusvi _1bsb1osq", fg('media-document-viewer-annotations') && "_1reo15vq _18m915vq _bfhk1j28 _syaz1j28 _p6m71wug _1chs1wug _jomru67f _f8pjr3uz"])
31
39
  }));
32
40
  };
33
41
  export var TextInputFormField = function TextInputFormField(_ref2) {
@@ -71,8 +79,8 @@ export var ComboBoxFormField = function ComboBoxFormField(_ref3) {
71
79
  }
72
80
  },
73
81
  readOnly: true,
74
- className: ax(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _r06hglyw _14zgglyw", "_1bsb1osq"])
75
- }), /*#__PURE__*/React.createElement(ChevronDownIcon, {
82
+ className: ax(["_19itglyw _ca0qidpf _u5f3idpf _n3tdidpf _19bvidpf _ect41ttw _vwz410nf _r06hglyw _14zgglyw", "_1bsb1osq", fg('media-document-viewer-annotations') && "_1reo15vq _18m915vq _bfhk1j28 _syaz1j28 _p6m71wug _1chs1wug _jomru67f _f8pjr3uz"])
83
+ }), !fg('media-document-viewer-annotations') && /*#__PURE__*/React.createElement(ChevronDownIcon, {
76
84
  label: "",
77
85
  size: "small"
78
86
  })));
@@ -10,6 +10,7 @@ import { getScrollElement } from './utils/getDocumentRoot';
10
10
  import { useCachedGetImage } from './utils/useCachedGetImage';
11
11
  var documentViewerStyles = null;
12
12
  var DEFAULT_PAGINATION_SIZE = 50;
13
+ var DEFAULT_MAX_PAGE_IMAGE_ZOOM = 6;
13
14
  export var DocumentViewer = function DocumentViewer(_ref) {
14
15
  var _documentMetadata$pag;
15
16
  var onSuccess = _ref.onSuccess,
@@ -17,12 +18,14 @@ export var DocumentViewer = function DocumentViewer(_ref) {
17
18
  getPageImageUrl = _ref.getPageImageUrl,
18
19
  _ref$paginationSize = _ref.paginationSize,
19
20
  paginationSize = _ref$paginationSize === void 0 ? DEFAULT_PAGINATION_SIZE : _ref$paginationSize,
21
+ _ref$maxPageImageZoom = _ref.maxPageImageZoom,
22
+ maxPageImageZoom = _ref$maxPageImageZoom === void 0 ? DEFAULT_MAX_PAGE_IMAGE_ZOOM : _ref$maxPageImageZoom,
20
23
  zoom = _ref.zoom;
21
24
  var _usePageContent = usePageContent(getContent, paginationSize),
22
25
  getPageContent = _usePageContent.getPageContent,
23
26
  loadPageContent = _usePageContent.loadPageContent,
24
27
  documentMetadata = _usePageContent.documentMetadata;
25
- var getImageUrl = useCachedGetImage(getPageImageUrl);
28
+ var getImageUrl = useCachedGetImage(getPageImageUrl, maxPageImageZoom);
26
29
  var style = {
27
30
  '--document-viewer-zoom': zoom
28
31
  };
@@ -66,6 +69,7 @@ export var DocumentViewer = function DocumentViewer(_ref) {
66
69
  return /*#__PURE__*/React.createElement(Page, {
67
70
  key: i,
68
71
  getPageSrc: getImageUrl,
72
+ maxPageImageZoom: maxPageImageZoom,
69
73
  pageIndex: i,
70
74
  zoom: zoom,
71
75
  defaultDimensions: documentMetadata.defaultDimensions,
package/dist/esm/page.js CHANGED
@@ -6,10 +6,12 @@ import * as React from 'react';
6
6
  import { ax, ix } from "@compiled/react/runtime";
7
7
  import { forwardRef, useEffect, useState } from 'react';
8
8
  import { useStaticCallback } from '@atlaskit/media-common';
9
+ import { fg } from '@atlaskit/platform-feature-flags';
9
10
  import Spinner from '@atlaskit/spinner';
10
11
  import { Annotations } from './annotations';
11
12
  import { DocumentLinks } from './documentLinks';
12
13
  import { getDocumentRoot } from './utils/getDocumentRoot';
14
+ import { getImageZoom } from './utils/useCachedGetImage';
13
15
  import { useIntersectionObserver } from './utils/useIntersectionObserver';
14
16
  var Span = function Span(_ref) {
15
17
  var span = _ref.span,
@@ -58,6 +60,7 @@ var Line = function Line() {
58
60
  };
59
61
  var pageSvgStyles = null;
60
62
  var pageImageStyles = null;
63
+ var pixelatedImageRendering = null;
61
64
  var pageSpinnerStyles = null;
62
65
  var pageWrapperStyles = null;
63
66
  var a4Dimensions = {
@@ -103,7 +106,7 @@ var PageView = /*#__PURE__*/forwardRef(function (_ref4, ref) {
103
106
  src: imageSrc,
104
107
  alt: "",
105
108
  onLoad: onImageLoad,
106
- className: ax(["_kqswstnw _154iidpf _1ltvidpf _uiztglyw _1kemd8h4"])
109
+ className: ax(["_kqswstnw _154iidpf _1ltvidpf _uiztglyw", !fg('media-document-viewer-clear-render') && "_1kemd8h4"])
107
110
  }), content && /*#__PURE__*/React.createElement("svg", {
108
111
  "data-testid": "page-".concat(pageIndex, "-text-layer"),
109
112
  style: style,
@@ -126,6 +129,7 @@ var PageView = /*#__PURE__*/forwardRef(function (_ref4, ref) {
126
129
  export var Page = function Page(_ref5) {
127
130
  var _ref6;
128
131
  var getPageSrc = _ref5.getPageSrc,
132
+ maxPageImageZoom = _ref5.maxPageImageZoom,
129
133
  content = _ref5.content,
130
134
  fonts = _ref5.fonts,
131
135
  pageIndex = _ref5.pageIndex,
@@ -158,9 +162,12 @@ export var Page = function Page(_ref5) {
158
162
  onLoad === null || onLoad === void 0 || onLoad();
159
163
  if (!content) {
160
164
  var _zoom = image.dataset.zoom ? Number(image.dataset.zoom) : 1;
165
+ var imageZoom = getImageZoom(_zoom, maxPageImageZoom);
166
+ var contentWidth = image.naturalWidth / imageZoom;
167
+ var contentHeight = image.naturalHeight / imageZoom;
161
168
  setDimensions({
162
- width: image.width / _zoom,
163
- height: image.height / _zoom
169
+ width: contentWidth,
170
+ height: contentHeight
164
171
  });
165
172
  }
166
173
  });
@@ -2,7 +2,8 @@ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
2
  import _regeneratorRuntime from "@babel/runtime/regenerator";
3
3
  import { useEffect, useRef } from 'react';
4
4
  import { useStaticCallback } from '@atlaskit/media-common';
5
- export var useCachedGetImage = function useCachedGetImage(getPageImageUrl) {
5
+ import { fg } from '@atlaskit/platform-feature-flags';
6
+ export var useCachedGetImage = function useCachedGetImage(getPageImageUrl, maxPageImageZoom) {
6
7
  var imageUrlRefs = useRef({});
7
8
  useEffect(function () {
8
9
  return function () {
@@ -15,37 +16,38 @@ export var useCachedGetImage = function useCachedGetImage(getPageImageUrl) {
15
16
  }, []);
16
17
  var getImageUrl = useStaticCallback( /*#__PURE__*/function () {
17
18
  var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(pageNumber, zoom) {
18
- var key, url, isBlobUrl, blob;
19
+ var imageZoom, key, url, isBlobUrl, blob;
19
20
  return _regeneratorRuntime.wrap(function _callee$(_context) {
20
21
  while (1) switch (_context.prev = _context.next) {
21
22
  case 0:
22
- key = "".concat(pageNumber, "-").concat(zoom);
23
+ imageZoom = getImageZoom(zoom, maxPageImageZoom);
24
+ key = "".concat(pageNumber, "-").concat(imageZoom);
23
25
  if (!imageUrlRefs.current[key]) {
24
- _context.next = 3;
26
+ _context.next = 4;
25
27
  break;
26
28
  }
27
29
  return _context.abrupt("return", imageUrlRefs.current[key]);
28
- case 3:
29
- _context.next = 5;
30
- return getPageImageUrl(pageNumber, zoom);
31
- case 5:
30
+ case 4:
31
+ _context.next = 6;
32
+ return getPageImageUrl(pageNumber, imageZoom);
33
+ case 6:
32
34
  url = _context.sent;
33
35
  isBlobUrl = url.startsWith('blob:');
34
36
  if (isBlobUrl) {
35
- _context.next = 12;
37
+ _context.next = 13;
36
38
  break;
37
39
  }
38
- _context.next = 10;
40
+ _context.next = 11;
39
41
  return fetch(url).then(function (res) {
40
42
  return res.blob();
41
43
  });
42
- case 10:
44
+ case 11:
43
45
  blob = _context.sent;
44
46
  url = URL.createObjectURL(blob);
45
- case 12:
47
+ case 13:
46
48
  imageUrlRefs.current[key] = url;
47
49
  return _context.abrupt("return", url);
48
- case 14:
50
+ case 15:
49
51
  case "end":
50
52
  return _context.stop();
51
53
  }
@@ -56,4 +58,21 @@ export var useCachedGetImage = function useCachedGetImage(getPageImageUrl) {
56
58
  };
57
59
  }());
58
60
  return getImageUrl;
59
- };
61
+ };
62
+
63
+ /**
64
+ * The actual zoom that will be requested from the image service.
65
+ *
66
+ * This is different from the 'zoom' prop because it is adjusted for the device pixel ratio.
67
+ * We're achieving the same result as a srcset, crisp images for high DPI screens.
68
+ *
69
+ * We also reduce impact of excessively slow rendering by setting a max zoom level.
70
+ * If the user is zoomed past this level, the image will just be scaled-up client side.
71
+ */
72
+ export function getImageZoom(zoom, maxPageImageZoom) {
73
+ if (!fg('media-document-viewer-clear-render')) {
74
+ return zoom;
75
+ }
76
+ var dpiAdjustedZoom = zoom * (window.devicePixelRatio || 1);
77
+ return Math.min(dpiAdjustedZoom, maxPageImageZoom);
78
+ }
@@ -1,10 +1,17 @@
1
1
  import { type PageRangeContent } from './types';
2
- type DocumentViewerProps = {
2
+ export type DocumentViewerProps = {
3
3
  getContent: (pageStart: number, pageEnd: number) => Promise<PageRangeContent>;
4
4
  getPageImageUrl: (pageNumber: number, zoom: number) => Promise<string>;
5
5
  paginationSize?: number;
6
+ /**
7
+ * The maximum zoom level that will be requested from the image service.
8
+ * This is used to prevent the page from being too large to render server side in a reasonable time.
9
+ *
10
+ * The 'zoom' prop can still be greater than this value, but the server side image service will return
11
+ * a smaller image and the image will be scaled-up client side.
12
+ */
13
+ maxPageImageZoom?: number;
6
14
  zoom: number;
7
15
  onSuccess?: () => void;
8
16
  };
9
- export declare const DocumentViewer: ({ onSuccess, getContent, getPageImageUrl, paginationSize, zoom, }: DocumentViewerProps) => JSX.Element;
10
- export {};
17
+ export declare const DocumentViewer: ({ onSuccess, getContent, getPageImageUrl, paginationSize, maxPageImageZoom, zoom, }: DocumentViewerProps) => JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { type Font, type PageContent } from './types';
2
2
  type PageProps = {
3
3
  getPageSrc: (pageIndex: number, zoom: number) => Promise<string>;
4
+ maxPageImageZoom: number;
4
5
  content?: PageContent;
5
6
  fonts: readonly Font[];
6
7
  pageIndex: number;
@@ -12,5 +13,5 @@ type PageProps = {
12
13
  onVisible: () => void;
13
14
  onLoad?: () => void;
14
15
  };
15
- export declare const Page: ({ getPageSrc, content, fonts, pageIndex, zoom, defaultDimensions, onVisible, onLoad, }: PageProps) => JSX.Element;
16
+ export declare const Page: ({ getPageSrc, maxPageImageZoom, content, fonts, pageIndex, zoom, defaultDimensions, onVisible, onLoad, }: PageProps) => JSX.Element;
16
17
  export {};
@@ -1 +1,11 @@
1
- export declare const useCachedGetImage: (getPageImageUrl: (pageNumber: number, zoom: number) => Promise<string>) => (pageNumber: number, zoom: number) => Promise<string>;
1
+ export declare const useCachedGetImage: (getPageImageUrl: (pageNumber: number, zoom: number) => Promise<string>, maxPageImageZoom: number) => (pageNumber: number, zoom: number) => Promise<string>;
2
+ /**
3
+ * The actual zoom that will be requested from the image service.
4
+ *
5
+ * This is different from the 'zoom' prop because it is adjusted for the device pixel ratio.
6
+ * We're achieving the same result as a srcset, crisp images for high DPI screens.
7
+ *
8
+ * We also reduce impact of excessively slow rendering by setting a max zoom level.
9
+ * If the user is zoomed past this level, the image will just be scaled-up client side.
10
+ */
11
+ export declare function getImageZoom(zoom: number, maxPageImageZoom: number): number;
@@ -1,10 +1,17 @@
1
1
  import { type PageRangeContent } from './types';
2
- type DocumentViewerProps = {
2
+ export type DocumentViewerProps = {
3
3
  getContent: (pageStart: number, pageEnd: number) => Promise<PageRangeContent>;
4
4
  getPageImageUrl: (pageNumber: number, zoom: number) => Promise<string>;
5
5
  paginationSize?: number;
6
+ /**
7
+ * The maximum zoom level that will be requested from the image service.
8
+ * This is used to prevent the page from being too large to render server side in a reasonable time.
9
+ *
10
+ * The 'zoom' prop can still be greater than this value, but the server side image service will return
11
+ * a smaller image and the image will be scaled-up client side.
12
+ */
13
+ maxPageImageZoom?: number;
6
14
  zoom: number;
7
15
  onSuccess?: () => void;
8
16
  };
9
- export declare const DocumentViewer: ({ onSuccess, getContent, getPageImageUrl, paginationSize, zoom, }: DocumentViewerProps) => JSX.Element;
10
- export {};
17
+ export declare const DocumentViewer: ({ onSuccess, getContent, getPageImageUrl, paginationSize, maxPageImageZoom, zoom, }: DocumentViewerProps) => JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { type Font, type PageContent } from './types';
2
2
  type PageProps = {
3
3
  getPageSrc: (pageIndex: number, zoom: number) => Promise<string>;
4
+ maxPageImageZoom: number;
4
5
  content?: PageContent;
5
6
  fonts: readonly Font[];
6
7
  pageIndex: number;
@@ -12,5 +13,5 @@ type PageProps = {
12
13
  onVisible: () => void;
13
14
  onLoad?: () => void;
14
15
  };
15
- export declare const Page: ({ getPageSrc, content, fonts, pageIndex, zoom, defaultDimensions, onVisible, onLoad, }: PageProps) => JSX.Element;
16
+ export declare const Page: ({ getPageSrc, maxPageImageZoom, content, fonts, pageIndex, zoom, defaultDimensions, onVisible, onLoad, }: PageProps) => JSX.Element;
16
17
  export {};
@@ -1 +1,11 @@
1
- export declare const useCachedGetImage: (getPageImageUrl: (pageNumber: number, zoom: number) => Promise<string>) => (pageNumber: number, zoom: number) => Promise<string>;
1
+ export declare const useCachedGetImage: (getPageImageUrl: (pageNumber: number, zoom: number) => Promise<string>, maxPageImageZoom: number) => (pageNumber: number, zoom: number) => Promise<string>;
2
+ /**
3
+ * The actual zoom that will be requested from the image service.
4
+ *
5
+ * This is different from the 'zoom' prop because it is adjusted for the device pixel ratio.
6
+ * We're achieving the same result as a srcset, crisp images for high DPI screens.
7
+ *
8
+ * We also reduce impact of excessively slow rendering by setting a max zoom level.
9
+ * If the user is zoomed past this level, the image will just be scaled-up client side.
10
+ */
11
+ export declare function getImageZoom(zoom: number, maxPageImageZoom: number): number;
package/package.json CHANGED
@@ -28,7 +28,8 @@
28
28
  "@atlaskit/css": "^0.15.0",
29
29
  "@atlaskit/icon": "^28.5.0",
30
30
  "@atlaskit/media-common": "^12.3.0",
31
- "@atlaskit/primitives": "^15.0.0",
31
+ "@atlaskit/platform-feature-flags": "^1.1.0",
32
+ "@atlaskit/primitives": "^16.0.0",
32
33
  "@atlaskit/spinner": "^19.0.0",
33
34
  "@atlaskit/tokens": "^7.0.0",
34
35
  "@babel/runtime": "^7.0.0",
@@ -41,10 +42,19 @@
41
42
  "@af/integration-testing": "workspace:^",
42
43
  "@af/visual-regression": "workspace:^",
43
44
  "@atlaskit/ssr": "workspace:^",
45
+ "@atlassian/feature-flags-test-utils": "^1.0.0",
44
46
  "@testing-library/react": "^13.4.0",
45
47
  "@testing-library/user-event": "^14.4.3",
46
48
  "react-dom": "^18.2.0"
47
49
  },
50
+ "platform-feature-flags": {
51
+ "media-document-viewer-clear-render": {
52
+ "type": "boolean"
53
+ },
54
+ "media-document-viewer-annotations": {
55
+ "type": "boolean"
56
+ }
57
+ },
48
58
  "techstack": {
49
59
  "@atlassian/frontend": {
50
60
  "import-structure": [
@@ -81,7 +91,7 @@
81
91
  }
82
92
  },
83
93
  "name": "@atlaskit/media-document-viewer",
84
- "version": "0.4.3",
94
+ "version": "0.5.0",
85
95
  "description": "Modern and fast document viewer",
86
96
  "author": "Atlassian Pty Ltd",
87
97
  "license": "Apache-2.0",