@geomak/ui 7.3.4 → 7.4.1

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.d.cts CHANGED
@@ -2061,35 +2061,55 @@ interface ScalableContainerProps {
2061
2061
  * Default `'top-right'` — matches the OS-window convention.
2062
2062
  */
2063
2063
  togglePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
2064
+ /**
2065
+ * Bounding element the expansion is allowed to grow within. When the
2066
+ * container sits in size-constrained flex-item wrappers (where width /
2067
+ * height 100% makes expand-in-place a no-op), providing this ref switches
2068
+ * to PUSH expansion: every flex item between the container and this
2069
+ * element gets its `flex-grow` raised (animated), so this container takes
2070
+ * most of the space while its siblings shrink — but stay visible.
2071
+ * Collapsing restores the wrappers' original sizing. Omit for the classic
2072
+ * expand-in-place behaviour.
2073
+ */
2074
+ expandContainerRef?: react__default.RefObject<HTMLElement | null>;
2075
+ /**
2076
+ * How dominant the pushed expansion is, as a flex-grow multiplier applied
2077
+ * to the container's wrappers (push mode only). Default `5` — i.e. the
2078
+ * expanded container takes roughly 5 parts for every 1 part a sibling
2079
+ * keeps. Raise for a more fullscreen feel, lower for a gentler split.
2080
+ */
2081
+ expandRatio?: number;
2064
2082
  /** Extra classes merged onto the container root. */
2065
2083
  className?: string;
2066
2084
  }
2067
2085
  /**
2068
- * Container that smoothly expands to fill its parent on click and
2069
- * collapses back to its resting size. Reads like a macOS / Windows
2070
- * window resizing — subtle elevation shift, smooth scale, no flash
2071
- * of colour or harsh background change.
2072
- *
2073
- * **What's different from the previous version**
2074
- * - Animates BOTH width and height (was width-only).
2075
- * - No baked-in background — the container is transparent by default,
2076
- * so it overlays whatever surface the consumer puts behind it.
2077
- * - Shadow lifts on expand (`shadow-md` `shadow-2xl`) like a window
2078
- * being raised. No colour change.
2079
- * - The toggle button is a plain rounded chip with the chevron icon,
2080
- * not the old `IconButton` with the heavy background. Floats over
2081
- * the content via absolute positioning so it doesn't push layout.
2082
- * - Configurable toggle position (default top-right, matching OS
2083
- * close-button convention).
2086
+ * Container that smoothly expands on click and collapses back to its
2087
+ * resting size. Reads like a macOS / Windows window resizing — subtle
2088
+ * elevation shift, smooth scale, no flash of colour or harsh background
2089
+ * change.
2090
+ *
2091
+ * Two expansion modes:
2092
+ * - **In place** (default): animates the container's own width/height to
2093
+ * `expandedWidth`/`expandedHeight`.
2094
+ * - **Push** (`expandContainerRef` set): for containers whose resting size is
2095
+ * owned by flex-item wrappers. Expanding raises `flex-grow` on every flex
2096
+ * item between the container and the bounding element, so the container
2097
+ * grows to dominate the section while sibling containers shrink but remain
2098
+ * visible. Collapsing restores the original layout.
2084
2099
  *
2085
2100
  * @example
2086
2101
  * ```tsx
2087
2102
  * <ScalableContainer width={480} height={300}>
2088
2103
  * <Chart data={metrics} />
2089
2104
  * </ScalableContainer>
2105
+ *
2106
+ * // Push mode inside a flex grid:
2107
+ * const sectionRef = useRef<HTMLDivElement>(null)
2108
+ * <div ref={sectionRef} className="flex flex-col flex-1 min-h-0 gap-2">…
2109
+ * <ScalableContainer width="100%" height="100%" expandContainerRef={sectionRef}>
2090
2110
  * ```
2091
2111
  */
2092
- declare function ScalableContainer({ width, height, expandedWidth, expandedHeight, expanded, onExpandedChange, children, assignClassOnClick, expandIcon, collapseIcon, togglePosition, className, }: ScalableContainerProps): react_jsx_runtime.JSX.Element;
2112
+ declare function ScalableContainer({ width, height, expandedWidth, expandedHeight, expanded, onExpandedChange, children, assignClassOnClick, expandIcon, collapseIcon, togglePosition, expandContainerRef, expandRatio, className, }: ScalableContainerProps): react_jsx_runtime.JSX.Element;
2093
2113
 
