@vector-business-services/cristal-ds-web 0.12.0 → 0.13.1

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.cjs CHANGED
@@ -88,6 +88,23 @@ var Accordion = react.forwardRef(function Accordion2({ multiple = false, activeI
88
88
  }
89
89
  );
90
90
  });
91
+
92
+ // src/components/popup.ts
93
+ function seguirLado(painel, alvo) {
94
+ if (!(painel instanceof HTMLElement) || !alvo) return;
95
+ const marcar = () => {
96
+ const acima = painel.getBoundingClientRect().top < alvo.getBoundingClientRect().top;
97
+ if (acima) painel.setAttribute("data-cr-lado", "acima");
98
+ else painel.removeAttribute("data-cr-lado");
99
+ };
100
+ marcar();
101
+ new MutationObserver(marcar).observe(painel, { attributes: true, attributeFilter: ["style"] });
102
+ }
103
+ var painelDoCampo = (campo, seletorDoPainel) => {
104
+ const lista = campo?.getAttribute("aria-controls");
105
+ return lista ? document.getElementById(lista)?.closest(seletorDoPainel) : null;
106
+ };
107
+ var aoPosicionar = (onEnter) => ({ onEnter });
91
108
  var AutoComplete = react.forwardRef(function AutoComplete2({
92
109
  variant = "outline",
93
110
  size = "large",
@@ -140,6 +157,11 @@ var AutoComplete = react.forwardRef(function AutoComplete2({
140
157
  // O Prime mostra um spinner próprio enquanto busca; o Figma não define esse estado.
141
158
  loadingIcon: { className: "cr-autocomplete__loader" },
142
159
  panel: { className: "cr-autocomplete__panel" },
160
+ // Lado da lista (acima ou abaixo do campo), medido logo depois de o Prime posicionar.
161
+ transition: aoPosicionar(() => {
162
+ const campo = document.getElementById(id);
163
+ seguirLado(painelDoCampo(campo, ".cr-autocomplete__panel"), campo);
164
+ }),
143
165
  list: { className: "cr-autocomplete__list" },
144
166
  item: { className: "cr-autocomplete__item" }
145
167
  },
@@ -211,6 +233,11 @@ var Card = react.forwardRef(function Card2({ padding = "xsmall", outline = false
211
233
  }
212
234
  );
213
235
  });
236
+ var usandoTeclado = false;
237
+ if (typeof document !== "undefined") {
238
+ document.addEventListener("keydown", () => usandoTeclado = true, true);
239
+ document.addEventListener("pointerdown", () => usandoTeclado = false, true);
240
+ }
214
241
  var resolveTargets = (target) => {
215
242
  if (typeof target === "string") return Array.from(document.querySelectorAll(target));
216
243
  if (target instanceof HTMLElement) return [target];
@@ -225,16 +252,27 @@ function Tooltip({
225
252
  showDelay,
226
253
  hideDelay,
227
254
  disabled,
255
+ describe = true,
228
256
  id,
229
257
  className
230
258
  }) {
231
259
  const autoId = react.useId();
232
260
  const tooltipId = id ?? autoId;
233
261
  react.useEffect(() => {
262
+ if (!describe) return;
234
263
  const elements = resolveTargets(target);
235
- elements.forEach((element) => element.setAttribute("aria-describedby", tooltipId));
236
- return () => elements.forEach((element) => element.removeAttribute("aria-describedby"));
237
- }, [target, tooltipId]);
264
+ const ids = (element) => (element.getAttribute("aria-describedby") ?? "").split(/\s+/).filter(Boolean);
265
+ const gravar = (element, lista) => lista.length ? element.setAttribute("aria-describedby", lista.join(" ")) : element.removeAttribute("aria-describedby");
266
+ elements.forEach((element) => {
267
+ if (!ids(element).includes(tooltipId)) gravar(element, [...ids(element), tooltipId]);
268
+ });
269
+ return () => elements.forEach(
270
+ (element) => gravar(
271
+ element,
272
+ ids(element).filter((idAtual) => idAtual !== tooltipId)
273
+ )
274
+ );
275
+ }, [target, tooltipId, describe]);
238
276
  const classes = ["cr-tooltip", `cr-tooltip--${type}`, className].filter(Boolean).join(" ");
239
277
  const pt = {
240
278
  root: (options) => {
@@ -255,6 +293,8 @@ function Tooltip({
255
293
  showDelay,
256
294
  hideDelay,
257
295
  disabled,
296
+ closeOnEscape: true,
297
+ onBeforeShow: (e) => e.originalEvent?.type !== "focus" || usandoTeclado,
258
298
  pt,
259
299
  children: content
260
300
  }
@@ -569,7 +609,10 @@ var Checkbox = react.forwardRef(function Checkbox2({
569
609
  value,
570
610
  icon: /* @__PURE__ */ jsxRuntime.jsx(react$1.Check, { size: 16 }),
571
611
  pt: {
572
- root: { className: "cr-checkbox__control" },
612
+ // Marcado pela prop do Cristal, não pelo atributo interno do Prime (data-p-highlight).
613
+ root: {
614
+ className: `cr-checkbox__control${checked ? " cr-checkbox__control--checked" : ""}`
615
+ },
573
616
  input: { className: "cr-checkbox__input" },
574
617
  box: { className: "cr-checkbox__box" },
575
618
  icon: { className: "cr-checkbox__icon", "aria-hidden": true }
@@ -658,24 +701,54 @@ var Divider = react.forwardRef(function Divider2({ orientation = "horizontal", v
658
701
  }
659
702
  );
660
703
  });
661
- var IconButton = react.forwardRef(function IconButton2({ variant = "primary", size = "large", icon, type = "button", className, ...props }, ref) {
704
+ var IconButton = react.forwardRef(function IconButton2({
705
+ variant = "primary",
706
+ size = "large",
707
+ icon,
708
+ type = "button",
709
+ tooltip,
710
+ tooltipPosition,
711
+ className,
712
+ ...props
713
+ }, ref) {
714
+ const botao = react.useRef(null);
715
+ const ligar = react.useCallback(
716
+ (elemento) => {
717
+ botao.current = elemento;
718
+ if (typeof ref === "function") ref(elemento);
719
+ else if (ref) ref.current = elemento;
720
+ },
721
+ [ref]
722
+ );
723
+ const texto = tooltip ?? props["aria-label"];
662
724
  const classes = [
663
725
  "cr-icon-button",
664
726
  `cr-icon-button--${variant}`,
665
727
  `cr-icon-button--${size}`,
666
728
  className
667
729
  ].filter(Boolean).join(" ");
668
- return /* @__PURE__ */ jsxRuntime.jsx(
669
- button.Button,
670
- {
671
- unstyled: true,
672
- ref,
673
- type,
674
- className: classes,
675
- ...props,
676
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cr-icon-button__icon", "aria-hidden": "true", children: icon })
677
- }
678
- );
730
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
731
+ /* @__PURE__ */ jsxRuntime.jsx(
732
+ button.Button,
733
+ {
734
+ unstyled: true,
735
+ ref: ligar,
736
+ type,
737
+ className: classes,
738
+ ...props,
739
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "cr-icon-button__icon", "aria-hidden": "true", children: icon })
740
+ }
741
+ ),
742
+ texto !== false && /* @__PURE__ */ jsxRuntime.jsx(
743
+ Tooltip,
744
+ {
745
+ target: botao,
746
+ content: texto,
747
+ position: tooltipPosition,
748
+ describe: texto !== props["aria-label"]
749
+ }
750
+ )
751
+ ] });
679
752
  });
680
753
  var FOCAVEIS = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
681
754
  function Drawer({
@@ -898,10 +971,17 @@ var Menu = react.forwardRef(function Menu2({
898
971
  className
899
972
  }, ref) {
900
973
  const primeRef = react.useRef(null);
974
+ const alvo = react.useRef(null);
901
975
  const context = react.useContext(api.PrimeReactContext);
902
976
  react.useImperativeHandle(ref, () => ({
903
- toggle: (event) => primeRef.current?.toggle(event),
904
- show: (event) => primeRef.current?.show(event),
977
+ toggle: (event) => {
978
+ alvo.current = event.currentTarget;
979
+ primeRef.current?.toggle(event);
980
+ },
981
+ show: (event) => {
982
+ alvo.current = event.currentTarget;
983
+ primeRef.current?.show(event);
984
+ },
905
985
  hide: (event) => primeRef.current?.hide(event),
906
986
  getElement: () => primeRef.current?.getElement() ?? null
907
987
  }));
@@ -939,6 +1019,12 @@ var Menu = react.forwardRef(function Menu2({
939
1019
  };
940
1020
  },
941
1021
  content: { className: "cr-menu__content" },
1022
+ // Lado do popup (acima ou abaixo de quem o abriu), medido logo depois de o Prime posicionar.
1023
+ // Numa microtarefa: no onEnter o Prime ainda está religando a ref (getElement vem vazio); ela
1024
+ // roda logo depois, antes de a tela ser pintada.
1025
+ transition: aoPosicionar(
1026
+ () => queueMicrotask(() => seguirLado(primeRef.current?.getElement(), alvo.current))
1027
+ ),
942
1028
  action: { className: "cr-menu__action" },
943
1029
  label: { className: "cr-menu__label" }
944
1030
  };
@@ -1196,9 +1282,12 @@ var MenuPrincipal = react.forwardRef(
1196
1282
  const primeRef = react.useRef(null);
1197
1283
  const context = react.useContext(api.PrimeReactContext);
1198
1284
  const [baseDoAlvo, setBaseDoAlvo] = react.useState();
1285
+ const alvo = react.useRef(null);
1199
1286
  const medirAlvo = (event) => {
1200
- const alvo = event.currentTarget;
1201
- if (alvo instanceof Element) setBaseDoAlvo(alvo.getBoundingClientRect().bottom);
1287
+ const elemento = event.currentTarget;
1288
+ if (!(elemento instanceof Element)) return;
1289
+ alvo.current = elemento;
1290
+ setBaseDoAlvo(elemento.getBoundingClientRect().bottom);
1202
1291
  };
1203
1292
  react.useImperativeHandle(ref, () => ({
1204
1293
  toggle: (event) => {
@@ -1257,7 +1346,12 @@ var MenuPrincipal = react.forwardRef(
1257
1346
  menu: { className: "cr-menu-principal__list", "aria-label": ariaLabel },
1258
1347
  submenuHeader: { className: "cr-menu-principal__group" },
1259
1348
  separator: { className: "cr-menu-principal__separator" },
1260
- menuitem: { className: "cr-menu-principal__item" }
1349
+ menuitem: { className: "cr-menu-principal__item" },
1350
+ // Lado do popup, medido logo depois de o Prime posicionar.
1351
+ // Numa microtarefa: no onEnter o Prime ainda está religando a ref (como no Menu).
1352
+ transition: aoPosicionar(
1353
+ () => queueMicrotask(() => seguirLado(primeRef.current?.getElement(), alvo.current))
1354
+ )
1261
1355
  };
1262
1356
  const menu$1 = /* @__PURE__ */ jsxRuntime.jsx(
1263
1357
  menu.Menu,
@@ -1592,7 +1686,9 @@ var PageHeader = react.forwardRef(function PageHeader2({
1592
1686
  segmentControl,
1593
1687
  actions,
1594
1688
  onExpand,
1689
+ expanded,
1595
1690
  expandLabel = "Expandir",
1691
+ collapseLabel = "Recolher",
1596
1692
  tabs,
1597
1693
  activeTab,
1598
1694
  onTabChange,
@@ -1602,6 +1698,8 @@ var PageHeader = react.forwardRef(function PageHeader2({
1602
1698
  }, ref) {
1603
1699
  const [interna, setInterna] = react.useState(0);
1604
1700
  const ativa = activeTab ?? interna;
1701
+ const [expandidoInterno, setExpandidoInterno] = react.useState(false);
1702
+ const expandido = expanded ?? expandidoInterno;
1605
1703
  const tools = segmentControl || actions;
1606
1704
  const tabTemplate = (tab) => (
1607
1705
  // O TabMenu também passa o index da aba nas opções, além do que o tipo do MenuItem declara.
@@ -1649,9 +1747,12 @@ var PageHeader = react.forwardRef(function PageHeader2({
1649
1747
  className: "cr-page-header__expand",
1650
1748
  variant: "tertiary",
1651
1749
  size: "medium",
1652
- icon: /* @__PURE__ */ jsxRuntime.jsx(react$1.ArrowsOutSimple, {}),
1653
- "aria-label": expandLabel,
1654
- onClick: onExpand
1750
+ icon: expandido ? /* @__PURE__ */ jsxRuntime.jsx(react$1.ArrowsInSimple, {}) : /* @__PURE__ */ jsxRuntime.jsx(react$1.ArrowsOutSimple, {}),
1751
+ "aria-label": expandido ? collapseLabel : expandLabel,
1752
+ onClick: () => {
1753
+ setExpandidoInterno(!expandido);
1754
+ onExpand(!expandido);
1755
+ }
1655
1756
  }
1656
1757
  )
1657
1758
  ]
@@ -1737,9 +1838,23 @@ var Select = react.forwardRef(function Select2({
1737
1838
  input: { className: "cr-select__value" },
1738
1839
  trigger: { className: "cr-field__icon cr-select__trigger", "aria-hidden": true },
1739
1840
  panel: { className: "cr-select__panel" },
1841
+ // Lado da lista (acima ou abaixo do campo), medido logo depois de o Prime posicionar.
1842
+ transition: aoPosicionar(
1843
+ () => seguirLado(
1844
+ document.getElementById(listId)?.closest(".cr-select__panel"),
1845
+ document.getElementById(inputId)?.closest(".cr-select__control")
1846
+ )
1847
+ ),
1740
1848
  wrapper: { className: "cr-select__wrapper" },
1741
1849
  list: { className: "cr-select__list", id: listId },
1742
- item: { className: "cr-select__item" },
1850
+ // Selecionado e em foco (teclado) pelo contexto do pt, a API pública do Prime (não data-p-*).
1851
+ item: ({ context }) => ({
1852
+ className: [
1853
+ "cr-select__item",
1854
+ context.selected && "cr-select__item--selected",
1855
+ context.focused && "cr-select__item--focused"
1856
+ ].filter(Boolean).join(" ")
1857
+ }),
1743
1858
  emptyMessage: { className: "cr-select__item cr-select__empty" }
1744
1859
  };
1745
1860
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classes, children: [
@@ -1927,7 +2042,8 @@ var Radio = react.forwardRef(function Radio2({
1927
2042
  disabled,
1928
2043
  required,
1929
2044
  pt: {
1930
- root: { className: "cr-radio__control" },
2045
+ // Marcado pela prop do Cristal, não pelo atributo interno do Prime (data-p-checked).
2046
+ root: { className: `cr-radio__control${checked ? " cr-radio__control--checked" : ""}` },
1931
2047
  input: { className: "cr-radio__input" },
1932
2048
  box: { className: "cr-radio__box" },
1933
2049
  icon: { className: "cr-radio__icon" }
@@ -2067,7 +2183,12 @@ var Switch = react.forwardRef(function Switch2({
2067
2183
  disabled,
2068
2184
  name,
2069
2185
  pt: {
2070
- root: { className: "cr-switch__control", role: void 0, "aria-checked": void 0 },
2186
+ // Ligado pela prop do Cristal, não pelo atributo interno do Prime (data-p-highlight).
2187
+ root: {
2188
+ className: `cr-switch__control${checked ? " cr-switch__control--checked" : ""}`,
2189
+ role: void 0,
2190
+ "aria-checked": void 0
2191
+ },
2071
2192
  input: { className: "cr-switch__input" },
2072
2193
  slider: { className: "cr-switch__track" }
2073
2194
  }