made-refine 0.2.4 → 0.2.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.
package/dist/index.mjs CHANGED
@@ -4025,6 +4025,8 @@ var MAX_ZOOM = 5;
4025
4025
  var ZOOM_SENSITIVITY = 0.0145;
4026
4026
  var LINE_HEIGHT_PX = 40;
4027
4027
  var PAGE_HEIGHT_PX = 800;
4028
+ var CANVAS_MEASURE_NODE_BUDGET = 12e3;
4029
+ var CANVAS_PRIORITY_ROOT_SELECTORS = ["#root", "#app", "#__next", "main"];
4028
4030
  function normalizeWheelDelta(e) {
4029
4031
  let { deltaX, deltaY } = e;
4030
4032
  if (e.deltaMode === 1) {
@@ -4036,6 +4038,52 @@ function normalizeWheelDelta(e) {
4036
4038
  }
4037
4039
  return { deltaX, deltaY };
4038
4040
  }
4041
+ function getResolvedOverflowY(style) {
4042
+ return style.overflowY || style.overflow;
4043
+ }
4044
+ function isScrollableOverflowY(value) {
4045
+ return value === "auto" || value === "scroll" || value === "overlay";
4046
+ }
4047
+ function isClippedOverflowY(value) {
4048
+ return value === "hidden" || value === "clip";
4049
+ }
4050
+ function getParentAcrossShadowTree(el) {
4051
+ const parent = el.parentElement;
4052
+ if (parent) return parent;
4053
+ const root = el.getRootNode();
4054
+ if (root instanceof ShadowRoot && root.host instanceof HTMLElement) {
4055
+ return root.host;
4056
+ }
4057
+ return null;
4058
+ }
4059
+ function enqueueChildren(el, queue) {
4060
+ for (const child of el.children) {
4061
+ if (child instanceof HTMLElement) queue.push(child);
4062
+ }
4063
+ const shadowRoot = el.shadowRoot;
4064
+ if (!shadowRoot) return;
4065
+ for (const child of shadowRoot.children) {
4066
+ if (child instanceof HTMLElement) queue.push(child);
4067
+ }
4068
+ }
4069
+ function measureContentBounds(el) {
4070
+ const rect = el.getBoundingClientRect();
4071
+ const pageLeft = rect.left + (window.scrollX || window.pageXOffset || 0);
4072
+ const pageTop = rect.top + (window.scrollY || window.pageYOffset || 0);
4073
+ return {
4074
+ width: Math.max(0, pageLeft) + el.scrollWidth,
4075
+ height: Math.max(0, pageTop) + el.scrollHeight
4076
+ };
4077
+ }
4078
+ function hasClippedAncestor(el) {
4079
+ let ancestor = getParentAcrossShadowTree(el);
4080
+ while (ancestor && ancestor !== document.body) {
4081
+ const ancestorStyle = getComputedStyle(ancestor);
4082
+ if (isClippedOverflowY(getResolvedOverflowY(ancestorStyle))) return true;
4083
+ ancestor = getParentAcrossShadowTree(ancestor);
4084
+ }
4085
+ return false;
4086
+ }
4039
4087
  var PAN_MARGIN = 0.1;
4040
4088
  function clampPan(zoom, panX, panY, bodyW, bodyH) {
4041
4089
  const vw = window.innerWidth;
@@ -4056,8 +4104,9 @@ function useCanvas({ stateRef, setState }) {
4056
4104
  const savedBodyOverflowRef = React7.useRef("");
4057
4105
  const savedHtmlOverflowRef = React7.useRef("");
4058
4106
  const savedHtmlBgColorRef = React7.useRef("");
4107
+ const domStateSavedRef = React7.useRef(false);
4059
4108
  const savedBodyDimensionsRef = React7.useRef({ width: 0, height: 0 });
4060
- const savedScrollContainersRef = React7.useRef([]);
4109
+ const savedExpandedNodesRef = React7.useRef([]);
4061
4110
  const rafIdRef = React7.useRef(null);
4062
4111
  const rafPendingRef = React7.useRef(false);
4063
4112
  const spaceHeldRef = React7.useRef(false);
@@ -4113,108 +4162,162 @@ function useCanvas({ stateRef, setState }) {
4113
4162
  });
4114
4163
  }
4115
4164
  }, [applyTransform, dispatchCanvasChange, setState]);
