analytica-frontend-lib 1.1.52 → 1.1.54

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.
@@ -1690,6 +1690,52 @@ AlertDialog.displayName = "AlertDialog";
1690
1690
  // src/components/Modal/Modal.tsx
1691
1691
  var import_react5 = require("react");
1692
1692
  var import_phosphor_react3 = require("phosphor-react");
1693
+
1694
+ // src/components/Modal/utils/videoUtils.ts
1695
+ var isYouTubeUrl = (url) => {
1696
+ const youtubeRegex = /^(https?:\/\/)?((www|m|music)\.)?(youtube\.com|youtu\.be|youtube-nocookie\.com)\/.+/i;
1697
+ return youtubeRegex.test(url);
1698
+ };
1699
+ var isValidYouTubeHost = (host) => {
1700
+ if (host === "youtu.be") return "youtu.be";
1701
+ const isValidYouTubeCom = host === "youtube.com" || host.endsWith(".youtube.com") && /^(www|m|music)\.youtube\.com$/.test(host);
1702
+ if (isValidYouTubeCom) return "youtube";
1703
+ const isValidNoCookie = host === "youtube-nocookie.com" || host.endsWith(".youtube-nocookie.com") && /^(www|m|music)\.youtube-nocookie\.com$/.test(host);
1704
+ if (isValidNoCookie) return "nocookie";
1705
+ return null;
1706
+ };
1707
+ var extractYoutuBeId = (pathname) => {
1708
+ const firstSeg = pathname.split("/").filter(Boolean)[0];
1709
+ return firstSeg || null;
1710
+ };
1711
+ var extractYouTubeId = (pathname, searchParams) => {
1712
+ const parts = pathname.split("/").filter(Boolean);
1713
+ const [first, second] = parts;
1714
+ if (first === "embed" && second) return second;
1715
+ if (first === "shorts" && second) return second;
1716
+ if (first === "live" && second) return second;
1717
+ const v = searchParams.get("v");
1718
+ if (v) return v;
1719
+ return null;
1720
+ };
1721
+ var getYouTubeVideoId = (url) => {
1722
+ try {
1723
+ const u = new URL(url);
1724
+ const hostType = isValidYouTubeHost(u.hostname.toLowerCase());
1725
+ if (!hostType) return null;
1726
+ if (hostType === "youtu.be") {
1727
+ return extractYoutuBeId(u.pathname);
1728
+ }
1729
+ return extractYouTubeId(u.pathname, u.searchParams);
1730
+ } catch {
1731
+ return null;
1732
+ }
1733
+ };
1734
+ var getYouTubeEmbedUrl = (videoId) => {
1735
+ return `https://www.youtube-nocookie.com/embed/${videoId}?autoplay=0&rel=0&modestbranding=1`;
1736
+ };
1737
+
1738
+ // src/components/Modal/Modal.tsx
1693
1739
  var import_jsx_runtime8 = require("react/jsx-runtime");
