@geomak/ui 1.7.1 → 1.7.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.d.cts CHANGED
@@ -588,16 +588,44 @@ declare function useNotification(): {
588
588
  };
589
589
 
590
590
  interface LoadingSpinnerProps {
591
- /** Text animated letter by letter */
591
+ /** Text revealed letter-by-letter beneath the spinner. */
592
592
  prompt: string;
593
+ /**
594
+ * Optional override for the spinner ring colour. Accepts any CSS colour.
595
+ * Defaults to the accent token so it picks up theme overrides.
596
+ */
597
+ spinnerColor?: string;
598
+ /**
599
+ * Optional override for the prompt text colour.
600
+ * Defaults to the foreground token (light/dark aware).
601
+ */
602
+ textColor?: string;
603
+ /**
604
+ * Backdrop opacity (0 – 1). Defaults to 0.92 — close enough to opaque to
605
+ * block UI underneath while still hinting at the previous state.
606
+ */
607
+ backdropOpacity?: number;
593
608
  }
594
609
  /**
595
- * Full-screen loading overlay with a spinning shape and staggered text reveal.
610
+ * Full-screen loading overlay with a spinning ring and a staggered text
611
+ * reveal. Portaled into `document.body` so it always covers the actual
612
+ * viewport regardless of where it's rendered in the React tree.
613
+ *
614
+ * Honours `prefers-reduced-motion`: the spinner still rotates (continuous
615
+ * spin is informative, not decorative) but the letter stagger collapses to
616
+ * an instant reveal.
596
617
  *
597
618
  * @example
598
- * {isLoading && <LoadingSpinner prompt="Loading data..." />}
619
+ * {isLoading && <LoadingSpinner prompt="Loading vessels…" />}
620
+ *
621
+ * @example
622
+ * <LoadingSpinner
623
+ * prompt="Saving"
624
+ * spinnerColor="#10b981"
625
+ * backdropOpacity={0.7}
626
+ * />
599
627
  */
600
- declare function LoadingSpinner({ prompt }: LoadingSpinnerProps): react_jsx_runtime.JSX.Element;
628
+ declare function LoadingSpinner({ prompt, spinnerColor, textColor, backdropOpacity, }: LoadingSpinnerProps): react_jsx_runtime.JSX.Element;
601
629
 
