@aurea-uds/react 0.6.0 → 0.8.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.
@@ -26,6 +26,7 @@ export declare const useDensity: () => {
26
26
  density?: AureaDensity;
27
27
  setDensity: (d: AureaDensity) => void;
28
28
  };
29
+ export declare const DentroDoProviderContext: React.Context<boolean>;
29
30
  export declare const PortalContext: React.Context<HTMLElement | null | undefined>;
30
31
  export declare const usePortalContainer: () => HTMLElement | null | undefined;
31
32
  export interface Reordenavel<E extends HTMLElement> {
package/dist/internal.js CHANGED
@@ -48,6 +48,17 @@ export const useDensity = () => useContext(DensityContext);
48
48
  // Agora tem, e entra pelo provider, UMA vez, como o sprite: é configuração de aplicação, não
49
49
  // prop de componente (foi a lição do achado A4, com 52 sítios repassando `spriteUrl` à mão).
50
50
  // `undefined` é o default e mantém o comportamento de sempre: `document.body`.
51
+ // 🔴 A SENTINELA DE "ESTOU DENTRO DE UM PROVIDER" — 09/09/2026, e ela existe por um defeito
52
+ // medido, não por precaução. O `useAureaTheme` (porta `/system`) escrevia o `data-theme` no
53
+ // documento DIRETO; o efeito do `AureaProvider` só reescreve o atributo quando o valor DELE muda,
54
+ // e não mudava. Resultado: o CSS ia para claro e o contexto continuava dizendo escuro, então todo
55
+ // componente que lê `useTheme()` renderizava do jeito errado — sem erro, sem aviso, publicado.
56
+ // ⚠ POR QUE UMA SENTINELA E NÃO "olhar o ThemeContext": o padrão dele é
57
+ // `{theme:undefined,setTheme:noop}` DE PROPÓSITO — `useTheme()` fora de um provider devolve isso
58
+ // em vez de lançar, e um componente isolado num teste depende disso. Então o valor do contexto
59
+ // NÃO distingue "sem provider" de "provider que ainda não adotou tema". Só um booleano que
60
+ // apenas o provider fornece distingue.
61
+ export const DentroDoProviderContext = createContext(false);
51
62
  export const PortalContext = createContext(undefined);
52
63
  export const usePortalContainer = () => useContext(PortalContext);
53
64
  export function useReorder({ count, order, onReorder, rowSelector, handleSelector }) {
package/dist/system.js CHANGED
@@ -8,7 +8,7 @@ import { Toast as BaseToast } from "@base-ui/react/toast";
8
8
  import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
9
9
  import { DirectionProvider } from "@base-ui/react/direction-provider";
10
10
  import { peleDoEixo } from "./pure.js";
11
- import { cx, StringsContext, SpriteContext, PortalContext, ThemeContext, DensityContext, usePortalContainer, defaultStrings, defaultSpriteUrl, useSpriteUrl, useAureaStrings } from "./internal.js";
11
+ import { cx, StringsContext, SpriteContext, PortalContext, ThemeContext, DensityContext, DentroDoProviderContext, usePortalContainer, defaultStrings, defaultSpriteUrl, useSpriteUrl, useAureaStrings } from "./internal.js";
12
12
  // `theme` e `density` seguem a convenção controlado/não-controlado do resto da biblioteca
13
13
  // (`Toggle`, `ToggleGroup`): passe `theme` para mandar, `defaultTheme` para semear, e ouça por
14
14
  // `onThemeChange`. Sem nenhum dos dois, o provider ADOTA o que o documento já trouxer no
@@ -30,9 +30,17 @@ export function AureaProvider({ children, strings, direction = "ltr", spriteUrl
30
30
  // `toggleTheme` existe porque é o gesto real: um botão de tema não escolhe entre dois
31
31
  // valores, ele inverte o atual. Deixar isso para o consumidor é como o catálogo e os docs
32
32
  // acabaram com duas implementações divergentes da mesma coisa.
33
- toggleTheme: () => temaCtx.set(temaCtx.valor === "light" ? "dark" : "light") }), [temaCtx]);
33
+ // 🔴 ERA `valor==="light"?"dark":"light"`, e o caso "ninguém escolheu ainda" saía INVERTIDO:
34
+ // com `valor` indefinido aquilo dava `light`, então quem está no claro do sistema clicava e
35
+ // NÃO VIA NADA ACONTECER — exatamente o defeito contra o qual o comentário do `useAureaTheme`
36
+ // avisa, 90 linhas abaixo, e que um teste de lá já cobrava. Os dois `toggleTheme` da
37
+ // biblioteca discordavam no mesmo caso de borda.
38
+ // ⚠ Achado em 09/09/2026 SÓ porque o `useAureaTheme` passou a delegar para cá: a divergência
39
+ // existia desde sempre e nenhum teste a pegava, porque cada metade era testada sozinha.
40
+ // Agora a regra é uma: desconhecido resolve para claro e alterna para ESCURO.
41
+ toggleTheme: () => temaCtx.set(temaCtx.valor === "dark" ? "light" : "dark") }), [temaCtx]);
34
42
  const dens = React.useMemo(() => ({ density: densCtx.valor, setDensity: densCtx.set }), [densCtx]);
