@geomak/ui 5.0.1 → 5.0.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.
package/dist/index.cjs CHANGED
@@ -10,7 +10,6 @@ var TooltipPrimitive = require('@radix-ui/react-tooltip');
10
10
  var TabsPrimitive = require('@radix-ui/react-tabs');
11
11
  var Accordion = require('@radix-ui/react-accordion');
12
12
  var ToggleGroup = require('@radix-ui/react-toggle-group');
13
- var Toast = require('@radix-ui/react-toast');
14
13
  var ContextMenuPrimitive = require('@radix-ui/react-context-menu');
15
14
  var Popover = require('@radix-ui/react-popover');
16
15
  var SwitchPrimitive = require('@radix-ui/react-switch');
@@ -42,7 +41,6 @@ var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespace(TooltipPrimitiv
42
41
  var TabsPrimitive__namespace = /*#__PURE__*/_interopNamespace(TabsPrimitive);
43
42
  var Accordion__namespace = /*#__PURE__*/_interopNamespace(Accordion);
44
43
  var ToggleGroup__namespace = /*#__PURE__*/_interopNamespace(ToggleGroup);
45
- var Toast__namespace = /*#__PURE__*/_interopNamespace(Toast);
46
44
  var ContextMenuPrimitive__namespace = /*#__PURE__*/_interopNamespace(ContextMenuPrimitive);
47
45
  var Popover__namespace = /*#__PURE__*/_interopNamespace(Popover);
48
46
  var SwitchPrimitive__namespace = /*#__PURE__*/_interopNamespace(SwitchPrimitive);
@@ -816,12 +814,12 @@ var VIEWPORT_CLASSES = {
816
814
  function getInitialMotion(pos, reduced) {
817
815
  if (reduced) return { opacity: 0, y: 0, scale: 1 };
818
816
  const bottom = pos.startsWith("bottom");
819
- return {
820
- opacity: 0,
821
- y: bottom ? 24 : -24,
822
- // rise from below (bottom) or drop from above (top)
823
- scale: 0.92
824
- };
817
+ return { opacity: 0, y: bottom ? 28 : -28, scale: 0.92 };
818
+ }
819
+ function getExitMotion(pos, reduced) {
820
+ if (reduced) return { opacity: 0, y: 0, scale: 1 };
821
+ const bottom = pos.startsWith("bottom");
822
+ return { opacity: 0, y: bottom ? 18 : -18, scale: 0.94 };
825
823
  }
826
824
  function TypeIcon({ type }) {
827
825
  if (type === "success") {
@@ -853,66 +851,87 @@ function NotificationItem({
853
851
  onClose,
854
852
  reduced
855
853
  }) {
856
- const [hovered, setHovered] = React8.useState(false);
857
- const initial = getInitialMotion(pos, reduced);
858
- const center = pos.endsWith("center");
854
+ const [paused, setPaused] = React8.useState(false);
859
855
  const duration = n.duration ?? 4e3;
860
- const showProgress = !reduced && isFinite(duration) && duration > 0;
856
+ const isAutoDismissing = isFinite(duration) && duration > 0;
857
+ const showProgress = !reduced && isAutoDismissing;
858
+ const timerRef = React8.useRef(null);
859
+ const startTimeRef = React8.useRef(0);
860
+ const remainingRef = React8.useRef(duration);
861
+ const clearTimer = React8.useCallback(() => {
862
+ if (timerRef.current !== null) {
863
+ clearTimeout(timerRef.current);
864
+ timerRef.current = null;
865
+ }
866
+ }, []);
867
+ const scheduleDismiss = React8.useCallback((ms) => {
868
+ clearTimer();
869
+ if (!isAutoDismissing) return;
870
+ startTimeRef.current = Date.now();
871
+ timerRef.current = setTimeout(() => onClose(n.id), ms);
872
+ }, [clearTimer, isAutoDismissing, n.id, onClose]);
873
+ React8.useEffect(() => {
874
+ if (paused || !isAutoDismissing) return;
875
+ scheduleDismiss(remainingRef.current);
876
+ return clearTimer;
877
+ }, [paused, isAutoDismissing, scheduleDismiss, clearTimer]);
878
+ const onPauseStart = () => {
879
+ if (!isAutoDismissing) return;
880
+ const elapsed = Date.now() - startTimeRef.current;
881
+ remainingRef.current = Math.max(0, remainingRef.current - elapsed);
882
+ setPaused(true);
883
+ };
884
+ const onPauseEnd = () => {
885
+ if (!isAutoDismissing) return;
886
+ setPaused(false);
887
+ };
861
888
  return /* @__PURE__ */ jsxRuntime.jsx(
862
889
  framerMotion.motion.div,
863
890
  {
891
+ layout: true,
864
892
  className: "pointer-events-auto",
865
- initial,
893
+ initial: getInitialMotion(pos, reduced),
866
894
  animate: { opacity: 1, y: 0, scale: 1 },
867
- exit: {
868
- opacity: 0,
869
- y: pos.startsWith("bottom") ? 16 : -16,
870
- scale: 0.94,
871
- transition: reduced ? { duration: 0 } : {
872
- opacity: { duration: 0.14, delay: 0.06 },
873
- y: { type: "tween", duration: 0.22, ease: [0.4, 0, 1, 1] },
874
- scale: { type: "tween", duration: 0.22, ease: [0.4, 0, 1, 1] }
875
- }
876
- },
895
+ exit: getExitMotion(pos, reduced),
877
896
  transition: reduced ? { duration: 0 } : {
878
- // Opacity finishes in 0.15 s card is fully opaque while y/scale
879
- // still have ~55 % of their travel left → movement is clearly visible.
897
+ // Opacity finishes in 0.15 s; y/scale take 0.34 s.
898
+ // Card is opaque while still travelling movement
899
+ // is clearly visible to the user.
880
900
  opacity: { duration: 0.15 },
881
901
  y: { type: "tween", duration: 0.34, ease: [0.16, 1, 0.3, 1] },
882
- scale: { type: "tween", duration: 0.34, ease: [0.16, 1, 0.3, 1] }
902
+ scale: { type: "tween", duration: 0.34, ease: [0.16, 1, 0.3, 1] },
903
+ layout: { duration: 0.22, ease: [0.16, 1, 0.3, 1] }
883
904
  },
884
- onMouseEnter: () => setHovered(true),
885
- onMouseLeave: () => setHovered(false),
905
+ onMouseEnter: onPauseStart,
906
+ onMouseLeave: onPauseEnd,
907
+ onFocus: onPauseStart,
908
+ onBlur: onPauseEnd,
909
+ role: n.type === "danger" || n.type === "warning" ? "alert" : "status",
910
+ "aria-live": n.type === "danger" || n.type === "warning" ? "assertive" : "polite",
886
911
  children: /* @__PURE__ */ jsxRuntime.jsxs(
887
- Toast__namespace.Root,
912
+ "div",
888
913
  {
889
- open: true,
890
- duration,
891
- onOpenChange: (o) => {
892
- if (!o) onClose(n.id);
893
- },
894
914
  className: [
895
- "w-[300px] rounded-md shadow-lg overflow-hidden",
896
- center ? "mx-auto" : "",
897
- "focus:outline-none",
915
+ "w-[300px] rounded-md shadow-lg overflow-hidden focus:outline-none",
898
916
  TYPE_BG[n.type ?? "info"]
899
917
  ].join(" "),
900
918
  children: [
901
919
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3 p-3 pr-2.5", children: [
902
920
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-0.5 flex-shrink-0 text-white/90", children: /* @__PURE__ */ jsxRuntime.jsx(TypeIcon, { type: n.type ?? "info" }) }),
903
921
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
904
- /* @__PURE__ */ jsxRuntime.jsx(Toast__namespace.Title, { className: "text-sm font-semibold text-white leading-snug", children: n.title }),
905
- n.description && /* @__PURE__ */ jsxRuntime.jsx(Toast__namespace.Description, { className: "mt-0.5 text-xs text-white/75 leading-relaxed", children: n.description })
922
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-white leading-snug", children: n.title }),
923
+ n.description && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-0.5 text-xs text-white/75 leading-relaxed", children: n.description })
906
924
  ] }),
907
- /* @__PURE__ */ jsxRuntime.jsx(Toast__namespace.Action, { asChild: true, altText: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(
925
+ /* @__PURE__ */ jsxRuntime.jsx(
908
926
  "button",
909
927
  {
910
- "aria-label": "Close",
928
+ type: "button",
929
+ "aria-label": "Close notification",
911
930
  onClick: () => onClose(n.id),
912
931
  className: "flex-shrink-0 mt-0.5 rounded p-1 text-white/60 hover:text-white hover:bg-white/15 transition-colors duration-100 focus:outline-none focus-visible:ring-1 focus-visible:ring-white/50",
913
932
  children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 3L3 9M3 3l6 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) })
914
933
  }
915
- ) })
934
+ )
916
935
  ] }),
917
936
  showProgress && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative h-[3px] bg-white/20 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
918
937
  "div",
@@ -920,7 +939,7 @@ function NotificationItem({
920
939
  className: "absolute inset-0 bg-white/60 [transform-origin:left]",
921
940
  style: {
922
941
  animation: `notification-progress ${duration}ms linear forwards`,
923
- animationPlayState: hovered ? "paused" : "running"
942
+ animationPlayState: paused ? "paused" : "running"
924
943
  }
925
944
  }
926
945
  ) })
