@zauru-sdk/components 6.16.0 → 6.17.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/CHANGELOG.md CHANGED
@@ -3,6 +3,28 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [6.17.0](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.16.1...@zauru-sdk/components@6.17.0) (2026-10-29)
7
+
8
+
9
+ ### Features
10
+
11
+ * reportar ErrorBoundaryAlert a CloudWatch ([de3c326](https://github.com/intuitiva/zauru-typescript-sdk/commit/de3c32674da2ebbbff53dc307e11ca213043d1c5))
12
+
13
+
14
+
15
+
16
+
17
+ ## [6.16.1](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.16.0...@zauru-sdk/components@6.16.1) (2026-10-29)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * navegar al elegir un ítem del submenu del NavBar ([75ba139](https://github.com/intuitiva/zauru-typescript-sdk/commit/75ba1395615f2c5dde2bd00d6e404296b45c0b3b))
23
+
24
+
25
+
26
+
27
+
6
28
  # [6.16.0](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/components@6.15.1...@zauru-sdk/components@6.16.0) (2026-10-29)
7
29
 
8
30
 
@@ -1,5 +1,17 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ //<reference> https://tailwindtemplates.io/templates?category=alert
3
+ import { useEffect } from "react";
4
+ import { sendClientError } from "../../observability/sendClientError.js";
2
5
  export const ErrorBoundaryAlert = (props) => {
3
6
  const { title, description } = props;
7
+ useEffect(() => {
8
+ const message = [title, description].filter(Boolean).join(" — ");
9
+ if (!message)
10
+ return;
11
+ sendClientError({
12
+ message,
13
+ source: "errorBoundary",
14
+ });
15
+ }, [title, description]);
4
16
  return (_jsx("div", { className: "rounded-full top-20 mx-auto p-3", children: _jsx("div", { className: "p-4 text-red-900 bg-red-100 border border-red-200 rounded-md", children: _jsxs("div", { className: "flex justify-between flex-wrap", children: [_jsxs("div", { className: "w-0 flex-1 flex", children: [_jsx("div", { className: "mr-3 pt-1", children: _jsx("svg", { width: "26", height: "26", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", children: _jsx("path", { d: "M13.6086 3.247l8.1916 15.8c.0999.2.1998.5.1998.8 0 1-.7992 1.8-1.7982 1.8H3.7188c-.2997 0-.4995-.1-.7992-.2-.7992-.5-1.1988-1.5-.6993-2.4 5.3067-10.1184 8.0706-15.385 8.2915-15.8.3314-.6222.8681-.8886 1.4817-.897.6135-.008 1.273.2807 1.6151.897zM12 18.95c.718 0 1.3-.582 1.3-1.3 0-.718-.582-1.3-1.3-1.3-.718 0-1.3.582-1.3 1.3 0 .718.582 1.3 1.3 1.3zm-.8895-10.203v5.4c0 .5.4.9.9.9s.9-.4.9-.9v-5.3c0-.5-.4-.9-.9-.9s-.9.4-.9.8z" }) }) }), _jsxs("div", { children: [_jsx("h4", { className: "text-md leading-6 font-medium", children: title?.toString() }), _jsx("p", { className: "text-sm", children: description?.toString() })] })] }), _jsx("div", { children: _jsx("button", { type: "button", className: "rounded-md focus:outline-none focus:ring-2 focus:ring-red-500", children: _jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", children: _jsx("path", { d: "M17.6555 6.3331a.9.9 0 0 1 .001 1.2728l-4.1032 4.1085a.4.4 0 0 0 0 .5653l4.1031 4.1088a.9002.9002 0 0 1 .0797 1.1807l-.0806.092a.9.9 0 0 1-1.2728-.0009l-4.1006-4.1068a.4.4 0 0 0-.5662 0l-4.099 4.1068a.9.9 0 1 1-1.2738-1.2718l4.1027-4.1089a.4.4 0 0 0 0-.5652L6.343 7.6059a.9002.9002 0 0 1-.0796-1.1807l.0806-.092a.9.9 0 0 1 1.2728.0009l4.099 4.1055a.4.4 0 0 0 .5662 0l4.1006-4.1055a.9.9 0 0 1 1.2728-.001z" }) }) }) })] }) }) }));
5
17
  };
@@ -78,14 +78,15 @@ const NavItems = ({ items, color, layout, openMenuId, setOpenMenuId, onNavigate,
78
78
  const children = visibleChildrenOf(item);
79
79
  const menuKey = `${item.name}-${index}`;
80
80
  if (children.length > 0) {
81
- return (_jsx(NavItemGroup, { item: item, color: color, layout: layout, open: openMenuId === menuKey, onToggle: () => setOpenMenuId(openMenuId === menuKey ? null : menuKey), onNavigate: onNavigate }, menuKey));
81
+ return (_jsx(NavItemGroup, { item: item, color: color, layout: layout, open: openMenuId === menuKey, onToggle: () => setOpenMenuId((current) => (current === menuKey ? null : menuKey)), onNavigate: onNavigate }, menuKey));
82
82
  }
83
83
  return (_jsx(NavLinkItem, { item: item, color: color, layout: layout, onNavigate: onNavigate }, menuKey));
84
84
  }) }));