1694
1740
  var SIZE_CLASSES5 = {
1695
1741
  xs: "max-w-[360px]",
@@ -1705,11 +1751,17 @@ var Modal = ({
1705
1751
  children,
1706
1752
  size = "md",
1707
1753
  className = "",
1708
- closeOnBackdropClick = true,
1709
1754
  closeOnEscape = true,
1710
1755
  footer,
1711
- hideCloseButton = false
1756
+ hideCloseButton = false,
1757
+ variant = "default",
1758
+ description,
1759
+ image,
1760
+ imageAlt,
1761
+ actionLink,
1762
+ actionLabel
1712
1763
  }) => {
1764
+ const titleId = (0, import_react5.useId)();
1713
1765
  (0, import_react5.useEffect)(() => {
1714
1766
  if (!isOpen || !closeOnEscape) return;
1715
1767
  const handleEscape = (event) => {
@@ -1731,16 +1783,6 @@ var Modal = ({
1731
1783
  document.body.style.overflow = originalOverflow;
1732
1784
  };
1733
1785
  }, [isOpen]);
1734
- const handleBackdropClick = (event) => {
1735
- if (closeOnBackdropClick && event.target === event.currentTarget) {
1736
- onClose();
1737
- }
1738
- };
1739
- const handleBackdropKeyDown = (event) => {
1740
- if (closeOnBackdropClick && (event.key === "Enter" || event.key === " ")) {
1741
- onClose();
1742
- }
1743
- };
1744
1786
  if (!isOpen) return null;
1745
1787
  const sizeClasses = SIZE_CLASSES5[size];
1746
1788
  const baseClasses = "bg-secondary-50 rounded-3xl shadow-hard-shadow-2 border border-border-100 w-full mx-4";
@@ -1751,18 +1793,105 @@ var Modal = ({
1751
1793
  dialogResetClasses,
1752
1794
  className
1753
1795
  );
1754
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1755
- "div",
1796
+ const normalizeUrl = (href) => /^https?:\/\//i.test(href) ? href : `https://${href}`;
1797
+ const handleActionClick = () => {
1798
+ if (actionLink) {
1799
+ window.open(normalizeUrl(actionLink), "_blank", "noopener,noreferrer");
1800
+ }
1801
+ };
1802
+ if (variant === "activity") {
1803
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs border-none p-0 m-0 w-full cursor-default", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1804
+ "dialog",
1805
+ {
1806
+ className: modalClasses,
1807
+ "aria-labelledby": titleId,
1808
+ "aria-modal": "true",
1809
+ open: true,
1810
+ children: [
1811
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex justify-end p-6 pb-0", children: !hideCloseButton && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1812
+ "button",
1813
+ {
1814
+ onClick: onClose,
1815
+ className: "p-1 text-text-500 hover:text-text-700 hover:bg-background-50 rounded-md transition-colors focus:outline-none focus:ring-2 focus:ring-indicator-info focus:ring-offset-2",
1816
+ "aria-label": "Fechar modal",
1817
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_phosphor_react3.X, { size: 18 })
1818
+ }
1819
+ ) }),
1820
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex flex-col items-center px-6 pb-6 gap-5", children: [
1821
+ image && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1822
+ "img",
1823
+ {
1824
+ src: image,
1825
+ alt: imageAlt ?? "",
1826
+ className: "w-[122px] h-[122px] object-contain"
1827
+ }
1828
+ ) }),
1829
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1830
+ "h2",
1831
+ {
1832
+ id: titleId,
1833
+ className: "text-lg font-semibold text-text-950 text-center",
1834
+ children: title
1835
+ }
1836
+ ),
1837
+ description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("p", { className: "text-sm font-normal text-text-400 text-center max-w-md leading-[21px]", children: description }),
1838
+ actionLink && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "w-full", children: [
1839
+ (() => {
1840
+ const normalized = normalizeUrl(actionLink);
1841
+ const isYT = isYouTubeUrl(normalized);
1842
+ if (!isYT) return null;
1843
+ const id = getYouTubeVideoId(normalized);
1844
+ if (!id) {
1845
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1846
+ Button_default,
1847
+ {
1848
+ variant: "solid",
1849
+ action: "primary",
1850
+ size: "large",
1851
+ className: "w-full",
1852
+ onClick: handleActionClick,
1853
+ children: actionLabel || "Iniciar Atividade"
1854
+ }
1855
+ );
1856
+ }
1857
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1858
+ "iframe",
1859
+ {
1860
+ src: getYouTubeEmbedUrl(id),
1861
+ className: "w-full aspect-video rounded-lg",
1862
+ allowFullScreen: true,
1863
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
1864
+ title: "V\xEDdeo YouTube"
1865
+ }
1866
+ );
1867
+ })(),
1868
+ !isYouTubeUrl(normalizeUrl(actionLink)) && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1869
+ Button_default,
1870
+ {
1871
+ variant: "solid",
1872
+ action: "primary",
1873
+ size: "large",
1874
+ className: "w-full",
1875
+ onClick: handleActionClick,
1876
+ children: actionLabel || "Iniciar Atividade"
1877
+ }
1878
+ )
1879
+ ] })
1880
+ ] })
1881
+ ]
1882
+ }
1883
+ ) });
1884
+ }
1885
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs border-none p-0 m-0 w-full cursor-default", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1886
+ "dialog",
1756
1887
  {
1757
- className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs",
1758
- onClick: handleBackdropClick,
1759
- onKeyDown: handleBackdropKeyDown,
1760
- role: "button",
1761
- tabIndex: closeOnBackdropClick ? 0 : -1,
1762
- "aria-label": "Fechar modal clicando no fundo",
1763
- children: /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("dialog", { className: modalClasses, "aria-labelledby": "modal-title", open: true, children: [
1888
+ className: modalClasses,
1889
+ "aria-labelledby": titleId,
1890
+ "aria-modal": "true",
1891
+ open: true,
1892
+ children: [
1764
1893
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "flex items-center justify-between px-6 py-6", children: [
1765
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { id: "modal-title", className: "text-lg font-semibold text-text-950", children: title }),
1894
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("h2", { id: titleId, className: "text-lg font-semibold text-text-950", children: title }),
1766
1895
  !hideCloseButton && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1767
1896
  "button",
1768
1897
  {
@@ -1773,11 +1902,11 @@ var Modal = ({
1773
1902
  }
1774
1903
  )
1775
1904
  ] }),
1776
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "px-6 pb-6", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-text-500 font-normal text-sm leading-6", children }) }),
1905
+ children && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "px-6 pb-6", children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "text-text-500 font-normal text-sm leading-6", children }) }),
1777
1906
  footer && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "flex justify-end gap-3 px-6 pb-6", children: footer })
1778
- ] })
1907
+ ]
1779
1908
  }
1780
- );
1909
+ ) });
1781
1910
  };
1782
1911
  var Modal_default = Modal;
1783
1912
 
@@ -5926,7 +6055,6 @@ var QuizFooter = (0, import_react12.forwardRef)(
5926
6055
  isOpen: modalResultOpen,
5927
6056
  onClose: () => setModalResultOpen(false),
5928
6057
  title: "",
5929
- closeOnBackdropClick: false,
5930
6058
  closeOnEscape: false,
5931
6059
  hideCloseButton: true,
5932
6060
  size: "md",