@geomak/ui 7.3.3 → 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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { C as COLORS, S as SemanticColorKey, a as SemanticSharedKey, V as VarColorKey, b as VarDensityKey, c as VarMotionKey, d as VarRadiusKey, e as VarShadowKey, f as VarTypoKey, g as VarZIndexKey, P as palette, s as semanticTokens, v as vars } from './index-5FQ64bx1.cjs';
1
+ export { C as COLORS, S as SemanticColorKey, a as SemanticSharedKey, V as VarColorKey, b as VarDensityKey, c as VarMotionKey, d as VarRadiusKey, e as VarShadowKey, f as VarTypoKey, g as VarZIndexKey, P as palette, s as semanticTokens, v as vars } from './index-BktppxXp.cjs';
2
2
  export { CreateIconOptions, Icon, IconComponent, IconProps, createIcon } from './icons/index.cjs';
3
3
  import * as react from 'react';
4
4
  import react__default from 'react';
@@ -2061,6 +2061,15 @@ 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 EXPANDED state should overlay. When provided, the
2066
+ * expanded content renders into a body portal positioned over this
2067
+ * element's rect instead of growing in place — letting the container break
2068
+ * out of a size-constrained wrapper (e.g. a flex item) whose normal-state
2069
+ * sizing it should otherwise respect. Collapsing returns it to normal
2070
+ * flow. Omit for the classic expand-in-place behaviour.
2071
+ */
2072
+ expandContainerRef?: react__default.RefObject<HTMLElement | null>;
2064
2073
  /** Extra classes merged onto the container root. */
2065
2074
  className?: string;
2066
2075
  }
@@ -2089,7 +2098,7 @@ interface ScalableContainerProps {
2089
2098
  * </ScalableContainer>
2090
2099
  * ```
2091
2100
  */
2092
- declare function ScalableContainer({ width, height, expandedWidth, expandedHeight, expanded, onExpandedChange, children, assignClassOnClick, expandIcon, collapseIcon, togglePosition, className, }: ScalableContainerProps): react_jsx_runtime.JSX.Element;
2101
+ declare function ScalableContainer({ width, height, expandedWidth, expandedHeight, expanded, onExpandedChange, children, assignClassOnClick, expandIcon, collapseIcon, togglePosition, expandContainerRef, className, }: ScalableContainerProps): react_jsx_runtime.JSX.Element;
2093
2102
 
2094
2103
  interface GridCardItem {
2095
2104
  key: string | number;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { C as COLORS, S as SemanticColorKey, a as SemanticSharedKey, V as VarColorKey, b as VarDensityKey, c as VarMotionKey, d as VarRadiusKey, e as VarShadowKey, f as VarTypoKey, g as VarZIndexKey, P as palette, s as semanticTokens, v as vars } from './index-5FQ64bx1.js';
1
+ export { C as COLORS, S as SemanticColorKey, a as SemanticSharedKey, V as VarColorKey, b as VarDensityKey, c as VarMotionKey, d as VarRadiusKey, e as VarShadowKey, f as VarTypoKey, g as VarZIndexKey, P as palette, s as semanticTokens, v as vars } from './index-BktppxXp.js';
2
2
  export { CreateIconOptions, Icon, IconComponent, IconProps, createIcon } from './icons/index.js';
3
3
  import * as react from 'react';
4
4
  import react__default from 'react';
@@ -2061,6 +2061,15 @@ 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 EXPANDED state should overlay. When provided, the
2066
+ * expanded content renders into a body portal positioned over this
2067
+ * element's rect instead of growing in place — letting the container break
2068
+ * out of a size-constrained wrapper (e.g. a flex item) whose normal-state
2069
+ * sizing it should otherwise respect. Collapsing returns it to normal
2070
+ * flow. Omit for the classic expand-in-place behaviour.
2071
+ */
2072
+ expandContainerRef?: react__default.RefObject<HTMLElement | null>;
2064
2073
  /** Extra classes merged onto the container root. */
2065
2074
  className?: string;
2066
2075
  }
@@ -2089,7 +2098,7 @@ interface ScalableContainerProps {
2089
2098
  * </ScalableContainer>
2090
2099
  * ```
2091
2100
  */
2092
- declare function ScalableContainer({ width, height, expandedWidth, expandedHeight, expanded, onExpandedChange, children, assignClassOnClick, expandIcon, collapseIcon, togglePosition, className, }: ScalableContainerProps): react_jsx_runtime.JSX.Element;
2101
+ declare function ScalableContainer({ width, height, expandedWidth, expandedHeight, expanded, onExpandedChange, children, assignClassOnClick, expandIcon, collapseIcon, togglePosition, expandContainerRef, className, }: ScalableContainerProps): react_jsx_runtime.JSX.Element;
2093
2102
 
2094
2103
  interface GridCardItem {
2095
2104
  key: string | number;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { icons_default as Icon, createIcon } from './chunk-KAFJJO5O.js';
2
- import { colors_default } from './chunk-I2P4JJDB.js';
3
- export { colors_default as COLORS, PALETTE as palette, semanticTokens, vars } from './chunk-I2P4JJDB.js';
2
+ import { colors_default } from './chunk-DXOWXLKK.js';
3
+ export { colors_default as COLORS, PALETTE as palette, semanticTokens, vars } from './chunk-DXOWXLKK.js';
4
4
  import React30, { createContext, useState, useEffect, useMemo, useId, useCallback, useRef, useContext, useSyncExternalStore, useLayoutEffect } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
@@ -4540,6 +4540,10 @@ function List2({
4540
4540
  );
4541
4541
  }) });