85
85
  export const NavBar = ({ title, loggedIn, items, selectedColor, version, reloadCatalogsOption, settingsOption, showDarkModeToggle = false, }) => {
86
86
  const color = COLORS[selectedColor];
87
87
  const [navOpen, setNavOpen] = useState(false);
88
- const [openMenuId, setOpenMenuId] = useState(null);
88
+ const [desktopMenuId, setDesktopMenuId] = useState(null);
89
+ const [mobileAccordionId, setMobileAccordionId] = useState(null);
89
90
  const [currentVersion, setCurrentVersion] = useState(version);
90
91
  const [isDarkMode, setIsDarkMode] = useState(false);
91
92
  const navigate = useNavigate();
@@ -105,7 +106,8 @@ export const NavBar = ({ title, loggedIn, items, selectedColor, version, reloadC
105
106
  }, [version, currentVersion]);
106
107
  useEffect(() => {
107
108
  setNavOpen(false);
108
- setOpenMenuId(null);
109
+ setDesktopMenuId(null);
110
+ setMobileAccordionId(null);
109
111
  }, [location.pathname]);
110
112
  useEffect(() => {
111
113
  if (!navOpen)
@@ -132,24 +134,33 @@ export const NavBar = ({ title, loggedIn, items, selectedColor, version, reloadC
132
134
  if (event.key !== "Escape")
133
135
  return;
134
136
  setNavOpen(false);
135
- setOpenMenuId(null);
137
+ setDesktopMenuId(null);
138
+ setMobileAccordionId(null);
136
139
  };
137
140
  document.addEventListener("keydown", onKeyDown);
138
141
  return () => document.removeEventListener("keydown", onKeyDown);
139
142
  }, []);
140
143
  useEffect(() => {
144
+ if (!desktopMenuId)
145
+ return;
141
146
  const onPointerDown = (event) => {
142
- if (desktopMenuRef.current &&
143
- !desktopMenuRef.current.contains(event.target)) {
144
- setOpenMenuId(null);
145
- }
147
+ const target = event.target;
148
+ if (mobileDrawerRef.current?.contains(target))
149
+ return;
150
+ if (desktopMenuRef.current?.contains(target))
151
+ return;
152
+ setDesktopMenuId(null);
146
153
  };
147
154
  document.addEventListener("mousedown", onPointerDown);
148
155
  return () => document.removeEventListener("mousedown", onPointerDown);
149
- }, []);
156
+ }, [desktopMenuId]);
150
157
  const closeMenus = () => {
151
158
  setNavOpen(false);
152
- setOpenMenuId(null);
159
+ setDesktopMenuId(null);
160
+ setMobileAccordionId(null);
161
+ };
162
+ const onLinkNavigate = () => {
163
+ window.setTimeout(closeMenus, 0);
153
164
  };
