@fabio.caffarello/react-design-system 3.9.0 → 3.11.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/dist/granular/index.js +369 -365
- package/dist/granular/index.js.map +1 -1
- package/dist/granular/ui/components/FilterChips/FilterChips.js +67 -0
- package/dist/granular/ui/components/FilterChips/FilterChips.js.map +1 -0
- package/dist/granular/ui/components/TabsAsLinks/TabsAsLinks.js +145 -0
- package/dist/granular/ui/components/TabsAsLinks/TabsAsLinks.js.map +1 -0
- package/dist/index.cjs +57 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1279 -1128
- package/dist/index.js.map +1 -1
- package/dist/react-design-system.css +1 -1
- package/dist/server/index.cjs +10 -10
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +662 -511
- package/dist/server/index.js.map +1 -1
- package/dist/ui/components/FilterChips/FilterChips.d.ts +83 -0
- package/dist/ui/components/FilterChips/index.d.ts +2 -0
- package/dist/ui/components/TabsAsLinks/TabsAsLinks.d.ts +80 -0
- package/dist/ui/components/TabsAsLinks/index.d.ts +2 -0
- package/dist/ui/components/index.d.ts +4 -0
- package/dist/ui/server.d.ts +4 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var p = Object.defineProperty, x = Object.defineProperties;
|
|
3
|
+
var g = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var n = Object.getOwnPropertySymbols;
|
|
5
|
+
var o = Object.prototype.hasOwnProperty, m = Object.prototype.propertyIsEnumerable;
|
|
6
|
+
var l = (e, r, a) => r in e ? p(e, r, { enumerable: !0, configurable: !0, writable: !0, value: a }) : e[r] = a, c = (e, r) => {
|
|
7
|
+
for (var a in r || (r = {}))
|
|
8
|
+
o.call(r, a) && l(e, a, r[a]);
|
|
9
|
+
if (n)
|
|
10
|
+
for (var a of n(r))
|
|
11
|
+
m.call(r, a) && l(e, a, r[a]);
|
|
12
|
+
return e;
|
|
13
|
+
}, u = (e, r) => x(e, g(r));
|
|
14
|
+
var f = (e, r) => {
|
|
15
|
+
var a = {};
|
|
16
|
+
for (var s in e)
|
|
17
|
+
o.call(e, s) && r.indexOf(s) < 0 && (a[s] = e[s]);
|
|
18
|
+
if (e != null && n)
|
|
19
|
+
for (var s of n(e))
|
|
20
|
+
r.indexOf(s) < 0 && m.call(e, s) && (a[s] = e[s]);
|
|
21
|
+
return a;
|
|
22
|
+
};
|
|
23
|
+
import { jsxs as h, jsx as C } from "react/jsx-runtime";
|
|
24
|
+
import { getSpacingClass as N } from "../../tokens/spacing.js";
|
|
25
|
+
import { cn as v } from "../../utils/cn.js";
|
|
26
|
+
function F(y) {
|
|
27
|
+
var i = y, {
|
|
28
|
+
label: e,
|
|
29
|
+
children: r,
|
|
30
|
+
wrap: a = !0,
|
|
31
|
+
className: s
|
|
32
|
+
} = i, t = f(i, [
|
|
33
|
+
"label",
|
|
34
|
+
"children",
|
|
35
|
+
"wrap",
|
|
36
|
+
"className"
|
|
37
|
+
]);
|
|
38
|
+
const d = !(t["aria-label"] != null || t["aria-labelledby"] != null) && typeof e == "string" && e !== "" ? e : void 0;
|
|
39
|
+
return /* @__PURE__ */ h(
|
|
40
|
+
"div",
|
|
41
|
+
u(c({
|
|
42
|
+
role: "group",
|
|
43
|
+
"aria-label": d,
|
|
44
|
+
className: v(
|
|
45
|
+
"flex items-center",
|
|
46
|
+
a ? "flex-wrap" : "flex-nowrap",
|
|
47
|
+
N("sm", "gap"),
|
|
48
|
+
s
|
|
49
|
+
)
|
|
50
|
+
}, t), {
|
|
51
|
+
children: [
|
|
52
|
+
e ? (
|
|
53
|
+
// shrink-0 keeps the label a stable leading unit: in the wrapping
|
|
54
|
+
// flex run it must not be squeezed or mid-word-wrapped when the
|
|
55
|
+
// chips overflow — it stays on one line and the chips wrap around it.
|
|
56
|
+
/* @__PURE__ */ C("span", { className: "shrink-0 text-fg-secondary text-sm", children: e })
|
|
57
|
+
) : null,
|
|
58
|
+
r
|
|
59
|
+
]
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
F as FilterChips,
|
|
65
|
+
F as default
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=FilterChips.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterChips.js","sources":["../../../../../src/ui/components/FilterChips/FilterChips.tsx"],"sourcesContent":["import type { HTMLAttributes, ReactNode } from \"react\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { cn } from \"../../utils\";\n\nexport interface FilterChipsProps extends HTMLAttributes<HTMLDivElement> {\n /**\n * Optional group label rendered as neutral text at the left of the\n * chips (e.g. \"Filtros\"). Deliberately NOT a `<legend>`/`<fieldset>`\n * pair — FilterChips groups navigation/selection chips, not form\n * controls, and fieldset semantics would imply a form that isn't\n * there. When `label` is a plain string it doubles as the group's\n * accessible name (see the aria-label contract in the component\n * JSDoc).\n */\n label?: ReactNode;\n /**\n * The chips. Typically `<Chip>` elements — including the\n * `<Chip asChild><Link/></Chip>` navigation form — but any inline\n * content composes.\n */\n children: ReactNode;\n /**\n * Whether chips wrap to new lines when they overflow the container\n * width. `true` (default) applies `flex-wrap` — the responsive\n * filter-bar behavior; `false` applies `flex-nowrap` and keeps\n * everything on one line (consumer owns overflow handling).\n * @default true\n */\n wrap?: boolean;\n}\n\n/**\n * `FilterChips` — groups `Chip`s into a labeled filter bar.\n *\n * The shell of every chip-based filter row: a `role=\"group\"` container\n * with an optional neutral text label at the left and a flex run of\n * chips that wraps responsively by default. Purely presentational — the\n * interactive identity (select, navigate, remove) lives in each `Chip`\n * (`onClick`/`onRemove`, or `asChild` with a consumer `<Link>`), never\n * in this wrapper.\n *\n * ### Accessible name contract\n *\n * The container carries `role=\"group\"` so assistive technology can\n * announce the chips as one named unit. The accessible name resolves in\n * this order:\n *\n * 1. An explicit `aria-label` OR `aria-labelledby` passed by the\n * consumer always wins — when either is present, no name is derived\n * from `label`, so the consumer's attribute is the only naming on the\n * element (no redundant `aria-label` is left alongside an\n * `aria-labelledby`).\n * 2. Otherwise, when `label` is a non-empty plain string, it is reused\n * as the group's `aria-label` automatically.\n * 3. When `label` is a non-string `ReactNode` (or absent), no\n * `aria-label` is derived — supply `aria-label`/`aria-labelledby`\n * yourself if the group needs a name AT users can identify it by.\n *\n * ### Server-safe\n *\n * Pure presentation — no hooks, no event handlers on the DOM. Ships in\n * the `./server` entry. Consumer-supplied chips may themselves be\n * client components (`<Chip onRemove>`); React's RSC boundary handles\n * that normally, and the zero-JS path (`<Chip asChild><Link/></Chip>`)\n * stays fully server-rendered.\n *\n * @example\n * ```tsx\n * // Navigation filter bar — server-rendered, zero-JS-friendly.\n * <FilterChips label=\"Filtros\">\n * <Chip asChild selected>\n * <Link href=\"?uf=SP\" aria-current=\"page\">UF: SP</Link>\n * </Chip>\n * <Chip asChild>\n * <Link href=\"?partido=PT\">Partido: PT</Link>\n * </Chip>\n * </FilterChips>\n *\n * // Single-line variant (consumer owns horizontal overflow).\n * <FilterChips label=\"Período\" wrap={false}>\n * <Chip>2024</Chip>\n * <Chip>2025</Chip>\n * </FilterChips>\n * ```\n */\nexport function FilterChips({\n label,\n children,\n wrap = true,\n className,\n ...props\n}: FilterChipsProps) {\n // The string label doubles as the group's accessible name — but only\n // when the consumer supplies no naming of their own. An explicit\n // `aria-label` OR `aria-labelledby` (both spread onto the root below)\n // takes precedence; deriving a name alongside `aria-labelledby` would\n // leave a redundant `aria-label` on the element, so suppress it here\n // rather than relying on ARIA name-computation precedence to hide it.\n const hasConsumerName =\n props[\"aria-label\"] != null || props[\"aria-labelledby\"] != null;\n const derivedAriaLabel =\n !hasConsumerName && typeof label === \"string\" && label !== \"\"\n ? label\n : undefined;\n\n return (\n <div\n role=\"group\"\n aria-label={derivedAriaLabel}\n className={cn(\n \"flex items-center\",\n wrap ? \"flex-wrap\" : \"flex-nowrap\",\n getSpacingClass(\"sm\", \"gap\"),\n className,\n )}\n {...props}\n >\n {label ? (\n // shrink-0 keeps the label a stable leading unit: in the wrapping\n // flex run it must not be squeezed or mid-word-wrapped when the\n // chips overflow — it stays on one line and the chips wrap around it.\n <span className=\"shrink-0 text-fg-secondary text-sm\">{label}</span>\n ) : null}\n {children}\n </div>\n );\n}\n\nexport default FilterChips;\n"],"names":["FilterChips","_a","_b","label","children","wrap","className","props","__objRest","derivedAriaLabel","jsxs","__spreadProps","__spreadValues","cn","getSpacingClass","jsx"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAqFO,SAASA,EAAYC,GAMP;AANO,MAAAC,IAAAD,GAC1B;AAAA,WAAAE;AAAA,IACA,UAAAC;AAAA,IACA,MAAAC,IAAO;AAAA,IACP,WAAAC;AAAA,MAJ0BJ,GAKvBK,IAAAC,EALuBN,GAKvB;AAAA,IAJH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAWA,QAAMO,IACJ,EAFAF,EAAM,YAAY,KAAK,QAAQA,EAAM,iBAAiB,KAAK,SAEvC,OAAOJ,KAAU,YAAYA,MAAU,KACvDA,IACA;AAEN,SACE,gBAAAO;AAAA,IAAC;AAAA,IAAAC,EAAAC,EAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAYH;AAAA,MACZ,WAAWI;AAAA,QACT;AAAA,QACAR,IAAO,cAAc;AAAA,QACrBS,EAAgB,MAAM,KAAK;AAAA,QAC3BR;AAAA,MAAA;AAAA,OAEEC,IATL;AAAA,MAWE,UAAA;AAAA,QAAAJ;AAAA;AAAA;AAAA;AAAA,UAIC,gBAAAY,EAAC,QAAA,EAAK,WAAU,sCAAsC,UAAAZ,EAAA,CAAM;AAAA,YAC1D;AAAA,QACHC;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGP;"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
var L = Object.defineProperty, j = Object.defineProperties;
|
|
3
|
+
var S = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var l = Object.getOwnPropertySymbols;
|
|
5
|
+
var b = Object.prototype.hasOwnProperty, p = Object.prototype.propertyIsEnumerable;
|
|
6
|
+
var u = (a, e, s) => e in a ? L(a, e, { enumerable: !0, configurable: !0, writable: !0, value: s }) : a[e] = s, m = (a, e) => {
|
|
7
|
+
for (var s in e || (e = {}))
|
|
8
|
+
b.call(e, s) && u(a, s, e[s]);
|
|
9
|
+
if (l)
|
|
10
|
+
for (var s of l(e))
|
|
11
|
+
p.call(e, s) && u(a, s, e[s]);
|
|
12
|
+
return a;
|
|
13
|
+
}, v = (a, e) => j(a, S(e));
|
|
14
|
+
var x = (a, e) => {
|
|
15
|
+
var s = {};
|
|
16
|
+
for (var r in a)
|
|
17
|
+
b.call(a, r) && e.indexOf(r) < 0 && (s[r] = a[r]);
|
|
18
|
+
if (a != null && l)
|
|
19
|
+
for (var r of l(a))
|
|
20
|
+
e.indexOf(r) < 0 && p.call(a, r) && (s[r] = a[r]);
|
|
21
|
+
return s;
|
|
22
|
+
};
|
|
23
|
+
import { jsx as o, jsxs as w } from "react/jsx-runtime";
|
|
24
|
+
import { forwardRef as E } from "react";
|
|
25
|
+
import { cn as n } from "../../utils/cn.js";
|
|
26
|
+
import { getSpacingClass as i } from "../../tokens/spacing.js";
|
|
27
|
+
import { getRadiusClass as h } from "../../tokens/radius.js";
|
|
28
|
+
import { cva as y } from "../../utils/cva.js";
|
|
29
|
+
import { getTypographySize as g } from "../../tokens/typography.js";
|
|
30
|
+
const P = y(n("flex items-center", "border-b"), {
|
|
31
|
+
variants: {
|
|
32
|
+
variant: {
|
|
33
|
+
default: n("border-line-default", i("base", "gap-x")),
|
|
34
|
+
sub: n("border-line-muted", i("sm", "gap-x"))
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
defaultVariants: {
|
|
38
|
+
variant: "default"
|
|
39
|
+
}
|
|
40
|
+
}), R = y(
|
|
41
|
+
n(
|
|
42
|
+
"relative -mb-px inline-flex items-center",
|
|
43
|
+
i("xs", "gap-x"),
|
|
44
|
+
"border-b-2 border-transparent",
|
|
45
|
+
"transition-colors",
|
|
46
|
+
"focus:outline-none",
|
|
47
|
+
"focus-visible:ring-2",
|
|
48
|
+
"focus-visible:ring-line-focus",
|
|
49
|
+
"focus-visible:ring-offset-2",
|
|
50
|
+
h("sm")
|
|
51
|
+
),
|
|
52
|
+
{
|
|
53
|
+
variants: {
|
|
54
|
+
variant: {
|
|
55
|
+
default: n(
|
|
56
|
+
i("sm", "px"),
|
|
57
|
+
i("sm", "py"),
|
|
58
|
+
g("body")
|
|
59
|
+
),
|
|
60
|
+
sub: n(
|
|
61
|
+
i("sm", "px"),
|
|
62
|
+
i("xs", "py"),
|
|
63
|
+
g("bodySmall")
|
|
64
|
+
)
|
|
65
|
+
},
|
|
66
|
+
active: {
|
|
67
|
+
true: n("border-line-brand", "text-fg-brand-emphasis", "font-medium"),
|
|
68
|
+
false: n(
|
|
69
|
+
"text-fg-secondary",
|
|
70
|
+
"hover:text-fg-primary",
|
|
71
|
+
"hover:border-line-muted"
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
compoundVariants: [
|
|
76
|
+
// Sub-tabs sit lower in the hierarchy: lighter resting foreground.
|
|
77
|
+
{
|
|
78
|
+
variant: "sub",
|
|
79
|
+
active: !1,
|
|
80
|
+
class: n("text-fg-tertiary", "hover:text-fg-secondary")
|
|
81
|
+
}
|
|
82
|
+
],
|
|
83
|
+
defaultVariants: {
|
|
84
|
+
variant: "default",
|
|
85
|
+
active: !1
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
), z = n(
|
|
89
|
+
"inline-flex items-center justify-center",
|
|
90
|
+
h("full"),
|
|
91
|
+
i("xs", "px"),
|
|
92
|
+
"bg-surface-muted text-fg-secondary text-xs"
|
|
93
|
+
), D = E(
|
|
94
|
+
function(O, T) {
|
|
95
|
+
var f = O, {
|
|
96
|
+
items: e,
|
|
97
|
+
variant: s = "default",
|
|
98
|
+
linkComponent: r,
|
|
99
|
+
className: N,
|
|
100
|
+
"aria-label": c,
|
|
101
|
+
"aria-labelledby": d
|
|
102
|
+
} = f, V = x(f, [
|
|
103
|
+
"items",
|
|
104
|
+
"variant",
|
|
105
|
+
"linkComponent",
|
|
106
|
+
"className",
|
|
107
|
+
"aria-label",
|
|
108
|
+
"aria-labelledby"
|
|
109
|
+
]);
|
|
110
|
+
typeof process != "undefined" && process.env.NODE_ENV !== "production" && !c && !d && console.warn(
|
|
111
|
+
'[TabsAsLinks] renders a <nav> landmark and should have an accessible name. Pass `aria-label` (e.g. "Painel") or `aria-labelledby` — multiple unnamed navs on a page are ambiguous to screen readers.'
|
|
112
|
+
);
|
|
113
|
+
const k = r != null ? r : "a";
|
|
114
|
+
return /* @__PURE__ */ o(
|
|
115
|
+
"nav",
|
|
116
|
+
v(m({
|
|
117
|
+
ref: T,
|
|
118
|
+
className: n(P({ variant: s }), N),
|
|
119
|
+
"aria-label": c,
|
|
120
|
+
"aria-labelledby": d
|
|
121
|
+
}, V), {
|
|
122
|
+
children: e.map((t, A) => /* @__PURE__ */ w(
|
|
123
|
+
k,
|
|
124
|
+
{
|
|
125
|
+
href: t.href,
|
|
126
|
+
"aria-current": t.active ? "page" : void 0,
|
|
127
|
+
"data-active": t.active ? "true" : void 0,
|
|
128
|
+
className: R({ variant: s, active: !!t.active }),
|
|
129
|
+
children: [
|
|
130
|
+
t.icon ? /* @__PURE__ */ o("span", { "aria-hidden": "true", className: "inline-flex shrink-0", children: t.icon }) : null,
|
|
131
|
+
/* @__PURE__ */ o("span", { children: t.label }),
|
|
132
|
+
t.count !== void 0 ? /* @__PURE__ */ o("span", { className: z, children: t.count }) : null
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
t.href || A
|
|
136
|
+
))
|
|
137
|
+
})
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
D.displayName = "TabsAsLinks";
|
|
142
|
+
export {
|
|
143
|
+
D as default
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=TabsAsLinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TabsAsLinks.js","sources":["../../../../../src/ui/components/TabsAsLinks/TabsAsLinks.tsx"],"sourcesContent":["import { forwardRef } from \"react\";\nimport type { ElementType, HTMLAttributes, ReactNode } from \"react\";\nimport { cn, cva } from \"../../utils\";\nimport {\n getRadiusClass,\n getSpacingClass,\n getTypographySize,\n} from \"../../tokens\";\n\n// Ambient declaration so the dev-only warn typechecks without pulling\n// @types/node in; the `typeof process` guard keeps it safe in browser/edge\n// runtimes. Mirrors Card.tsx / HeroSection.tsx.\ndeclare const process: { env: { NODE_ENV?: string } };\n\n/** Visual hierarchy: `default` = primary tab bar, `sub` = nested sub-tabs. */\nexport type TabsAsLinksVariant = \"default\" | \"sub\";\n\n/** A single navigation tab. The active state is decided by the caller. */\nexport interface TabAsLink {\n /** Visible tab label. */\n label: ReactNode;\n /** Destination URL — pre-computed by the caller. */\n href: string;\n /**\n * Whether this tab is the current one. The caller derives it (from\n * `pathname` / `searchParams`); the component does no detection of its own.\n * @default false\n */\n active?: boolean;\n /** Optional leading icon (decorative — rendered `aria-hidden`). */\n icon?: ReactNode;\n /** Optional trailing count (e.g. number of items behind the tab). */\n count?: number;\n}\n\nexport interface TabsAsLinksProps extends HTMLAttributes<HTMLElement> {\n /** The tabs to render, in order. */\n items: TabAsLink[];\n /**\n * Visual hierarchy.\n * @default 'default'\n */\n variant?: TabsAsLinksVariant;\n /**\n * Element/component each tab renders as. Defaults to a plain `<a>` (zero\n * JS, works without hydration). Pass a router link — e.g. Next's `Link` —\n * to keep client-side navigation/prefetch: `linkComponent={Link}`. It\n * receives `href`, `className`, `aria-current`, and `children`.\n * @default 'a'\n */\n linkComponent?: ElementType;\n /** Additional CSS classes merged onto the root `<nav>`. */\n className?: string;\n}\n\n/**\n * Tab-bar container (the `<nav>` track). Only the gap and the track-line\n * weight differ between tiers; the active underline lives on each link.\n */\nconst navVariants = cva(cn(\"flex items-center\", \"border-b\"), {\n variants: {\n variant: {\n default: cn(\"border-line-default\", getSpacingClass(\"base\", \"gap-x\")),\n sub: cn(\"border-line-muted\", getSpacingClass(\"sm\", \"gap-x\")),\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n});\n\n/**\n * A single tab link. The 2px bottom border with `-mb-px` overlaps the 1px\n * `<nav>` track so the active underline visually replaces the track segment\n * (the classic tab-bar look). `active` and `variant` are independent axes.\n */\nconst tabLinkVariants = cva(\n cn(\n \"relative -mb-px inline-flex items-center\",\n getSpacingClass(\"xs\", \"gap-x\"),\n \"border-b-2 border-transparent\",\n \"transition-colors\",\n \"focus:outline-none\",\n \"focus-visible:ring-2\",\n \"focus-visible:ring-line-focus\",\n \"focus-visible:ring-offset-2\",\n getRadiusClass(\"sm\"),\n ),\n {\n variants: {\n variant: {\n default: cn(\n getSpacingClass(\"sm\", \"px\"),\n getSpacingClass(\"sm\", \"py\"),\n getTypographySize(\"body\"),\n ),\n sub: cn(\n getSpacingClass(\"sm\", \"px\"),\n getSpacingClass(\"xs\", \"py\"),\n getTypographySize(\"bodySmall\"),\n ),\n },\n active: {\n true: cn(\"border-line-brand\", \"text-fg-brand-emphasis\", \"font-medium\"),\n false: cn(\n \"text-fg-secondary\",\n \"hover:text-fg-primary\",\n \"hover:border-line-muted\",\n ),\n },\n },\n compoundVariants: [\n // Sub-tabs sit lower in the hierarchy: lighter resting foreground.\n {\n variant: \"sub\",\n active: false,\n class: cn(\"text-fg-tertiary\", \"hover:text-fg-secondary\"),\n },\n ],\n defaultVariants: {\n variant: \"default\",\n active: false,\n },\n },\n);\n\nconst countClasses = cn(\n \"inline-flex items-center justify-center\",\n getRadiusClass(\"full\"),\n getSpacingClass(\"xs\", \"px\"),\n \"bg-surface-muted text-fg-secondary text-xs\",\n);\n\n/**\n * `TabsAsLinks` — tabs rendered as **navigation links**, with the active tab\n * decided by the caller (from the URL), not by interactive state.\n *\n * This is the server-safe counterpart to the interactive `Tabs` widget. Use\n * it for tab bars whose selection lives in the URL (`?tab=`, `/section`) so\n * they work without JavaScript and survive a shared link. Because each tab is\n * a real link to a distinct destination, the component uses the **navigation**\n * pattern — a named `<nav>` landmark with `aria-current=\"page\"` on the active\n * link — NOT the `role=\"tab\"` widget pattern (which would promise arrow-key\n * semantics that links don't have).\n *\n * ### Accessible name\n *\n * Renders a `<nav>` landmark, which must be named so screen-reader users can\n * tell multiple tab bars apart. Pass `aria-label` (e.g. `\"Painel\"`) or\n * `aria-labelledby`. With neither, a dev-only warning fires (the landmark\n * still renders, just anonymously).\n *\n * ### Server-safe\n *\n * No hooks, no event handlers on the DOM — pure presentation. Ships in the\n * `./server` entry. Defaults to a plain `<a>`; pass `linkComponent={Link}` to\n * keep a router's client-side navigation, which crosses the RSC boundary as a\n * client reference.\n *\n * @example\n * ```tsx\n * // Next App Router — active derived from searchParams in a Server Component\n * <TabsAsLinks\n * aria-label=\"Painel\"\n * linkComponent={Link}\n * items={[\n * { label: \"Visão geral\", href: \"/painel?tab=overview\", active: tab === \"overview\" },\n * { label: \"Alertas\", href: \"/painel?tab=alerts\", active: tab === \"alerts\", count: 3 },\n * ]}\n * />\n * ```\n */\nconst TabsAsLinks = forwardRef<HTMLElement, TabsAsLinksProps>(\n function TabsAsLinks(\n {\n items,\n variant = \"default\",\n linkComponent,\n className,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...rest\n },\n ref,\n ) {\n if (\n typeof process !== \"undefined\" &&\n process.env.NODE_ENV !== \"production\" &&\n !ariaLabel &&\n !ariaLabelledBy\n ) {\n console.warn(\n \"[TabsAsLinks] renders a <nav> landmark and should have an \" +\n 'accessible name. Pass `aria-label` (e.g. \"Painel\") or ' +\n \"`aria-labelledby` — multiple unnamed navs on a page are ambiguous \" +\n \"to screen readers.\",\n );\n }\n\n const LinkComponent: ElementType = linkComponent ?? \"a\";\n\n return (\n <nav\n ref={ref}\n className={cn(navVariants({ variant }), className)}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n {...rest}\n >\n {items.map((item, index) => (\n <LinkComponent\n key={item.href || index}\n href={item.href}\n aria-current={item.active ? \"page\" : undefined}\n data-active={item.active ? \"true\" : undefined}\n className={tabLinkVariants({ variant, active: !!item.active })}\n >\n {item.icon ? (\n <span aria-hidden=\"true\" className=\"inline-flex shrink-0\">\n {item.icon}\n </span>\n ) : null}\n <span>{item.label}</span>\n {item.count !== undefined ? (\n <span className={countClasses}>{item.count}</span>\n ) : null}\n </LinkComponent>\n ))}\n </nav>\n );\n },\n);\n\nTabsAsLinks.displayName = \"TabsAsLinks\";\n\nexport default TabsAsLinks;\n"],"names":["navVariants","cva","cn","getSpacingClass","tabLinkVariants","getRadiusClass","getTypographySize","countClasses","TabsAsLinks","forwardRef","_a","ref","_b","items","variant","linkComponent","className","ariaLabel","ariaLabelledBy","rest","__objRest","LinkComponent","jsx","__spreadProps","__spreadValues","item","index","jsxs"],"mappings":"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"}
|