@uncinc/uncinc-react-kitchen-sink 2.23.1 → 2.24.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.
@@ -19,7 +19,8 @@ export var Checkbox = function Checkbox(props) {
19
19
  className = props.className,
20
20
  wrapperClassName = props.wrapperClassName,
21
21
  disabled = props.disabled,
22
- id = props.id;
22
+ id = props.id,
23
+ descriptionAboveInput = props.descriptionAboveInput;
23
24
  var _useExtendedFormikCon = useExtendedFormikContext(),
24
25
  values = _useExtendedFormikCon.values,
25
26
  errors = _useExtendedFormikCon.errors,
@@ -49,7 +50,8 @@ export var Checkbox = function Checkbox(props) {
49
50
  error: error,
50
51
  errorId: errorId,
51
52
  descriptionId: descriptionId,
52
- displayRequiredIndicator: displayRequiredIndicator
53
+ displayRequiredIndicator: displayRequiredIndicator,
54
+ descriptionAboveInput: descriptionAboveInput
53
55
  }, /*#__PURE__*/React.createElement(Field, {
54
56
  required: required,
55
57
  name: fieldName,
@@ -125,7 +125,8 @@ var Checkboxes = function Checkboxes(props) {
125
125
  otherLabel = props.otherLabel,
126
126
  otherPlaceholder = props.otherPlaceholder,
127
127
  onChange = props.onChange,
128
- includeFieldSet = props.includeFieldSet;
128
+ includeFieldSet = props.includeFieldSet,
129
+ descriptionAboveInput = props.descriptionAboveInput;
129
130
  var _useExtendedFormikCon = useExtendedFormikContext(),
130
131
  errors = _useExtendedFormikCon.errors,
131
132
  touched = _useExtendedFormikCon.touched,
@@ -156,7 +157,8 @@ var Checkboxes = function Checkboxes(props) {
156
157
  isTouched: isTouched,
157
158
  descriptionId: descriptionId,
158
159
  displayRequiredIndicator: displayRequiredIndicator,
159
- includeFieldSet: includeFieldSet
160
+ includeFieldSet: includeFieldSet,
161
+ descriptionAboveInput: descriptionAboveInput
160
162
  }, Object.keys(options).map(function (item) {
161
163
  var label = _typeof(options[item]) === 'object' ? options[item].label : options[item];
162
164
  var value = _typeof(options[item]) === 'object' ? options[item].value : item;
@@ -15,6 +15,7 @@ export declare interface PDFReaderProps {
15
15
  height?: number;
16
16
  dualPageWidthThreshold?: number;
17
17
  defaultScale?: number;
18
+ scrollable?: boolean;
18
19
  }
19
20
  declare const PDFReader: React.FC<PDFReaderProps>;
20
21
  export default PDFReader;
@@ -1,3 +1,9 @@
1
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
2
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
6
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
1
7
  function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
2
8
  function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
9
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
@@ -9,6 +15,7 @@ import { Document, Page, pdfjs } from 'react-pdf';
9
15
  // @ts-ignore
10
16
  import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry';
11
17
  import ControlPanel from './ControlPanel';
18
+ import useScrollablePDF from './useScrollablePDF';
12
19
  import 'react-pdf/dist/esm/Page/TextLayer.css';
13
20
  import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
14
21
  import useWindowDimensions from '../../hooks/useWindowDimensions';
@@ -31,7 +38,10 @@ var PDFReader = function PDFReader(_ref) {
31
38
  dualPageWidthThreshold = _ref.dualPageWidthThreshold,
32
39
  _ref$defaultScale = _ref.defaultScale,
33
40
  defaultScale = _ref$defaultScale === void 0 ? 1.0 : _ref$defaultScale,
34
- downloadName = _ref.downloadName;
41
+ downloadName = _ref.downloadName,
42
+ _ref$scrollable = _ref.scrollable,
43
+ scrollable = _ref$scrollable === void 0 ? false : _ref$scrollable;
44
+ // Common state
35
45
  var _useState = useState(defaultScale),
36
46
  _useState2 = _slicedToArray(_useState, 2),
37
47
  scale = _useState2[0],
@@ -44,18 +54,37 @@ var PDFReader = function PDFReader(_ref) {
44
54
  _useState6 = _slicedToArray(_useState5, 2),
45
55
  pageNumber = _useState6[0],
46
56
  setPageNumber = _useState6[1];
57
+ var _useWindowDimensions = useWindowDimensions(),
58
+ windowWidth = _useWindowDimensions.width;
59
+
60
+ // Paginated mode state
47
61
  var _useState7 = useState(1),
48
62
  _useState8 = _slicedToArray(_useState7, 2),
49
63
  renderedPageNumber = _useState8[0],
50
64
  setRenderedPageNumber = _useState8[1];
51
- var _useWindowDimensions = useWindowDimensions(),
52
- windowWidth = _useWindowDimensions.width;
53
65
  var isLoading = renderedPageNumber !== pageNumber;
66
+ var showDualPage = !scrollable && dualPageWidthThreshold ? windowWidth > dualPageWidthThreshold : false;
67
+
68
+ // Scrollable mode hook
69
+ var _useScrollablePDF = useScrollablePDF({
70
+ scrollable: scrollable,
71
+ numPages: numPages,
72
+ scale: scale,
73
+ width: width,
74
+ setScale: setScale,
75
+ setPageNumber: setPageNumber
76
+ }),
77
+ scrollContainerRef = _useScrollablePDF.scrollContainerRef,
78
+ visiblePages = _useScrollablePDF.visiblePages,
79
+ estimatedPageHeight = _useScrollablePDF.estimatedPageHeight,
80
+ handleSetScale = _useScrollablePDF.handleSetScale,
81
+ handleSetPageNumber = _useScrollablePDF.handleSetPageNumber;
54
82
  var onDocumentLoadSuccess = function onDocumentLoadSuccess(_ref2) {
55
83
  var numPagesTemp = _ref2.numPages;
56
84
  setNumPages(numPagesTemp);
57
85
  };
58
- var showDualPage = dualPageWidthThreshold ? windowWidth > dualPageWidthThreshold : false;
86
+
87
+ // Paginated mode: render page with loading transition
59
88
  var renderPage = function renderPage(pageNumberToRender, isPageLoading, renderedPageNum) {
60
89
  return /*#__PURE__*/React.createElement(React.Fragment, null, isPageLoading && renderedPageNum ? /*#__PURE__*/React.createElement(Page, {
61
90
  key: renderedPageNum,
@@ -75,12 +104,56 @@ var PDFReader = function PDFReader(_ref) {
75
104
  }
76
105
  }));
77
106
  };
107
+
108
+ // Scrollable mode: render all pages in a scroll container with lazy loading
109
+ var renderScrollablePages = function renderScrollablePages() {
110
+ return /*#__PURE__*/React.createElement("div", {
111
+ ref: scrollContainerRef,
112
+ className: "PDFReader__scrollContainer",
113
+ style: {
114
+ overflow: 'auto',
115
+ maxHeight: '80vh',
116
+ width: '100%',
117
+ WebkitOverflowScrolling: 'touch'
118
+ }
119
+ }, Array.from({
120
+ length: numPages
121
+ }, function (_, i) {
122
+ return i + 1;
123
+ }).map(function (pageNum) {
124
+ return /*#__PURE__*/React.createElement("div", {
125
+ key: pageNum,
126
+ "data-page-number": pageNum,
127
+ className: "PDFReader__pageWrapper",
128
+ style: _objectSpread({
129
+ marginBottom: pageNum < numPages ? '8px' : undefined
130
+ }, !visiblePages.has(pageNum) ? {
131
+ height: "".concat(estimatedPageHeight, "px")
132
+ } : {})
133
+ }, visiblePages.has(pageNum) && /*#__PURE__*/React.createElement(Page, {
134
+ pageNumber: pageNum,
135
+ scale: scale,
136
+ width: width,
137
+ height: height
138
+ }));
139
+ }));
140
+ };
141
+
142
+ // Paginated mode: render single or dual page view
143
+ var renderPaginatedPages = function renderPaginatedPages() {
144
+ if (showDualPage) {
145
+ return /*#__PURE__*/React.createElement("div", {
146
+ className: "PDFReader__dualPage"
147
+ }, renderPage(pageNumber, isLoading, renderedPageNumber), pageNumber < numPages && renderPage(pageNumber + 1, isLoading, renderedPageNumber + 1));
148
+ }
149
+ return renderPage(pageNumber, isLoading, renderedPageNumber);
150
+ };
78
151
  return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(ControlPanel, {
79
152
  scale: scale,
80
- setScale: setScale,
153
+ setScale: handleSetScale,
81
154
  numPages: numPages,
82
155
  pageNumber: pageNumber,
83
- setPageNumber: setPageNumber,
156
+ setPageNumber: handleSetPageNumber,
84
157
  file: url,
85
158
  goToFirstPageButton: goToFirstPageButton,
86
159
  goToPreviousPageButton: goToPreviousPageButton,
@@ -97,8 +170,6 @@ var PDFReader = function PDFReader(_ref) {
97
170
  onLoadSuccess: onDocumentLoadSuccess,
98
171
  onLoadError: console.error,
99
172
  loading: loader
100
- }, showDualPage ? /*#__PURE__*/React.createElement("div", {
101
- className: "PDFReader__dualPage"
102
- }, renderPage(pageNumber, isLoading, renderedPageNumber), pageNumber < numPages && renderPage(pageNumber + 1, isLoading, renderedPageNumber + 1)) : renderPage(pageNumber, isLoading, renderedPageNumber)));
173
+ }, scrollable ? renderScrollablePages() : renderPaginatedPages()));
103
174
  };
104
175
  export default PDFReader;
@@ -0,0 +1,26 @@
1
+ /// <reference types="react" />
2
+ interface UseScrollablePDFOptions {
3
+ scrollable: boolean;
4
+ numPages: number;
5
+ scale: number;
6
+ width?: number;
7
+ setScale: (scale: number) => void;
8
+ setPageNumber: (page: number) => void;
9
+ }
10
+ /**
11
+ * Encapsulates all scrollable PDF viewer logic:
12
+ * - IntersectionObserver for lazy page rendering
13
+ * - Scroll-driven page tracking
14
+ * - Zoom scroll position preservation
15
+ * - Scroll-to-page on page input change
16
+ *
17
+ * When `scrollable` is false, all handlers are pass-through (no-op wrappers).
18
+ */
19
+ declare const useScrollablePDF: ({ scrollable, numPages, scale, width, setScale, setPageNumber, }: UseScrollablePDFOptions) => {
20
+ scrollContainerRef: import("react").RefObject<HTMLDivElement>;
21
+ visiblePages: Set<number>;
22
+ estimatedPageHeight: number;
23
+ handleSetScale: (newScale: number) => void;
24
+ handleSetPageNumber: (page: number) => void;
25
+ };
26
+ export default useScrollablePDF;
@@ -0,0 +1,157 @@
1
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
2
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
3
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
4
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
5
+ function _iterableToArrayLimit(arr, i) { var _i = null == arr ? null : "undefined" != typeof Symbol && arr[Symbol.iterator] || arr["@@iterator"]; if (null != _i) { var _s, _e, _x, _r, _arr = [], _n = !0, _d = !1; try { if (_x = (_i = _i.call(arr)).next, 0 === i) { if (Object(_i) !== _i) return; _n = !1; } else for (; !(_n = (_s = _x.call(_i)).done) && (_arr.push(_s.value), _arr.length !== i); _n = !0); } catch (err) { _d = !0, _e = err; } finally { try { if (!_n && null != _i.return && (_r = _i.return(), Object(_r) !== _r)) return; } finally { if (_d) throw _e; } } return _arr; } }
6
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
7
+ import { useRef, useEffect, useCallback, useMemo, useState } from 'react';
8
+ var A4_RATIO = 297 / 210;
9
+ /**
10
+ * Encapsulates all scrollable PDF viewer logic:
11
+ * - IntersectionObserver for lazy page rendering
12
+ * - Scroll-driven page tracking
13
+ * - Zoom scroll position preservation
14
+ * - Scroll-to-page on page input change
15
+ *
16
+ * When `scrollable` is false, all handlers are pass-through (no-op wrappers).
17
+ */
18
+ var useScrollablePDF = function useScrollablePDF(_ref) {
19
+ var scrollable = _ref.scrollable,
20
+ numPages = _ref.numPages,
21
+ scale = _ref.scale,
22
+ width = _ref.width,
23
+ setScale = _ref.setScale,
24
+ setPageNumber = _ref.setPageNumber;
25
+ var DEFAULT_PAGE_WIDTH = 600;
26
+ var scrollContainerRef = useRef(null);
27
+ var observerRef = useRef(null);
28
+ var _useState = useState(new Set()),
29
+ _useState2 = _slicedToArray(_useState, 2),
30
+ visiblePages = _useState2[0],
31
+ setVisiblePages = _useState2[1];
32
+ var scrollRatioRef = useRef(0);
33
+ var isZoomingRef = useRef(false);
34
+ var isScrollingToPageRef = useRef(false);
35
+ var rafRef = useRef(0);
36
+
37
+ // Estimated page height for placeholders (A4 ratio)
38
+ var estimatedPageHeight = useMemo(function () {
39
+ var pageWidth = width || DEFAULT_PAGE_WIDTH;
40
+ return pageWidth * A4_RATIO;
41
+ }, [width]);
42
+
43
+ // IntersectionObserver: lazy-render pages in/near the viewport
44
+ useEffect(function () {
45
+ var _observerRef$current;
46
+ if (!scrollable || numPages === 0) return undefined;
47
+ var container = scrollContainerRef.current;
48
+ if (!container) return undefined;
49
+ (_observerRef$current = observerRef.current) === null || _observerRef$current === void 0 ? void 0 : _observerRef$current.disconnect();
50
+ var observer = new IntersectionObserver(function (entries) {
51
+ setVisiblePages(function (prev) {
52
+ var next = new Set(prev);
53
+ entries.forEach(function (entry) {
54
+ var pageNum = Number(entry.target.getAttribute('data-page-number'));
55
+ if (entry.isIntersecting) {
56
+ next.add(pageNum);
57
+ } else {
58
+ next.delete(pageNum);
59
+ }
60
+ });
61
+ return next;
62
+ });
63
+ }, {
64
+ root: container,
65
+ rootMargin: '200% 0px',
66
+ threshold: 0
67
+ });
68
+ observerRef.current = observer;
69
+ container.querySelectorAll('[data-page-number]').forEach(function (el) {
70
+ observer.observe(el);
71
+ });
72
+ return function () {
73
+ return observer.disconnect();
74
+ };
75
+ }, [scrollable, numPages]);
76
+
77
+ // Scroll handler: track which page is currently most visible
78
+ useEffect(function () {
79
+ if (!scrollable || numPages === 0) return undefined;
80
+ var container = scrollContainerRef.current;
81
+ if (!container) return undefined;
82
+ var handleScroll = function handleScroll() {
83
+ if (isScrollingToPageRef.current) return;
84
+ cancelAnimationFrame(rafRef.current);
85
+ rafRef.current = requestAnimationFrame(function () {
86
+ var containerRect = container.getBoundingClientRect();
87
+ var containerMidY = containerRect.top + containerRect.height / 2;
88
+ var closestPage = 1;
89
+ var closestDistance = Infinity;
90
+ container.querySelectorAll('[data-page-number]').forEach(function (el) {
91
+ var rect = el.getBoundingClientRect();
92
+ var pageMidY = rect.top + rect.height / 2;
93
+ var distance = Math.abs(pageMidY - containerMidY);
94
+ if (distance < closestDistance) {
95
+ closestDistance = distance;
96
+ closestPage = Number(el.getAttribute('data-page-number'));
97
+ }
98
+ });
99
+ setPageNumber(closestPage);
100
+ });
101
+ };
102
+ container.addEventListener('scroll', handleScroll, {
103
+ passive: true
104
+ });
105
+ return function () {
106
+ container.removeEventListener('scroll', handleScroll);
107
+ cancelAnimationFrame(rafRef.current);
108
+ };
109
+ }, [scrollable, numPages, setPageNumber]);
110
+
111
+ // Preserve scroll position after zoom
112
+ useEffect(function () {
113
+ if (!scrollable || !isZoomingRef.current) return;
114
+ var container = scrollContainerRef.current;
115
+ if (!container) return;
116
+ requestAnimationFrame(function () {
117
+ container.scrollTop = scrollRatioRef.current * container.scrollHeight;
118
+ isZoomingRef.current = false;
119
+ });
120
+ }, [scale, scrollable]);
121
+
122
+ // Wrapped setScale: saves scroll position before zoom change
123
+ var handleSetScale = useCallback(function (newScale) {
124
+ if (scrollable && scrollContainerRef.current) {
125
+ var container = scrollContainerRef.current;
126
+ scrollRatioRef.current = container.scrollTop / container.scrollHeight;
127
+ isZoomingRef.current = true;
128
+ }
129
+ setScale(newScale);
130
+ }, [scrollable, setScale]);
131
+
132
+ // Wrapped setPageNumber: scrolls to page in scrollable mode
133
+ var handleSetPageNumber = useCallback(function (page) {
134
+ if (scrollable && scrollContainerRef.current) {
135
+ isScrollingToPageRef.current = true;
136
+ var target = scrollContainerRef.current.querySelector("[data-page-number=\"".concat(page, "\"]"));
137
+ target === null || target === void 0 ? void 0 : target.scrollIntoView({
138
+ behavior: 'smooth',
139
+ block: 'start'
140
+ });
141
+
142
+ // Re-enable scroll tracking after animation completes
143
+ setTimeout(function () {
144
+ isScrollingToPageRef.current = false;
145
+ }, 1000);
146
+ }
147
+ setPageNumber(page);
148
+ }, [scrollable, setPageNumber]);
149
+ return {
150
+ scrollContainerRef: scrollContainerRef,
151
+ visiblePages: visiblePages,
152
+ estimatedPageHeight: estimatedPageHeight,
153
+ handleSetScale: handleSetScale,
154
+ handleSetPageNumber: handleSetPageNumber
155
+ };
156
+ };
157
+ export default useScrollablePDF;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uncinc/uncinc-react-kitchen-sink",
3
- "version": "2.23.1",
3
+ "version": "2.24.0",
4
4
  "description": "Default React components that are easily extended.",
5
5
  "author": "uncinc",
6
6
  "license": "MIT",