4542
4542
  }
4543
+ var rectOf = (el) => {
4544
+ const r = el.getBoundingClientRect();
4545
+ return { left: r.left, top: r.top, width: r.width, height: r.height };
4546
+ };
4543
4547
  var TOGGLE_POSITION_CLASS = {
4544
4548
  "top-left": "top-2 left-2",
4545
4549
  "top-right": "top-2 right-2",
@@ -4558,17 +4562,56 @@ function ScalableContainer({
4558
4562
  expandIcon,
4559
4563
  collapseIcon,
4560
4564
  togglePosition = "top-right",
4565
+ expandContainerRef,
4561
4566
  className = ""
4562
4567
  }) {
4563
4568
  const containerRef = useRef(null);
4564
4569
  const [internalScaled, setInternalScaled] = useState(false);
4565
4570
  const isScaled = expanded ?? internalScaled;
4566
4571
  const reduced = useReducedMotion();
4572
+ const usePortal = expandContainerRef != null;
4573
+ const [overlay, setOverlay] = useState("closed");
4574
+ const [fromRect, setFromRect] = useState(null);
4575
+ const [targetRect, setTargetRect] = useState(null);
4576
+ const prevScaled = useRef(isScaled);
4577
+ useEffect(() => {
4578
+ if (!usePortal || isScaled === prevScaled.current) return;
4579
+ prevScaled.current = isScaled;
4580
+ if (isScaled) {
4581
+ const src = containerRef.current ? rectOf(containerRef.current) : null;
4582
+ const tgt = expandContainerRef.current ? rectOf(expandContainerRef.current) : null;
4583
+ if (src && tgt) {
4584
+ setFromRect(src);
4585
+ setTargetRect(tgt);
4586
+ setOverlay("open");
4587
+ }
4588
+ } else if (containerRef.current) {
4589
+ setTargetRect(rectOf(containerRef.current));
4590
+ setOverlay("closing");
4591
+ }
4592
+ }, [isScaled, usePortal, expandContainerRef]);
4593
+ useEffect(() => {
4594
+ if (overlay !== "closing") return;
4595
+ const t = window.setTimeout(() => setOverlay("closed"), reduced ? 0 : 360);
4596
+ return () => window.clearTimeout(t);
4597
+ }, [overlay, reduced]);
4598
+ useEffect(() => {
4599
+ if (overlay !== "open" || !expandContainerRef?.current) return;
4600
+ const update = () => {
4601
+ if (expandContainerRef.current) setTargetRect(rectOf(expandContainerRef.current));
4602
+ };
4603
+ window.addEventListener("resize", update);
4604
+ window.addEventListener("scroll", update, true);
4605
+ return () => {
4606
+ window.removeEventListener("resize", update);
4607
+ window.removeEventListener("scroll", update, true);
4608
+ };
4609
+ }, [overlay, expandContainerRef]);
4567
4610
  const onToggle = () => {
4568
4611
  const next = !isScaled;
4569
4612
  if (expanded === void 0) setInternalScaled(next);
4570
4613
  onExpandedChange?.(next);
4571
- if (next) {
4614
+ if (next && !usePortal) {
4572
4615
  window.setTimeout(
4573
4616
  () => containerRef.current?.scrollIntoView({ behavior: "smooth", block: "nearest" }),
4574
4617
  reduced ? 0 : 340
@@ -4576,50 +4619,79 @@ function ScalableContainer({
4576
4619
  }
4577
4620
  };
4578
4621
  const wrapperClass = isScaled ? assignClassOnClick : void 0;
4579
- return /* @__PURE__ */ jsxs(
4580
- motion.div,
4622
+ const overlayActive = usePortal && overlay !== "closed";
4623
+ const toggleButton = (scaled) => /* @__PURE__ */ jsx(Tooltip, { placement: "bottom", title: scaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsx(
4624
+ "button",
4581
4625
  {
4582
- ref: containerRef,
4583
- animate: {
4584
- width: isScaled ? expandedWidth : width,
4585
- height: isScaled ? expandedHeight : height
4586
- },
4587
- transition: reduced ? { duration: 0 } : {
4588
- width: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
4589
- height: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] }
4590
- },
4591
- className: cx(
4592
- "relative rounded-lg overflow-hidden",
4593
- // OS-window aesthetic: subtle elevation at rest, lifted shadow
4594
- // when expanded. No background colour change.
4595
- isScaled ? "shadow-2xl" : "shadow-md",
4596
- "transition-shadow duration-300",
4597
- className
4598
- ),
4599
- children: [
4600
- /* @__PURE__ */ jsx(Tooltip, { placement: "bottom", title: isScaled ? "Collapse" : "Expand", children: /* @__PURE__ */ jsx(
4601
- "button",
4602
- {
4603
- type: "button",
4604
- onClick: onToggle,
4605
- "aria-label": isScaled ? "Collapse container" : "Expand container",
4606
- "aria-expanded": isScaled,
4607
- className: [
4608
- "absolute z-10",
4609
- TOGGLE_POSITION_CLASS[togglePosition],
4610
- "w-7 h-7 inline-flex items-center justify-center",
4611
- "rounded-md bg-surface/80 backdrop-blur-sm border border-border",
4612
- "text-foreground-secondary hover:text-foreground hover:bg-surface",
4613
- "shadow-sm transition-colors duration-150",
4614
- "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
4615
- ].join(" "),
4616
- children: isScaled ? collapseIcon ?? /* @__PURE__ */ jsx(CollapseIcon, {}) : expandIcon ?? /* @__PURE__ */ jsx(ExpandIcon, {})
4617
- }
4618
- ) }),
4619
- /* @__PURE__ */ jsx("div", { className: wrapperClass, children })
4620
- ]
4626
+ type: "button",
4627
+ onClick: onToggle,
4628
+ "aria-label": scaled ? "Collapse container" : "Expand container",
4629
+ "aria-expanded": scaled,
4630
+ className: [
4631
+ "absolute z-10",
4632
+ TOGGLE_POSITION_CLASS[togglePosition],
4633
+ "w-7 h-7 inline-flex items-center justify-center",
4634
+ "rounded-md bg-surface/80 backdrop-blur-sm border border-border",
4635
+ "text-foreground-secondary hover:text-foreground hover:bg-surface",
4636
+ "shadow-sm transition-colors duration-150",
4637
+ "focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
4638
+ ].join(" "),
4639
+ children: scaled ? collapseIcon ?? /* @__PURE__ */ jsx(CollapseIcon, {}) : expandIcon ?? /* @__PURE__ */ jsx(ExpandIcon, {})
4621
4640
  }
4622
- );
4641
+ ) });
4642
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4643
+ /* @__PURE__ */ jsxs(
4644
+ motion.div,
4645
+ {
4646
+ ref: containerRef,
4647
+ animate: {
4648
+ // Breakout mode never grows in place — the in-flow box stays
4649
+ // at its resting size and acts as the collapse target.
4650
+ width: isScaled && !usePortal ? expandedWidth : width,
4651
+ height: isScaled && !usePortal ? expandedHeight : height
4652
+ },
4653
+ transition: reduced ? { duration: 0 } : {
4654
+ width: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
4655
+ height: { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] }
4656
+ },
4657
+ className: cx(
4658
+ "relative rounded-lg overflow-hidden",
4659
+ // OS-window aesthetic: subtle elevation at rest, lifted shadow
4660
+ // when expanded. No background colour change.
4661
+ isScaled && !usePortal ? "shadow-2xl" : "shadow-md",
4662
+ "transition-shadow duration-300",
4663
+ className
4664
+ ),
4665
+ children: [
4666
+ !overlayActive && toggleButton(isScaled),
4667
+ !overlayActive && /* @__PURE__ */ jsx("div", { className: wrapperClass, children })
4668
+ ]
4669
+ }
4670
+ ),
4671
+ overlayActive && fromRect && targetRect && createPortal(
4672
+ /* @__PURE__ */ jsxs(
4673
+ motion.div,
4674
+ {
4675
+ initial: { ...fromRect },
4676
+ animate: { ...targetRect },
4677
+ transition: reduced ? { duration: 0 } : { type: "tween", duration: 0.32, ease: [0.16, 1, 0.3, 1] },
4678
+ onAnimationComplete: () => {
4679
+ if (overlay === "closing") setOverlay("closed");
4680
+ },
4681
+ style: { position: "fixed" },
4682
+ className: cx(
4683
+ "z-dropdown rounded-lg overflow-hidden bg-surface shadow-2xl",
4684
+ className
4685
+ ),
4686
+ children: [
4687
+ toggleButton(isScaled),
4688
+ /* @__PURE__ */ jsx("div", { className: cx("h-full w-full", wrapperClass), children })
4689
+ ]
4690
+ }
4691
+ ),
4692
+ document.body
4693
+ )
4694
+ ] });
4623
4695
  }
