analytica-frontend-lib 1.1.53 → 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.
@@ -936,7 +936,7 @@ import {
936
936
  forwardRef as forwardRef10,
937
937
  useEffect as useEffect7,
938
938
  useMemo,
939
- useId as useId7,
939
+ useId as useId8,
940
940
  useState as useState7,
941
941
  useCallback,
942
942
  useRef as useRef5
@@ -1660,8 +1660,54 @@ var AlertDialog = forwardRef4(
1660
1660
  AlertDialog.displayName = "AlertDialog";
1661
1661
 
1662
1662
  // src/components/Modal/Modal.tsx
1663
- import { useEffect as useEffect3 } from "react";
1663
+ import { useEffect as useEffect3, useId as useId3 } from "react";
1664
1664
  import { X } from "phosphor-react";
1665
+
1666
+ // src/components/Modal/utils/videoUtils.ts
1667
+ var isYouTubeUrl = (url) => {
1668
+ const youtubeRegex = /^(https?:\/\/)?((www|m|music)\.)?(youtube\.com|youtu\.be|youtube-nocookie\.com)\/.+/i;
1669
+ return youtubeRegex.test(url);
1670
+ };
1671
+ var isValidYouTubeHost = (host) => {
1672
+ if (host === "youtu.be") return "youtu.be";
1673
+ const isValidYouTubeCom = host === "youtube.com" || host.endsWith(".youtube.com") && /^(www|m|music)\.youtube\.com$/.test(host);
1674
+ if (isValidYouTubeCom) return "youtube";
1675
+ const isValidNoCookie = host === "youtube-nocookie.com" || host.endsWith(".youtube-nocookie.com") && /^(www|m|music)\.youtube-nocookie\.com$/.test(host);
1676
+ if (isValidNoCookie) return "nocookie";
1677
+ return null;
1678
+ };
1679
+ var extractYoutuBeId = (pathname) => {
1680
+ const firstSeg = pathname.split("/").filter(Boolean)[0];
1681
+ return firstSeg || null;
1682
+ };
1683
+ var extractYouTubeId = (pathname, searchParams) => {
1684
+ const parts = pathname.split("/").filter(Boolean);
1685
+ const [first, second] = parts;
1686
+ if (first === "embed" && second) return second;
1687
+ if (first === "shorts" && second) return second;
1688
+ if (first === "live" && second) return second;
1689
+ const v = searchParams.get("v");
1690
+ if (v) return v;
1691
+ return null;
1692
+ };
1693
+ var getYouTubeVideoId = (url) => {
1694
+ try {
1695
+ const u = new URL(url);
1696
+ const hostType = isValidYouTubeHost(u.hostname.toLowerCase());
1697
+ if (!hostType) return null;
1698
+ if (hostType === "youtu.be") {
1699
+ return extractYoutuBeId(u.pathname);
1700
+ }
1701
+ return extractYouTubeId(u.pathname, u.searchParams);
1702
+ } catch {
1703
+ return null;
1704
+ }
1705
+ };
1706
+ var getYouTubeEmbedUrl = (videoId) => {
1707
+ return `https://www.youtube-nocookie.com/embed/${videoId}?autoplay=0&rel=0&modestbranding=1`;
1708
+ };
1709
+
1710
+ // src/components/Modal/Modal.tsx
1665
1711
  import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1666
1712
  var SIZE_CLASSES5 = {
1667
1713
  xs: "max-w-[360px]",
@@ -1677,11 +1723,17 @@ var Modal = ({
1677
1723
  children,
1678
1724
  size = "md",
1679
1725
  className = "",
1680
- closeOnBackdropClick = true,
1681
1726
  closeOnEscape = true,
1682
1727
  footer,
1683
- hideCloseButton = false
1728
+ hideCloseButton = false,
1729
+ variant = "default",
1730
+ description,
1731
+ image,
1732
+ imageAlt,
1733
+ actionLink,
1734
+ actionLabel
1684
1735
  }) => {
1736
+ const titleId = useId3();
1685
1737
  useEffect3(() => {
1686
1738
  if (!isOpen || !closeOnEscape) return;
1687
1739
  const handleEscape = (event) => {
@@ -1703,16 +1755,6 @@ var Modal = ({
1703
1755
  document.body.style.overflow = originalOverflow;
1704
1756
  };
1705
1757
  }, [isOpen]);
1706
- const handleBackdropClick = (event) => {
1707
- if (closeOnBackdropClick && event.target === event.currentTarget) {
1708
- onClose();
1709
- }
1710
- };
1711
- const handleBackdropKeyDown = (event) => {
1712
- if (closeOnBackdropClick && (event.key === "Enter" || event.key === " ")) {
1713
- onClose();
1714
- }
1715
- };
1716
1758
  if (!isOpen) return null;
1717
1759
  const sizeClasses = SIZE_CLASSES5[size];
1718
1760
  const baseClasses = "bg-secondary-50 rounded-3xl shadow-hard-shadow-2 border border-border-100 w-full mx-4";
@@ -1723,18 +1765,105 @@ var Modal = ({
1723
1765
  dialogResetClasses,
1724
1766
  className
1725
1767
  );
1726
- return /* @__PURE__ */ jsx8(
1727
- "div",
1768
+ const normalizeUrl = (href) => /^https?:\/\//i.test(href) ? href : `https://${href}`;
1769
+ const handleActionClick = () => {
1770
+ if (actionLink) {
1771
+ window.open(normalizeUrl(actionLink), "_blank", "noopener,noreferrer");
1772
+ }
1773
+ };
1774
+ if (variant === "activity") {
1775
+ return /* @__PURE__ */ jsx8("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__ */ jsxs6(
1776
+ "dialog",
1777
+ {
1778
+ className: modalClasses,
1779
+ "aria-labelledby": titleId,
1780
+ "aria-modal": "true",
1781
+ open: true,
1782
+ children: [
1783
+ /* @__PURE__ */ jsx8("div", { className: "flex justify-end p-6 pb-0", children: !hideCloseButton && /* @__PURE__ */ jsx8(
1784
+ "button",
1785
+ {
1786
+ onClick: onClose,
1787
+ 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",
1788
+ "aria-label": "Fechar modal",
1789
+ children: /* @__PURE__ */ jsx8(X, { size: 18 })
1790
+ }
1791
+ ) }),
1792
+ /* @__PURE__ */ jsxs6("div", { className: "flex flex-col items-center px-6 pb-6 gap-5", children: [
1793
+ image && /* @__PURE__ */ jsx8("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx8(
1794
+ "img",
1795
+ {
1796
+ src: image,
1797
+ alt: imageAlt ?? "",
1798
+ className: "w-[122px] h-[122px] object-contain"
1799
+ }
1800
+ ) }),
1801
+ /* @__PURE__ */ jsx8(
1802
+ "h2",
1803
+ {
1804
+ id: titleId,
1805
+ className: "text-lg font-semibold text-text-950 text-center",
1806
+ children: title
1807
+ }
1808
+ ),
1809
+ description && /* @__PURE__ */ jsx8("p", { className: "text-sm font-normal text-text-400 text-center max-w-md leading-[21px]", children: description }),
1810
+ actionLink && /* @__PURE__ */ jsxs6("div", { className: "w-full", children: [
1811
+ (() => {
1812
+ const normalized = normalizeUrl(actionLink);
1813
+ const isYT = isYouTubeUrl(normalized);
1814
+ if (!isYT) return null;
1815
+ const id = getYouTubeVideoId(normalized);
1816
+ if (!id) {
1817
+ return /* @__PURE__ */ jsx8(
1818
+ Button_default,
1819
+ {
1820
+ variant: "solid",
1821
+ action: "primary",
1822
+ size: "large",
1823
+ className: "w-full",
1824
+ onClick: handleActionClick,
1825
+ children: actionLabel || "Iniciar Atividade"
1826
+ }
1827
+ );
1828
+ }
1829
+ return /* @__PURE__ */ jsx8(
1830
+ "iframe",
1831
+ {
1832
+ src: getYouTubeEmbedUrl(id),
1833
+ className: "w-full aspect-video rounded-lg",
1834
+ allowFullScreen: true,
1835
+ allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
1836
+ title: "V\xEDdeo YouTube"
1837
+ }
1838
+ );
1839
+ })(),
1840
+ !isYouTubeUrl(normalizeUrl(actionLink)) && /* @__PURE__ */ jsx8(
1841
+ Button_default,
1842
+ {
1843
+ variant: "solid",
1844
+ action: "primary",
1845
+ size: "large",
1846
+ className: "w-full",
1847
+ onClick: handleActionClick,
1848
+ children: actionLabel || "Iniciar Atividade"
1849
+ }
1850
+ )
1851
+ ] })
1852
+ ] })
1853
+ ]
1854
+ }
1855
+ ) });
1856
+ }
1857
+ return /* @__PURE__ */ jsx8("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__ */ jsxs6(
1858
+ "dialog",
1728
1859
  {
1729
- className: "fixed inset-0 z-50 flex items-center justify-center bg-black/60 backdrop-blur-xs",
1730
- onClick: handleBackdropClick,
1731
- onKeyDown: handleBackdropKeyDown,
1732
- role: "button",
1733
- tabIndex: closeOnBackdropClick ? 0 : -1,
1734
- "aria-label": "Fechar modal clicando no fundo",
1735
- children: /* @__PURE__ */ jsxs6("dialog", { className: modalClasses, "aria-labelledby": "modal-title", open: true, children: [
1860
+ className: modalClasses,
1861
+ "aria-labelledby": titleId,
1862
+ "aria-modal": "true",
1863
+ open: true,
1864
+ children: [
1736
1865
  /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-between px-6 py-6", children: [
1737
- /* @__PURE__ */ jsx8("h2", { id: "modal-title", className: "text-lg font-semibold text-text-950", children: title }),
1866
+ /* @__PURE__ */ jsx8("h2", { id: titleId, className: "text-lg font-semibold text-text-950", children: title }),
1738
1867
  !hideCloseButton && /* @__PURE__ */ jsx8(
1739
1868
  "button",
1740
1869
  {
@@ -1745,11 +1874,11 @@ var Modal = ({
1745
1874
  }
1746
1875
  )
1747
1876
  ] }),
1748
- /* @__PURE__ */ jsx8("div", { className: "px-6 pb-6", children: /* @__PURE__ */ jsx8("div", { className: "text-text-500 font-normal text-sm leading-6", children }) }),
1877
+ children && /* @__PURE__ */ jsx8("div", { className: "px-6 pb-6", children: /* @__PURE__ */ jsx8("div", { className: "text-text-500 font-normal text-sm leading-6", children }) }),
1749
1878
  footer && /* @__PURE__ */ jsx8("div", { className: "flex justify-end gap-3 px-6 pb-6", children: footer })
1750
- ] })
1879
+ ]
1751
1880
  }
1752
- );
1881
+ ) });
1753
1882
  };