154
165
  const userEntries = useMemo(() => {
155
166
  if (!loggedIn)
@@ -202,8 +213,11 @@ export const NavBar = ({ title, loggedIn, items, selectedColor, version, reloadC
202
213
  if (!activeGroup)
203
214
  return;
204
215
  const index = visibleItems.indexOf(activeGroup);
205
- setOpenMenuId(`${activeGroup.name}-${index}`);
216
+ setMobileAccordionId(`${activeGroup.name}-${index}`);
206
217
  }, [navOpen, visibleItems, location.pathname]);
207
- const renderCluster = (layout) => (_jsxs(_Fragment, { children: [_jsx(NavItems, { items: visibleItems, color: color, layout: layout, openMenuId: openMenuId, setOpenMenuId: setOpenMenuId, onNavigate: closeMenus }), _jsx(UserMenu, { color: color, layout: layout, open: openMenuId === "user", onToggle: () => setOpenMenuId(openMenuId === "user" ? null : "user"), onNavigate: closeMenus, entries: userEntries })] }));
218
+ const renderCluster = (layout) => {
219
+ const isMobile = layout === "mobile";
220
+ return (_jsxs(_Fragment, { children: [_jsx(NavItems, { items: visibleItems, color: color, layout: layout, openMenuId: isMobile ? mobileAccordionId : desktopMenuId, setOpenMenuId: isMobile ? setMobileAccordionId : setDesktopMenuId, onNavigate: onLinkNavigate }), _jsx(UserMenu, { color: color, layout: layout, open: desktopMenuId === "user", onToggle: () => setDesktopMenuId((current) => (current === "user" ? null : "user")), onNavigate: onLinkNavigate, entries: userEntries })] }));
221
+ };
208
222
  return (_jsx("nav", { className: `py-2 ${color.bg600}`, "aria-label": "Principal", children: _jsxs("div", { className: "flex items-center justify-between gap-3 px-4 sm:px-5", children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center justify-between gap-2 lg:w-auto lg:flex-none", children: [_jsxs(Link, { className: `inline-flex min-h-11 min-w-0 cursor-pointer items-center gap-2 truncate text-sm font-bold uppercase text-white ${focusRing}`, to: "/home", children: [_jsx("img", { className: "h-7 w-auto shrink-0", src: "/logo.png", alt: "" }), _jsx("span", { className: "truncate", children: title })] }), version !== currentVersion && (_jsx("button", { type: "button", className: `shrink-0 cursor-pointer rounded-full px-3 py-2 text-xs text-white ${color.bg700} hover:opacity-90 ${focusRing}`, onClick: () => navigate(0), children: "Actualizar versi\u00F3n" })), _jsx("button", { type: "button", className: `inline-flex min-h-11 min-w-11 cursor-pointer items-center justify-center rounded-md text-white lg:hidden ${focusRing} ${navOpen ? "pointer-events-none invisible" : ""}`, "aria-label": "Abrir men\u00FA", "aria-expanded": navOpen, "aria-controls": mobileNavId, "aria-hidden": navOpen, tabIndex: navOpen ? -1 : undefined, onClick: () => setNavOpen(true), children: _jsx(MenuAlt4Svg, { open: false }) })] }), navOpen && (_jsx("button", { type: "button", "aria-label": "Cerrar men\u00FA", className: "fixed inset-0 z-40 cursor-pointer bg-black/40 lg:hidden", onClick: closeMenus })), _jsxs("div", { ref: mobileDrawerRef, id: mobileNavId, "aria-hidden": !navOpen, className: `fixed inset-y-0 left-0 z-50 flex w-[min(20rem,86vw)] flex-col ${color.bg700} shadow-lg transition-transform duration-200 ease-out motion-reduce:transition-none lg:hidden ${navOpen ? "translate-x-0" : "pointer-events-none -translate-x-full"}`, children: [_jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-white/15 px-4 py-3", children: [_jsx("p", { className: "truncate text-sm font-bold uppercase text-white", children: title }), _jsx("button", { type: "button", className: `inline-flex min-h-11 min-w-11 cursor-pointer items-center justify-center rounded-md text-white ${focusRing}`, "aria-label": "Cerrar men\u00FA", onClick: closeMenus, children: _jsx(ExitSvg, {}) })] }), _jsx("div", { className: "flex-1 overflow-y-auto overscroll-contain p-3", children: renderCluster("mobile") })] }), _jsx("div", { ref: desktopMenuRef, className: "hidden min-w-0 flex-1 items-center gap-2 lg:flex", children: renderCluster("desktop") })] }) }));
209
223
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zauru-sdk/components",
3
- "version": "6.16.0",
3
+ "version": "6.17.0",
4
4
  "description": "Componentes reutilizables en las WebApps de Zauru.",