602
630
  interface FadingBaseProps {
603
631
  className?: string;
package/dist/index.d.ts CHANGED
@@ -588,16 +588,44 @@ declare function useNotification(): {
588
588
  };
589
589
 
590
590
  interface LoadingSpinnerProps {
591
- /** Text animated letter by letter */
591
+ /** Text revealed letter-by-letter beneath the spinner. */
592
592
  prompt: string;
593
+ /**
594
+ * Optional override for the spinner ring colour. Accepts any CSS colour.
595
+ * Defaults to the accent token so it picks up theme overrides.
596
+ */
597
+ spinnerColor?: string;
598
+ /**
599
+ * Optional override for the prompt text colour.
600
+ * Defaults to the foreground token (light/dark aware).
601
+ */
602
+ textColor?: string;
603
+ /**
604
+ * Backdrop opacity (0 – 1). Defaults to 0.92 — close enough to opaque to
605
+ * block UI underneath while still hinting at the previous state.
606
+ */
607
+ backdropOpacity?: number;
593
608
  }
594
609
  /**
595
- * Full-screen loading overlay with a spinning shape and staggered text reveal.
610
+ * Full-screen loading overlay with a spinning ring and a staggered text
611
+ * reveal. Portaled into `document.body` so it always covers the actual
612
+ * viewport regardless of where it's rendered in the React tree.
613
+ *
614
+ * Honours `prefers-reduced-motion`: the spinner still rotates (continuous
615
+ * spin is informative, not decorative) but the letter stagger collapses to
616
+ * an instant reveal.
596
617
  *
597
618
  * @example
598
- * {isLoading && <LoadingSpinner prompt="Loading data..." />}
619
+ * {isLoading && <LoadingSpinner prompt="Loading vessels…" />}
620
+ *
621
+ * @example
622
+ * <LoadingSpinner
623
+ * prompt="Saving"
624
+ * spinnerColor="#10b981"
625
+ * backdropOpacity={0.7}
626
+ * />
599
627
  */
600
- declare function LoadingSpinner({ prompt }: LoadingSpinnerProps): react_jsx_runtime.JSX.Element;
628
+ declare function LoadingSpinner({ prompt, spinnerColor, textColor, backdropOpacity, }: LoadingSpinnerProps): react_jsx_runtime.JSX.Element;
601
629
 
602
630
  interface FadingBaseProps {
603
631
  className?: string;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { colors_default } from './chunk-GKXP6OJJ.js';
2
2
  export { colors_default as COLORS, PALETTE as palette, semanticTokens, vars } from './chunk-GKXP6OJJ.js';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
- import React10, { createContext, useState, useEffect, useMemo, useContext, useRef, useCallback, useId } from 'react';
4
+ import React9, { createContext, useState, useEffect, useMemo, useContext, useRef, useCallback, useId } from 'react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import * as Dialog from '@radix-ui/react-dialog';
7
7
  import { useReducedMotion, AnimatePresence, motion } from 'framer-motion';
@@ -940,39 +940,61 @@ function useNotification() {
940
940
  danger: (props) => open({ type: "danger", ...props })
941
941
  };
942
942
  }
943
- function LoadingSpinner({ prompt }) {
944
- const letterRefs = useMemo(() => [], []);
945
- const letters = prompt.split("");
946
- useEffect(() => {
947
- const timeouts = [];
948
- if (letterRefs.length === letters.length) {
949
- letterRefs.forEach((ref, index) => {
950
- const t = setTimeout(() => {
951
- ref?.classList.add("slowly-appear");
952
- }, index * 100);
953
- timeouts.push(t);
954
- });
943
+ var containerVariants = {
944
+ hidden: {},
945
+ visible: { transition: { staggerChildren: 0.06 } }
946
+ };
947
+ var letterVariants = {
948
+ hidden: { opacity: 0, y: 6 },
949
+ visible: { opacity: 1, y: 0, transition: { duration: 0.25, ease: "easeOut" } }
950
+ };
951
+ function LoadingSpinner({
952
+ prompt,
953
+ spinnerColor,
954
+ textColor,
955
+ backdropOpacity = 0.92
956
+ }) {
957
+ const reduced = useReducedMotion();
958
+ const letters = Array.from(prompt);
959
+ return /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs(
960
+ "div",
961
+ {
962
+ role: "status",
963
+ "aria-live": "polite",
964
+ "aria-label": prompt,
965
+ className: "fixed inset-0 z-[8000000] flex flex-col items-center justify-center gap-6 bg-background",
966
+ style: { opacity: backdropOpacity },
967
+ children: [
968
+ /* @__PURE__ */ jsx(
969
+ "div",
970
+ {
971
+ className: "w-20 h-20 rounded-2xl border-[6px] border-transparent border-t-current border-r-current animate-spin",
972
+ style: { color: spinnerColor ?? "var(--color-accent)" },
973
+ "aria-hidden": "true"
974
+ }
975
+ ),
976
+ /* @__PURE__ */ jsx(
977
+ motion.div,
978
+ {
979
+ className: "text-3xl font-bold tracking-tight select-none",
980
+ style: { color: textColor ?? "var(--color-foreground)" },
981
+ variants: containerVariants,
982
+ initial: reduced ? "visible" : "hidden",
983
+ animate: "visible",
984
+ children: letters.map((letter, index) => /* @__PURE__ */ jsx(
985
+ motion.span,
986
+ {
987
+ className: "inline-block whitespace-pre",
988
+ variants: letterVariants,
989
+ children: letter
990
+ },
991
+ index
992
+ ))
993
+ }
994
+ )
995
+ ]
955
996
  }
956
- return () => timeouts.forEach(clearTimeout);
957
- }, [letterRefs, letters.length]);
958
- return (
959
- // Portaled so the full-screen overlay always covers the real viewport,
960
- // not whatever container the consumer renders LoadingSpinner inside.
961
- /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsxs("div", { className: "fixed top-0 bottom-0 right-0 left-0 bg-oxford-blue-700-opaque z-[8000000] flex flex-col gap-5 items-center justify-start pt-80", children: [
962
- /* @__PURE__ */ jsx("div", { className: "border-r-prussian-blue border-l-prussian-blue border-t-white border-b-white border-[10px] w-[80px] h-[80px] rounded-xl shapeshift" }),
963
- /* @__PURE__ */ jsx("div", { className: "text-prussian-blue dark:text-white text-3xl font-bold", children: letters.map((letter, index) => /* @__PURE__ */ jsx(
964
- "span",
965
- {
966
- className: "select-none",
967
- ref: (ref) => {
968
- letterRefs[index] = ref;
969
- },
970
- children: letter
971
- },
972
- index
973
- )) })
974
- ] }) })
975
- );
997
+ ) });
976
998
  }
977
999
  function FadingBase({
978
1000
  className = "",
@@ -1447,7 +1469,7 @@ function Wizard({ children, steps, storageKey = "po_wizard" }) {
1447
1469
  children
1448
1470
  ] });
1449
1471
  }
1450
- var SearchInput = React10.forwardRef(function SearchInput2({
1472
+ var SearchInput = React9.forwardRef(function SearchInput2({
1451
1473
  value,
1452
1474
  onChange,
1453
1475
  disabled,
@@ -1712,7 +1734,7 @@ function TableBody({
1712
1734
  setVisibleRows(initial);
1713
1735
  }
1714
1736
  }, [rows]);
1715
- return /* @__PURE__ */ jsx("tbody", { className: "w-full", children: rows.map((row, i) => /* @__PURE__ */ jsxs(React10.Fragment, { children: [
1737
+ return /* @__PURE__ */ jsx("tbody", { className: "w-full", children: rows.map((row, i) => /* @__PURE__ */ jsxs(React9.Fragment, { children: [
1716
1738
  /* @__PURE__ */ jsxs(
1717
1739
  "tr",
1718
1740
  {
@@ -2293,7 +2315,7 @@ function ThemeProvider({
2293
2315
  className = "",
2294
2316
  style
2295
2317
  }) {
2296
- const id = React10.useId().replace(/:/g, "");
2318
+ const id = React9.useId().replace(/:/g, "");
2297
2319
  const scopeClass = `geo-th-${id}`;
2298
2320
  const divRef = useRef(null);
2299
2321
  useEffect(() => {