1754
1883
  var Modal_default = Modal;
1755
1884
 
@@ -1762,7 +1891,7 @@ import {
1762
1891
  isValidElement as isValidElement2,
1763
1892
  Children as Children2,
1764
1893
  cloneElement as cloneElement2,
1765
- useId as useId3
1894
+ useId as useId4
1766
1895
  } from "react";
1767
1896
  import { CaretDown, Check, WarningCircle } from "phosphor-react";
1768
1897
  import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
@@ -1868,7 +1997,7 @@ var Select = ({
1868
1997
  const store = storeRef.current;
1869
1998
  const selectRef = useRef2(null);
1870
1999
  const { open, setOpen, setValue, selectedLabel } = useStore2(store, (s) => s);
1871
- const generatedId = useId3();
2000
+ const generatedId = useId4();
1872
2001
  const selectId = id ?? `select-${generatedId}`;
1873
2002
  const findLabelForValue = (children2, targetValue) => {
1874
2003
  let found = null;
@@ -4162,7 +4291,7 @@ import { useEffect as useEffect6, useState as useState5 } from "react";
4162
4291
  // src/components/CheckBox/CheckboxList.tsx
4163
4292
  import {
4164
4293
  forwardRef as forwardRef8,
4165
- useId as useId5,
4294
+ useId as useId6,
4166
4295
  useEffect as useEffect5,
4167
4296
  useRef as useRef4,
4168
4297
  Children as Children3,
@@ -4175,7 +4304,7 @@ import { create as create4, useStore as useStore3 } from "zustand";
4175
4304
  import {
4176
4305
  forwardRef as forwardRef7,
4177
4306
  useState as useState4,
4178
- useId as useId4
4307
+ useId as useId5
4179
4308
  } from "react";
4180
4309
  import { Check as Check2, Minus } from "phosphor-react";
4181
4310
  import { jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
@@ -4254,7 +4383,7 @@ var CheckBox = forwardRef7(
4254
4383
  onChange,
4255
4384
  ...props
4256
4385
  }, ref) => {
4257
- const generatedId = useId4();
4386
+ const generatedId = useId5();
4258
4387
  const inputId = id ?? `checkbox-${generatedId}`;
4259
4388
  const [internalChecked, setInternalChecked] = useState4(false);
4260
4389
  const isControlled = checkedProp !== void 0;
@@ -4424,7 +4553,7 @@ var CheckboxList = forwardRef8(
4424
4553
  children,
4425
4554
  ...props
4426
4555
  }, ref) => {
4427
- const generatedId = useId5();
4556
+ const generatedId = useId6();
4428
4557
  const name = propName || `checkbox-list-${generatedId}`;
4429
4558
  const storeRef = useRef4(null);
4430
4559
  storeRef.current ??= createCheckboxListStore(
@@ -4480,7 +4609,7 @@ var CheckboxListItem = forwardRef8(
4480
4609
  disabled: groupDisabled,
4481
4610
  name
4482
4611
  } = useStore3(store);
4483
- const generatedId = useId5();
4612
+ const generatedId = useId6();
4484
4613
  const inputId = id ?? `checkbox-item-${generatedId}`;
4485
4614
  const isChecked = groupValues.includes(value);
4486
4615
  const isDisabled = groupDisabled || itemDisabled;
@@ -4646,7 +4775,7 @@ var MultipleChoiceList = ({
4646
4775
  import {
4647
4776
  forwardRef as forwardRef9,
4648
4777
  useState as useState6,
4649
- useId as useId6
4778
+ useId as useId7
4650
4779
  } from "react";
4651
4780
  import { WarningCircle as WarningCircle2 } from "phosphor-react";
4652
4781
  import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
@@ -4715,7 +4844,7 @@ var TextArea = forwardRef9(
4715
4844
  placeholder,
4716
4845
  ...props
4717
4846
  }, ref) => {
4718
- const generatedId = useId6();
4847
+ const generatedId = useId7();
4719
4848
  const inputId = id ?? `textarea-${generatedId}`;
4720
4849
  const [isFocused, setIsFocused] = useState6(false);
4721
4850
  const handleChange = (event) => {
@@ -5426,7 +5555,7 @@ var QuizFill = ({ paddingBottom }) => {
5426
5555
  }
5427
5556
  ];
5428
5557
  const [answers, setAnswers] = useState7({});
5429
- const baseId = useId7();
5558
+ const baseId = useId8();
5430
5559
  const getAvailableOptionsForSelect = (selectId) => {
5431
5560
  const usedOptions = Object.entries(answers).filter(([key]) => key !== selectId).map(([, value]) => value);
5432
5561
  return options.filter((option) => !usedOptions.includes(option));
@@ -5938,7 +6067,6 @@ var QuizFooter = forwardRef10(
5938
6067
  isOpen: modalResultOpen,
5939
6068
  onClose: () => setModalResultOpen(false),
5940
6069
  title: "",
5941
- closeOnBackdropClick: false,
5942
6070
  closeOnEscape: false,
5943
6071
  hideCloseButton: true,
5944
6072
  size: "md",