@aurea-uds/react 0.59.0 → 0.62.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.
@@ -38,7 +38,7 @@ import { cx, useAureaStrings } from "./internal.js";
38
38
  // CodeEditor (e o CodeMirror) somem quando não usados. Split por subpath = decisão do Victor.
39
39
  export const aureaEditorTheme = /*@__PURE__*/ EditorView.theme({
40
40
  "&": { backgroundColor: "var(--surface-inset)", color: "var(--foreground)", border: "var(--border-width) solid transparent", borderRadius: "var(--radius-lg)", fontSize: "var(--text-xs)" },
41
- "&.cm-focused": { outline: "2px solid var(--focus-strong)", outlineOffset: "-2px" },
41
+ "&.cm-focused": { outline: "var(--focus-width) solid var(--focus-strong)", outlineOffset: "calc(-1 * var(--focus-width))" },
42
42
  ".cm-scroller": { fontFamily: "var(--font-code)", lineHeight: "var(--leading-relaxed)", borderRadius: "inherit" },
43
43
  ".cm-content": { caretColor: "var(--foreground)", padding: "var(--space-2) 0" },
44
44
  ".cm-line": { padding: "0 var(--space-3)" },
@@ -17,7 +17,12 @@ import { Icon } from "./system.js";
17
17
  export function Accordion({ items, variant = "default", multiple = false, defaultValue, indicator = "chevron", size = "md", orientation = "vertical", className }) {
18
18
  const grupo = React.useId();
19
19
  const deLado = orientation === "horizontal";
20
- const lista = _jsx("div", { className: cx("accordion", variant === "surface" && "accordion-surface", indicator === "plus" && "accordion-plus", size === "lg" && "accordion-lg", deLado && "accordion-horizontal", !deLado && className), children: items.map(i => _jsxs("details", { className: "accordion-item", name: multiple && !deLado ? undefined : grupo, open: defaultValue?.includes(i.id) || undefined, children: [_jsxs("summary", { "aria-disabled": i.disabled || undefined, tabIndex: i.disabled ? -1 : undefined, onClick: i.disabled ? (e) => e.preventDefault()
20
+ // DE LADO, SEMPRE HÁ UM À VISTA também na abertura (06/11/2026, a D4 da auditoria externa — decisão do Victor, "Abrir o
21
+ // primeiro"): sem `defaultValue`, o horizontal nascia com tudo fechado, só as tiras em pé e nenhuma área de conteúdo. Agora
22
+ // nasce com o primeiro item que não está desligado. A referência não tem o horizontal; o de pé continua como o dela,
23
+ // fechado.
24
+ const abertos = defaultValue ?? (deLado ? [items.find(i => !i.disabled)?.id].filter(Boolean) : undefined);
25
+ const lista = _jsx("div", { className: cx("accordion", variant === "surface" && "accordion-surface", indicator === "plus" && "accordion-plus", size === "lg" && "accordion-lg", deLado && "accordion-horizontal", !deLado && className), children: items.map(i => _jsxs("details", { className: "accordion-item", name: multiple && !deLado ? undefined : grupo, open: abertos?.includes(i.id) || undefined, children: [_jsxs("summary", { "aria-disabled": i.disabled || undefined, tabIndex: i.disabled ? -1 : undefined, onClick: i.disabled ? (e) => e.preventDefault()
21
26
  : deLado ? (e) => { if (e.currentTarget.parentElement.open)
22
27
  e.preventDefault(); } : undefined, children: [_jsx("span", { className: "accordion-title", children: i.title }), _jsx("span", { className: "accordion-chevron", "aria-hidden": "true" })] }), _jsx("div", { className: "accordion-content", children: i.content })] }, i.id)) });
23
28
  return deLado ? _jsx("div", { className: cx("accordion-horizontal-frame", className), children: lista }) : lista;
@@ -112,9 +112,9 @@ function useGavetaFechaNoDesktop(docs = false) {
112
112
  }
113
113
  catch { /* motor sem popover */ }
114
114
  };
115
- const pares = [[window.matchMedia(`(min-width: ${docs ? ESCALA.md : ESCALA.lg}px)`), fechar(SHELL_NAV_ID)]];
115
+ const pares = [[window.matchMedia(`(min-width: ${(docs ? ESCALA.md : ESCALA.lg) / 16}em)`), fechar(SHELL_NAV_ID)]];
116
116
  if (docs)
117
- pares.push([window.matchMedia(`(min-width: ${ESCALA.xl}px)`), fechar(SHELL_TOC_ID)]);
117
+ pares.push([window.matchMedia(`(min-width: ${ESCALA.xl / 16}em)`), fechar(SHELL_TOC_ID)]);
118
118
  for (const [mq, f] of pares)
119
119
  mq.addEventListener?.("change", f);
120
120
  return () => { for (const [mq, f] of pares)
@@ -142,7 +142,9 @@ function useGavetaFechaNoDesktop(docs = false) {
142
142
  //
143
143
  // Tudo LIGADO por `sidebarCollapsible`: sem ele o shell é o de antes, e quem já usa
144
144
  // `sidebarCollapsed` com o próprio botão não ganha um segundo.
145
- const MEDIA_MEDIA = `(min-width: ${ESCALA.lg}px) and (max-width: ${ESCALA.xl - 1}px)`;
145
+ // Em `em`, como o CSS (06/11/2026, o texto a 200%): `em` numa consulta de mídia é a fonte que a pessoa escolheu no
146
+ // navegador — com a fonte em dobro, a tela "encolhe" para a metade, e o JS tem de concordar com o CSS.
147
+ const MEDIA_MEDIA = `(min-width: ${ESCALA.lg / 16}em) and (max-width: ${(ESCALA.xl - 1) / 16}em)`;
146
148
  const MEDIA_ESTREITA = `(max-width: ${ESCALA.lg - 1}px)`;
147
149
  // A largura pela API do navegador, e não por `resize`: o `useSyncExternalStore` dá a resposta certa
148
150
  // já no primeiro desenho do lado do cliente, e no servidor (sem janela) diz "não" — a folha cuida da
package/dist/markup.js CHANGED
@@ -219,7 +219,9 @@ export function MediaPlayerShell({ children, className, ...props }) { return _js
219
219
  // O item da barra e o do painel são o MESMO elemento com a mesma pele: o atual é o atual nos dois.
220
220
  function linksDoHeader(items, current) {
221
221
  return _jsx("ul", { className: "topbar-links", children: items.map(it => {
222
- const p = { className: "topbar-link", "aria-current": it.id === current ? "page" : undefined, children: it.label };
222
+ // O `onClick` do item vale aqui também (06/11/2026): a `Sidebar` o liga e o `Header` o jogava fora — o mesmo `SidebarItem`
223
+ // fazia coisas diferentes nas duas peças. Não é hook: é a prop do `<a>`, que a marcação pura pode passar.
224
+ const p = { className: "topbar-link", "aria-current": it.id === current ? "page" : undefined, onClick: it.onClick, children: it.label };
223
225
  return _jsx("li", { children: it.render ? fundirRender(it.render, p, "a") : _jsx("a", { href: it.href, ...p }) }, it.id);
224
226
  }) });
225
227
  }
@@ -103,6 +103,10 @@ export function MediaPlayer({ kind = "video", src, poster, title, subtitle, clas
103
103
  setCurrent(el.currentTime); onTimeUpdate?.(e); }, onLoadedMetadata: (e) => { onMeta(); onLoadedMetadata?.(e); }, onDurationChange: (e) => { const el = m(); if (el)
104
104
  setDuration(el.duration); onDurationChange?.(e); }, onProgress: (e) => { syncBuf(); onProgress?.(e); }, onVolumeChange: (e) => { syncVol(); onVolumeChange?.(e); }, children: children })] }), kind === "video" && title && _jsx("div", { className: "media-overlay-title", children: _jsxs("div", { children: [_jsx("strong", { children: title }), subtitle && _jsx("span", { children: subtitle })] }) }), _jsxs("div", { className: "media-controls", children: [_jsxs("div", { className: "media-seek", style: { "--media-played": `${playedPct}%` }, children: [_jsxs("div", { className: "media-seek-track", children: [_jsx("span", { className: "media-seek-buffered", style: { width: `${bufferedPct}%` } }), _jsx("span", { className: "media-seek-played" })] }), _jsx("input", { type: "range", min: 0, max: duration > 0 ? duration : 0, step: "any", value: Math.min(current, duration || 0), "aria-label": s.mediaSeek, "aria-valuetext": valueText, onChange: e => seek(Number(e.target.value)) })] }), _jsxs("div", { className: "media-control-row", children: [_jsxs("div", { className: "media-control-group", children: [_jsx("button", { className: "media-control", type: "button", "aria-label": playing ? s.mediaPause : s.mediaPlay, onClick: togglePlay, children: _jsx(Icon, { name: playing ? "pause" : "play" }) }), _jsx("button", { className: "media-control", type: "button", "aria-label": s.mediaSkipBack, onClick: () => skip(-10), children: _jsx(Icon, { name: "clock-counter-clockwise" }) }), _jsx("button", { className: "media-control", type: "button", "aria-label": s.mediaSkipForward, onClick: () => skip(10), children: _jsx(Icon, { name: "clock-clockwise" }) }), _jsxs("span", { className: "media-time", children: [clockTime(current), " / ", clockTime(duration)] })] }), _jsxs("div", { className: "media-control-group", children: [_jsx("button", { className: "media-control", type: "button", "aria-label": muted ? s.mediaUnmute : s.mediaMute, onClick: toggleMute, children: _jsx(Icon, { name: muted || volume === 0 ? "speaker-slash" : "speaker-high" }) }), _jsx("input", { className: "media-volume", type: "range", min: 0, max: 100, value: volPct, "aria-label": s.mediaVolume, "aria-valuetext": `${volPct}%`, onChange: e => setVol(Number(e.target.value) / 100) }), hasCaptions && _jsx("button", { className: cx("media-control", captionsOn && "active"), type: "button", "aria-label": captionsOn ? s.mediaCaptionsHide : s.mediaCaptionsShow, "aria-pressed": captionsOn, onClick: toggleCaptions, children: _jsx(Icon, { name: "closed-captioning" }) }), kind === "video" && _jsx("button", { className: "media-control", type: "button", "aria-label": fullscreen ? s.mediaFullscreenExit : s.mediaFullscreenEnter, onClick: toggleFullscreen, children: _jsx(Icon, { name: fullscreen ? "arrows-in" : "arrows-out" }) })] })] })] })] });
105
105
  }
106
+ // SÓ `https:` (06/11/2026, a D5 da auditoria externa — decisão do Victor): a moldura aceitava qualquer endereço, sem
107
+ // `sandbox` — não rouba nada da página (medido: o `data:` roda isolado), mas pode mostrar conteúdo falso. Sem `https:`, a
108
+ // moldura fica vazia e o link de origem não aparece.
109
+ const soHttps = (u) => !!u && /^https:\/\//i.test(u.trim());
106
110
  function comAutoplay(src) { try {
107
111
  const u = new URL(src);
108
112
  u.searchParams.set("autoplay", "1");
@@ -119,9 +123,9 @@ export function MediaEmbed({ src, title, poster, ratio = "16/9", href, autoplay
119
123
  React.useEffect(() => { if (clicou)
120
124
  frameRef.current?.focus(); }, [clicou]);
121
125
  const endereco = clicou && autoplay ? comAutoplay(src) : src;
122
- return _jsxs("div", { className: cx("media-embed", className), style: style, children: [_jsx("div", { className: "media-embed-frame", style: { aspectRatio: ratio }, children: ativo
126
+ return _jsxs("div", { className: cx("media-embed", className), style: style, children: [_jsx("div", { className: "media-embed-frame", style: { aspectRatio: ratio }, children: !soHttps(src) ? null : ativo
123
127
  ? _jsx("iframe", { ref: frameRef, src: endereco, title: title, loading: "lazy", referrerPolicy: "strict-origin-when-cross-origin", allow: "autoplay; encrypted-media; fullscreen; picture-in-picture", allowFullScreen: true, ...rest })
124
- : _jsxs("button", { type: "button", className: "media-embed-facade", "aria-label": `${s.mediaPlay}: ${title}`, onClick: () => { setAtivo(true); setClicou(true); }, children: [_jsx("img", { src: poster, alt: "", loading: "lazy", decoding: "async" }), _jsx("span", { className: "media-embed-play", "aria-hidden": "true", children: _jsx(Icon, { name: "play-circle", weight: "fill" }) })] }) }), href && _jsxs("a", { className: "media-embed-link", href: href, target: "_blank", rel: "noopener", children: [_jsx(Icon, { name: "arrow-square-out" }), s.mediaEmbedOpen] })] });
128
+ : _jsxs("button", { type: "button", className: "media-embed-facade", "aria-label": `${s.mediaPlay}: ${title}`, onClick: () => { setAtivo(true); setClicou(true); }, children: [_jsx("img", { src: poster, alt: "", loading: "lazy", decoding: "async" }), _jsx("span", { className: "media-embed-play", "aria-hidden": "true", children: _jsx(Icon, { name: "play-circle", weight: "fill" }) })] }) }), soHttps(href) && _jsxs("a", { className: "media-embed-link", href: href, target: "_blank", rel: "noopener", children: [_jsx(Icon, { name: "arrow-square-out" }), s.mediaEmbedOpen] })] });
125
129
  }
126
130
  export function Image({ ratio, fit, alt, className, style, render, onError, frame, srcDark, ...props }) {
127
131
  const [quebrou, setQuebrou] = React.useState(false);
@@ -58,7 +58,8 @@ export function ContainerScope({ children, className, ...props }) {
58
58
  const temMatchMedia = () => typeof window !== "undefined" && typeof window.matchMedia === "function";
59
59
  const mqls = new Map();
60
60
  const mql = (px) => {
61
- const q = `(min-width:${px}px)`;
61
+ // em `em`, como o CSS gerado (06/11/2026): a fonte que a pessoa escolheu no navegador entra na conta
62
+ const q = `(min-width:${px / 16}em)`;
62
63
  let m = mqls.get(q);
63
64
  if (!m) {
64
65
  m = window.matchMedia(q);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurea-uds/react",
3
- "version": "0.59.0",
3
+ "version": "0.62.0",
4
4
  "description": "Os componentes React da Aurea UDS. Importe @aurea-uds/fonts/css e @aurea-uds/core/css junto.",
5
5
  "keywords": [
6
6
  "aurea",