@almadar/ui 5.14.0 → 5.14.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.
@@ -23981,11 +23981,13 @@ var init_Coachmark = __esm({
23981
23981
  onSecondary,
23982
23982
  secondaryLabel,
23983
23983
  showBeacon = false,
23984
+ fallbackCentered = false,
23984
23985
  className
23985
23986
  }) => {
23986
23987
  const cardRef = React80.useRef(null);
23987
23988
  const rect = useAnchorRect(anchor, open);
23988
23989
  const [pos, setPos] = React80.useState(null);
23990
+ const centered = open && !rect && fallbackCentered;
23989
23991
  React80.useLayoutEffect(() => {
23990
23992
  if (!open || !rect || !cardRef.current) {
23991
23993
  setPos(null);
@@ -23997,8 +23999,18 @@ var init_Coachmark = __esm({
23997
23999
  };
23998
24000
  setPos(placeCard(placement, rect, size));
23999
24001
  }, [open, rect, placement, children, title]);
24000
- if (!open || !rect || typeof document === "undefined") return null;
24002
+ React80.useEffect(() => {
24003
+ if (!open) return;
24004
+ const onKey = (e) => {
24005
+ if (e.key === "Escape") onDismiss();
24006
+ };
24007
+ window.addEventListener("keydown", onKey);
24008
+ return () => window.removeEventListener("keydown", onKey);
24009
+ }, [open, onDismiss]);
24010
+ if (!open || typeof document === "undefined") return null;
24011
+ if (!rect && !centered) return null;
24001
24012
  const hasFooter = Boolean(onPrimary || onSecondary);
24013
+ const cardStyle = centered ? { top: "50%", left: "50%", transform: "translate(-50%, -50%)" } : pos ? { top: pos.top, left: pos.left } : { top: -9999, left: -9999 };
24002
24014
  const card = /* @__PURE__ */ jsxRuntime.jsxs(
24003
24015
  exports.Box,
24004
24016
  {
@@ -24012,10 +24024,10 @@ var init_Coachmark = __esm({
24012
24024
  "aria-label": title,
24013
24025
  className: cn(
24014
24026
  "fixed z-50 max-w-xs w-72 transition-opacity duration-150",
24015
- pos ? "opacity-100" : "opacity-0",
24027
+ centered || pos ? "opacity-100" : "opacity-0",
24016
24028
  className
24017
24029
  ),
24018
- style: pos ? { top: pos.top, left: pos.left } : { top: -9999, left: -9999 },
24030
+ style: cardStyle,
24019
24031
  children: [
24020
24032
  /* @__PURE__ */ jsxRuntime.jsx(
24021
24033
  "button",
@@ -24036,7 +24048,7 @@ var init_Coachmark = __esm({
24036
24048
  ]
24037
24049
  }
24038
24050
  );
24039
- const beacon = showBeacon ? /* @__PURE__ */ jsxRuntime.jsx(
24051
+ const beacon = showBeacon && rect ? /* @__PURE__ */ jsxRuntime.jsx(
24040
24052
  "div",
24041
24053
  {
24042
24054
  className: "fixed z-50 pointer-events-none",
@@ -24102,6 +24114,7 @@ var init_OnboardingSpotlight = __esm({
24102
24114
  open: true,
24103
24115
  anchor: step.anchor,
24104
24116
  placement: step.placement ?? "bottom",
24117
+ fallbackCentered: true,
24105
24118
  title: step.title,
24106
24119
  onDismiss: onSkip,
24107
24120
  onSecondary: onSkip,
@@ -23932,11 +23932,13 @@ var init_Coachmark = __esm({
23932
23932
  onSecondary,
23933
23933
  secondaryLabel,
23934
23934
  showBeacon = false,
23935
+ fallbackCentered = false,
23935
23936
  className
23936
23937
  }) => {
23937
23938
  const cardRef = useRef(null);
23938
23939
  const rect = useAnchorRect(anchor, open);
23939
23940
  const [pos, setPos] = useState(null);
23941
+ const centered = open && !rect && fallbackCentered;
23940
23942
  useLayoutEffect(() => {
23941
23943
  if (!open || !rect || !cardRef.current) {
23942
23944
  setPos(null);
@@ -23948,8 +23950,18 @@ var init_Coachmark = __esm({
23948
23950
  };
23949
23951
  setPos(placeCard(placement, rect, size));
23950
23952
  }, [open, rect, placement, children, title]);
23951
- if (!open || !rect || typeof document === "undefined") return null;
23953
+ useEffect(() => {
23954
+ if (!open) return;
23955
+ const onKey = (e) => {
23956
+ if (e.key === "Escape") onDismiss();
23957
+ };
23958
+ window.addEventListener("keydown", onKey);
23959
+ return () => window.removeEventListener("keydown", onKey);
23960
+ }, [open, onDismiss]);
23961
+ if (!open || typeof document === "undefined") return null;
23962
+ if (!rect && !centered) return null;
23952
23963
  const hasFooter = Boolean(onPrimary || onSecondary);
23964
+ const cardStyle = centered ? { top: "50%", left: "50%", transform: "translate(-50%, -50%)" } : pos ? { top: pos.top, left: pos.left } : { top: -9999, left: -9999 };
23953
23965
  const card = /* @__PURE__ */ jsxs(
23954
23966
  Box,
23955
23967
  {
@@ -23963,10 +23975,10 @@ var init_Coachmark = __esm({
23963
23975
  "aria-label": title,
23964
23976
  className: cn(
23965
23977
  "fixed z-50 max-w-xs w-72 transition-opacity duration-150",
23966
- pos ? "opacity-100" : "opacity-0",
23978
+ centered || pos ? "opacity-100" : "opacity-0",
23967
23979
  className
23968
23980
  ),
23969
- style: pos ? { top: pos.top, left: pos.left } : { top: -9999, left: -9999 },
23981
+ style: cardStyle,
23970
23982
  children: [
23971
23983
  /* @__PURE__ */ jsx(
23972
23984
  "button",
@@ -23987,7 +23999,7 @@ var init_Coachmark = __esm({
23987
23999
  ]
23988
24000
  }
23989
24001
  );
23990
- const beacon = showBeacon ? /* @__PURE__ */ jsx(
24002
+ const beacon = showBeacon && rect ? /* @__PURE__ */ jsx(
23991
24003
  "div",
23992
24004
  {
23993
24005
  className: "fixed z-50 pointer-events-none",
@@ -24053,6 +24065,7 @@ var init_OnboardingSpotlight = __esm({
24053
24065
  open: true,
24054
24066
  anchor: step.anchor,
24055
24067
  placement: step.placement ?? "bottom",
24068
+ fallbackCentered: true,
24056
24069
  title: step.title,
24057
24070
  onDismiss: onSkip,
24058
24071
  onSecondary: onSkip,
@@ -29,6 +29,13 @@ export interface CoachmarkProps {
29
29
  secondaryLabel?: string;
30
30
  /** Render a pulsing beacon dot over the anchor (keystone hints). */
31
31
  showBeacon?: boolean;
32
+ /**
33
+ * If the anchor can't be resolved, render the card centered in the viewport
34
+ * instead of hiding it. Guarantees the card (and its dismiss/skip) is always
35
+ * reachable — used by OnboardingSpotlight so a missing anchor never traps the
36
+ * user behind a dimmed backdrop. Default false: a missing anchor hides the card.
37
+ */
38
+ fallbackCentered?: boolean;
32
39
  className?: string;
33
40
  }
34
41
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/ui",
3
- "version": "5.14.0",
3
+ "version": "5.14.1",
4
4
  "description": "React UI components, hooks, and providers for Almadar",
5
5
  "type": "module",
6
6
  "sideEffects": [