2094
2114
  interface GridCardItem {
2095
2115
  key: string | number;
package/dist/index.d.ts CHANGED
@@ -2061,35 +2061,55 @@ interface ScalableContainerProps {
2061
2061
  * Default `'top-right'` — matches the OS-window convention.
2062
2062
  */
2063
2063
  togglePosition?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
2064
+ /**
2065
+ * Bounding element the expansion is allowed to grow within. When the
2066
+ * container sits in size-constrained flex-item wrappers (where width /
2067
+ * height 100% makes expand-in-place a no-op), providing this ref switches
2068
+ * to PUSH expansion: every flex item between the container and this
2069
+ * element gets its `flex-grow` raised (animated), so this container takes
2070
+ * most of the space while its siblings shrink — but stay visible.
2071
+ * Collapsing restores the wrappers' original sizing. Omit for the classic
2072
+ * expand-in-place behaviour.
2073
+ */
2074
+ expandContainerRef?: react__default.RefObject<HTMLElement | null>;
2075
+ /**
2076
+ * How dominant the pushed expansion is, as a flex-grow multiplier applied
2077
+ * to the container's wrappers (push mode only). Default `5` — i.e. the
2078
+ * expanded container takes roughly 5 parts for every 1 part a sibling
2079
+ * keeps. Raise for a more fullscreen feel, lower for a gentler split.
2080
+ */
2081
+ expandRatio?: number;
2064
2082
  /** Extra classes merged onto the container root. */
2065
2083
  className?: string;
2066
2084
  }
2067
2085
  /**
2068
- * Container that smoothly expands to fill its parent on click and
2069
- * collapses back to its resting size. Reads like a macOS / Windows
2070
- * window resizing — subtle elevation shift, smooth scale, no flash
2071
- * of colour or harsh background change.
2072
- *
2073
- * **What's different from the previous version**
2074
- * - Animates BOTH width and height (was width-only).
2075
- * - No baked-in background — the container is transparent by default,
2076
- * so it overlays whatever surface the consumer puts behind it.
2077
- * - Shadow lifts on expand (`shadow-md` `shadow-2xl`) like a window
2078
- * being raised. No colour change.
2079
- * - The toggle button is a plain rounded chip with the chevron icon,
2080
- * not the old `IconButton` with the heavy background. Floats over
2081
- * the content via absolute positioning so it doesn't push layout.
2082
- * - Configurable toggle position (default top-right, matching OS
2083
- * close-button convention).
2086
+ * Container that smoothly expands on click and collapses back to its
2087
+ * resting size. Reads like a macOS / Windows window resizing — subtle
2088
+ * elevation shift, smooth scale, no flash of colour or harsh background
2089
+ * change.
2090
+ *
2091
+ * Two expansion modes:
2092
+ * - **In place** (default): animates the container's own width/height to
2093
+ * `expandedWidth`/`expandedHeight`.
2094
+ * - **Push** (`expandContainerRef` set): for containers whose resting size is
2095
+ * owned by flex-item wrappers. Expanding raises `flex-grow` on every flex
2096
+ * item between the container and the bounding element, so the container
2097
+ * grows to dominate the section while sibling containers shrink but remain
2098
+ * visible. Collapsing restores the original layout.
2084
2099
  *
2085
2100
  * @example
2086
2101
  * ```tsx
2087
2102
  * <ScalableContainer width={480} height={300}>
2088
2103
  * <Chart data={metrics} />
2089
2104
  * </ScalableContainer>
2105
+ *
2106
+ * // Push mode inside a flex grid:
2107
+ * const sectionRef = useRef<HTMLDivElement>(null)
2108
+ * <div ref={sectionRef} className="flex flex-col flex-1 min-h-0 gap-2">…
2109
+ * <ScalableContainer width="100%" height="100%" expandContainerRef={sectionRef}>
2090
2110
  * ```
2091
2111
  */
2092
- declare function ScalableContainer({ width, height, expandedWidth, expandedHeight, expanded, onExpandedChange, children, assignClassOnClick, expandIcon, collapseIcon, togglePosition, className, }: ScalableContainerProps): react_jsx_runtime.JSX.Element;
2112
+ declare function ScalableContainer({ width, height, expandedWidth, expandedHeight, expanded, onExpandedChange, children, assignClassOnClick, expandIcon, collapseIcon, togglePosition, expandContainerRef, expandRatio, className, }: ScalableContainerProps): react_jsx_runtime.JSX.Element;
2093
2113
 
2094
2114
  interface GridCardItem {
2095
2115
  key: string | number;
package/dist/index.js CHANGED
@@ -4558,17 +4558,70 @@ function ScalableContainer({
4558
4558
  expandIcon,
4559
4559
  collapseIcon,
4560
4560
  togglePosition = "top-right",
4561
+ expandContainerRef,
4562
+ expandRatio = 5,
4561
4563
  className = ""
4562
4564
  }) {
4563
4565
  const containerRef = useRef(null);
4564
4566
  const [internalScaled, setInternalScaled] = useState(false);
4565
4567
  const isScaled = expanded ?? internalScaled;
4566
4568
  const reduced = useReducedMotion();
4569
+ const usePush = expandContainerRef != null;
4570
+ const grownRef = useRef([]);
4571
+ const prevScaled = useRef(isScaled);
4572
+ const growAncestors = () => {
4573
+ const bound = expandContainerRef?.current;
4574
+ if (!bound || !containerRef.current) return;
4575
+ const grown = [];
4576
+ let el = containerRef.current.parentElement;
4577
+ while (el && el !== bound && bound.contains(el)) {
4578
+ const parent = el.parentElement;
4579
+ if (parent && getComputedStyle(parent).display.includes("flex")) {
4580
+ grown.push({
4581
+ el,
4582
+ prev: {
4583
+ flexGrow: el.style.flexGrow,
4584
+ flexBasis: el.style.flexBasis,
4585
+ transition: el.style.transition
4586
+ }
4587
+ });
4588
+ const grow = `flex-grow ${reduced ? 0 : 0.32}s cubic-bezier(0.16, 1, 0.3, 1), flex-basis ${reduced ? 0 : 0.32}s cubic-bezier(0.16, 1, 0.3, 1)`;
4589
+ el.style.transition = el.style.transition ? `${el.style.transition}, ${grow}` : grow;
4590
+ el.style.flexBasis = "0%";
4591
+ el.style.flexGrow = String(expandRatio);
4592
+ }
4593
+ el = parent;
4594
+ }
4595
+ grownRef.current = grown;
4596
+ };
4597
+ const restoreAncestors = () => {
4598
+ for (const { el, prev } of grownRef.current) {
4599
+ el.style.flexGrow = prev.flexGrow;
4600
+ el.style.flexBasis = prev.flexBasis;
4601
+ window.setTimeout(() => {
4602
+ el.style.transition = prev.transition;
4603
+ }, reduced ? 0 : 360);
4604
+ }
4605
+ grownRef.current = [];
4606
+ };
4607
+ useEffect(() => {
4608
+ if (!usePush || isScaled === prevScaled.current) return;
4609
+ prevScaled.current = isScaled;
4610
+ if (isScaled) growAncestors();
4611
+ else restoreAncestors();
4612
+ }, [isScaled, usePush]);
4613
+ useEffect(() => () => {
4614
+ for (const { el, prev } of grownRef.current) {
4615
+ el.style.flexGrow = prev.flexGrow;
4616
+ el.style.flexBasis = prev.flexBasis;
4617
+ el.style.transition = prev.transition;
4618
+ }
4619
+ }, []);
4567
4620
  const onToggle = () => {
4568
4621
  const next = !isScaled;
4569
4622
  if (expanded === void 0) setInternalScaled(next);
4570
4623
  onExpandedChange?.(next);
4571
- if (next) {
4624
+ if (next && !usePush) {
4572
4625
  window.setTimeout(
4573
4626
  () => containerRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }),
4574
4627
  reduced ? 0 : 340
@@ -4581,8 +4634,10 @@ function ScalableContainer({
4581
4634
  {
4582
4635
  ref: containerRef,
4583
4636
  animate: {
4584
- width: isScaled ? expandedWidth : width,
4585
- height: isScaled ? expandedHeight : height
4637
+ // Push mode keeps the container filling its (now growing)
4638
+ // wrapper the wrapper's flex-grow does the work.
4639
+ width: isScaled && !usePush ? expandedWidth : width,
4640
+ height: isScaled && !usePush ? expandedHeight : height
4586
4641
  },
4587
4642
  transition: reduced ? { duration: 0 } : {
4588
4643
  width: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
@@ -4616,7 +4671,7 @@ function ScalableContainer({
4616
4671
  children: isScaled ? collapseIcon ?? /* @__PURE__ */ jsx(CollapseIcon, {}) : expandIcon ?? /* @__PURE__ */ jsx(ExpandIcon, {})
4617
4672
  }
4618
4673
  ) }),
4619
- /* @__PURE__ */ jsx("div", { className: wrapperClass, children })
4674
+ /* @__PURE__ */ jsx("div", { className: cx("h-full w-full", wrapperClass), children })
4620
4675
  ]
4621
4676
  }
4622
4677
  );