@@ -936,26 +955,27 @@ function NotificationProvider({
936
955
  }) {
937
956
  const [notifications, setNotifications] = React8.useState([]);
938
957
  const reduced = framerMotion.useReducedMotion();
939
- const open = (payload) => {
958
+ const open = React8.useCallback((payload) => {
940
959
  setNotifications((prev) => [
941
960
  ...prev,
942
961
  { duration: 4e3, ...payload, id: Date.now() + Math.random() }
943
962
  ]);
944
- };
945
- const close = (id) => {
963
+ }, []);
964
+ const close = React8.useCallback((id) => {
946
965
  setNotifications((prev) => prev.filter((n) => n.id !== id));
947
- };
948
- return /* @__PURE__ */ jsxRuntime.jsx(NotificationContext.Provider, { value: { open, close }, children: /* @__PURE__ */ jsxRuntime.jsxs(Toast__namespace.Provider, { swipeDirection: position.endsWith("right") ? "right" : position.endsWith("left") ? "left" : "up", children: [
966
+ }, []);
967
+ return /* @__PURE__ */ jsxRuntime.jsxs(NotificationContext.Provider, { value: { open, close }, children: [
949
968
  children,
950
969
  /* @__PURE__ */ jsxRuntime.jsx(Portal, { children: /* @__PURE__ */ jsxRuntime.jsx(
951
- Toast__namespace.Viewport,
970
+ "ul",
952
971
  {
953
- asChild: true,
972
+ role: "region",
973
+ "aria-label": "Notifications",
954
974
  className: [
955
975
  VIEWPORT_CLASSES[position],
956
- "z-[500000] gap-2 w-[332px] outline-none pointer-events-none"
976
+ "z-[500000] gap-2 w-[316px] outline-none pointer-events-none m-0 p-0 list-none"
957
977
  ].join(" "),
958
- children: /* @__PURE__ */ jsxRuntime.jsx("ul", { children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { initial: false, children: notifications.map((n) => /* @__PURE__ */ jsxRuntime.jsx(
978
+ children: /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { initial: false, children: notifications.map((n) => /* @__PURE__ */ jsxRuntime.jsx(
959
979
  NotificationItem,
960
980
  {
961
981
  n,
@@ -964,10 +984,10 @@ function NotificationProvider({
964
984
  reduced
965
985
  },
966
986
  n.id
967
- )) }) })
987
+ )) })
968
988
  }
969
989
  ) })
970
- ] }) });
990
+ ] });
971
991
  }