35
- return _jsx(StringsContext.Provider, { value: value, children: _jsx(SpriteContext.Provider, { value: spriteUrl, children: _jsx(PortalContext.Provider, { value: portalContainer, children: _jsx(ThemeContext.Provider, { value: tema, children: _jsx(DensityContext.Provider, { value: dens, children: _jsx(DirectionProvider, { direction: direction, children: _jsx(BaseToast.Provider, { children: _jsxs(BaseTooltip.Provider, { children: [children, _jsx(AureaToastViewport, {})] }) }) }) }) }) }) }) });
43
+ return _jsx(DentroDoProviderContext.Provider, { value: true, children: _jsx(StringsContext.Provider, { value: value, children: _jsx(SpriteContext.Provider, { value: spriteUrl, children: _jsx(PortalContext.Provider, { value: portalContainer, children: _jsx(ThemeContext.Provider, { value: tema, children: _jsx(DensityContext.Provider, { value: dens, children: _jsx(DirectionProvider, { direction: direction, children: _jsx(BaseToast.Provider, { children: _jsxs(BaseTooltip.Provider, { children: [children, _jsx(AureaToastViewport, {})] }) }) }) }) }) }) }) }) });
36
44
  }
37
45
  /** Um eixo de apresentação que vive no `<html>`: tema ou densidade. A conta é a mesma para os
38
46
  * dois, e escrevê-la duas vezes seria o defeito do §21 cometido dentro do próprio conserto
@@ -98,15 +106,43 @@ const semServidor = () => null;
98
106
  export function useAureaTheme() {
99
107
  const theme = React.useSyncExternalStore(assinaHtml, leAtributo("data-theme"), semServidor);
100
108
  const density = React.useSyncExternalStore(assinaHtml, leAtributo("data-density"), semServidor);
109
+ // 🔴 QUEM ESCREVE MUDA CONFORME HAJA PROVIDER — conserto de 09/09/2026, com o defeito medido
110
+ // em `tests/unit/tema-fonte-unica.test.tsx`. Escrever o atributo direto DENTRO de um
111
+ // `AureaProvider` faz o CSS mudar e o contexto ficar para trás: o efeito do provider só
112
+ // reescreve o atributo quando o valor DELE muda, e ele não mudou. Delegar resolve na origem —
113
+ // o provider vira o único que escreve, e o atributo continua saindo dele.
114
+ // ⚠ E a LEITURA continua vindo do DOM nos dois casos, de propósito: o provider escreve o
115
+ // atributo, então o DOM é o denominador comum, e é ele que o CSS obedece.
116
+ const dentroDeProvider = React.useContext(DentroDoProviderContext);
117
+ const ctxTema = React.useContext(ThemeContext);
118
+ const ctxDens = React.useContext(DensityContext);
101
119
  return React.useMemo(() => ({
102
120
  theme, density,
103
- setTheme: (t) => { document.documentElement.dataset.theme = t; },
104
- setDensity: (d) => { document.documentElement.dataset.density = d; },
121
+ setTheme: (t) => {
122
+ if (dentroDeProvider) {
123
+ ctxTema.setTheme(t);
124
+ return;
125
+ }
126
+ document.documentElement.dataset.theme = t;
127
+ },
128
+ setDensity: (d) => {
129
+ if (dentroDeProvider) {
130
+ ctxDens.setDensity(d);
131
+ return;
132
+ }
133
+ document.documentElement.dataset.density = d;
134
+ },
105
135
  // Alternar é sobre o que está NA TELA, então `null` (servidor, ou ninguém escolheu ainda)
106
136
  // resolve para claro e vira escuro — e não o contrário, que deixaria o primeiro clique sem
107
137
  // efeito visível em quem estava no claro do sistema.
108
- toggleTheme: () => { document.documentElement.dataset.theme = theme === "dark" ? "light" : "dark"; },
109
- }), [theme, density]);
138
+ toggleTheme: () => {
139
+ if (dentroDeProvider) {
140
+ ctxTema.toggleTheme();
141
+ return;
142
+ }
143
+ document.documentElement.dataset.theme = theme === "dark" ? "light" : "dark";
144
+ },
145
+ }), [theme, density, dentroDeProvider, ctxTema, ctxDens]);
110
146
  }
111
147
  function AureaToastList() {
112
148
  const { toasts } = BaseToast.useToastManager();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aurea-uds/react",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "React components for Aurea UDS. Import @aurea-uds/fonts/css and @aurea-uds/core/css alongside.",
5
5
  "keywords": [
6
6
  "aurea",
@@ -112,9 +112,6 @@
112
112
  "files": [
113
113
  "dist"
114
114
  ],
115
- "scripts": {
116
- "build": "tsc"
117
- },
118
115
  "dependencies": {
119
116
  "@base-ui/react": "^1.6.0"
120
117
  },
@@ -176,5 +173,8 @@
176
173
  "react-day-picker": "^10.0.1",
177
174
  "react-dom": "^19.2.0",
178
175
  "recharts": "^3.10.1"
176
+ },
177
+ "scripts": {
178
+ "build": "tsc"
179
179
  }
180
- }
180
+ }