@papyrus-sdk/ui-react 0.2.15 → 0.2.17

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/index.js CHANGED
@@ -1366,6 +1366,7 @@ var import_react4 = require("react");
1366
1366
  var import_core4 = require("@papyrus-sdk/core");
1367
1367
  var import_types = require("@papyrus-sdk/types");
1368
1368
  var import_jsx_runtime4 = require("react/jsx-runtime");
1369
+ var SCALE_PRECISION = 1e3;
1369
1370
  var PageRenderer = ({
1370
1371
  engine,
1371
1372
  pageIndex,
@@ -1437,21 +1438,22 @@ var PageRenderer = ({
1437
1438
  if (!availableWidth || !pageSize?.width) return 1;
1438
1439
  const targetWidth = Math.max(0, availableWidth - 48);
1439
1440
  if (!targetWidth) return 1;
1440
- return Math.min(1, targetWidth / pageSize.width);
1441
+ const rawScale = Math.min(1, targetWidth / pageSize.width);
1442
+ return Math.round(rawScale * SCALE_PRECISION) / SCALE_PRECISION;
1441
1443
  }, [availableWidth, pageSize]);
1442
1444
  const displaySize = (0, import_react4.useMemo)(() => {
1443
1445
  if (!pageSize) return null;
1444
1446
  const scale = zoom * fitScale;
1445
1447
  return {
1446
- width: pageSize.width * scale,
1447
- height: pageSize.height * scale
1448
+ width: Math.max(1, Math.round(pageSize.width * scale)),
1449
+ height: Math.max(1, Math.round(pageSize.height * scale))
1448
1450
  };
1449
1451
  }, [pageSize, zoom, fitScale]);
1450
1452
  (0, import_react4.useEffect)(() => {
1451
1453
  if (!displaySize || !onMeasuredSize) return;
1452
1454
  onMeasuredSize(pageIndex, {
1453
- width: Math.round(displaySize.width),
1454
- height: Math.round(displaySize.height)
1455
+ width: displaySize.width,
1456
+ height: displaySize.height
1455
1457
  });
1456
1458
  }, [displaySize, onMeasuredSize, pageIndex]);
1457
1459
  (0, import_react4.useEffect)(() => {
@@ -2102,6 +2104,8 @@ var import_jsx_runtime5 = require("react/jsx-runtime");
2102
2104
  var BASE_OVERSCAN = 6;
2103
2105
  var MIN_ZOOM = 0.2;
2104
2106
  var MAX_ZOOM = 5;
2107
+ var WIDTH_SNAP_PX = 4;
2108
+ var WIDTH_HYSTERESIS_PX = 6;
2105
2109
  var Viewer = ({ engine }) => {
2106
2110
  const {
2107
2111
  pageCount,
@@ -2124,6 +2128,7 @@ var Viewer = ({ engine }) => {
2124
2128
  const frameRef = (0, import_react5.useRef)(null);
2125
2129
  const jumpRef = (0, import_react5.useRef)(false);
2126
2130
  const jumpTimerRef = (0, import_react5.useRef)(null);
2131
+ const lastWidthRef = (0, import_react5.useRef)(null);
2127
2132
  const pinchRef = (0, import_react5.useRef)({
2128
2133
  active: false,
2129
2134
  startDistance: 0,
@@ -2171,20 +2176,47 @@ var Viewer = ({ engine }) => {
2171
2176
  []
2172
2177
  );
2173
2178
  (0, import_react5.useEffect)(() => {
2174
- const element = viewerRef.current;
2175
- if (!element) return;
2179
+ const viewerElement = viewerRef.current;
2180
+ if (!viewerElement) return;
2181
+ const measurementTarget = viewerElement.parentElement ?? viewerElement;
2182
+ let rafId = null;
2183
+ const normalizeWidth = (rawWidth) => Math.max(0, Math.floor(rawWidth / WIDTH_SNAP_PX) * WIDTH_SNAP_PX);
2176
2184
  const updateWidth = () => {
2177
- const nextWidth = element.clientWidth;
2178
- if (nextWidth > 0) setAvailableWidth(nextWidth);
2185
+ const rawWidth = measurementTarget.getBoundingClientRect?.().width ?? measurementTarget.clientWidth ?? measurementTarget.offsetWidth;
2186
+ const nextWidth = normalizeWidth(rawWidth);
2187
+ if (nextWidth <= 0) return;
2188
+ const previousWidth = lastWidthRef.current;
2189
+ if (previousWidth != null && Math.abs(nextWidth - previousWidth) < WIDTH_HYSTERESIS_PX)
2190
+ return;
2191
+ lastWidthRef.current = nextWidth;
2192
+ setAvailableWidth(nextWidth);
2179
2193
  };
2180
- updateWidth();
2194
+ const scheduleWidthUpdate = () => {
2195
+ if (rafId != null) cancelAnimationFrame(rafId);
2196
+ rafId = requestAnimationFrame(() => {
2197
+ rafId = null;
2198
+ updateWidth();
2199
+ });
2200
+ };
2201
+ scheduleWidthUpdate();
2181
2202
  if (typeof ResizeObserver === "undefined") {
2182
- window.addEventListener("resize", updateWidth);
2183
- return () => window.removeEventListener("resize", updateWidth);
2203
+ window.addEventListener("resize", scheduleWidthUpdate);
2204
+ window.visualViewport?.addEventListener("resize", scheduleWidthUpdate);
2205
+ return () => {
2206
+ if (rafId != null) cancelAnimationFrame(rafId);
2207
+ window.removeEventListener("resize", scheduleWidthUpdate);
2208
+ window.visualViewport?.removeEventListener(
2209
+ "resize",
2210
+ scheduleWidthUpdate
2211
+ );
2212
+ };
2184
2213
  }
2185
- const observer = new ResizeObserver(() => updateWidth());
2186
- observer.observe(element);
2187
- return () => observer.disconnect();
2214
+ const observer = new ResizeObserver(() => scheduleWidthUpdate());
2215
+ observer.observe(measurementTarget);
2216
+ return () => {
2217
+ if (rafId != null) cancelAnimationFrame(rafId);
2218
+ observer.disconnect();
2219
+ };
2188
2220
  }, []);
2189
2221
  (0, import_react5.useEffect)(() => {
2190
2222
  let active = true;