972
992
  function useNotification() {
973
993
  const { open } = React8.useContext(NotificationContext);
@@ -1556,6 +1576,7 @@ function Wizard({
1556
1576
  const tooltipRef = React8.useRef(null);
1557
1577
  const tooltipTitleId = React8.useId();
1558
1578
  const tooltipBodyId = React8.useId();
1579
+ const reduced = framerMotion.useReducedMotion();
1559
1580
  const [open, setOpen] = React8.useState(() => steps.length > 0 && !readDismissed(storageKey));
1560
1581
  const [activeIndex, setActiveIndex] = React8.useState(0);
1561
1582
  const step = steps[activeIndex];
@@ -1599,24 +1620,36 @@ function Wizard({
1599
1620
  const isLast = activeIndex === steps.length - 1;
1600
1621
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1601
1622
  children,
1602
- open && step && /* @__PURE__ */ jsxRuntime.jsxs(Portal, { children: [
1623
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: open && step && /* @__PURE__ */ jsxRuntime.jsxs(Portal, { children: [
1603
1624
  /* @__PURE__ */ jsxRuntime.jsx(
1604
- "div",
1625
+ framerMotion.motion.div,
1605
1626
  {
1606
1627
  className: "fixed inset-0 z-[7000000] bg-foreground/40 backdrop-blur-[1px] pointer-events-auto",
1628
+ initial: { opacity: 0 },
1629
+ animate: { opacity: 1 },
1630
+ exit: { opacity: 0 },
1631
+ transition: { duration: reduced ? 0 : 0.18, ease: "easeOut" },
1607
1632
  "aria-hidden": "true"
1608
1633
  }
1609
1634
  ),
1610
1635
  /* @__PURE__ */ jsxRuntime.jsx(
1611
- "div",
1636
+ framerMotion.motion.div,
1612
1637
  {
1613
- className: "fixed z-[7000001] pointer-events-none rounded-md ring-2 ring-accent ring-offset-2 ring-offset-background transition-all duration-200",
1638
+ className: "fixed z-[7000001] pointer-events-none rounded-md ring-2 ring-accent ring-offset-2 ring-offset-background",
1614
1639
  style: highlightStyle,
1640
+ initial: { opacity: 0, scale: 1.08 },
1641
+ animate: { opacity: 1, scale: 1 },
1642
+ exit: { opacity: 0, scale: 1.08 },
1643
+ transition: {
1644
+ duration: reduced ? 0 : 0.32,
1645
+ ease: [0.16, 1, 0.3, 1]
1646
+ // ease-out-expo — settles softly
1647
+ },
1615
1648
  "aria-hidden": "true"
1616
1649
  }
1617
1650
  ),
1618
1651
  /* @__PURE__ */ jsxRuntime.jsxs(
1619
- "div",
1652
+ framerMotion.motion.div,
1620
1653
  {
1621
1654
  ref: tooltipRef,
1622
1655
  role: "dialog",
@@ -1625,6 +1658,14 @@ function Wizard({
1625
1658
  "aria-describedby": tooltipBodyId,
1626
1659
  className: "fixed z-[7000002] rounded-lg bg-surface text-foreground border border-border shadow-xl p-4 pointer-events-auto",
1627
1660
  style: tooltipStyle,
1661
+ initial: { opacity: 0, scale: 0.96, y: 6 },
1662
+ animate: { opacity: 1, scale: 1, y: 0 },
1663
+ exit: { opacity: 0, scale: 0.97, y: 4 },
1664
+ transition: reduced ? { duration: 0 } : {
1665
+ opacity: { duration: 0.18 },
1666
+ scale: { type: "tween", duration: 0.26, ease: [0.16, 1, 0.3, 1] },
1667
+ y: { type: "tween", duration: 0.26, ease: [0.16, 1, 0.3, 1] }
1668
+ },
1628
1669
  children: [
1629
1670
  step.title && /* @__PURE__ */ jsxRuntime.jsx("h3", { id: tooltipTitleId, className: "text-sm font-semibold text-foreground mb-1", children: step.title }),
1630
1671
  /* @__PURE__ */ jsxRuntime.jsx("div", { id: tooltipBodyId, className: "text-sm text-foreground-secondary leading-relaxed", children: step.description }),
@@ -1664,9 +1705,10 @@ function Wizard({
1664
1705
  ] })
1665
1706
  ] })
1666
1707
  ]
1667
- }
1708
+ },
1709
+ activeIndex
1668
1710
  )
1669
- ] })
1711
+ ] }) })
1670
1712
  ] });
1671
1713
  }
1672
1714
  var SearchInput = React8__default.default.forwardRef(function SearchInput2({