@geomak/ui 7.3.4 → 7.4.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/dist/index.cjs +115 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +115 -43
- package/dist/index.js.map +1 -1
- package/dist/styles.css +6 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4577,6 +4577,10 @@ function List2({
|
|
|
4577
4577
|
);
|
|
4578
4578
|
}) });
|
|
4579
4579
|
}
|
|
4580
|
+
var rectOf = (el) => {
|
|
4581
|
+
const r = el.getBoundingClientRect();
|
|
4582
|
+
return { left: r.left, top: r.top, width: r.width, height: r.height };
|
|
4583
|
+
};
|
|
4580
4584
|
var TOGGLE_POSITION_CLASS = {
|
|
4581
4585
|
"top-left": "top-2 left-2",
|
|
4582
4586
|
"top-right": "top-2 right-2",
|
|
@@ -4595,17 +4599,56 @@ function ScalableContainer({
|
|
|
4595
4599
|
expandIcon,
|
|
4596
4600
|
collapseIcon,
|
|
4597
4601
|
togglePosition = "top-right",
|
|
4602
|
+
expandContainerRef,
|
|
4598
4603
|
className = ""
|
|
4599
4604
|
}) {
|
|
4600
4605
|
const containerRef = React30.useRef(null);
|
|
4601
4606
|
const [internalScaled, setInternalScaled] = React30.useState(false);
|
|
4602
4607
|
const isScaled = expanded ?? internalScaled;
|
|
4603
4608
|
const reduced = framerMotion.useReducedMotion();
|
|
4609
|
+
const usePortal = expandContainerRef != null;
|
|
4610
|
+
const [overlay, setOverlay] = React30.useState("closed");
|
|
4611
|
+
const [fromRect, setFromRect] = React30.useState(null);
|
|
4612
|
+
const [targetRect, setTargetRect] = React30.useState(null);
|
|
4613
|
+
const prevScaled = React30.useRef(isScaled);
|
|
4614
|
+
React30.useEffect(() => {
|
|
4615
|
+
if (!usePortal || isScaled === prevScaled.current) return;
|
|
4616
|
+
prevScaled.current = isScaled;
|
|
4617
|
+
if (isScaled) {
|
|
4618
|
+
const src = containerRef.current ? rectOf(containerRef.current) : null;
|
|
4619
|
+
const tgt = expandContainerRef.current ? rectOf(expandContainerRef.current) : null;
|
|
4620
|
+
if (src && tgt) {
|
|
4621
|
+
setFromRect(src);
|
|
4622
|
+
setTargetRect(tgt);
|
|
4623
|
+
setOverlay("open");
|
|
4624
|
+
}
|
|
4625
|
+
} else if (containerRef.current) {
|
|
4626
|
+
setTargetRect(rectOf(containerRef.current));
|
|
4627
|
+
setOverlay("closing");
|
|
4628
|
+
}
|
|
4629
|
+
}, [isScaled, usePortal, expandContainerRef]);
|
|
4630
|
+
React30.useEffect(() => {
|
|
4631
|
+
if (overlay !== "closing") return;
|
|
4632
|
+
const t = window.setTimeout(() => setOverlay("closed"), reduced ? 0 : 360);
|
|
4633
|
+
return () => window.clearTimeout(t);
|
|
4634
|
+
}, [overlay, reduced]);
|
|
4635
|
+
React30.useEffect(() => {
|
|
4636
|
+
if (overlay !== "open" || !expandContainerRef?.current) return;
|
|
4637
|
+
const update = () => {
|
|
4638
|
+
if (expandContainerRef.current) setTargetRect(rectOf(expandContainerRef.current));
|
|
4639
|
+
};
|
|
4640
|
+
window.addEventListener("resize", update);
|
|
4641
|
+
window.addEventListener("scroll", update, true);
|
|
4642
|
+
return () => {
|
|
4643
|
+
window.removeEventListener("resize", update);
|
|
4644
|
+
window.removeEventListener("scroll", update, true);
|
|
4645
|
+
};
|
|
4646
|
+
}, [overlay, expandContainerRef]);
|
|
4604
4647
|
const onToggle = () => {
|
|
4605
4648
|
const next = !isScaled;
|
|
4606
4649
|
if (expanded === void 0) setInternalScaled(next);
|
|
4607
4650
|
onExpandedChange?.(next);
|
|
4608
|
-
if (next) {
|
|
4651
|
+
if (next && !usePortal) {
|
|
4609
4652
|
window.setTimeout(
|
|
4610
4653
|
() => containerRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }),
|
|
4611
4654
|
reduced ? 0 : 340
|
|
@@ -4613,50 +4656,79 @@ function ScalableContainer({
|
|
|
4613
4656
|
}
|
|
4614
4657
|
};
|
|
4615
4658
|
const wrapperClass = isScaled ? assignClassOnClick : void 0;
|
|
4616
|
-
|
|
4617
|
-
|
|
4659
|
+
const overlayActive = usePortal && overlay !== "closed";
|
|
4660
|
+
const toggleButton = (scaled) => /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { placement: "bottom", title: scaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4661
|
+
"button",
|
|
4618
4662
|
{
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
"
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
"transition-shadow duration-300",
|
|
4634
|
-
className
|
|
4635
|
-
),
|
|
4636
|
-
children: [
|
|
4637
|
-
/* @__PURE__ */ jsxRuntime.jsx(Tooltip, { placement: "bottom", title: isScaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4638
|
-
"button",
|
|
4639
|
-
{
|
|
4640
|
-
type: "button",
|
|
4641
|
-
onClick: onToggle,
|
|
4642
|
-
"aria-label": isScaled ? "Collapse container" : "Expand container",
|
|
4643
|
-
"aria-expanded": isScaled,
|
|
4644
|
-
className: [
|
|
4645
|
-
"absolute z-10",
|
|
4646
|
-
TOGGLE_POSITION_CLASS[togglePosition],
|
|
4647
|
-
"w-7 h-7 inline-flex items-center justify-center",
|
|
4648
|
-
"rounded-md bg-surface/80 backdrop-blur-sm border border-border",
|
|
4649
|
-
"text-foreground-secondary hover:text-foreground hover:bg-surface",
|
|
4650
|
-
"shadow-sm transition-colors duration-150",
|
|
4651
|
-
"focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
|
|
4652
|
-
].join(" "),
|
|
4653
|
-
children: isScaled ? collapseIcon ?? /* @__PURE__ */ jsxRuntime.jsx(CollapseIcon, {}) : expandIcon ?? /* @__PURE__ */ jsxRuntime.jsx(ExpandIcon, {})
|
|
4654
|
-
}
|
|
4655
|
-
) }),
|
|
4656
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapperClass, children })
|
|
4657
|
-
]
|
|
4663
|
+
type: "button",
|
|
4664
|
+
onClick: onToggle,
|
|
4665
|
+
"aria-label": scaled ? "Collapse container" : "Expand container",
|
|
4666
|
+
"aria-expanded": scaled,
|
|
4667
|
+
className: [
|
|
4668
|
+
"absolute z-10",
|
|
4669
|
+
TOGGLE_POSITION_CLASS[togglePosition],
|
|
4670
|
+
"w-7 h-7 inline-flex items-center justify-center",
|
|
4671
|
+
"rounded-md bg-surface/80 backdrop-blur-sm border border-border",
|
|
4672
|
+
"text-foreground-secondary hover:text-foreground hover:bg-surface",
|
|
4673
|
+
"shadow-sm transition-colors duration-150",
|
|
4674
|
+
"focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
|
|
4675
|
+
].join(" "),
|
|
4676
|
+
children: scaled ? collapseIcon ?? /* @__PURE__ */ jsxRuntime.jsx(CollapseIcon, {}) : expandIcon ?? /* @__PURE__ */ jsxRuntime.jsx(ExpandIcon, {})
|
|
4658
4677
|
}
|
|
4659
|
-
);
|
|
4678
|
+
) });
|
|
4679
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4680
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4681
|
+
framerMotion.motion.div,
|
|
4682
|
+
{
|
|
4683
|
+
ref: containerRef,
|
|
4684
|
+
animate: {
|
|
4685
|
+
// Breakout mode never grows in place — the in-flow box stays
|
|
4686
|
+
// at its resting size and acts as the collapse target.
|
|
4687
|
+
width: isScaled && !usePortal ? expandedWidth : width,
|
|
4688
|
+
height: isScaled && !usePortal ? expandedHeight : height
|
|
4689
|
+
},
|
|
4690
|
+
transition: reduced ? { duration: 0 } : {
|
|
4691
|
+
width: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
|
|
4692
|
+
height: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] }
|
|
4693
|
+
},
|
|
4694
|
+
className: cx(
|
|
4695
|
+
"relative rounded-lg overflow-hidden",
|
|
4696
|
+
// OS-window aesthetic: subtle elevation at rest, lifted shadow
|
|
4697
|
+
// when expanded. No background colour change.
|
|
4698
|
+
isScaled && !usePortal ? "shadow-2xl" : "shadow-md",
|
|
4699
|
+
"transition-shadow duration-300",
|
|
4700
|
+
className
|
|
4701
|
+
),
|
|
4702
|
+
children: [
|
|
4703
|
+
!overlayActive && toggleButton(isScaled),
|
|
4704
|
+
!overlayActive && /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapperClass, children })
|
|
4705
|
+
]
|
|
4706
|
+
}
|
|
4707
|
+
),
|
|
4708
|
+
overlayActive && fromRect && targetRect && reactDom.createPortal(
|
|
4709
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4710
|
+
framerMotion.motion.div,
|
|
4711
|
+
{
|
|
4712
|
+
initial: { ...fromRect },
|
|
4713
|
+
animate: { ...targetRect },
|
|
4714
|
+
transition: reduced ? { duration: 0 } : { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
|
|
4715
|
+
onAnimationComplete: () => {
|
|
4716
|
+
if (overlay === "closing") setOverlay("closed");
|
|
4717
|
+
},
|
|
4718
|
+
style: { position: "fixed" },
|
|
4719
|
+
className: cx(
|
|
4720
|
+
"z-dropdown rounded-lg overflow-hidden bg-surface shadow-2xl",
|
|
4721
|
+
className
|
|
4722
|
+
),
|
|
4723
|
+
children: [
|
|
4724
|
+
toggleButton(isScaled),
|
|
4725
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: cx("h-full w-full", wrapperClass), children })
|
|
4726
|
+
]
|
|
4727
|
+
}
|
|
4728
|
+
),
|
|
4729
|
+
document.body
|
|
4730
|
+
)
|
|
4731
|
+
] });
|
|
4660
4732
|
}
|
|
4661
4733
|
function CollapseIcon() {
|
|
4662
4734
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 9L4 4M9 9V4M9 9H4M15 9L20 4M15 9V4M15 9H20M9 15L4 20M9 15V20M9 15H4M15 15L20 20M15 15V20M15 15H20" }) });
|