@softize/opus 22.2.0 → 24.0.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.
- package/CHANGELOG.md +120 -1
- package/bin/cli.mjs +3 -9
- package/bin/lib/check.mjs +242 -49
- package/bin/lib/copy.mjs +17 -35
- package/bin/lib/gen-runner.mjs +2 -0
- package/bin/lib/gen-stubs.mjs +3 -1
- package/docs/adr/0005-structural-surfaces-share-an-explicit-anatomy.md +1 -1
- package/docs/adr/0023-surfaces-share-one-anatomy-and-two-layouts.md +6 -0
- package/docs/adr/0032-tab-baseline-respects-the-container-inset.md +16 -12
- package/docs/adr/0034-tabs-can-own-a-frame-without-owning-a-surface.md +8 -6
- package/docs/adr/0036-tabs-declares-trigger-distribution.md +11 -8
- package/docs/adr/0037-design-data-lives-outside-the-contract.md +1 -1
- package/docs/adr/0038-content-level-defines-primary-presentation.md +62 -0
- package/docs/adr/0039-filter-presentation-is-independent-from-filter-type.md +62 -0
- package/docs/adr/0040-tabs-use-a-single-navigation-presentation.md +59 -0
- package/docs/adr/0042-toggle-group-shares-the-grouped-control-grammar.md +79 -0
- package/docs/adr/0043-neutral-surfaces-and-interactions-use-opaque-role-tokens.md +73 -0
- package/docs/adr/0044-neutral-appearance-derives-from-bounded-axes-per-mode.md +133 -0
- package/docs/adr/0045-surface-replaces-content-and-card.md +230 -0
- package/docs/adr/0046-structural-body-owns-content-rhythm.md +103 -0
- package/docs/adr/0047-pane-is-only-a-split-layout-unit.md +71 -0
- package/docs/adr/0048-modal-intro-separates-content-from-chrome.md +34 -0
- package/docs/code-style.md +1 -1
- package/package.json +5 -1
- package/registry/skills/build-opus-ui/SKILL.md +11 -11
- package/registry/skills/build-opus-ui/references/evaluations.md +10 -9
- package/registry/skills/build-opus-ui/references/ui-patterns.md +17 -16
- package/registry/skills/create-opus-action/references/contract-and-binding.md +3 -3
- package/registry/templates/app/src/App.tsx +24 -12
- package/src/core/contracts.ts +1 -1
- package/src/core/runtime.ts +4 -37
- package/src/core/types.ts +5 -23
- package/src/design/index.ts +14 -3
- package/src/testing/index.ts +6 -26
- package/src/ui/appearance.ts +149 -0
- package/src/ui/components/patterns/action-form-card.tsx +46 -33
- package/src/ui/components/patterns/action-list-dialog.tsx +2 -4
- package/src/ui/components/patterns/confirm.tsx +3 -1
- package/src/ui/components/patterns/fill-region.ts +8 -7
- package/src/ui/components/patterns/form-dialog.tsx +1 -3
- package/src/ui/components/patterns/form.tsx +8 -7
- package/src/ui/components/patterns/list.tsx +64 -14
- package/src/ui/components/patterns/page.tsx +15 -11
- package/src/ui/components/patterns/pane.tsx +9 -240
- package/src/ui/components/patterns/presentation.tsx +14 -14
- package/src/ui/components/patterns/sidebar.tsx +7 -17
- package/src/ui/components/patterns/split.tsx +111 -59
- package/src/ui/components/patterns/{surface-header.tsx → structural-header.tsx} +50 -19
- package/src/ui/components/patterns/structural-media.tsx +26 -0
- package/src/ui/components/patterns/surface-anatomy.ts +71 -61
- package/src/ui/components/patterns/surface-assistant.tsx +2 -4
- package/src/ui/components/patterns/surface.tsx +620 -0
- package/src/ui/components/patterns/trigger.tsx +11 -9
- package/src/ui/components/primitives/ask.tsx +155 -83
- package/src/ui/components/primitives/button.tsx +11 -9
- package/src/ui/components/primitives/checkbox.tsx +8 -8
- package/src/ui/components/primitives/command.tsx +1 -1
- package/src/ui/components/primitives/composer.tsx +47 -45
- package/src/ui/components/primitives/detail.tsx +9 -2
- package/src/ui/components/primitives/dialog.tsx +60 -26
- package/src/ui/components/primitives/drawer.tsx +58 -12
- package/src/ui/components/primitives/icon-picker.tsx +93 -70
- package/src/ui/components/primitives/input-group.tsx +35 -28
- package/src/ui/components/primitives/input-otp.tsx +16 -16
- package/src/ui/components/primitives/input.tsx +20 -10
- package/src/ui/components/primitives/item.tsx +9 -12
- package/src/ui/components/primitives/menu.tsx +44 -65
- package/src/ui/components/primitives/metric-card.tsx +75 -59
- package/src/ui/components/primitives/radio-group.tsx +9 -9
- package/src/ui/components/primitives/select.tsx +344 -209
- package/src/ui/components/primitives/switch.tsx +10 -10
- package/src/ui/components/primitives/table.tsx +29 -24
- package/src/ui/components/primitives/tabs.tsx +58 -88
- package/src/ui/components/primitives/textarea.tsx +6 -6
- package/src/ui/components/primitives/toggle-group-context.ts +24 -0
- package/src/ui/components/primitives/toggle-group.tsx +116 -74
- package/src/ui/components/primitives/toggle.tsx +82 -16
- package/src/ui/docs/DocBrowser.tsx +77 -69
- package/src/ui/docs/content/action-form-card.md +9 -9
- package/src/ui/docs/content/action-list.md +85 -70
- package/src/ui/docs/content/action-view.md +33 -18
- package/src/ui/docs/content/actions.md +6 -7
- package/src/ui/docs/content/button.md +1 -1
- package/src/ui/docs/content/communication.md +1 -1
- package/src/ui/docs/content/customization.md +64 -11
- package/src/ui/docs/content/detail.md +8 -6
- package/src/ui/docs/content/dialog.md +100 -58
- package/src/ui/docs/content/drawer.md +63 -19
- package/src/ui/docs/content/field.md +14 -15
- package/src/ui/docs/content/icon-tile.md +14 -13
- package/src/ui/docs/content/page.md +34 -26
- package/src/ui/docs/content/pane.md +41 -290
- package/src/ui/docs/content/presentation.md +3 -3
- package/src/ui/docs/content/semantic-context.md +0 -1
- package/src/ui/docs/content/separator.md +6 -6
- package/src/ui/docs/content/sidebar.md +68 -266
- package/src/ui/docs/content/skeleton.md +20 -18
- package/src/ui/docs/content/split.md +14 -14
- package/src/ui/docs/content/surface.md +513 -0
- package/src/ui/docs/content/tabs.md +82 -83
- package/src/ui/docs/content/testing.md +2 -3
- package/src/ui/docs/content/toggle.md +120 -63
- package/src/ui/docs/content/tokens.md +124 -40
- package/src/ui/docs/registry.tsx +4 -6
- package/src/ui/drivers/react.tsx +4 -3
- package/src/ui/index.ts +30 -27
- package/src/ui/meta.ts +15 -27
- package/src/ui/react.tsx +42 -46
- package/src/ui/theme.css +311 -64
- package/src/vite/design.ts +23 -21
- package/src/ui/components/patterns/content-header.tsx +0 -532
- package/src/ui/components/patterns/surface-media.tsx +0 -69
- package/src/ui/components/primitives/card.tsx +0 -191
- package/src/ui/docs/content/card.md +0 -292
- package/src/ui/docs/content/content.md +0 -276
package/src/ui/react.tsx
CHANGED
|
@@ -10,6 +10,9 @@ export * from "./drivers/react.tsx";
|
|
|
10
10
|
// Utilitário
|
|
11
11
|
export { cn } from "./lib/cn.ts";
|
|
12
12
|
|
|
13
|
+
// Personalização de aparência (ADR 0044): o mesmo módulo sem React de `./ui/appearance`.
|
|
14
|
+
export * from "./appearance.ts";
|
|
15
|
+
|
|
13
16
|
// Primitivos
|
|
14
17
|
export { Button, buttonVariants } from "./components/primitives/button.tsx";
|
|
15
18
|
export type {
|
|
@@ -90,18 +93,6 @@ export type {
|
|
|
90
93
|
DetailGroupVariant,
|
|
91
94
|
} from "./components/primitives/detail.tsx";
|
|
92
95
|
|
|
93
|
-
export {
|
|
94
|
-
Card,
|
|
95
|
-
CardHeader,
|
|
96
|
-
CardMedia,
|
|
97
|
-
CardTitle,
|
|
98
|
-
CardDescription,
|
|
99
|
-
CardAction,
|
|
100
|
-
CardBody,
|
|
101
|
-
CardContent,
|
|
102
|
-
CardFooter,
|
|
103
|
-
} from "./components/primitives/card.tsx";
|
|
104
|
-
|
|
105
96
|
export { MetricCard } from "./components/primitives/metric-card.tsx";
|
|
106
97
|
export type {
|
|
107
98
|
MetricCardProps,
|
|
@@ -136,6 +127,8 @@ export {
|
|
|
136
127
|
DialogNavigation,
|
|
137
128
|
DialogMedia,
|
|
138
129
|
DialogActions,
|
|
130
|
+
DialogIntro,
|
|
131
|
+
DialogIntroActions,
|
|
139
132
|
DialogBody,
|
|
140
133
|
DialogFooter,
|
|
141
134
|
DialogTitle,
|
|
@@ -146,7 +139,7 @@ export type {
|
|
|
146
139
|
DialogMode,
|
|
147
140
|
} from "./components/primitives/dialog.tsx";
|
|
148
141
|
|
|
149
|
-
// O pacote de anatomia que
|
|
142
|
+
// O pacote de anatomia que Surface, Dialog, Drawer e Pane declaram no root (ADR 0023). As
|
|
150
143
|
// tabelas e o contexto continuam internos; o consumidor escolhe entre os dois nomes.
|
|
151
144
|
export type { SurfaceLayout } from "./components/patterns/surface-anatomy.ts";
|
|
152
145
|
|
|
@@ -192,8 +185,8 @@ export { Separator } from "./components/primitives/separator.tsx";
|
|
|
192
185
|
export {
|
|
193
186
|
Tabs,
|
|
194
187
|
TabsList,
|
|
195
|
-
|
|
196
|
-
|
|
188
|
+
TabsListItem,
|
|
189
|
+
TabsPanel,
|
|
197
190
|
} from "./components/primitives/tabs.tsx";
|
|
198
191
|
|
|
199
192
|
export { Skeleton } from "./components/primitives/skeleton.tsx";
|
|
@@ -278,6 +271,8 @@ export {
|
|
|
278
271
|
export {
|
|
279
272
|
Drawer,
|
|
280
273
|
DrawerActions,
|
|
274
|
+
DrawerIntro,
|
|
275
|
+
DrawerIntroActions,
|
|
281
276
|
DrawerClose,
|
|
282
277
|
DrawerContent,
|
|
283
278
|
DrawerFooter,
|
|
@@ -372,10 +367,16 @@ export {
|
|
|
372
367
|
export { ScrollArea, ScrollBar } from "./components/primitives/scroll-area.tsx";
|
|
373
368
|
export { Slider } from "./components/primitives/slider.tsx";
|
|
374
369
|
export { Switch } from "./components/primitives/switch.tsx";
|
|
375
|
-
export {
|
|
370
|
+
export {
|
|
371
|
+
Toggle,
|
|
372
|
+
type ToggleProps,
|
|
373
|
+
toggleVariants,
|
|
374
|
+
} from "./components/primitives/toggle.tsx";
|
|
376
375
|
export {
|
|
377
376
|
ToggleGroup,
|
|
378
|
-
|
|
377
|
+
type ToggleGroupDistribution,
|
|
378
|
+
type ToggleGroupMode,
|
|
379
|
+
type ToggleGroupProps,
|
|
379
380
|
} from "./components/primitives/toggle-group.tsx";
|
|
380
381
|
export { Truncate } from "./components/primitives/truncate.tsx";
|
|
381
382
|
export type { TruncateProps } from "./components/primitives/truncate.tsx";
|
|
@@ -482,27 +483,30 @@ export type {
|
|
|
482
483
|
PageStateStatus,
|
|
483
484
|
} from "./components/patterns/page-state.tsx";
|
|
484
485
|
|
|
485
|
-
//
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
486
|
+
// Superfície: região de página, grupo de campos, entidade, item ou bloco clicável. A
|
|
487
|
+
// semântica vem de `as`/`asChild`; forma curta e slots compartilham a anatomia (ADR 0045).
|
|
488
|
+
export {
|
|
489
|
+
Surface,
|
|
490
|
+
SurfaceHeader,
|
|
491
|
+
SurfaceMedia,
|
|
492
|
+
SurfaceTitle,
|
|
493
|
+
SurfaceDescription,
|
|
494
|
+
SurfaceMeta,
|
|
495
|
+
SurfaceActions,
|
|
496
|
+
SurfaceBody,
|
|
497
|
+
SurfaceFooter,
|
|
498
|
+
} from "./components/patterns/surface.tsx";
|
|
496
499
|
export type {
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
} from "./components/patterns/
|
|
504
|
-
|
|
505
|
-
|
|
500
|
+
SurfaceProps,
|
|
501
|
+
SurfaceHeaderProps,
|
|
502
|
+
SurfaceMediaProps,
|
|
503
|
+
SurfaceBodyProps,
|
|
504
|
+
SurfaceElement,
|
|
505
|
+
SurfaceElevation,
|
|
506
|
+
} from "./components/patterns/surface.tsx";
|
|
507
|
+
export type { HeadingLevel } from "./components/patterns/heading-level.ts";
|
|
508
|
+
|
|
509
|
+
// Layout composicional: Split decide a relação espacial; Pane declara somente dimensão.
|
|
506
510
|
export { Split, Pane } from "./components/patterns/split.tsx";
|
|
507
511
|
export type {
|
|
508
512
|
SplitProps,
|
|
@@ -530,16 +534,8 @@ export type {
|
|
|
530
534
|
SurfaceStatusContext,
|
|
531
535
|
} from "./components/patterns/dock.tsx";
|
|
532
536
|
|
|
533
|
-
// Barra lateral composicional
|
|
537
|
+
// Barra lateral composicional e navegação, sem possuir o layout.
|
|
534
538
|
export {
|
|
535
|
-
PaneActions,
|
|
536
|
-
PaneDescription,
|
|
537
|
-
PaneHeader,
|
|
538
|
-
PaneMedia,
|
|
539
|
-
PaneTitle,
|
|
540
|
-
PaneBody,
|
|
541
|
-
PaneContent,
|
|
542
|
-
PaneFooter,
|
|
543
539
|
Sidebar,
|
|
544
540
|
SidebarItem,
|
|
545
541
|
SidebarGroupLabel,
|
package/src/ui/theme.css
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
*
|
|
7
7
|
* ── DIVERGÊNCIAS DECLARADAS vs shadcn upstream (regra: o que não está aqui é DRIFT
|
|
8
8
|
* e deve ser sincronizado; ver skill `build-opus-ui`) ─────────────────────────────
|
|
9
|
-
* 1. Formato HSL nos tokens (upstream migrou pra oklch) — legibilidade/ferramentas
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* 1. Formato HSL nos tokens (upstream migrou pra oklch) — legibilidade/ferramentas nossas.
|
|
10
|
+
* 2. Hierarquia de superfície nos dois temas: canvas, superfície elevada, controle e estados
|
|
11
|
+
* neutros têm valores opacos por papel (ADR 0043), sem depender do fundo ancestral. A escala
|
|
12
|
+
* neutra é derivada de quatro eixos de aparência por modo (ADR 0044); os presets reproduzem
|
|
13
|
+
* os valores calibrados e o app personaliza por custom property.
|
|
13
14
|
* 3. Radius mapeado (xs a 2xl em @theme inline) preservando o sentido pré-v4 dos
|
|
14
15
|
* utilitários `rounded-*` — neutraliza o rename do v4 e mantém a escala monotônica.
|
|
15
16
|
* 4. Escala shadow-* recomposta diretamente em duas camadas claras, difusas e com spread
|
|
@@ -18,10 +19,10 @@
|
|
|
18
19
|
* canvas quase-branco; superfícies elevadas usam a mesma borda real dos demais papéis.
|
|
19
20
|
* 6. Radius base em 0.75rem — identidade mais arredondada; os componentes continuam usando
|
|
20
21
|
* diretamente a escala Tailwind, sem tokens por papel (ver docs/radius-scale.md).
|
|
21
|
-
* Tudo o mais (
|
|
22
|
+
* Tudo o mais (semânticas e contratos das primitives) segue o upstream.
|
|
22
23
|
*/
|
|
23
|
-
@import
|
|
24
|
-
@import
|
|
24
|
+
@import "tailwindcss";
|
|
25
|
+
@import "tw-animate-css";
|
|
25
26
|
@plugin '@tailwindcss/typography';
|
|
26
27
|
|
|
27
28
|
/* dark por classe (v4 é CSS-first) */
|
|
@@ -31,20 +32,112 @@
|
|
|
31
32
|
/* Scrollbars e controles NATIVOS (date picker, autofill…) seguem o tema — sem
|
|
32
33
|
isto o browser assume light e pinta scrollbar branca no dark. */
|
|
33
34
|
color-scheme: light;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
|
|
36
|
+
/* ── Aparência (ADR 0044) ──────────────────────────────────────────────────────────
|
|
37
|
+
Quatro eixos inteiros de 0 a 100, declarados por modo. Estes são os presets: com eles a
|
|
38
|
+
escala neutra abaixo reproduz exatamente os valores calibrados do tema. O consumidor
|
|
39
|
+
sobrescreve `--appearance-light-*` e `--appearance-dark-*` (inline em <html>, por exemplo)
|
|
40
|
+
e remove a propriedade para voltar ao preset; `@softize/opus/ui/appearance` publica nomes e
|
|
41
|
+
presets. `--neutral-hue` é identidade do app — o matiz que a intensidade aplica aos
|
|
42
|
+
neutros — e não um eixo. Primary e contextos semânticos não participam desta derivação.
|
|
43
|
+
|
|
44
|
+
Os limites protegem o tema calibrado. Contraste e contraste entre camadas partem do preset
|
|
45
|
+
e só ampliam as separações. O brilho move as superfícies dentro de uma faixa em que o texto
|
|
46
|
+
secundário compensa a mudança. Nenhuma combinação de 0 a 100 fica abaixo do preset em
|
|
47
|
+
separação entre papéis nem em contraste do texto sobre as superfícies em repouso. */
|
|
48
|
+
--appearance-light-color-intensity: 0;
|
|
49
|
+
--appearance-light-contrast: 0;
|
|
50
|
+
--appearance-light-surface-brightness: 100;
|
|
51
|
+
--appearance-light-layer-contrast: 0;
|
|
52
|
+
--appearance-dark-color-intensity: 0;
|
|
53
|
+
--appearance-dark-contrast: 0;
|
|
54
|
+
--appearance-dark-surface-brightness: 50;
|
|
55
|
+
--appearance-dark-layer-contrast: 0;
|
|
56
|
+
--neutral-hue: 220;
|
|
57
|
+
|
|
58
|
+
/* Eixos ativos no modo claro. */
|
|
59
|
+
--appearance-color-intensity: var(--appearance-light-color-intensity);
|
|
60
|
+
--appearance-contrast: var(--appearance-light-contrast);
|
|
61
|
+
--appearance-surface-brightness: var(--appearance-light-surface-brightness);
|
|
62
|
+
--appearance-layer-contrast: var(--appearance-light-layer-contrast);
|
|
63
|
+
|
|
64
|
+
/* Escala neutra derivada (luminosidade em número, 0 a 100). No claro a superfície elevada
|
|
65
|
+
parte do branco; o canvas desce dela conforme o contraste entre camadas e o controle fica
|
|
66
|
+
entre os dois. Estados neutros, muted e bordas descem a partir do canvas — a superfície
|
|
67
|
+
mais escura — na direção do texto, em passos que o contraste amplia. O texto secundário
|
|
68
|
+
recebe só uma fração da saturação e escurece junto com as superfícies e com a intensidade,
|
|
69
|
+
para que nem o ajuste nem o matiz escolhido pelo app reduzam a leitura. */
|
|
70
|
+
--neutral-saturation: calc(var(--appearance-color-intensity) * 0.2%);
|
|
71
|
+
--neutral-text-saturation: calc(var(--appearance-color-intensity) * 0.08%);
|
|
72
|
+
--neutral-step: calc(1 + var(--appearance-contrast) * 0.01);
|
|
73
|
+
--neutral-layer-l: calc(95 + var(--appearance-surface-brightness) * 0.05);
|
|
74
|
+
--neutral-canvas-l: calc(
|
|
75
|
+
var(--neutral-layer-l) - 2.5 - var(--appearance-layer-contrast) * 0.025
|
|
76
|
+
);
|
|
77
|
+
--neutral-control-l: calc(
|
|
78
|
+
var(--neutral-canvas-l) + 1 + var(--appearance-layer-contrast) * 0.01
|
|
79
|
+
);
|
|
80
|
+
--neutral-muted-l: calc(var(--neutral-canvas-l) - 1.4 * var(--neutral-step));
|
|
81
|
+
--neutral-hover-l: calc(var(--neutral-canvas-l) - 2 * var(--neutral-step));
|
|
82
|
+
--neutral-selected-l: calc(var(--neutral-canvas-l) - 5 * var(--neutral-step));
|
|
83
|
+
--neutral-pressed-l: calc(
|
|
84
|
+
var(--neutral-canvas-l) - 6.5 * var(--neutral-step)
|
|
85
|
+
);
|
|
86
|
+
--neutral-line-l: calc(var(--neutral-canvas-l) - 5 * var(--neutral-step));
|
|
87
|
+
--neutral-ring-l: calc(var(--neutral-line-l) - 6.5 * var(--neutral-step));
|
|
88
|
+
--neutral-muted-foreground-l: calc(
|
|
89
|
+
45.1 - (96.1 - var(--neutral-muted-l)) * 0.8 -
|
|
90
|
+
var(--appearance-color-intensity) * 0.04
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
--background: hsl(
|
|
94
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
95
|
+
calc(var(--neutral-canvas-l) * 1%)
|
|
96
|
+
);
|
|
97
|
+
--foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 3.9%);
|
|
98
|
+
--card: hsl(
|
|
99
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
100
|
+
calc(var(--neutral-layer-l) * 1%)
|
|
101
|
+
);
|
|
102
|
+
--card-foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 3.9%);
|
|
103
|
+
--control: hsl(
|
|
104
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
105
|
+
calc(var(--neutral-control-l) * 1%)
|
|
106
|
+
);
|
|
107
|
+
--interaction-hover: hsl(
|
|
108
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
109
|
+
calc(var(--neutral-hover-l) * 1%)
|
|
110
|
+
);
|
|
111
|
+
--interaction-selected: hsl(
|
|
112
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
113
|
+
calc(var(--neutral-selected-l) * 1%)
|
|
114
|
+
);
|
|
115
|
+
--interaction-pressed: hsl(
|
|
116
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
117
|
+
calc(var(--neutral-pressed-l) * 1%)
|
|
118
|
+
);
|
|
119
|
+
--popover: hsl(
|
|
120
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
121
|
+
calc(var(--neutral-layer-l) * 1%)
|
|
122
|
+
);
|
|
123
|
+
--popover-foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 3.9%);
|
|
40
124
|
--primary: hsl(0 0% 9%);
|
|
41
125
|
--primary-foreground: hsl(0 0% 98%);
|
|
42
|
-
--secondary: hsl(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
--
|
|
47
|
-
--
|
|
126
|
+
--secondary: hsl(
|
|
127
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
128
|
+
calc(var(--neutral-muted-l) * 1%)
|
|
129
|
+
);
|
|
130
|
+
--secondary-foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 9%);
|
|
131
|
+
--muted: hsl(
|
|
132
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
133
|
+
calc(var(--neutral-muted-l) * 1%)
|
|
134
|
+
);
|
|
135
|
+
--muted-foreground: hsl(
|
|
136
|
+
var(--neutral-hue) var(--neutral-text-saturation)
|
|
137
|
+
calc(var(--neutral-muted-foreground-l) * 1%)
|
|
138
|
+
);
|
|
139
|
+
--accent: var(--interaction-hover);
|
|
140
|
+
--accent-foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 9%);
|
|
48
141
|
--destructive: hsl(0 84.2% 60.2%);
|
|
49
142
|
--destructive-foreground: hsl(0 0% 98%);
|
|
50
143
|
/* Contextos semânticos (ADR 0006): família independente do tratamento
|
|
@@ -58,7 +151,11 @@
|
|
|
58
151
|
--context-primary-foreground: var(--primary-foreground);
|
|
59
152
|
--context-primary-subtle: color-mix(in oklab, var(--primary) 8%, transparent);
|
|
60
153
|
--context-primary-emphasis: var(--foreground);
|
|
61
|
-
--context-primary-border: color-mix(
|
|
154
|
+
--context-primary-border: color-mix(
|
|
155
|
+
in oklab,
|
|
156
|
+
var(--primary) 25%,
|
|
157
|
+
transparent
|
|
158
|
+
);
|
|
62
159
|
/* info/success/warning: base, foreground, subtle e border (12 tokens) valem nos dois temas
|
|
63
160
|
de propósito — são cores saturadas com alpha, que já se assentam sobre qualquer canvas;
|
|
64
161
|
só `*-emphasis` (texto sobre o popover) precisa clarear no escuro, e é redefinido em .dark. */
|
|
@@ -79,35 +176,119 @@
|
|
|
79
176
|
--context-warning-border: hsl(38 92% 50% / 0.35);
|
|
80
177
|
--context-danger: var(--destructive);
|
|
81
178
|
--context-danger-foreground: var(--destructive-foreground);
|
|
82
|
-
--context-danger-subtle: color-mix(
|
|
179
|
+
--context-danger-subtle: color-mix(
|
|
180
|
+
in oklab,
|
|
181
|
+
var(--destructive) 10%,
|
|
182
|
+
transparent
|
|
183
|
+
);
|
|
83
184
|
--context-danger-emphasis: hsl(0 72% 45%);
|
|
84
|
-
--context-danger-border: color-mix(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
--
|
|
185
|
+
--context-danger-border: color-mix(
|
|
186
|
+
in oklab,
|
|
187
|
+
var(--destructive) 35%,
|
|
188
|
+
transparent
|
|
189
|
+
);
|
|
190
|
+
--border: hsl(
|
|
191
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
192
|
+
calc(var(--neutral-line-l) * 1%)
|
|
193
|
+
);
|
|
194
|
+
--input: hsl(
|
|
195
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
196
|
+
calc(var(--neutral-line-l) * 1%)
|
|
197
|
+
);
|
|
198
|
+
/* O aro acompanha a borda e o contraste escolhidos, preservando o degrau do preset. */
|
|
199
|
+
--ring: hsl(
|
|
200
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
201
|
+
calc(var(--neutral-ring-l) * 1%)
|
|
202
|
+
);
|
|
90
203
|
--radius: 0.75rem;
|
|
91
204
|
}
|
|
92
205
|
|
|
93
206
|
.dark {
|
|
94
207
|
color-scheme: dark;
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
--
|
|
100
|
-
--
|
|
101
|
-
|
|
102
|
-
|
|
208
|
+
|
|
209
|
+
/* Eixos ativos no modo escuro. */
|
|
210
|
+
--appearance-color-intensity: var(--appearance-dark-color-intensity);
|
|
211
|
+
--appearance-contrast: var(--appearance-dark-contrast);
|
|
212
|
+
--appearance-surface-brightness: var(--appearance-dark-surface-brightness);
|
|
213
|
+
--appearance-layer-contrast: var(--appearance-dark-layer-contrast);
|
|
214
|
+
|
|
215
|
+
/* No escuro o brilho leva o canvas do preto, em 0, até um escuro suave, em 100. Elevação com
|
|
216
|
+
contraste de verdade (dialog e card "sobem" da página): a camada sobe do canvas conforme o
|
|
217
|
+
contraste entre camadas e o controle fica entre os dois. Estados neutros, muted e bordas
|
|
218
|
+
sobem a partir da camada — a superfície mais clara — na direção do texto. Mesmos papéis do
|
|
219
|
+
claro, direção invertida. O texto secundário clareia quando as superfícies sobem acima do
|
|
220
|
+
preset e nunca escurece abaixo dele. */
|
|
221
|
+
--neutral-saturation: calc(var(--appearance-color-intensity) * 0.2%);
|
|
222
|
+
--neutral-text-saturation: calc(var(--appearance-color-intensity) * 0.08%);
|
|
223
|
+
--neutral-step: calc(1 + var(--appearance-contrast) * 0.006);
|
|
224
|
+
--neutral-canvas-l: calc(var(--appearance-surface-brightness) * 0.078);
|
|
225
|
+
--neutral-layer-l: calc(
|
|
226
|
+
var(--neutral-canvas-l) + 6.1 + var(--appearance-layer-contrast) * 0.03
|
|
227
|
+
);
|
|
228
|
+
--neutral-control-l: calc(
|
|
229
|
+
var(--neutral-canvas-l) + 3.8 + var(--appearance-layer-contrast) * 0.018
|
|
230
|
+
);
|
|
231
|
+
--neutral-muted-l: calc(var(--neutral-layer-l) + 4.9 * var(--neutral-step));
|
|
232
|
+
--neutral-hover-l: calc(var(--neutral-layer-l) + 4.9 * var(--neutral-step));
|
|
233
|
+
--neutral-selected-l: calc(
|
|
234
|
+
var(--neutral-layer-l) + 8.5 * var(--neutral-step)
|
|
235
|
+
);
|
|
236
|
+
--neutral-pressed-l: calc(var(--neutral-layer-l) + 11 * var(--neutral-step));
|
|
237
|
+
--neutral-line-l: calc(var(--neutral-layer-l) + 6.5 * var(--neutral-step));
|
|
238
|
+
--neutral-ring-l: calc(var(--neutral-line-l) + 19.5 * var(--neutral-step));
|
|
239
|
+
--neutral-muted-foreground-l: calc(
|
|
240
|
+
63.9 + max(0, var(--neutral-muted-l) - 14.9) * 1.6 +
|
|
241
|
+
var(--appearance-color-intensity) * 0.04
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
--background: hsl(
|
|
245
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
246
|
+
calc(var(--neutral-canvas-l) * 1%)
|
|
247
|
+
);
|
|
248
|
+
--foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 98%);
|
|
249
|
+
--card: hsl(
|
|
250
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
251
|
+
calc(var(--neutral-layer-l) * 1%)
|
|
252
|
+
);
|
|
253
|
+
--card-foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 98%);
|
|
254
|
+
--control: hsl(
|
|
255
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
256
|
+
calc(var(--neutral-control-l) * 1%)
|
|
257
|
+
);
|
|
258
|
+
--interaction-hover: hsl(
|
|
259
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
260
|
+
calc(var(--neutral-hover-l) * 1%)
|
|
261
|
+
);
|
|
262
|
+
--interaction-selected: hsl(
|
|
263
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
264
|
+
calc(var(--neutral-selected-l) * 1%)
|
|
265
|
+
);
|
|
266
|
+
--interaction-pressed: hsl(
|
|
267
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
268
|
+
calc(var(--neutral-pressed-l) * 1%)
|
|
269
|
+
);
|
|
270
|
+
--popover: hsl(
|
|
271
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
272
|
+
calc(var(--neutral-layer-l) * 1%)
|
|
273
|
+
);
|
|
274
|
+
--popover-foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 98%);
|
|
103
275
|
--primary: hsl(0 0% 98%);
|
|
104
276
|
--primary-foreground: hsl(0 0% 9%);
|
|
105
|
-
--secondary: hsl(
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
--
|
|
110
|
-
--
|
|
277
|
+
--secondary: hsl(
|
|
278
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
279
|
+
calc(var(--neutral-muted-l) * 1%)
|
|
280
|
+
);
|
|
281
|
+
--secondary-foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 98%);
|
|
282
|
+
--muted: hsl(
|
|
283
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
284
|
+
calc(var(--neutral-muted-l) * 1%)
|
|
285
|
+
);
|
|
286
|
+
--muted-foreground: hsl(
|
|
287
|
+
var(--neutral-hue) var(--neutral-text-saturation)
|
|
288
|
+
calc(var(--neutral-muted-foreground-l) * 1%)
|
|
289
|
+
);
|
|
290
|
+
--accent: var(--interaction-hover);
|
|
291
|
+
--accent-foreground: hsl(var(--neutral-hue) var(--neutral-saturation) 98%);
|
|
111
292
|
/* Vermelho CLARO no escuro (era 30.6% — calibrado só pra FUNDO, com texto branco).
|
|
112
293
|
Como o menu/alert/field/erros usam `text-destructive` como FOREGROUND, o valor
|
|
113
294
|
escuro dava ~1,7:1 sobre o popover — ilegível. ~58% passa o AA como texto, o mesmo
|
|
@@ -119,10 +300,18 @@
|
|
|
119
300
|
--context-success-emphasis: hsl(142 69% 58%);
|
|
120
301
|
--context-warning-emphasis: hsl(43 96% 56%);
|
|
121
302
|
--context-danger-emphasis: hsl(0 91% 71%);
|
|
122
|
-
--border: hsl(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
303
|
+
--border: hsl(
|
|
304
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
305
|
+
calc(var(--neutral-line-l) * 1%)
|
|
306
|
+
);
|
|
307
|
+
--input: hsl(
|
|
308
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
309
|
+
calc(var(--neutral-line-l) * 1%)
|
|
310
|
+
);
|
|
311
|
+
--ring: hsl(
|
|
312
|
+
var(--neutral-hue) var(--neutral-saturation)
|
|
313
|
+
calc(var(--neutral-ring-l) * 1%)
|
|
314
|
+
);
|
|
126
315
|
}
|
|
127
316
|
|
|
128
317
|
/* Syntax highlighting (CodeBlock via prism-react-renderer): paleta calma mapeada por CSS
|
|
@@ -156,6 +345,10 @@
|
|
|
156
345
|
--color-foreground: var(--foreground);
|
|
157
346
|
--color-card: var(--card);
|
|
158
347
|
--color-card-foreground: var(--card-foreground);
|
|
348
|
+
--color-control: var(--control);
|
|
349
|
+
--color-interaction-hover: var(--interaction-hover);
|
|
350
|
+
--color-interaction-selected: var(--interaction-selected);
|
|
351
|
+
--color-interaction-pressed: var(--interaction-pressed);
|
|
159
352
|
--color-popover: var(--popover);
|
|
160
353
|
--color-popover-foreground: var(--popover-foreground);
|
|
161
354
|
--color-primary: var(--primary);
|
|
@@ -211,14 +404,38 @@
|
|
|
211
404
|
|
|
212
405
|
/* Escala Tailwind, com receita direta para o compilador preservar modifiers `/opacity`.
|
|
213
406
|
`light-dark()` mantém o peso adequado em cada tema sem uma variável intermediária. */
|
|
214
|
-
--shadow-2xs: 0 0.0625rem 0.125rem -0.0625rem
|
|
215
|
-
|
|
216
|
-
--shadow-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
--shadow-
|
|
407
|
+
--shadow-2xs: 0 0.0625rem 0.125rem -0.0625rem
|
|
408
|
+
light-dark(rgb(15 15 15 / 0.03), rgb(0 0 0 / 0.12));
|
|
409
|
+
--shadow-xs:
|
|
410
|
+
0 0.0625rem 0.125rem -0.0625rem
|
|
411
|
+
light-dark(rgb(15 15 15 / 0.025), rgb(0 0 0 / 0.12)),
|
|
412
|
+
0 0.125rem 0.25rem -0.125rem
|
|
413
|
+
light-dark(rgb(15 15 15 / 0.035), rgb(0 0 0 / 0.18));
|
|
414
|
+
--shadow-sm:
|
|
415
|
+
0 0.125rem 0.25rem -0.125rem
|
|
416
|
+
light-dark(rgb(15 15 15 / 0.025), rgb(0 0 0 / 0.16)),
|
|
417
|
+
0 0.25rem 0.5rem -0.25rem
|
|
418
|
+
light-dark(rgb(15 15 15 / 0.04), rgb(0 0 0 / 0.28));
|
|
419
|
+
--shadow:
|
|
420
|
+
0 0.125rem 0.375rem -0.125rem
|
|
421
|
+
light-dark(rgb(15 15 15 / 0.03), rgb(0 0 0 / 0.16)),
|
|
422
|
+
0 0.375rem 0.875rem -0.375rem
|
|
423
|
+
light-dark(rgb(15 15 15 / 0.05), rgb(0 0 0 / 0.29));
|
|
424
|
+
--shadow-md:
|
|
425
|
+
0 0.25rem 0.5rem -0.25rem
|
|
426
|
+
light-dark(rgb(15 15 15 / 0.03), rgb(0 0 0 / 0.16)),
|
|
427
|
+
0 0.625rem 1.75rem -0.5rem
|
|
428
|
+
light-dark(rgb(15 15 15 / 0.065), rgb(0 0 0 / 0.3));
|
|
429
|
+
--shadow-lg:
|
|
430
|
+
0 0.375rem 1rem -0.375rem
|
|
431
|
+
light-dark(rgb(15 15 15 / 0.03), rgb(0 0 0 / 0.18)),
|
|
432
|
+
0 1.125rem 3rem -0.75rem light-dark(rgb(15 15 15 / 0.07), rgb(0 0 0 / 0.3));
|
|
433
|
+
--shadow-xl:
|
|
434
|
+
0 0.5rem 1.5rem -0.625rem light-dark(rgb(15 15 15 / 0.04), rgb(0 0 0 / 0.2)),
|
|
435
|
+
0 1.5rem 4rem -1.125rem light-dark(rgb(15 15 15 / 0.08), rgb(0 0 0 / 0.34));
|
|
436
|
+
--shadow-2xl:
|
|
437
|
+
0 0.75rem 2rem -0.875rem light-dark(rgb(15 15 15 / 0.05), rgb(0 0 0 / 0.22)),
|
|
438
|
+
0 2rem 5.5rem -1.5rem light-dark(rgb(15 15 15 / 0.1), rgb(0 0 0 / 0.38));
|
|
222
439
|
}
|
|
223
440
|
|
|
224
441
|
/* Base canônica do consumidor — vem DAQUI, não do entry de cada app. Tailwind v4
|
|
@@ -261,7 +478,12 @@
|
|
|
261
478
|
}
|
|
262
479
|
:root:is(:hover, :focus, :focus-within),
|
|
263
480
|
:root *:is(:hover, :focus, :focus-within) {
|
|
264
|
-
scrollbar-color: color-mix(
|
|
481
|
+
scrollbar-color: color-mix(
|
|
482
|
+
in srgb,
|
|
483
|
+
var(--muted-foreground) 35%,
|
|
484
|
+
transparent
|
|
485
|
+
)
|
|
486
|
+
transparent;
|
|
265
487
|
}
|
|
266
488
|
:root::-webkit-scrollbar,
|
|
267
489
|
:root *::-webkit-scrollbar {
|
|
@@ -281,7 +503,11 @@
|
|
|
281
503
|
}
|
|
282
504
|
:root:is(:hover, :focus, :focus-within)::-webkit-scrollbar-thumb,
|
|
283
505
|
:root *:is(:hover, :focus, :focus-within)::-webkit-scrollbar-thumb {
|
|
284
|
-
background-color: color-mix(
|
|
506
|
+
background-color: color-mix(
|
|
507
|
+
in srgb,
|
|
508
|
+
var(--muted-foreground) 35%,
|
|
509
|
+
transparent
|
|
510
|
+
);
|
|
285
511
|
}
|
|
286
512
|
}
|
|
287
513
|
|
|
@@ -311,19 +537,28 @@
|
|
|
311
537
|
* O guard [class~='not-prose'] espelha o escopo do plugin typography: sem ele a
|
|
312
538
|
* regra custom vaza pra dentro do not-prose (o CodeBlock ganhava uma SEGUNDA
|
|
313
539
|
* borda no <pre>, colada na do contêiner — a "borda duplicada"). */
|
|
314
|
-
.prose
|
|
540
|
+
.prose
|
|
541
|
+
:where(code):not(
|
|
542
|
+
:where(pre code, [class~="not-prose"], [class~="not-prose"] *)
|
|
543
|
+
) {
|
|
315
544
|
border-radius: calc(var(--radius) - 0.25rem);
|
|
316
545
|
background: var(--muted);
|
|
317
546
|
padding: 0.125rem 0.375rem;
|
|
318
547
|
font-weight: 400;
|
|
319
548
|
}
|
|
320
|
-
.prose
|
|
321
|
-
|
|
549
|
+
.prose
|
|
550
|
+
:where(code):not(
|
|
551
|
+
:where(pre code, [class~="not-prose"], [class~="not-prose"] *)
|
|
552
|
+
)::before,
|
|
553
|
+
.prose
|
|
554
|
+
:where(code):not(
|
|
555
|
+
:where(pre code, [class~="not-prose"], [class~="not-prose"] *)
|
|
556
|
+
)::after {
|
|
322
557
|
content: none;
|
|
323
558
|
}
|
|
324
559
|
|
|
325
560
|
/* Code block = superfície da casa (borda + bg muted) — só o <pre> CRU do prose. */
|
|
326
|
-
.prose :where(pre):not(:where([class~=
|
|
561
|
+
.prose :where(pre):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
|
|
327
562
|
border: 1px solid var(--border); /* px: hairline do bloco de código — 1 pixel físico, não escala. */
|
|
328
563
|
}
|
|
329
564
|
|
|
@@ -347,11 +582,15 @@
|
|
|
347
582
|
justify-content: center;
|
|
348
583
|
}
|
|
349
584
|
|
|
350
|
-
.toaster
|
|
585
|
+
.toaster
|
|
586
|
+
.opus-toast[data-sonner-toast]
|
|
587
|
+
.opus-toast-close[data-close-button]:focus-visible {
|
|
351
588
|
box-shadow: 0 0 0 0.125rem color-mix(in srgb, var(--ring) 50%, transparent);
|
|
352
589
|
}
|
|
353
590
|
|
|
354
|
-
.toaster
|
|
591
|
+
.toaster
|
|
592
|
+
.opus-toast[data-sonner-toast]
|
|
593
|
+
.opus-toast-close[data-close-button][data-disabled="true"] {
|
|
355
594
|
pointer-events: none;
|
|
356
595
|
opacity: 0.5;
|
|
357
596
|
}
|
|
@@ -367,15 +606,23 @@
|
|
|
367
606
|
background: var(--popover);
|
|
368
607
|
color: var(--muted-foreground);
|
|
369
608
|
outline: none;
|
|
370
|
-
transition:
|
|
609
|
+
transition:
|
|
610
|
+
color 150ms,
|
|
611
|
+
background-color 150ms,
|
|
612
|
+
box-shadow 150ms;
|
|
371
613
|
}
|
|
372
614
|
|
|
373
|
-
.toaster
|
|
615
|
+
.toaster
|
|
616
|
+
.opus-toast[data-sonner-toast]
|
|
617
|
+
.opus-toast-close[data-close-button]:hover {
|
|
374
618
|
background: var(--accent);
|
|
375
619
|
color: var(--accent-foreground);
|
|
376
620
|
}
|
|
377
621
|
|
|
378
|
-
.toaster
|
|
622
|
+
.toaster
|
|
623
|
+
.opus-toast[data-sonner-toast]
|
|
624
|
+
.opus-toast-close[data-close-button]
|
|
625
|
+
svg {
|
|
379
626
|
width: 1rem;
|
|
380
627
|
height: 1rem;
|
|
381
628
|
}
|