4624
4696
  function CollapseIcon() {
4625
4697
  return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, className: "w-4 h-4", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M9 9L4 4M9 9V4M9 9H4M15 9L20 4M15 9V4M15 9H20M9 15L4 20M9 15V20M9 15H4M15 15L20 20M15 15V20M15 15H20" }) });
@@ -7544,8 +7616,9 @@ function Dropdown({
7544
7616
  {
7545
7617
  align: "start",
7546
7618
  sideOffset: 4,
7619
+ collisionPadding: 8,
7547
7620
  style: { width: style?.width || 240 },
7548
- className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-2 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7621
+ className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-popover p-2 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7549
7622
  onInteractOutside: () => setOpen(false),
7550
7623
  children: [
7551
7624
  hasSearch && /* @__PURE__ */ jsx("div", { className: "mb-2", children: /* @__PURE__ */ jsx(
@@ -7728,8 +7801,9 @@ function AutoComplete({
7728
7801
  {
7729
7802
  align: "start",
7730
7803
  sideOffset: 4,
7804
+ collisionPadding: 8,
7731
7805
  onOpenAutoFocus: (e) => e.preventDefault(),
7732
- className: "w-64 bg-surface border border-border rounded-lg mt-1 shadow-md z-50 overflow-y-auto max-h-36 animate-in fade-in-0 zoom-in-95",
7806
+ className: "w-64 bg-surface border border-border rounded-lg mt-1 shadow-md z-popover overflow-y-auto max-h-36 animate-in fade-in-0 zoom-in-95",
7733
7807
  children: loading ? /* @__PURE__ */ jsxs("div", { className: "h-full w-full flex items-center justify-center gap-2 py-4 text-sm text-foreground-secondary", children: [
7734
7808
  /* @__PURE__ */ jsx(LoadingSpinner, { inline: true, size: "xs" }),
7735
7809
  /* @__PURE__ */ jsx("span", { children: loadingText })
@@ -7913,8 +7987,9 @@ function TreeSelect({
7913
7987
  {
7914
7988
  align: "start",
7915
7989
  sideOffset: 4,
7990
+ collisionPadding: 8,
7916
7991
  style: { width: style?.width || 280 },
7917
- className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-1 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7992
+ className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-popover p-1 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
7918
7993
  onOpenAutoFocus: (e) => {
7919
7994
  e.preventDefault();
7920
7995
  listRef.current?.focus();
@@ -8362,7 +8437,8 @@ function DatePicker({
8362
8437
  {
8363
8438
  align: "start",
8364
8439
  sideOffset: 4,
8365
- className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-3 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
8440
+ collisionPadding: 8,
8441
+ className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-popover p-3 animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
8366
8442
  onOpenAutoFocus: (e) => {
8367
8443
  e.preventDefault();
8368
8444
  },
@@ -9161,7 +9237,8 @@ function TimePicker({
9161
9237
  {
9162
9238
  align: "start",
9163
9239
  sideOffset: 4,
9164
- className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-2 flex gap-1 animate-in fade-in-0 zoom-in-95",
9240
+ collisionPadding: 8,
9241
+ className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-popover p-2 flex gap-1 animate-in fade-in-0 zoom-in-95",
9165
9242
  children: [
9166
9243
  /* @__PURE__ */ jsx(
9167
9244
  Column,
@@ -9334,7 +9411,8 @@ function DateRangePicker({
9334
9411
  {
9335
9412
  align: "start",
9336
9413
  sideOffset: 4,
9337
- className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-3 flex flex-col gap-3 sm:flex-row max-w-[calc(100vw-1rem)] max-h-[calc(100vh-2rem)] overflow-auto animate-in fade-in-0 zoom-in-95",
9414
+ collisionPadding: 8,
9415
+ className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-popover p-3 flex flex-col gap-3 sm:flex-row max-w-[calc(100vw-1rem)] max-h-[calc(100vh-2rem)] overflow-auto animate-in fade-in-0 zoom-in-95",
9338
9416
  children: [
9339
9417
  presets && presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-1 min-w-[120px] sm:pr-3 sm:border-r sm:border-border", children: presets.map((p) => /* @__PURE__ */ jsx(
9340
9418
  "button",
@@ -9457,7 +9535,8 @@ function ColorPicker({
9457
9535
  {
9458
9536
  align: "start",
9459
9537
  sideOffset: 4,
9460
- className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-50 p-3 w-56 animate-in fade-in-0 zoom-in-95",
9538
+ collisionPadding: 8,
9539
+ className: "bg-surface text-foreground border border-border rounded-lg shadow-md z-popover p-3 w-56 animate-in fade-in-0 zoom-in-95",
9461
9540
  children: [
9462
9541
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-6 gap-2 mb-3", children: swatches.map((sw) => /* @__PURE__ */ jsx(
9463
9542
  "button",