5
5
  "main": "./dist/esm/index.js",
6
6
  "module": "./dist/esm/index.js",
@@ -44,12 +44,12 @@
44
44
  "@reduxjs/toolkit": "^2.2.1",
45
45
  "@remix-run/node": "^2.8.1",
46
46
  "@remix-run/react": "^2.8.1",
47
- "@zauru-sdk/common": "^6.12.0",
47
+ "@zauru-sdk/common": "^6.13.0",
48
48
  "@zauru-sdk/hooks": "^6.4.1",
49
49
  "@zauru-sdk/icons": "^6.2.0",
50
50
  "@zauru-sdk/redux": "^6.8.2",
51
- "@zauru-sdk/types": "^6.28.0",
52
- "@zauru-sdk/utils": "^6.27.0",
51
+ "@zauru-sdk/types": "^6.29.0",
52
+ "@zauru-sdk/utils": "^6.29.0",
53
53
  "browser-image-compression": "^2.0.2",
54
54
  "framer-motion": "^12.0.0",
55
55
  "jsonwebtoken": "^9.0.2",
@@ -62,5 +62,5 @@
62
62
  "styled-components": "^5.3.5",
63
63
  "zod": "^3.23.8"
64
64
  },
65
- "gitHead": "5a47bf012ebb44d51bc409fb3828b2512befb8dd"
65
+ "gitHead": "4355159e008ace641976ba4c5598fc3c7a8e8263"
66
66
  }
@@ -1,10 +1,21 @@
1
1
  //<reference> https://tailwindtemplates.io/templates?category=alert
2
- import React from "react";
2
+ import React, { useEffect } from "react";
3
+ import { sendClientError } from "../../observability/sendClientError.js";
3
4
 
4
5
  type Props = { title: string; description: string };
5
6
 