4116
- function isScrollableContainer(el) {
4117
- if (el.scrollHeight <= el.clientHeight + 1) return false;
4118
- const style = getComputedStyle(el);
4119
- const overflowY = style.overflowY || style.overflow;
4120
- if (overflowY === "hidden" || overflowY === "clip") return false;
4121
- return overflowY === "auto" || overflowY === "scroll" || overflowY === "overlay";
4122
- }
4123
- function expandScrollContainers() {
4124
- const saved = [];
4125
- const queue = Array.from(document.body.children).filter(
4126
- (el) => el instanceof HTMLElement
4127
- );
4128
- let visited = 0;
4129
- const maxNodes = 5e3;
4130
- while (queue.length > 0 && visited < maxNodes) {
4131
- const nextQueue = [];
4132
- for (const el of queue) {
4133
- if (visited >= maxNodes) break;
4134
- visited++;
4135
- if (isScrollableContainer(el)) {
4136
- const style = el.style;
4137
- saved.push({
4138
- el,
4139
- height: style.height,
4140
- maxHeight: style.maxHeight,
4141
- overflowX: style.overflowX,
4142
- overflowY: style.overflowY
4143
- });
4144
- style.height = "auto";
4145
- style.maxHeight = "none";
4146
- style.overflowX = "visible";
4147
- style.overflowY = "visible";
4148
- }
4149
- for (const child of el.children) {
4150
- if (child instanceof HTMLElement) nextQueue.push(child);
4165
+ function collectTraversalSeeds() {
4166
+ const out = [];
4167
+ const seen = /* @__PURE__ */ new Set();
4168
+ const push = (el) => {
4169
+ if (!(el instanceof HTMLElement)) return;
4170
+ if (!document.body.contains(el)) return;
4171
+ if (seen.has(el)) return;
4172
+ seen.add(el);
4173
+ out.push(el);
4174
+ };
4175
+ for (const selector of CANVAS_PRIORITY_ROOT_SELECTORS) {
4176
+ push(document.querySelector(selector));
4177
+ }
4178
+ for (const child of document.body.children) {
4179
+ push(child);
4180
+ }
4181
+ return out;
4182
+ }
4183
+ function expandScrollableRegionsAndMeasureBody() {
4184
+ const snapshots = /* @__PURE__ */ new Map();
4185
+ const expandedOrder = [];
4186
+ const queue = collectTraversalSeeds();
4187
+ const visited = /* @__PURE__ */ new Set();
4188
+ let visitedCount = 0;
4189
+ let fallbackWidth = 0;
4190
+ let fallbackHeight = 0;
4191
+ const expandNode = (el) => {
4192
+ if (snapshots.has(el)) return;
4193
+ snapshots.set(el, {
4194
+ height: el.style.height,
4195
+ maxHeight: el.style.maxHeight,
4196
+ overflowY: el.style.overflowY
4197
+ });
4198
+ expandedOrder.push(el);
4199
+ el.style.height = "auto";
4200
+ el.style.maxHeight = "none";
4201
+ el.style.overflowY = "visible";
4202
+ };
4203
+ while (queue.length > 0 && visitedCount < CANVAS_MEASURE_NODE_BUDGET) {
4204
+ const el = queue.shift();
4205
+ if (!el || visited.has(el)) continue;
4206
+ visited.add(el);
4207
+ visitedCount++;
4208
+ const hasVerticalOverflow = el.scrollHeight > el.clientHeight + 1;
4209
+ const style = getComputedStyle(el);
4210
+ const overflowY = getResolvedOverflowY(style);
4211
+ const isScrollable = hasVerticalOverflow && isScrollableOverflowY(overflowY);
4212
+ if (isScrollable) {
4213
+ expandNode(el);
4214
+ let ancestor = getParentAcrossShadowTree(el);
4215
+ while (ancestor && ancestor !== document.body) {
4216
+ const ancestorStyle = getComputedStyle(ancestor);
4217
+ if (isClippedOverflowY(getResolvedOverflowY(ancestorStyle))) {
4218
+ expandNode(ancestor);
4219
+ }
4220
+ ancestor = getParentAcrossShadowTree(ancestor);
4151
4221
  }
4152
4222
  }
4153
- queue.length = 0;
4154
- queue.push(...nextQueue);
4223
+ const canContributeFallback = hasVerticalOverflow && (isScrollable || !isClippedOverflowY(overflowY) && !hasClippedAncestor(el));
4224
+ if (canContributeFallback) {
4225
+ const bounds = measureContentBounds(el);
4226
+ fallbackWidth = Math.max(fallbackWidth, bounds.width);
4227
+ fallbackHeight = Math.max(fallbackHeight, bounds.height);
4228
+ }
4229
+ enqueueChildren(el, queue);
4155
4230
  }
4156
- savedScrollContainersRef.current = saved;
4231
+ savedExpandedNodesRef.current = expandedOrder.map((el) => ({ el, ...snapshots.get(el) }));
4232
+ return {
4233
+ width: Math.max(document.body.scrollWidth, document.documentElement.scrollWidth, fallbackWidth, window.innerWidth),
4234
+ height: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, fallbackHeight, window.innerHeight)
4235
+ };
4157
4236
  }
4158
- function restoreScrollContainers() {
4159
- for (let i = savedScrollContainersRef.current.length - 1; i >= 0; i--) {
4160
- const { el, height, maxHeight, overflowX, overflowY } = savedScrollContainersRef.current[i];
4237
+ function restoreExpandedNodes() {
4238
+ for (let i = savedExpandedNodesRef.current.length - 1; i >= 0; i--) {
4239
+ const { el, height, maxHeight, overflowY } = savedExpandedNodesRef.current[i];
4161
4240
  el.style.height = height;
4162
4241
  el.style.maxHeight = maxHeight;
4163
- el.style.overflowX = overflowX;
4164
4242
  el.style.overflowY = overflowY;
4165
4243
  }
4166
- savedScrollContainersRef.current = [];
4244
+ savedExpandedNodesRef.current = [];
4167
4245
  }
4168
4246
  const enterCanvas = React7.useCallback(() => {
4247
+ if (canvasRef.current.active) return;
4248
+ if (domStateSavedRef.current || savedExpandedNodesRef.current.length > 0) {
4249
+ restoreExpandedNodes();
4250
+ domStateSavedRef.current = false;
4251
+ }
4169
4252
  const scrollX = window.scrollX;
4170
4253
  const scrollY = window.scrollY;
4171
4254
  savedScrollRef.current = { x: scrollX, y: scrollY };
4172
4255
  savedBodyOverflowRef.current = document.body.style.overflow;
4173
4256
  savedHtmlOverflowRef.current = document.documentElement.style.overflow;
4174
4257
  savedHtmlBgColorRef.current = document.documentElement.style.backgroundColor;
4258
+ domStateSavedRef.current = true;
4175
4259
  const existingTransform = document.body.style.transform;
4176
4260
  if (existingTransform && existingTransform !== "none" && existingTransform !== "") {
4177
4261
  console.warn("[made-refine] canvas mode: overriding existing body transform:", existingTransform);
4178
4262
  }
4179
- window.scrollTo(0, 0);
4180
- expandScrollContainers();
4181
- savedBodyDimensionsRef.current = {
4182
- width: document.body.scrollWidth,
4183
- height: document.body.scrollHeight
4184
- };
4185
- updateBodyOffset();
4186
- document.body.style.overflow = "hidden";
4187
- document.documentElement.style.overflow = "hidden";
4188
- document.documentElement.style.backgroundColor = "#F5F5F5";
4189
- const initialPanX = -scrollX;
4190
- const initialPanY = -scrollY;
4191
- applyTransform(1, initialPanX, initialPanY);
4192
- canvasRef.current = { active: true, zoom: 1, panX: initialPanX, panY: initialPanY };
4193
- setCanvasSnapshot(canvasRef.current);
4194
- setState((prev) => ({
4195
- ...prev,
4196
- canvas: { active: true, zoom: 1, panX: initialPanX, panY: initialPanY }
4197
- }));
4198
- dispatchCanvasChange();
4263
+ let entered = false;
4264
+ try {
4265
+ window.scrollTo(0, 0);
4266
+ savedBodyDimensionsRef.current = expandScrollableRegionsAndMeasureBody();
4267
+ updateBodyOffset();
4268
+ document.body.style.overflow = "hidden";
4269
+ document.documentElement.style.overflow = "hidden";
4270
+ document.documentElement.style.backgroundColor = "#F5F5F5";
4271
+ const initialPanX = -scrollX;
4272
+ const initialPanY = -scrollY;
4273
+ applyTransform(1, initialPanX, initialPanY);
4274
+ canvasRef.current = { active: true, zoom: 1, panX: initialPanX, panY: initialPanY };
4275
+ setCanvasSnapshot(canvasRef.current);
4276
+ setState((prev) => ({
4277
+ ...prev,
4278
+ canvas: { active: true, zoom: 1, panX: initialPanX, panY: initialPanY }
4279
+ }));
4280
+ dispatchCanvasChange();
4281
+ entered = true;
4282
+ } finally {
4283
+ if (!entered) {
4284
+ document.body.style.transform = "";
4285
+ document.body.style.transformOrigin = "";
4286
+ restoreExpandedNodes();
4287
+ document.body.style.overflow = savedBodyOverflowRef.current;
4288
+ document.documentElement.style.overflow = savedHtmlOverflowRef.current;
4289
+ document.documentElement.style.backgroundColor = savedHtmlBgColorRef.current;
4290
+ window.scrollTo(scrollX, scrollY);
4291
+ domStateSavedRef.current = false;
4292
+ }
4293
+ }
4199
4294
  }, [applyTransform, dispatchCanvasChange, setState, updateBodyOffset]);
4200
4295
  const exitCanvas = React7.useCallback(() => {
4296
+ const shouldRestoreDom = domStateSavedRef.current || savedExpandedNodesRef.current.length > 0;
4297
+ const wasActive = canvasRef.current.active;
4298
+ if (!wasActive && !shouldRestoreDom) return;
4201
4299
  cancelPendingRaf();
4202
4300
  document.body.style.transform = "";
4203
4301
  document.body.style.transformOrigin = "";
4204
- restoreScrollContainers();
4205
- document.body.style.overflow = savedBodyOverflowRef.current;
4206
- document.documentElement.style.overflow = savedHtmlOverflowRef.current;
4207
- document.documentElement.style.backgroundColor = savedHtmlBgColorRef.current;
4302
+ restoreExpandedNodes();
4303
+ if (shouldRestoreDom) {
4304
+ document.body.style.overflow = savedBodyOverflowRef.current;
4305
+ document.documentElement.style.overflow = savedHtmlOverflowRef.current;
4306
+ document.documentElement.style.backgroundColor = savedHtmlBgColorRef.current;
4307
+ window.scrollTo(savedScrollRef.current.x, savedScrollRef.current.y);
4308
+ }
4208
4309
  document.body.style.cursor = "";
4209
- window.scrollTo(savedScrollRef.current.x, savedScrollRef.current.y);
4310
+ domStateSavedRef.current = false;
4210
4311
  setBodyOffset({ x: 0, y: 0 });
4211
4312
  canvasRef.current = { active: false, zoom: 1, panX: 0, panY: 0 };
4212
4313
  setCanvasSnapshot(canvasRef.current);
4213
- setState((prev) => ({
4214
- ...prev,
4215
- canvas: { active: false, zoom: 1, panX: 0, panY: 0 }
4216
- }));
4217
- dispatchCanvasChange();
4314
+ if (wasActive) {
4315
+ setState((prev) => ({
4316
+ ...prev,
4317
+ canvas: { active: false, zoom: 1, panX: 0, panY: 0 }
4318
+ }));
4319
+ dispatchCanvasChange();
4320
+ }
4218
4321
  }, [cancelPendingRaf, dispatchCanvasChange, setState]);
4219
4322
  const toggleCanvas = React7.useCallback(() => {
4220
4323
  if (canvasRef.current.active) {
@@ -4341,7 +4444,7 @@ function useCanvas({ stateRef, setState }) {
4341
4444
  React7.useEffect(() => {
4342
4445
  return () => {
4343
4446
  cancelPendingRaf();
4344
- if (canvasRef.current.active) {
4447
+ if (canvasRef.current.active || domStateSavedRef.current || savedExpandedNodesRef.current.length > 0) {
4345
4448
  exitCanvas();
4346
4449
  }
4347
4450
  };