@floegence/floe-webapp-core 0.73.0 → 0.74.2

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.
@@ -22,11 +22,13 @@ export interface ViewportSnapshot {
22
22
  };
23
23
  safeArea: ViewportInsets;
24
24
  keyboardOpen: boolean;
25
- /** Add to client coordinates when positioning a document-level fixed element. */
25
+ /** Add to client coordinates before dividing by fixedScale for document-level fixed CSS. */
26
26
  fixedOffset: {
27
27
  left: number;
28
28
  top: number;
29
29
  };
30
+ /** Effective CSS zoom inherited by a document-body portal. Client bounds stay unscaled. */
31
+ fixedScale: number;
30
32
  }
31
33
  export interface ViewportSource {
32
34
  width: number;
@@ -35,6 +37,7 @@ export interface ViewportSource {
35
37
  left: number;
36
38
  top: number;
37
39
  };
40
+ fixedScale?: number;
38
41
  visualViewport?: {
39
42
  width: number;
40
43
  height: number;
package/dist/viewport.js CHANGED
@@ -1,90 +1,95 @@
1
- const u = (t, e) => Number.isFinite(t) && Number(t) > 0 ? Number(t) : Math.max(0, e);
1
+ const p = (t, e) => Number.isFinite(t) && Number(t) > 0 ? Number(t) : Math.max(0, e);
2
2
  function g(t) {
3
- const e = t.visualViewport, n = u(e?.width, t.width), i = u(e?.height, t.height), o = t.fixedOrigin ?? { left: 0, top: 0 }, s = Math.max(0, e?.offsetLeft || 0) + o.left, a = Math.max(0, e?.offsetTop || 0) + o.top, r = t.touch && t.editing && Math.abs((e?.scale ?? 1) - 1) < 0.01 && t.height - i > 100;
3
+ const e = t.visualViewport, o = p(e?.width, t.width), s = p(e?.height, t.height), n = t.fixedOrigin ?? { left: 0, top: 0 }, r = Math.max(0, e?.offsetLeft || 0) + n.left, a = Math.max(0, e?.offsetTop || 0) + n.top, i = t.touch && t.editing && Math.abs((e?.scale ?? 1) - 1) < 0.01 && t.height - s > 100;
4
4
  return {
5
- visible: { left: s, top: a, width: n, height: i, right: s + n, bottom: a + i },
5
+ visible: { left: r, top: a, width: o, height: s, right: r + o, bottom: a + s },
6
6
  layout: { width: t.width, height: t.height },
7
- safeArea: { ...t.safeArea, bottom: r ? 0 : t.safeArea.bottom },
8
- keyboardOpen: r,
9
- fixedOffset: { left: -o.left, top: -o.top }
7
+ safeArea: { ...t.safeArea, bottom: i ? 0 : t.safeArea.bottom },
8
+ keyboardOpen: i,
9
+ fixedOffset: { left: -n.left, top: -n.top },
10
+ fixedScale: p(t.fixedScale, 1)
10
11
  };
11
12
  }
12
- function b(t) {
13
+ function x(t) {
13
14
  let e = t.activeElement;
14
15
  for (; e?.shadowRoot?.activeElement; ) e = e.shadowRoot.activeElement;
15
16
  return !e || e.matches('[disabled], [readonly], [inputmode="none"]') ? !1 : e.matches('textarea, input:not([type]), input[type="text"], input[type="search"], input[type="email"], input[type="url"], input[type="tel"], input[type="password"], input[type="number"], [contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"]');
16
17
  }
17
- function m(t) {
18
+ function b(t) {
18
19
  const e = t.document.createElement("div");
19
20
  return e.setAttribute("aria-hidden", "true"), e.style.cssText = "position:fixed;top:0;left:0;width:100%;height:100dvh;visibility:hidden;pointer-events:none;box-sizing:border-box;padding:env(safe-area-inset-top,0px) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px)", t.document.documentElement.append(e), e;
20
21
  }
21
- function l(t, e) {
22
- const n = e.getBoundingClientRect(), i = t.getComputedStyle(e), o = (s) => Math.max(0, Number.parseFloat(s) || 0);
22
+ function u(t, e) {
23
+ const o = e.getBoundingClientRect(), s = t.getComputedStyle(e), n = (i) => Math.max(0, Number.parseFloat(i) || 0), r = (i) => i ? p(Number.parseFloat(t.getComputedStyle(i).zoom), 1) : 1, a = r(t.document.documentElement);
23
24
  return g({
24
- width: n.width || t.innerWidth,
25
- height: n.height || t.innerHeight,
25
+ width: o.width || t.innerWidth,
26
+ height: o.height / a || t.innerHeight,
26
27
  visualViewport: t.visualViewport,
27
- fixedOrigin: { left: n.left, top: n.top },
28
- safeArea: { top: o(i.paddingTop), right: o(i.paddingRight), bottom: o(i.paddingBottom), left: o(i.paddingLeft) },
29
- editing: b(t.document),
28
+ fixedOrigin: { left: o.left, top: o.top },
29
+ fixedScale: a * r(t.document.body),
30
+ safeArea: { top: n(s.paddingTop), right: n(s.paddingRight), bottom: n(s.paddingBottom), left: n(s.paddingLeft) },
31
+ editing: x(t.document),
30
32
  touch: t.matchMedia?.("(any-pointer: coarse)").matches ?? !1
31
33
  });
32
34
  }
33
- const d = /* @__PURE__ */ new WeakMap();
34
- function x(t) {
35
- const e = d.get(t);
35
+ const c = /* @__PURE__ */ new WeakMap();
36
+ function y(t) {
37
+ const e = c.get(t);
36
38
  if (e) return e.snapshot;
37
- const n = m(t);
39
+ const o = b(t);
38
40
  try {
39
- return l(t, n);
41
+ return u(t, o);
40
42
  } finally {
41
- n.remove();
43
+ o.remove();
42
44
  }
43
45
  }
44
- function y(t, e) {
45
- let n = d.get(t);
46
- if (!n) {
47
- const o = m(t);
48
- let s = 0;
49
- const a = /* @__PURE__ */ new Set(), r = { snapshot: l(t, o), listeners: a, dispose: () => {
50
- } }, c = () => {
51
- s || (s = t.requestAnimationFrame(() => {
52
- s = 0, r.snapshot = l(t, o);
53
- for (const p of a) p(r.snapshot);
46
+ function S(t, e) {
47
+ let o = c.get(t);
48
+ if (!o) {
49
+ const n = b(t);
50
+ let r = 0;
51
+ const a = /* @__PURE__ */ new Set(), i = { snapshot: u(t, n), listeners: a, dispose: () => {
52
+ } }, f = () => {
53
+ r || (r = t.requestAnimationFrame(() => {
54
+ r = 0, i.snapshot = u(t, n);
55
+ for (const d of a) d(i.snapshot);
54
56
  }));
55
- }, f = [
57
+ }, l = [
56
58
  [t, "resize"],
57
59
  [t, "scroll"],
58
60
  [t, "orientationchange"],
59
61
  [t.document, "focusin"],
60
62
  [t.document, "focusout"]
61
63
  ];
62
- t.visualViewport && f.push([t.visualViewport, "resize"], [t.visualViewport, "scroll"]);
63
- for (const [p, h] of f) p.addEventListener(h, c);
64
- r.dispose = () => {
65
- for (const [p, h] of f) p.removeEventListener(h, c);
66
- s && t.cancelAnimationFrame(s), o.remove(), d.delete(t);
67
- }, d.set(t, r), n = r;
64
+ t.visualViewport && l.push([t.visualViewport, "resize"], [t.visualViewport, "scroll"]);
65
+ for (const [d, h] of l) d.addEventListener(h, f);
66
+ const m = new MutationObserver(f);
67
+ for (const d of [t.document.documentElement, t.document.body])
68
+ d && m.observe(d, { attributes: !0, attributeFilter: ["class", "style"] });
69
+ i.dispose = () => {
70
+ for (const [d, h] of l) d.removeEventListener(h, f);
71
+ m.disconnect(), r && t.cancelAnimationFrame(r), n.remove(), c.delete(t);
72
+ }, c.set(t, i), o = i;
68
73
  }
69
- n.listeners.add(e), e(n.snapshot);
70
- const i = n;
74
+ o.listeners.add(e), e(o.snapshot);
75
+ const s = o;
71
76
  return () => {
72
- i.listeners.delete(e), i.listeners.size === 0 && i.dispose();
77
+ s.listeners.delete(e), s.listeners.size === 0 && s.dispose();
73
78
  };
74
79
  }
75
- function V(t) {
76
- const { visible: e } = t;
80
+ function E(t) {
81
+ const { visible: e, fixedScale: o } = t;
77
82
  return {
78
83
  position: "fixed",
79
- left: `${e.left + t.fixedOffset.left}px`,
80
- top: `${e.top + t.fixedOffset.top}px`,
81
- width: `${e.width}px`,
82
- height: `${e.height}px`
84
+ left: `${(e.left + t.fixedOffset.left) / o}px`,
85
+ top: `${(e.top + t.fixedOffset.top) / o}px`,
86
+ width: `${e.width / o}px`,
87
+ height: `${e.height / o}px`
83
88
  };
84
89
  }
85
90
  export {
86
- y as observeViewport,
87
- x as readViewportSnapshot,
91
+ S as observeViewport,
92
+ y as readViewportSnapshot,
88
93
  g as resolveViewportSnapshot,
89
- V as viewportStyle
94
+ E as viewportStyle
90
95
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@floegence/floe-webapp-core",
3
- "version": "0.73.0",
3
+ "version": "0.74.2",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",