@geomak/ui 1.9.0 → 3.0.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
@@ -853,72 +853,162 @@ interface MenuBarProps {
853
853
  */
854
854
  declare function MenuBar({ items }: MenuBarProps): react_jsx_runtime.JSX.Element;
855
855
 
856
+ /**
857
+ * A single action in the context menu.
858
+ *
859
+ * - Leaf items (no `children`) call `onClick` when activated.
860
+ * - Parent items (with `children`) open a sub-menu on hover / arrow-right.
861
+ * - `disabled` items render but cannot be activated; screen readers
862
+ * announce them as disabled.
863
+ */
856
864
  interface ContextMenuActionItem {
857
- key: string | number;
865
+ key: React$1.Key;
866
+ /** Label shown for the item. May be plain text or a node. */
858
867
  value: React$1.ReactNode;
859
868
  icon?: React$1.ReactNode;
860
- onClick?: (path?: string, reportType?: string) => void;
861
- path?: string;
862
- reportType?: string;
869
+ /** Fires when the item is activated. Ignored when `children` is set. */
870
+ onClick?: () => void;
871
+ /** Optional sub-menu items. */
863
872
  children?: ContextMenuActionItem[];
864
- }
865
- interface ContextMenuPosition {
866
- x: number;
867
- y: number;
873
+ /** Render as disabled — still visible but not activatable. */
874
+ disabled?: boolean;
868
875
  }
869
876
  interface ContextMenuProps {
877
+ /** Top-level items. Each may carry nested `children` for sub-menus. */
870
878
  items: ContextMenuActionItem[];
871
- position: ContextMenuPosition;
872
- visible: boolean;
873
- onClose: () => void;
879
+ /**
880
+ * The element that should respond to right-click. The entire React
881
+ * subtree underneath becomes the trigger area. Wrap an existing
882
+ * component / div / image — anything you can right-click on.
883
+ */
884
+ children: React$1.ReactNode;
874
885
  }
875
886
  /**
876
- * Right-click context menu positioned at arbitrary screen coordinates.
887
+ * Right-click context menu, built on `@radix-ui/react-context-menu`.
877
888
  *
878
- * Decoupled from `useData()` the app manages `visible`, `position`, and
879
- * `items` in its own state and passes them here.
889
+ * **Idiomatic usage**: wrap the element that should respond to right-click.
890
+ * Radix handles positioning (avoids viewport edges automatically), keyboard
891
+ * navigation (↑↓ to move, → to open sub-menu, ← to close, Enter to activate,
892
+ * Esc to dismiss), focus management, and portal-based stacking.
880
893
  *
881
- * @example
882
- * const [ctx, setCtx] = useState({ visible: false, items: [], position: { x: 0, y: 0 } })
883
- *
884
- * <div onContextMenu={(e) => {
885
- * e.preventDefault()
886
- * setCtx({ visible: true, items: menuItems, position: { x: e.clientX, y: e.clientY } })
887
- * }}>...</div>
894
+ * @example Basic — flat menu
895
+ * ```tsx
896
+ * <ContextMenu
897
+ * items={[
898
+ * { key: 'edit', value: 'Edit', onClick: () => openEditor() },
899
+ * { key: 'delete', value: 'Delete', onClick: () => askDelete() },
900
+ * ]}
901
+ * >
902
+ * <Card vessel={vessel} />
903
+ * </ContextMenu>
904
+ * ```
888
905
  *
889
- * <ContextMenu {...ctx} onClose={() => setCtx(c => ({ ...c, visible: false }))} />
906
+ * @example With sub-menu
907
+ * ```tsx
908
+ * <ContextMenu
909
+ * items={[
910
+ * {
911
+ * key: 'export', value: 'Export',
912
+ * children: [
913
+ * { key: 'csv', value: 'as CSV', onClick: () => exportCsv() },
914
+ * { key: 'xlsx', value: 'as Excel', onClick: () => exportXlsx() },
915
+ * ],
916
+ * },
917
+ * ]}
918
+ * >
919
+ * <Table rows={rows} />
920
+ * </ContextMenu>
921
+ * ```
890
922
  */
891
- declare function ContextMenu({ items, position, visible, onClose }: ContextMenuProps): react_jsx_runtime.JSX.Element;
923
+ declare function ContextMenu({ items, children }: ContextMenuProps): react_jsx_runtime.JSX.Element;
924
+ /** @deprecated The Radix rewrite positions the menu automatically — no coordinates needed. */
925
+ interface ContextMenuPosition {
926
+ x: number;
927
+ y: number;
928
+ }
892
929
 
893
930
  interface WizardStep {
894
- /** Ref to the DOM element to highlight */
895
- stepRef: React$1.RefObject<HTMLElement>;
931
+ /** Ref to the DOM element to highlight for this step. */
932
+ stepRef: React$1.RefObject<HTMLElement | null>;
933
+ /** Tooltip body content. */
896
934
  description: React$1.ReactNode;
897
- /** 'natural' | 'center' — controls tooltip position relative to target */
898
- positioning?: 'natural' | 'center';
935
+ /**
936
+ * Tooltip placement relative to the highlighted element.
937
+ * - `'right'` (default) — to the right of the highlight
938
+ * - `'left'` — to the left of the highlight
939
+ * - `'top'` — above the highlight
940
+ * - `'bottom'` — below the highlight
941
+ */
942
+ placement?: 'right' | 'left' | 'top' | 'bottom';
943
+ /** Optional heading for the step's tooltip. */
944
+ title?: React$1.ReactNode;
899
945
  }
900
946
  interface WizardProps {
947
+ /** The wrapped subtree — refs in `steps` point into this tree. */
901
948
  children: React$1.ReactNode;
949
+ /** Ordered list of steps to walk the user through. */
902
950
  steps: WizardStep[];
903
- /** localStorage key used to remember dismissal (default: 'oxygen_wizard') */
904
- storageKey?: string;
951
+ /**
952
+ * `localStorage` key used to remember dismissal. When the user clicks
953
+ * "Done" (or "Skip" when dismissible), this key is set so the wizard
954
+ * won't reopen on subsequent mounts.
955
+ *
956
+ * Pass `null` to disable persistence entirely (useful for tests or
957
+ * tours that should always run).
958
+ *
959
+ * Default: `'oxygen.wizard.completed'`.
960
+ */
961
+ storageKey?: string | null;
962
+ /** Show a "Skip tour" button + Esc-to-dismiss. Default `true`. */
963
+ dismissible?: boolean;
964
+ /** Called when the user reaches the final step's "Done" button. */
965
+ onComplete?: () => void;
966
+ /** Called when the user skips (or presses Esc) before completing. */
967
+ onSkip?: () => void;
905
968
  }
906
969
  /**
907
- * Guided-tour overlay wizard.
970
+ * Guided-tour overlay that walks the user through a sequence of UI elements.
908
971
  *
909
- * Highlights a DOM element via a border, then shows a floating tooltip
910
- * adjacent to it. Remembers dismissal via localStorage.
972
+ * Highlights each step's target element with an outlined "spotlight", shows a
973
+ * tooltip with the description, and provides Prev / Next / Done navigation.
974
+ * The wrapped tree is rendered unchanged; the overlay sits on top of it via a
975
+ * portal so it always covers the real viewport regardless of where Wizard
976
+ * lives in the React tree.
977
+ *
978
+ * **What's improved over the previous version**
979
+ * - `localStorage` access is SSR-safe and try/catch-guarded (Safari private
980
+ * mode, quota exceeded, no-storage browsers all degrade silently).
981
+ * - No more `classList.add(...)` on consumer-owned DOM. The spotlight is a
982
+ * portaled outline rectangle that tracks the target's bbox via
983
+ * `ResizeObserver` + scroll/resize listeners. The consumer's DOM is never
984
+ * mutated, so unmounting Wizard mid-tour leaves no orphan classes.
985
+ * - Focus trap inside the tooltip — Tab and Shift+Tab cycle through the
986
+ * tooltip's buttons. Esc dismisses (when `dismissible`).
987
+ * - Backdrop blocks click-through on the rest of the page so the user can't
988
+ * stumble into unrelated UI mid-tour. The highlighted target itself stays
989
+ * click-blocked too (use the "Next" button to advance).
990
+ * - Position recalculates on scroll / resize / target size changes via
991
+ * `ResizeObserver`.
992
+ * - All `dark-cornflower-blue` / `prussian-blue` / `bg-white` swapped for
993
+ * semantic tokens — both light and dark modes work out of the box.
911
994
  *
912
995
  * @example
913
- * const step1Ref = useRef<HTMLDivElement>(null)
914
- * const steps = [
915
- * { stepRef: step1Ref, description: 'Click here to start.', positioning: 'natural' },
916
- * ]
917
- * <Wizard steps={steps}>
918
- * <div ref={step1Ref}>...</div>
996
+ * ```tsx
997
+ * const dashRef = useRef<HTMLDivElement>(null)
998
+ * const sidebarRef = useRef<HTMLElement>(null)
999
+ *
1000
+ * <Wizard
1001
+ * steps={[
1002
+ * { stepRef: dashRef, title: 'Dashboard', description: 'Your fleet at a glance.' },
1003
+ * { stepRef: sidebarRef, title: 'Navigation', description: 'Jump between sections here.', placement: 'right' },
1004
+ * ]}
1005
+ * onComplete={() => track('onboarding_complete')}
1006
+ * >
1007
+ * <Layout dashRef={dashRef} sidebarRef={sidebarRef} />
919
1008
  * </Wizard>
1009
+ * ```
920
1010
  */
921
- declare function Wizard({ children, steps, storageKey }: WizardProps): react_jsx_runtime.JSX.Element;
1011
+ declare function Wizard({ children, steps, storageKey, dismissible, onComplete, onSkip, }: WizardProps): react_jsx_runtime.JSX.Element;
922
1012
 
923
1013
  /** ─────────────────── types ─────────────────── */
924
1014
  /**
package/dist/index.d.ts CHANGED
@@ -853,72 +853,162 @@ interface MenuBarProps {
853
853
  */
854
854
  declare function MenuBar({ items }: MenuBarProps): react_jsx_runtime.JSX.Element;
855
855
 
856
+ /**
857
+ * A single action in the context menu.
858
+ *
859
+ * - Leaf items (no `children`) call `onClick` when activated.
860
+ * - Parent items (with `children`) open a sub-menu on hover / arrow-right.
861
+ * - `disabled` items render but cannot be activated; screen readers
862
+ * announce them as disabled.
863
+ */
856
864
  interface ContextMenuActionItem {
857
- key: string | number;
865
+ key: React$1.Key;
866
+ /** Label shown for the item. May be plain text or a node. */
858
867
  value: React$1.ReactNode;
859
868
  icon?: React$1.ReactNode;
860
- onClick?: (path?: string, reportType?: string) => void;
861
- path?: string;
862
- reportType?: string;
869
+ /** Fires when the item is activated. Ignored when `children` is set. */
870
+ onClick?: () => void;
871
+ /** Optional sub-menu items. */
863
872
  children?: ContextMenuActionItem[];
864
- }
865
- interface ContextMenuPosition {
866
- x: number;
867
- y: number;
873
+ /** Render as disabled — still visible but not activatable. */
874
+ disabled?: boolean;
868
875
  }
869
876
  interface ContextMenuProps {
877
+ /** Top-level items. Each may carry nested `children` for sub-menus. */
870
878
  items: ContextMenuActionItem[];
871
- position: ContextMenuPosition;
872
- visible: boolean;
873
- onClose: () => void;
879
+ /**
880
+ * The element that should respond to right-click. The entire React
881
+ * subtree underneath becomes the trigger area. Wrap an existing
882
+ * component / div / image — anything you can right-click on.
883
+ */
884
+ children: React$1.ReactNode;
874
885
  }
875
886
  /**
876
- * Right-click context menu positioned at arbitrary screen coordinates.
887
+ * Right-click context menu, built on `@radix-ui/react-context-menu`.
877
888
  *
878
- * Decoupled from `useData()` the app manages `visible`, `position`, and
879
- * `items` in its own state and passes them here.
889
+ * **Idiomatic usage**: wrap the element that should respond to right-click.
890
+ * Radix handles positioning (avoids viewport edges automatically), keyboard
891
+ * navigation (↑↓ to move, → to open sub-menu, ← to close, Enter to activate,
892
+ * Esc to dismiss), focus management, and portal-based stacking.
880
893
  *
881
- * @example
882
- * const [ctx, setCtx] = useState({ visible: false, items: [], position: { x: 0, y: 0 } })
883
- *
884
- * <div onContextMenu={(e) => {
885
- * e.preventDefault()
886
- * setCtx({ visible: true, items: menuItems, position: { x: e.clientX, y: e.clientY } })
887
- * }}>...</div>
894
+ * @example Basic — flat menu
895
+ * ```tsx
896
+ * <ContextMenu
897
+ * items={[
898
+ * { key: 'edit', value: 'Edit', onClick: () => openEditor() },
899
+ * { key: 'delete', value: 'Delete', onClick: () => askDelete() },
900
+ * ]}
901
+ * >
902
+ * <Card vessel={vessel} />
903
+ * </ContextMenu>
904
+ * ```
888
905
  *
889
- * <ContextMenu {...ctx} onClose={() => setCtx(c => ({ ...c, visible: false }))} />
906
+ * @example With sub-menu
907
+ * ```tsx
908
+ * <ContextMenu
909
+ * items={[
910
+ * {
911
+ * key: 'export', value: 'Export',
912
+ * children: [
913
+ * { key: 'csv', value: 'as CSV', onClick: () => exportCsv() },
914
+ * { key: 'xlsx', value: 'as Excel', onClick: () => exportXlsx() },
915
+ * ],
916
+ * },
917
+ * ]}
918
+ * >
919
+ * <Table rows={rows} />
920
+ * </ContextMenu>
921
+ * ```
890
922
  */
891
- declare function ContextMenu({ items, position, visible, onClose }: ContextMenuProps): react_jsx_runtime.JSX.Element;
923
+ declare function ContextMenu({ items, children }: ContextMenuProps): react_jsx_runtime.JSX.Element;
924
+ /** @deprecated The Radix rewrite positions the menu automatically — no coordinates needed. */
925
+ interface ContextMenuPosition {
926
+ x: number;
927
+ y: number;
928
+ }
892
929
 
893
930
  interface WizardStep {
894
- /** Ref to the DOM element to highlight */
895
- stepRef: React$1.RefObject<HTMLElement>;
931
+ /** Ref to the DOM element to highlight for this step. */
932
+ stepRef: React$1.RefObject<HTMLElement | null>;
933
+ /** Tooltip body content. */
896
934
  description: React$1.ReactNode;
897
- /** 'natural' | 'center' — controls tooltip position relative to target */
898
- positioning?: 'natural' | 'center';
935
+ /**
936
+ * Tooltip placement relative to the highlighted element.
937
+ * - `'right'` (default) — to the right of the highlight
938
+ * - `'left'` — to the left of the highlight
939
+ * - `'top'` — above the highlight
940
+ * - `'bottom'` — below the highlight
941
+ */
942
+ placement?: 'right' | 'left' | 'top' | 'bottom';
943
+ /** Optional heading for the step's tooltip. */
944
+ title?: React$1.ReactNode;
899
945
  }
900
946
  interface WizardProps {
947
+ /** The wrapped subtree — refs in `steps` point into this tree. */
901
948
  children: React$1.ReactNode;
949
+ /** Ordered list of steps to walk the user through. */
902
950
  steps: WizardStep[];
903
- /** localStorage key used to remember dismissal (default: 'oxygen_wizard') */
904
- storageKey?: string;
951
+ /**
952
+ * `localStorage` key used to remember dismissal. When the user clicks
953
+ * "Done" (or "Skip" when dismissible), this key is set so the wizard
954
+ * won't reopen on subsequent mounts.
955
+ *
956
+ * Pass `null` to disable persistence entirely (useful for tests or
957
+ * tours that should always run).
958
+ *
959
+ * Default: `'oxygen.wizard.completed'`.
960
+ */
961
+ storageKey?: string | null;
962
+ /** Show a "Skip tour" button + Esc-to-dismiss. Default `true`. */
963
+ dismissible?: boolean;
964
+ /** Called when the user reaches the final step's "Done" button. */
965
+ onComplete?: () => void;
966
+ /** Called when the user skips (or presses Esc) before completing. */
967
+ onSkip?: () => void;
905
968
  }
906
969
  /**
907
- * Guided-tour overlay wizard.
970
+ * Guided-tour overlay that walks the user through a sequence of UI elements.
908
971
  *
909
- * Highlights a DOM element via a border, then shows a floating tooltip
910
- * adjacent to it. Remembers dismissal via localStorage.
972
+ * Highlights each step's target element with an outlined "spotlight", shows a
973
+ * tooltip with the description, and provides Prev / Next / Done navigation.
974
+ * The wrapped tree is rendered unchanged; the overlay sits on top of it via a
975
+ * portal so it always covers the real viewport regardless of where Wizard
976
+ * lives in the React tree.
977
+ *
978
+ * **What's improved over the previous version**
979
+ * - `localStorage` access is SSR-safe and try/catch-guarded (Safari private
980
+ * mode, quota exceeded, no-storage browsers all degrade silently).
981
+ * - No more `classList.add(...)` on consumer-owned DOM. The spotlight is a
982
+ * portaled outline rectangle that tracks the target's bbox via
983
+ * `ResizeObserver` + scroll/resize listeners. The consumer's DOM is never
984
+ * mutated, so unmounting Wizard mid-tour leaves no orphan classes.
985
+ * - Focus trap inside the tooltip — Tab and Shift+Tab cycle through the
986
+ * tooltip's buttons. Esc dismisses (when `dismissible`).
987
+ * - Backdrop blocks click-through on the rest of the page so the user can't
988
+ * stumble into unrelated UI mid-tour. The highlighted target itself stays
989
+ * click-blocked too (use the "Next" button to advance).
990
+ * - Position recalculates on scroll / resize / target size changes via
991
+ * `ResizeObserver`.
992
+ * - All `dark-cornflower-blue` / `prussian-blue` / `bg-white` swapped for
993
+ * semantic tokens — both light and dark modes work out of the box.
911
994
  *
912
995
  * @example
913
- * const step1Ref = useRef<HTMLDivElement>(null)
914
- * const steps = [
915
- * { stepRef: step1Ref, description: 'Click here to start.', positioning: 'natural' },
916
- * ]
917
- * <Wizard steps={steps}>
918
- * <div ref={step1Ref}>...</div>
996
+ * ```tsx
997
+ * const dashRef = useRef<HTMLDivElement>(null)
998
+ * const sidebarRef = useRef<HTMLElement>(null)
999
+ *
1000
+ * <Wizard
1001
+ * steps={[
1002
+ * { stepRef: dashRef, title: 'Dashboard', description: 'Your fleet at a glance.' },
1003
+ * { stepRef: sidebarRef, title: 'Navigation', description: 'Jump between sections here.', placement: 'right' },
1004
+ * ]}
1005
+ * onComplete={() => track('onboarding_complete')}
1006
+ * >
1007
+ * <Layout dashRef={dashRef} sidebarRef={sidebarRef} />
919
1008
  * </Wizard>
1009
+ * ```
920
1010
  */
921
- declare function Wizard({ children, steps, storageKey }: WizardProps): react_jsx_runtime.JSX.Element;
1011
+ declare function Wizard({ children, steps, storageKey, dismissible, onComplete, onSkip, }: WizardProps): react_jsx_runtime.JSX.Element;
922
1012
 
923
1013
  /** ─────────────────── types ─────────────────── */
924
1014
  /**