@fabio.caffarello/react-design-system 4.3.0 → 4.5.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/README.md CHANGED
@@ -120,7 +120,8 @@ Consumers can import from:
120
120
  - `@fabio.caffarello/react-design-system/server` — the opt-in server entry (issue #150). Re-exports only the components whose render tree is safe to evaluate inside a React Server Component: presentational primitives (`Text`, `Skeleton`, `Spinner`, `Progress`, `Chip`, `ErrorMessage`, `Info`), layout (`Container`, `Stack`), and structural / informational components (`Breadcrumb`, `Timeline`, `AutocompleteOption`, `DialogHeader`, `DialogFooter`, `DrawerHeader`, `DrawerFooter`, `HeaderActions`, `HeaderNavigation`, `MenuSeparator`, `NavbarSeparator`, `TableCell`). The bundle carries NO `"use client"` directive, so importing from it in a Server Component does NOT cross a client boundary — useful for SEO-critical / first-paint-critical routes where the shell shouldn't ship JS to the client.
121
121
  - `@fabio.caffarello/react-design-system/hooks` — the granular public-hooks entry (issue #203). Re-exports only the public hooks (today: `useScrollSpy`) as a tiny standalone client bundle (<1KB) with every dependency external. Use it when a route's client component needs a hook but nothing else from RDS: importing a hook from the main entry pulls the whole pre-bundled barrel into the route's client JS (+277KB minified measured on a Next 16 route), because the single-file `"use client"` bundle is opaque to the consumer bundler's tree-shaking. The same hooks remain available from the main entry for back-compat.
122
122
  - `@fabio.caffarello/react-design-system/granular` — the granular client entry (issue #208). The SAME public surface as the default entry, emitted as a `preserveModules` tree (one module per source file, `"use client"` on every module, all deps external). Use it for leaf component imports on size-critical routes: importing one component from the default entry pulls the whole pre-bundled barrel (+264KB minified measured for `Accordion` on a Next 16 route); the same import from `./granular` ships only that component's module graph (~36KB, 13% of the barrel payload — gated in CI). Keep app-wide setup (`AppProvider`/providers) on the default entry: the single bundle preserves provider initialization order by construction.
123
- - `@fabio.caffarello/react-design-system/styles` — the bundled CSS. Same stylesheet regardless of which JS entry you import.
123
+ - `@fabio.caffarello/react-design-system/styles` — the bundled, Tailwind-**compiled** CSS (resolved tokens + every component class). Same stylesheet regardless of which JS entry you import. For consumers who do **not** run Tailwind: import it and the classes already exist.
124
+ - `@fabio.caffarello/react-design-system/theme` (+ `./theme.css`) — the **raw, uncompiled** `@theme` token source plus the light/dark overrides (issue #234). For consumers who run **Tailwind v4 themselves**: import it and your own Tailwind generates the token utilities (`text-fg-brand`, `bg-surface-brand-strong`, `ring-line-focus`, …) natively, theme-aware, from one source of truth — no re-export bridge. See "Extending the tokens with your own Tailwind" below.
124
125
 
125
126
  The JS entries can be mixed in one Server Component — `import { Text } from "…/server"; import { Button } from "…"` is the normal pattern. The server entry is purely additive; consumers who never use it see no behavioural change.
126
127
 
@@ -145,6 +146,19 @@ export default function Profile() {
145
146
 
146
147
  Sub-entries (`/primitives`, `/components`, `/tokens`, `/providers`) were removed in Phase 13d — they had been silently broken for external consumers since v1.0.0 because cross-chunk references to `cva` and other shared utilities failed at runtime. A single main entry collapses that class of bug structurally; tree-shaking still works at the named-export level via any modern bundler. The `./server`, `./hooks`, and `./granular` entries sidestep the same regression by each being their OWN independent Vite build with all third-party deps externalised — no chunks are shared between entries, and `./granular`'s preserveModules layout has no extracted chunks at all (source modules map 1:1 to output files).
147
148
 
149
+ ## Extending the tokens with your own Tailwind
150
+
151
+ If your app **also** runs Tailwind v4, you can let your own Tailwind generate the design system's token utilities — so `text-fg-brand`, `bg-surface-brand-strong`, `ring-line-focus`, `text-fg-brand/80`, etc. are first-class in your project, theme-aware, with no copied values. Import the **compiled** stylesheet for RDS's own component classes and the **raw** token source for the `@theme`:
152
+
153
+ ```css
154
+ /* your globals.css */
155
+ @import "tailwindcss";
156
+ @import "@fabio.caffarello/react-design-system/styles" layer(rds); /* compiled RDS component classes */
157
+ @import "@fabio.caffarello/react-design-system/theme"; /* raw @theme: your Tailwind builds the token utilities */
158
+ ```
159
+
160
+ `./theme` ships the `@theme` blocks **uncompiled** (not the resolved `@layer theme` output), so your Tailwind reads them and emits the utilities referencing `var(--color-…)` — the light/dark selector overrides in the same file then flip the resolved color at runtime. Do **not** wrap the tokens in a `@theme inline { … }` bridge: `inline` resolves the value at build time and breaks theming (and a self-referential bridge collapses to `transparent` — the bug that motivated this export). Batteries-included consumers who don't run Tailwind keep importing only `./styles` and need none of this.
161
+
148
162
  ## Working with Claude Code
149
163
 
150
164
  - `.claude/rules/` carries the enforced rules (components, testing, tokens).
@@ -3,66 +3,69 @@ var S = Object.defineProperty, B = Object.defineProperties;
3
3
  var D = Object.getOwnPropertyDescriptors;
4
4
  var i = Object.getOwnPropertySymbols;
5
5
  var p = Object.prototype.hasOwnProperty, b = Object.prototype.propertyIsEnumerable;
6
- var g = (r, a, e) => a in r ? S(r, a, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[a] = e, f = (r, a) => {
7
- for (var e in a || (a = {}))
8
- p.call(a, e) && g(r, e, a[e]);
6
+ var g = (e, r, a) => r in e ? S(e, r, { enumerable: !0, configurable: !0, writable: !0, value: a }) : e[r] = a, f = (e, r) => {
7
+ for (var a in r || (r = {}))
8
+ p.call(r, a) && g(e, a, r[a]);
9
9
  if (i)
10
- for (var e of i(a))
11
- b.call(a, e) && g(r, e, a[e]);
12
- return r;
13
- }, u = (r, a) => B(r, D(a));
14
- var h = (r, a) => {
15
- var e = {};
16
- for (var s in r)
17
- p.call(r, s) && a.indexOf(s) < 0 && (e[s] = r[s]);
18
- if (r != null && i)
19
- for (var s of i(r))
20
- a.indexOf(s) < 0 && b.call(r, s) && (e[s] = r[s]);
10
+ for (var a of i(r))
11
+ b.call(r, a) && g(e, a, r[a]);
21
12
  return e;
13
+ }, u = (e, r) => B(e, D(r));
14
+ var x = (e, r) => {
15
+ var a = {};
16
+ for (var n in e)
17
+ p.call(e, n) && r.indexOf(n) < 0 && (a[n] = e[n]);
18
+ if (e != null && i)
19
+ for (var n of i(e))
20
+ r.indexOf(n) < 0 && b.call(e, n) && (a[n] = e[n]);
21
+ return a;
22
22
  };
23
- import { jsxs as x, jsx as o, Fragment as j } from "react/jsx-runtime";
23
+ import { jsxs as h, jsx as d, Fragment as j } from "react/jsx-runtime";
24
24
  import { memo as C, forwardRef as R } from "react";
25
25
  import { getRadiusClass as T } from "../../tokens/radius.js";
26
- import { getSpacingClass as t } from "../../tokens/spacing.js";
27
- import { getTypographyWeight as y, getTypographySize as d } from "../../tokens/typography.js";
28
- import { cn as n } from "../../utils/cn.js";
26
+ import { getSpacingClass as s } from "../../tokens/spacing.js";
27
+ import { getTypographyWeight as y, getTypographySize as o } from "../../tokens/typography.js";
28
+ import { cn as t } from "../../utils/cn.js";
29
29
  import { cva as V } from "../../utils/cva.js";
30
30
  const _ = V(
31
- n("inline-flex", "items-center", "border", T("md")),
31
+ t("inline-flex", "items-center", "border", T("md")),
32
32
  {
33
33
  variants: {
34
34
  tone: {
35
- neutral: n(
35
+ neutral: t(
36
36
  "bg-surface-muted",
37
37
  "text-fg-primary",
38
38
  "border-line-default"
39
39
  ),
40
- success: n("bg-success-bg", "text-success-dark", "border-success"),
41
- warning: n("bg-warning-bg", "text-warning-dark", "border-warning"),
42
- error: n("bg-error-bg", "text-error-dark", "border-error"),
43
- info: n("bg-info-bg", "text-info-dark", "border-info"),
44
- primary: n(
40
+ success: t("bg-success-bg", "text-success-dark", "border-success"),
41
+ warning: t("bg-warning-bg", "text-warning-dark", "border-warning"),
42
+ error: t("bg-error-bg", "text-error-dark", "border-error"),
43
+ info: t("bg-info-bg", "text-info-dark", "border-info"),
44
+ primary: t(
45
45
  "bg-surface-brand-subtle",
46
46
  "text-fg-brand-emphasis",
47
47
  "border-line-brand"
48
48
  ),
49
- secondary: n(
49
+ secondary: t(
50
50
  "bg-surface-secondary-subtle",
51
51
  "text-fg-brand-secondary-emphasis",
52
52
  "border-line-secondary"
53
- )
53
+ ),
54
+ // Categorical data-viz tone — fuchsia soft-wash, sibling to the
55
+ // chart palette. Not a status; distinct from secondary (brand violet).
56
+ dataviz: t("bg-dataviz-bg", "text-dataviz-dark", "border-dataviz")
54
57
  },
55
58
  size: {
56
- sm: n(
57
- t("1.5", "px"),
58
- t("0.5", "py"),
59
- t("0.5", "gap"),
59
+ sm: t(
60
+ s("1.5", "px"),
61
+ s("0.5", "py"),
62
+ s("0.5", "gap"),
60
63
  "[&_svg]:size-3"
61
64
  ),
62
- md: n(
63
- t("sm", "px"),
64
- t("0.5", "py"),
65
- t("xs", "gap"),
65
+ md: t(
66
+ s("sm", "px"),
67
+ s("0.5", "py"),
68
+ s("xs", "gap"),
66
69
  "[&_svg]:size-3.5"
67
70
  )
68
71
  }
@@ -70,15 +73,15 @@ const _ = V(
70
73
  defaultVariants: { tone: "neutral", size: "md" }
71
74
  }
72
75
  ), F = C(
73
- R(function(W, v) {
76
+ R(function(W, k) {
74
77
  var m = W, {
75
- label: a,
76
- source: e,
77
- tone: s = "neutral",
78
+ label: r,
79
+ source: a,
80
+ tone: n = "neutral",
78
81
  size: l = "md",
79
82
  icon: c,
80
- className: N = ""
81
- } = m, k = h(m, [
83
+ className: v = ""
84
+ } = m, z = x(m, [
82
85
  "label",
83
86
  "source",
84
87
  "tone",
@@ -86,15 +89,15 @@ const _ = V(
86
89
  "icon",
87
90
  "className"
88
91
  ]);
89
- const w = e != null && e !== "", z = l === "sm" ? "caption" : "bodySmall";
90
- return /* @__PURE__ */ x(
92
+ const N = a != null && a !== "", w = l === "sm" ? "caption" : "bodySmall";
93
+ return /* @__PURE__ */ h(
91
94
  "span",
92
95
  u(f({
93
- ref: v,
94
- className: n(_({ tone: s, size: l }), N)
95
- }, k), {
96
+ ref: k,
97
+ className: t(_({ tone: n, size: l }), v)
98
+ }, z), {
96
99
  children: [
97
- c ? /* @__PURE__ */ o(
100
+ c ? /* @__PURE__ */ d(
98
101
  "span",
99
102
  {
100
103
  className: "inline-flex shrink-0 items-center",
@@ -102,26 +105,26 @@ const _ = V(
102
105
  children: c
103
106
  }
104
107
  ) : null,
105
- /* @__PURE__ */ o(
108
+ /* @__PURE__ */ d(
106
109
  "span",
107
110
  {
108
- className: n(
109
- d(z),
111
+ className: t(
112
+ o(w),
110
113
  y("label")
111
114
  ),
112
- children: a
115
+ children: r
113
116
  }
114
117
  ),
115
- w ? /* @__PURE__ */ x(j, { children: [
116
- /* @__PURE__ */ o("span", { "aria-hidden": "true", className: d("caption"), children: "·" }),
117
- /* @__PURE__ */ o(
118
+ N ? /* @__PURE__ */ h(j, { children: [
119
+ /* @__PURE__ */ d("span", { "aria-hidden": "true", className: o("caption"), children: "·" }),
120
+ /* @__PURE__ */ d(
118
121
  "span",
119
122
  {
120
- className: n(
121
- d("caption"),
123
+ className: t(
124
+ o("caption"),
122
125
  y("caption")
123
126
  ),
124
- children: e
127
+ children: a
125
128
  }
126
129
  )
127
130
  ] }) : null
@@ -1 +1 @@
1
- {"version":3,"file":"DataBadge.js","sources":["../../../../../src/ui/primitives/DataBadge/DataBadge.tsx"],"sourcesContent":["import { memo, forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { getRadiusClass } from \"../../tokens/radius\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport {\n getTypographySize,\n getTypographyWeight,\n} from \"../../tokens/typography\";\nimport { cn, cva } from \"../../utils\";\n\n/**\n * Semantic tone for a {@link DataBadge}. Mirrors the `Badge` vocabulary\n * (role, not tone) so the soft-wash color treatment is shared and already\n * AA-verified. Map a consumer's tone names onto these roles:\n * `default → neutral`, `destructive → error`, `brand → primary`,\n * `accent → info` (or `secondary`).\n */\nexport type DataBadgeTone =\n | \"neutral\"\n | \"success\"\n | \"warning\"\n | \"error\"\n | \"info\"\n | \"primary\"\n | \"secondary\";\n\nexport type DataBadgeSize = \"sm\" | \"md\";\n\nexport interface DataBadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Primary datum — the value the badge is about (e.g. \"L2\", \"Aprovada\"). */\n label: ReactNode;\n /**\n * Provenance of the datum, rendered as a lesser-emphasis sub-label after\n * the label (e.g. \"Câmara\", \"Portal Transparência\"). Omitted when absent.\n */\n source?: ReactNode;\n /** Semantic tone (role-based color). Defaults to `neutral`. */\n tone?: DataBadgeTone;\n /** Optional decorative leading icon (rendered `aria-hidden`). */\n icon?: ReactNode;\n /** Size scale. Defaults to `md`. */\n size?: DataBadgeSize;\n}\n\n// Tone → soft-wash classes, mirroring Badge's already-AA-verified scale.\nconst dataBadgeVariants = cva(\n cn(\"inline-flex\", \"items-center\", \"border\", getRadiusClass(\"md\")),\n {\n variants: {\n tone: {\n neutral: cn(\n \"bg-surface-muted\",\n \"text-fg-primary\",\n \"border-line-default\",\n ),\n success: cn(\"bg-success-bg\", \"text-success-dark\", \"border-success\"),\n warning: cn(\"bg-warning-bg\", \"text-warning-dark\", \"border-warning\"),\n error: cn(\"bg-error-bg\", \"text-error-dark\", \"border-error\"),\n info: cn(\"bg-info-bg\", \"text-info-dark\", \"border-info\"),\n primary: cn(\n \"bg-surface-brand-subtle\",\n \"text-fg-brand-emphasis\",\n \"border-line-brand\",\n ),\n secondary: cn(\n \"bg-surface-secondary-subtle\",\n \"text-fg-brand-secondary-emphasis\",\n \"border-line-secondary\",\n ),\n },\n size: {\n sm: cn(\n getSpacingClass(\"1.5\", \"px\"),\n getSpacingClass(\"0.5\", \"py\"),\n getSpacingClass(\"0.5\", \"gap\"),\n \"[&_svg]:size-3\",\n ),\n md: cn(\n getSpacingClass(\"sm\", \"px\"),\n getSpacingClass(\"0.5\", \"py\"),\n getSpacingClass(\"xs\", \"gap\"),\n \"[&_svg]:size-3.5\",\n ),\n },\n },\n defaultVariants: { tone: \"neutral\", size: \"md\" },\n },\n);\n\n/**\n * DataBadge\n *\n * An inline metadata chip: a primary `label`, an optional lesser-emphasis\n * `source` sub-label (the datum's provenance), a semantic `tone`, and an\n * optional decorative `icon`. Built for transparency/data UIs where a value\n * must travel with where it came from (\"L2 · Portal Transparência\").\n *\n * Why a separate primitive and not `Badge`: `Badge` is a single-string\n * status label; `DataBadge` carries a value + its source as a structured\n * pair. The `source` is the differentiator — it has no slot in `Badge` /\n * `Chip` / `Info`.\n *\n * Accessibility: the visible text (label, then source) IS the accessible\n * name — the separator and any `icon` are `aria-hidden`. Hierarchy between\n * label and source is conveyed by size + weight, never by dropping the\n * source below its tone's AA-safe text color. The root is a plain inline\n * `<span>` with no live-region role (metadata is static, not announced);\n * pass `role` / `aria-label` via props if a grouping role is wanted.\n *\n * Server-safe: no hooks, no client APIs, no DOM handlers of its own — ships\n * from the `./server` entry.\n *\n * @example\n * ```tsx\n * <DataBadge label=\"L2\" source=\"Portal Transparência\" tone=\"warning\" />\n * <DataBadge label=\"Aprovada\" tone=\"success\" />\n * ```\n */\nconst DataBadge = memo(\n forwardRef<HTMLSpanElement, DataBadgeProps>(function DataBadge(\n {\n label,\n source,\n tone = \"neutral\",\n size = \"md\",\n icon,\n className = \"\",\n ...rest\n },\n ref,\n ) {\n const hasSource = source !== undefined && source !== null && source !== \"\";\n // Label is the larger/heavier tier; source is one size smaller and a\n // lighter weight. Both keep the tone's AA-safe text color — hierarchy\n // comes from size + weight, not from reducing contrast.\n const labelSize = size === \"sm\" ? \"caption\" : \"bodySmall\";\n\n return (\n <span\n ref={ref}\n className={cn(dataBadgeVariants({ tone, size }), className)}\n {...rest}\n >\n {icon ? (\n <span\n className=\"inline-flex shrink-0 items-center\"\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n ) : null}\n <span\n className={cn(\n getTypographySize(labelSize),\n getTypographyWeight(\"label\"),\n )}\n >\n {label}\n </span>\n {hasSource ? (\n <>\n <span aria-hidden=\"true\" className={getTypographySize(\"caption\")}>\n ·\n </span>\n <span\n className={cn(\n getTypographySize(\"caption\"),\n getTypographyWeight(\"caption\"),\n )}\n >\n {source}\n </span>\n </>\n ) : null}\n </span>\n );\n }),\n);\n\nDataBadge.displayName = \"DataBadge\";\n\nexport default DataBadge;\n"],"names":["dataBadgeVariants","cva","cn","getRadiusClass","getSpacingClass","DataBadge","memo","forwardRef","_a","ref","_b","label","source","tone","size","icon","className","rest","__objRest","hasSource","labelSize","jsxs","__spreadProps","__spreadValues","jsx","getTypographySize","getTypographyWeight","Fragment"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6CA,MAAMA,IAAoBC;AAAA,EACxBC,EAAG,eAAe,gBAAgB,UAAUC,EAAe,IAAI,CAAC;AAAA,EAChE;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,SAASD;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA,QAEF,SAASA,EAAG,iBAAiB,qBAAqB,gBAAgB;AAAA,QAClE,SAASA,EAAG,iBAAiB,qBAAqB,gBAAgB;AAAA,QAClE,OAAOA,EAAG,eAAe,mBAAmB,cAAc;AAAA,QAC1D,MAAMA,EAAG,cAAc,kBAAkB,aAAa;AAAA,QACtD,SAASA;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA,QAEF,WAAWA;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA,MACF;AAAA,MAEF,MAAM;AAAA,QACJ,IAAIA;AAAA,UACFE,EAAgB,OAAO,IAAI;AAAA,UAC3BA,EAAgB,OAAO,IAAI;AAAA,UAC3BA,EAAgB,OAAO,KAAK;AAAA,UAC5B;AAAA,QAAA;AAAA,QAEF,IAAIF;AAAA,UACFE,EAAgB,MAAM,IAAI;AAAA,UAC1BA,EAAgB,OAAO,IAAI;AAAA,UAC3BA,EAAgB,MAAM,KAAK;AAAA,UAC3B;AAAA,QAAA;AAAA,MACF;AAAA,IACF;AAAA,IAEF,iBAAiB,EAAE,MAAM,WAAW,MAAM,KAAA;AAAA,EAAK;AAEnD,GA+BMC,IAAYC;AAAA,EAChBC,EAA4C,SAC1CC,GASAC,GACA;AAVA,QAAAC,IAAAF,GACE;AAAA,aAAAG;AAAA,MACA,QAAAC;AAAA,MACA,MAAAC,IAAO;AAAA,MACP,MAAAC,IAAO;AAAA,MACP,MAAAC;AAAA,MACA,WAAAC,IAAY;AAAA,QANdN,GAOKO,IAAAC,EAPLR,GAOK;AAAA,MANH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAKF,UAAMS,IAAoCP,KAAW,QAAQA,MAAW,IAIlEQ,IAAYN,MAAS,OAAO,YAAY;AAE9C,WACE,gBAAAO;AAAA,MAAC;AAAA,MAAAC,EAAAC,EAAA;AAAA,QACC,KAAAd;AAAA,QACA,WAAWP,EAAGF,EAAkB,EAAE,MAAAa,GAAM,MAAAC,EAAA,CAAM,GAAGE,CAAS;AAAA,SACtDC,IAHL;AAAA,QAKE,UAAA;AAAA,UAAAF,IACC,gBAAAS;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAY;AAAA,cAEX,UAAAT;AAAA,YAAA;AAAA,UAAA,IAED;AAAA,UACJ,gBAAAS;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWtB;AAAA,gBACTuB,EAAkBL,CAAS;AAAA,gBAC3BM,EAAoB,OAAO;AAAA,cAAA;AAAA,cAG5B,UAAAf;AAAA,YAAA;AAAA,UAAA;AAAA,UAEFQ,IACC,gBAAAE,EAAAM,GAAA,EACE,UAAA;AAAA,YAAA,gBAAAH,EAAC,UAAK,eAAY,QAAO,WAAWC,EAAkB,SAAS,GAAG,UAAA,KAElE;AAAA,YACA,gBAAAD;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,WAAWtB;AAAA,kBACTuB,EAAkB,SAAS;AAAA,kBAC3BC,EAAoB,SAAS;AAAA,gBAAA;AAAA,gBAG9B,UAAAd;AAAA,cAAA;AAAA,YAAA;AAAA,UACH,EAAA,CACF,IACE;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV,CAAC;AACH;AAEAP,EAAU,cAAc;"}
1
+ {"version":3,"file":"DataBadge.js","sources":["../../../../../src/ui/primitives/DataBadge/DataBadge.tsx"],"sourcesContent":["import { memo, forwardRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { getRadiusClass } from \"../../tokens/radius\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport {\n getTypographySize,\n getTypographyWeight,\n} from \"../../tokens/typography\";\nimport { cn, cva } from \"../../utils\";\n\n/**\n * Semantic tone for a {@link DataBadge}. The status/brand members mirror the\n * `Badge` vocabulary (role, not tone) so the soft-wash treatment is shared\n * and already AA-verified; `dataviz` adds a CATEGORICAL member (a\n * reddish-purple wash for \"category / analytical\" data, the badge-facing\n * counterpart to the chart palette) that is intentionally NOT a status.\n * Map a consumer's tone names onto these roles: `default → neutral`,\n * `destructive → error`, `brand → primary`, `accent → dataviz` (the\n * data-viz purple — RDS `accent` is cyan, so the category tone is `dataviz`).\n */\nexport type DataBadgeTone =\n | \"neutral\"\n | \"success\"\n | \"warning\"\n | \"error\"\n | \"info\"\n | \"primary\"\n | \"secondary\"\n | \"dataviz\";\n\nexport type DataBadgeSize = \"sm\" | \"md\";\n\nexport interface DataBadgeProps extends HTMLAttributes<HTMLSpanElement> {\n /** Primary datum — the value the badge is about (e.g. \"L2\", \"Aprovada\"). */\n label: ReactNode;\n /**\n * Provenance of the datum, rendered as a lesser-emphasis sub-label after\n * the label (e.g. \"Câmara\", \"Portal Transparência\"). Omitted when absent.\n */\n source?: ReactNode;\n /** Semantic tone (role-based color). Defaults to `neutral`. */\n tone?: DataBadgeTone;\n /** Optional decorative leading icon (rendered `aria-hidden`). */\n icon?: ReactNode;\n /** Size scale. Defaults to `md`. */\n size?: DataBadgeSize;\n}\n\n// Tone → soft-wash classes, mirroring Badge's already-AA-verified scale.\nconst dataBadgeVariants = cva(\n cn(\"inline-flex\", \"items-center\", \"border\", getRadiusClass(\"md\")),\n {\n variants: {\n tone: {\n neutral: cn(\n \"bg-surface-muted\",\n \"text-fg-primary\",\n \"border-line-default\",\n ),\n success: cn(\"bg-success-bg\", \"text-success-dark\", \"border-success\"),\n warning: cn(\"bg-warning-bg\", \"text-warning-dark\", \"border-warning\"),\n error: cn(\"bg-error-bg\", \"text-error-dark\", \"border-error\"),\n info: cn(\"bg-info-bg\", \"text-info-dark\", \"border-info\"),\n primary: cn(\n \"bg-surface-brand-subtle\",\n \"text-fg-brand-emphasis\",\n \"border-line-brand\",\n ),\n secondary: cn(\n \"bg-surface-secondary-subtle\",\n \"text-fg-brand-secondary-emphasis\",\n \"border-line-secondary\",\n ),\n // Categorical data-viz tone — fuchsia soft-wash, sibling to the\n // chart palette. Not a status; distinct from secondary (brand violet).\n dataviz: cn(\"bg-dataviz-bg\", \"text-dataviz-dark\", \"border-dataviz\"),\n },\n size: {\n sm: cn(\n getSpacingClass(\"1.5\", \"px\"),\n getSpacingClass(\"0.5\", \"py\"),\n getSpacingClass(\"0.5\", \"gap\"),\n \"[&_svg]:size-3\",\n ),\n md: cn(\n getSpacingClass(\"sm\", \"px\"),\n getSpacingClass(\"0.5\", \"py\"),\n getSpacingClass(\"xs\", \"gap\"),\n \"[&_svg]:size-3.5\",\n ),\n },\n },\n defaultVariants: { tone: \"neutral\", size: \"md\" },\n },\n);\n\n/**\n * DataBadge\n *\n * An inline metadata chip: a primary `label`, an optional lesser-emphasis\n * `source` sub-label (the datum's provenance), a semantic `tone`, and an\n * optional decorative `icon`. Built for transparency/data UIs where a value\n * must travel with where it came from (\"L2 · Portal Transparência\").\n *\n * Why a separate primitive and not `Badge`: `Badge` is a single-string\n * status label; `DataBadge` carries a value + its source as a structured\n * pair. The `source` is the differentiator — it has no slot in `Badge` /\n * `Chip` / `Info`.\n *\n * Accessibility: the visible text (label, then source) IS the accessible\n * name — the separator and any `icon` are `aria-hidden`. Hierarchy between\n * label and source is conveyed by size + weight, never by dropping the\n * source below its tone's AA-safe text color. The root is a plain inline\n * `<span>` with no live-region role (metadata is static, not announced);\n * pass `role` / `aria-label` via props if a grouping role is wanted.\n *\n * Server-safe: no hooks, no client APIs, no DOM handlers of its own — ships\n * from the `./server` entry.\n *\n * @example\n * ```tsx\n * <DataBadge label=\"L2\" source=\"Portal Transparência\" tone=\"warning\" />\n * <DataBadge label=\"Aprovada\" tone=\"success\" />\n * ```\n */\nconst DataBadge = memo(\n forwardRef<HTMLSpanElement, DataBadgeProps>(function DataBadge(\n {\n label,\n source,\n tone = \"neutral\",\n size = \"md\",\n icon,\n className = \"\",\n ...rest\n },\n ref,\n ) {\n const hasSource = source !== undefined && source !== null && source !== \"\";\n // Label is the larger/heavier tier; source is one size smaller and a\n // lighter weight. Both keep the tone's AA-safe text color — hierarchy\n // comes from size + weight, not from reducing contrast.\n const labelSize = size === \"sm\" ? \"caption\" : \"bodySmall\";\n\n return (\n <span\n ref={ref}\n className={cn(dataBadgeVariants({ tone, size }), className)}\n {...rest}\n >\n {icon ? (\n <span\n className=\"inline-flex shrink-0 items-center\"\n aria-hidden=\"true\"\n >\n {icon}\n </span>\n ) : null}\n <span\n className={cn(\n getTypographySize(labelSize),\n getTypographyWeight(\"label\"),\n )}\n >\n {label}\n </span>\n {hasSource ? (\n <>\n <span aria-hidden=\"true\" className={getTypographySize(\"caption\")}>\n ·\n </span>\n <span\n className={cn(\n getTypographySize(\"caption\"),\n getTypographyWeight(\"caption\"),\n )}\n >\n {source}\n </span>\n </>\n ) : null}\n </span>\n );\n }),\n);\n\nDataBadge.displayName = \"DataBadge\";\n\nexport default DataBadge;\n"],"names":["dataBadgeVariants","cva","cn","getRadiusClass","getSpacingClass","DataBadge","memo","forwardRef","_a","ref","_b","label","source","tone","size","icon","className","rest","__objRest","hasSource","labelSize","jsxs","__spreadProps","__spreadValues","jsx","getTypographySize","getTypographyWeight","Fragment"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,MAAMA,IAAoBC;AAAA,EACxBC,EAAG,eAAe,gBAAgB,UAAUC,EAAe,IAAI,CAAC;AAAA,EAChE;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA,QACJ,SAASD;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA,QAEF,SAASA,EAAG,iBAAiB,qBAAqB,gBAAgB;AAAA,QAClE,SAASA,EAAG,iBAAiB,qBAAqB,gBAAgB;AAAA,QAClE,OAAOA,EAAG,eAAe,mBAAmB,cAAc;AAAA,QAC1D,MAAMA,EAAG,cAAc,kBAAkB,aAAa;AAAA,QACtD,SAASA;AAAA,UACP;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA,QAEF,WAAWA;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAAA;AAAA;AAAA,QAIF,SAASA,EAAG,iBAAiB,qBAAqB,gBAAgB;AAAA,MAAA;AAAA,MAEpE,MAAM;AAAA,QACJ,IAAIA;AAAA,UACFE,EAAgB,OAAO,IAAI;AAAA,UAC3BA,EAAgB,OAAO,IAAI;AAAA,UAC3BA,EAAgB,OAAO,KAAK;AAAA,UAC5B;AAAA,QAAA;AAAA,QAEF,IAAIF;AAAA,UACFE,EAAgB,MAAM,IAAI;AAAA,UAC1BA,EAAgB,OAAO,IAAI;AAAA,UAC3BA,EAAgB,MAAM,KAAK;AAAA,UAC3B;AAAA,QAAA;AAAA,MACF;AAAA,IACF;AAAA,IAEF,iBAAiB,EAAE,MAAM,WAAW,MAAM,KAAA;AAAA,EAAK;AAEnD,GA+BMC,IAAYC;AAAA,EAChBC,EAA4C,SAC1CC,GASAC,GACA;AAVA,QAAAC,IAAAF,GACE;AAAA,aAAAG;AAAA,MACA,QAAAC;AAAA,MACA,MAAAC,IAAO;AAAA,MACP,MAAAC,IAAO;AAAA,MACP,MAAAC;AAAA,MACA,WAAAC,IAAY;AAAA,QANdN,GAOKO,IAAAC,EAPLR,GAOK;AAAA,MANH;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAKF,UAAMS,IAAoCP,KAAW,QAAQA,MAAW,IAIlEQ,IAAYN,MAAS,OAAO,YAAY;AAE9C,WACE,gBAAAO;AAAA,MAAC;AAAA,MAAAC,EAAAC,EAAA;AAAA,QACC,KAAAd;AAAA,QACA,WAAWP,EAAGF,EAAkB,EAAE,MAAAa,GAAM,MAAAC,EAAA,CAAM,GAAGE,CAAS;AAAA,SACtDC,IAHL;AAAA,QAKE,UAAA;AAAA,UAAAF,IACC,gBAAAS;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAU;AAAA,cACV,eAAY;AAAA,cAEX,UAAAT;AAAA,YAAA;AAAA,UAAA,IAED;AAAA,UACJ,gBAAAS;AAAA,YAAC;AAAA,YAAA;AAAA,cACC,WAAWtB;AAAA,gBACTuB,EAAkBL,CAAS;AAAA,gBAC3BM,EAAoB,OAAO;AAAA,cAAA;AAAA,cAG5B,UAAAf;AAAA,YAAA;AAAA,UAAA;AAAA,UAEFQ,IACC,gBAAAE,EAAAM,GAAA,EACE,UAAA;AAAA,YAAA,gBAAAH,EAAC,UAAK,eAAY,QAAO,WAAWC,EAAkB,SAAS,GAAG,UAAA,KAElE;AAAA,YACA,gBAAAD;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,WAAWtB;AAAA,kBACTuB,EAAkB,SAAS;AAAA,kBAC3BC,EAAoB,SAAS;AAAA,gBAAA;AAAA,gBAG9B,UAAAd;AAAA,cAAA;AAAA,YAAA;AAAA,UACH,EAAA,CACF,IACE;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGV,CAAC;AACH;AAEAP,EAAU,cAAc;"}