6
7
  export const ErrorBoundaryAlert = (props: Props) => {
7
8
  const { title, description } = props;
9
+
10
+ useEffect(() => {
11
+ const message = [title, description].filter(Boolean).join(" — ");
12
+ if (!message) return;
13
+ sendClientError({
14
+ message,
15
+ source: "errorBoundary",
16
+ });
17
+ }, [title, description]);
18
+
8
19
  return (
9
20
  <div className="rounded-full top-20 mx-auto p-3">
10
21
  <div className="p-4 text-red-900 bg-red-100 border border-red-200 rounded-md">
@@ -4,7 +4,9 @@ import {
4
4
  useMemo,
5
5
  useRef,
6
6
  useState,
7
+ type Dispatch,
7
8
  type ReactNode,
9
+ type SetStateAction,
8
10
  } from "react";
9
11
  import {
10
12
  DropDownArrowSvgIcon,
@@ -383,7 +385,7 @@ const NavItems = ({
383
385
  color: ColorInterface;
384
386
  layout: NavLayout;
385
387
  openMenuId: string | null;
386
- setOpenMenuId: (id: string | null) => void;
388
+ setOpenMenuId: Dispatch<SetStateAction<string | null>>;
387
389
  onNavigate?: () => void;
388
390
  }) => (
389
391
  <ul
@@ -405,7 +407,7 @@ const NavItems = ({
405
407
  layout={layout}
406
408
  open={openMenuId === menuKey}
407
409
  onToggle={() =>
408
- setOpenMenuId(openMenuId === menuKey ? null : menuKey)
410
+ setOpenMenuId((current) => (current === menuKey ? null : menuKey))
409
411
  }
410
412
  onNavigate={onNavigate}
411
413
  />
@@ -436,7 +438,10 @@ export const NavBar = ({
436
438
  }: NavBarProps) => {
437
439
  const color: ColorInterface = COLORS[selectedColor];
438
440
  const [navOpen, setNavOpen] = useState(false);
439
- const [openMenuId, setOpenMenuId] = useState<string | null>(null);
441
+ const [desktopMenuId, setDesktopMenuId] = useState<string | null>(null);
442
+ const [mobileAccordionId, setMobileAccordionId] = useState<string | null>(
443
+ null
444
+ );
440
445
  const [currentVersion, setCurrentVersion] = useState(version);
441
446
  const [isDarkMode, setIsDarkMode] = useState(false);
442
447
  const navigate = useNavigate();
@@ -464,7 +469,8 @@ export const NavBar = ({
464
469
 
465
470
  useEffect(() => {
466
471
  setNavOpen(false);
467
- setOpenMenuId(null);
472
+ setDesktopMenuId(null);
473
+ setMobileAccordionId(null);
468
474
  }, [location.pathname]);
469
475
 
470
476
  useEffect(() => {
@@ -490,28 +496,33 @@ export const NavBar = ({
490
496
  const onKeyDown = (event: KeyboardEvent) => {
491
497
  if (event.key !== "Escape") return;
492
498
  setNavOpen(false);
493
- setOpenMenuId(null);
499
+ setDesktopMenuId(null);
500
+ setMobileAccordionId(null);
494
501
  };
495
502
  document.addEventListener("keydown", onKeyDown);
496
503
  return () => document.removeEventListener("keydown", onKeyDown);
497
504
  }, []);
498
505
 
499
506
  useEffect(() => {
507
+ if (!desktopMenuId) return;
500
508
  const onPointerDown = (event: MouseEvent) => {
501
- if (
502
- desktopMenuRef.current &&
503
- !desktopMenuRef.current.contains(event.target as Node)
504
- ) {
505
- setOpenMenuId(null);
506
- }
509
+ const target = event.target as Node;
510
+ if (mobileDrawerRef.current?.contains(target)) return;
511
+ if (desktopMenuRef.current?.contains(target)) return;
512
+ setDesktopMenuId(null);
507
513
  };
508
514
  document.addEventListener("mousedown", onPointerDown);
509
515
  return () => document.removeEventListener("mousedown", onPointerDown);
510
- }, []);
516
+ }, [desktopMenuId]);
511
517
 
512
518
  const closeMenus = () => {
513
519
  setNavOpen(false);
514
- setOpenMenuId(null);
520
+ setDesktopMenuId(null);
521
+ setMobileAccordionId(null);
522
+ };
523
+
524
+ const onLinkNavigate = () => {
525
+ window.setTimeout(closeMenus, 0);
515
526
  };
516
527
 
517
528
  const userEntries = useMemo<UserMenuEntry[]>(() => {
@@ -602,29 +613,34 @@ export const NavBar = ({
602
613
  );
603
614
  if (!activeGroup) return;
604
615
  const index = visibleItems.indexOf(activeGroup);
605
- setOpenMenuId(`${activeGroup.name}-${index}`);
616
+ setMobileAccordionId(`${activeGroup.name}-${index}`);
606
617
  }, [navOpen, visibleItems, location.pathname]);
607
618
 
608
- const renderCluster = (layout: NavLayout) => (
609
- <>
610
- <NavItems
611
- items={visibleItems}
612
- color={color}
613
- layout={layout}
614
- openMenuId={openMenuId}
615
- setOpenMenuId={setOpenMenuId}
616
- onNavigate={closeMenus}
617
- />
618
- <UserMenu
619
- color={color}
620
- layout={layout}
621
- open={openMenuId === "user"}
622
- onToggle={() => setOpenMenuId(openMenuId === "user" ? null : "user")}
623
- onNavigate={closeMenus}
624
- entries={userEntries}
625
- />
626
- </>
627
- );
619
+ const renderCluster = (layout: NavLayout) => {
620
+ const isMobile = layout === "mobile";
621
+ return (
622
+ <>
623
+ <NavItems
624
+ items={visibleItems}
625
+ color={color}
626
+ layout={layout}
627
+ openMenuId={isMobile ? mobileAccordionId : desktopMenuId}
628
+ setOpenMenuId={isMobile ? setMobileAccordionId : setDesktopMenuId}
629
+ onNavigate={onLinkNavigate}
630
+ />
631
+ <UserMenu
632
+ color={color}
633
+ layout={layout}
634
+ open={desktopMenuId === "user"}
635
+ onToggle={() =>
636
+ setDesktopMenuId((current) => (current === "user" ? null : "user"))
637
+ }
638
+ onNavigate={onLinkNavigate}
639
+ entries={userEntries}
640
+ />
641
+ </>
642
+ );
643
+ };
628
644
 
629
645
  return (
630
646
  <nav className={`py-2 ${color.bg600}`} aria-label="Principal">