@graundtech/fluent2-react-kit 0.5.1

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.
Files changed (98) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -0
  3. package/dist/components/ui/accordion.d.ts +133 -0
  4. package/dist/components/ui/accordion.js +80 -0
  5. package/dist/components/ui/accordion.js.map +1 -0
  6. package/dist/components/ui/alert.d.ts +106 -0
  7. package/dist/components/ui/alert.js +73 -0
  8. package/dist/components/ui/alert.js.map +1 -0
  9. package/dist/components/ui/avatar.d.ts +42 -0
  10. package/dist/components/ui/avatar.js +55 -0
  11. package/dist/components/ui/avatar.js.map +1 -0
  12. package/dist/components/ui/badge.d.ts +36 -0
  13. package/dist/components/ui/badge.js +81 -0
  14. package/dist/components/ui/badge.js.map +1 -0
  15. package/dist/components/ui/breadcrumb.d.ts +53 -0
  16. package/dist/components/ui/breadcrumb.js +149 -0
  17. package/dist/components/ui/breadcrumb.js.map +1 -0
  18. package/dist/components/ui/button.d.ts +24 -0
  19. package/dist/components/ui/button.js +86 -0
  20. package/dist/components/ui/button.js.map +1 -0
  21. package/dist/components/ui/card.d.ts +51 -0
  22. package/dist/components/ui/card.js +97 -0
  23. package/dist/components/ui/card.js.map +1 -0
  24. package/dist/components/ui/checkbox.d.ts +101 -0
  25. package/dist/components/ui/checkbox.js +57 -0
  26. package/dist/components/ui/checkbox.js.map +1 -0
  27. package/dist/components/ui/combobox.d.ts +212 -0
  28. package/dist/components/ui/combobox.js +236 -0
  29. package/dist/components/ui/combobox.js.map +1 -0
  30. package/dist/components/ui/command.d.ts +187 -0
  31. package/dist/components/ui/command.js +225 -0
  32. package/dist/components/ui/command.js.map +1 -0
  33. package/dist/components/ui/dialog.d.ts +117 -0
  34. package/dist/components/ui/dialog.js +165 -0
  35. package/dist/components/ui/dialog.js.map +1 -0
  36. package/dist/components/ui/dropdown-menu.d.ts +155 -0
  37. package/dist/components/ui/dropdown-menu.js +295 -0
  38. package/dist/components/ui/dropdown-menu.js.map +1 -0
  39. package/dist/components/ui/input.d.ts +44 -0
  40. package/dist/components/ui/input.js +43 -0
  41. package/dist/components/ui/input.js.map +1 -0
  42. package/dist/components/ui/label.d.ts +39 -0
  43. package/dist/components/ui/label.js +30 -0
  44. package/dist/components/ui/label.js.map +1 -0
  45. package/dist/components/ui/link.d.ts +62 -0
  46. package/dist/components/ui/link.js +61 -0
  47. package/dist/components/ui/link.js.map +1 -0
  48. package/dist/components/ui/multi-select.d.ts +115 -0
  49. package/dist/components/ui/multi-select.js +133 -0
  50. package/dist/components/ui/multi-select.js.map +1 -0
  51. package/dist/components/ui/pagination.d.ts +46 -0
  52. package/dist/components/ui/pagination.js +164 -0
  53. package/dist/components/ui/pagination.js.map +1 -0
  54. package/dist/components/ui/popover.d.ts +117 -0
  55. package/dist/components/ui/popover.js +62 -0
  56. package/dist/components/ui/popover.js.map +1 -0
  57. package/dist/components/ui/progress.d.ts +98 -0
  58. package/dist/components/ui/progress.js +67 -0
  59. package/dist/components/ui/progress.js.map +1 -0
  60. package/dist/components/ui/radio-group.d.ts +94 -0
  61. package/dist/components/ui/radio-group.js +65 -0
  62. package/dist/components/ui/radio-group.js.map +1 -0
  63. package/dist/components/ui/select.d.ts +145 -0
  64. package/dist/components/ui/select.js +240 -0
  65. package/dist/components/ui/select.js.map +1 -0
  66. package/dist/components/ui/separator.d.ts +43 -0
  67. package/dist/components/ui/separator.js +27 -0
  68. package/dist/components/ui/separator.js.map +1 -0
  69. package/dist/components/ui/skeleton.d.ts +81 -0
  70. package/dist/components/ui/skeleton.js +24 -0
  71. package/dist/components/ui/skeleton.js.map +1 -0
  72. package/dist/components/ui/spinner.d.ts +56 -0
  73. package/dist/components/ui/spinner.js +83 -0
  74. package/dist/components/ui/spinner.js.map +1 -0
  75. package/dist/components/ui/switch.d.ts +60 -0
  76. package/dist/components/ui/switch.js +63 -0
  77. package/dist/components/ui/switch.js.map +1 -0
  78. package/dist/components/ui/tabs.d.ts +107 -0
  79. package/dist/components/ui/tabs.js +102 -0
  80. package/dist/components/ui/tabs.js.map +1 -0
  81. package/dist/components/ui/textarea.d.ts +28 -0
  82. package/dist/components/ui/textarea.js +36 -0
  83. package/dist/components/ui/textarea.js.map +1 -0
  84. package/dist/components/ui/toast.d.ts +185 -0
  85. package/dist/components/ui/toast.js +181 -0
  86. package/dist/components/ui/toast.js.map +1 -0
  87. package/dist/components/ui/tooltip.d.ts +115 -0
  88. package/dist/components/ui/tooltip.js +72 -0
  89. package/dist/components/ui/tooltip.js.map +1 -0
  90. package/dist/index.d.ts +55 -0
  91. package/dist/index.js +284 -0
  92. package/dist/index.js.map +1 -0
  93. package/dist/lib/utils.d.ts +9 -0
  94. package/dist/lib/utils.js +9 -0
  95. package/dist/lib/utils.js.map +1 -0
  96. package/package.json +77 -0
  97. package/src/styles/tokens.css +596 -0
  98. package/src/styles/tokens.test.ts +216 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/progress.tsx"],"sourcesContent":["import { Progress as ProgressPrimitive } from \"@base-ui/react/progress\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\n/**\n * Progress — Fluent 2-styled, shadcn-API progress bar.\n *\n * Base UI ships a Progress primitive (`@base-ui/react/progress`, imported as\n * a namespace exposing `Root` / `Track` / `Indicator` / `Label` / `Value`,\n * matching the actual export shape in node_modules — same pattern as\n * `avatar.tsx`). This is the batch's Base UI case (conventions §9): value→\n * percentage math, `role=\"progressbar\"`, `aria-valuemin`/`aria-valuemax`/\n * `aria-valuenow`/`aria-valuetext` wiring, and indeterminate detection\n * (`aria-valuenow` correctly omitted when `value` is `null`/`undefined`) are\n * exactly the kind of genuine behavior a primitive should own rather than\n * hand-rolling ARIA math. `Root`, `Track`, and `Indicator` are composed\n * internally into a single `Progress` export to match shadcn's flat API\n * (`<Progress value={33} />`) — the sub-parts are not re-exported, since the\n * spec calls for one component, not shadcn's newer multi-part variant.\n *\n * `\"use client\"` is intentionally omitted, mirroring `avatar.tsx`'s\n * reasoning: Base UI's Root/Track/Indicator modules each carry their own\n * `'use client'` directive at the source level, so they are already client\n * boundaries on their own. This wrapper file has no hooks/handlers of its\n * own — it only forwards props and branches on a plain value comparison — so\n * it stays a plain (server-renderable) module per conventions §2. Confirmed\n * via `pnpm typecheck` + the test suite.\n *\n * Aesthetics follow Fluent 2's ProgressBar, which is thin — 2px (`h-0.5`),\n * not shadcn's 8px `h-2` default. This is a deliberate, documented deviation\n * from the shadcn reference; consumers who want the shadcn-thick bar (or any\n * other height) can override via `className` (`cn` + tailwind-merge resolve\n * the conflict, last utility wins). Track is `bg-secondary` (flat neutral\n * fill) with `rounded-full overflow-hidden`; the indicator is `bg-primary`,\n * also `rounded-full`.\n *\n * Intent variants: Fluent's ProgressBar ships a `State` axis (Default/Success/\n * Error/Warning), so `Progress` exposes a matching `variant` prop\n * (`default`/`success`/`warning`/`destructive`) via `progressVariants` — a\n * `cva` on the indicator sub-part, the same precedent `spinner.tsx` sets by\n * putting its `cva` on the inner glyph. `success` (`bg-success` `#107c10`) and\n * `warning` (`bg-warning` `#da3b01`) are exact hex matches to Fluent's\n * Success/Warning `State`. `destructive` reuses `bg-destructive` (`#d13438`)\n * rather than Fluent's filled-status `#c50f1f`: this kit standardizes on one\n * destructive red across Badge/Progress/Label per the single-red policy\n * (docs/design/tokens-research.md §12.9), keeping consistency over a one-off\n * fifth red token. The indicator width is driven by Base UI's own computed\n * `style.width` percentage (`ProgressIndicator` reads `value`/`min`/`max`\n * from context and sets `width: ${percent}%` — this is \"the cleaner\" of the\n * two width strategies the spec allows: it needs no manual percent math on\n * our side, unlike shadcn's classic `translateX(-${100 - value}%)` recipe).\n * `transition-[width]` (not `transition-all`/`transform`, since Base UI\n * animates `width` directly) plus the token duration/easing pair animates\n * value changes; reduced motion is handled automatically by the token layer\n * (conventions §3.5) since `duration-normal`/`ease-ease` are token-driven.\n *\n * Indeterminate (`value` is `null`/undefined): Fluent's sliding segment. The\n * indicator renders a `w-1/3` segment driven by the token-layer\n * `--animate-progress-indeterminate` keyframes (tokens.css): it travels from\n * fully off-track left (`translate: -100%` of its own width) to fully\n * off-track right (`300%`), clipped by the root's `overflow-hidden`.\n *\n * Under `prefers-reduced-motion` the slide is fully stopped via\n * `motion-reduce:animate-none` (same call as `skeleton.tsx`, not `spinner.tsx`'s\n * slow-down): the pulse carries no information a reduced-motion user would\n * lose by holding it still — the indeterminate/busy state is conveyed by the\n * `role=\"progressbar\"` + omitted `aria-valuenow` to assistive tech and by the\n * bar's presence to sighted users — and a persistently animating region is\n * exactly what `prefers-reduced-motion` asks apps to avoid. `motion-reduce:\n * animate-none` is a plain Tailwind utility (not a `duration-*` token), so it\n * isn't covered by the automatic duration collapse `tokens.css` applies and\n * has to be declared here explicitly.\n *\n * `role=\"progressbar\"` requires an accessible name; Base UI does not default\n * one. Pass `aria-label` (forwarded straight through to the root via\n * `...props`) or compose Base UI's own `Progress.Label` alongside this\n * component — consumers must supply one or the other.\n */\nconst progressVariants = cva(\n \"h-full rounded-full transition-[width] duration-normal ease-ease\",\n {\n variants: {\n variant: {\n default: \"bg-primary\",\n success: \"bg-success\",\n warning: \"bg-warning\",\n destructive: \"bg-destructive\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n }\n);\n\nfunction Progress({\n className,\n value,\n variant = \"default\",\n size = \"default\",\n ...props\n}: Omit<ComponentProps<typeof ProgressPrimitive.Root>, \"value\"> &\n VariantProps<typeof progressVariants> & {\n /**\n * 0–100 (relative to `min`/`max`, both default 0/100). Omit or pass `null`\n * for the indeterminate state — Base UI's Root then correctly omits\n * `aria-valuenow` and this wrapper renders the pulsing stand-in indicator.\n */\n value?: number | null;\n /**\n * Fluent ProgressBar `Size` axis: `default` = Medium (2px track),\n * `lg` = Large (4px) — surfaced by the pass-1 Figma validation.\n */\n size?: \"default\" | \"lg\";\n }) {\n return (\n <ProgressPrimitive.Root\n data-slot=\"progress\"\n data-variant={variant}\n data-size={size}\n value={value ?? null}\n className={cn(\n \"relative w-full overflow-hidden rounded-full bg-secondary\",\n size === \"lg\" ? \"h-1\" : \"h-0.5\",\n className\n )}\n {...props}\n >\n <ProgressPrimitive.Track\n data-slot=\"progress-track\"\n className=\"relative h-full w-full\"\n >\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className={cn(\n progressVariants({ variant }),\n // Fluent indeterminate: the token-layer keyframes slide the 1/3\n // segment from off-track left to off-track right (root clips).\n value == null &&\n \"w-1/3 animate-progress-indeterminate motion-reduce:animate-none\"\n )}\n />\n </ProgressPrimitive.Track>\n </ProgressPrimitive.Root>\n );\n}\n\nexport { Progress, progressVariants };\n"],"mappings":"AAsIQ;AAtIR,SAAS,YAAY,yBAAyB;AAC9C,SAAS,WAA8B;AAGvC,SAAS,UAAU;AA4EnB,MAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAEA,SAAS,SAAS;AAAA,EAChB;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,OAAO;AAAA,EACP,GAAG;AACL,GAaK;AACH,SACE;AAAA,IAAC,kBAAkB;AAAA,IAAlB;AAAA,MACC,aAAU;AAAA,MACV,gBAAc;AAAA,MACd,aAAW;AAAA,MACX,OAAO,SAAS;AAAA,MAChB,WAAW;AAAA,QACT;AAAA,QACA,SAAS,OAAO,QAAQ;AAAA,QACxB;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA,QAAC,kBAAkB;AAAA,QAAlB;AAAA,UACC,aAAU;AAAA,UACV,WAAU;AAAA,UAEV;AAAA,YAAC,kBAAkB;AAAA,YAAlB;AAAA,cACC,aAAU;AAAA,cACV,WAAW;AAAA,gBACT,iBAAiB,EAAE,QAAQ,CAAC;AAAA;AAAA;AAAA,gBAG5B,SAAS,QACP;AAAA,cACJ;AAAA;AAAA,UACF;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,94 @@
1
+ import * as react from 'react';
2
+ import { Radio } from '@base-ui/react/radio';
3
+ import { RadioGroup as RadioGroup$1 } from '@base-ui/react/radio-group';
4
+
5
+ /**
6
+ * RadioGroup / RadioGroupItem — Fluent 2-styled, shadcn-API radio group.
7
+ *
8
+ * This is a Base UI case (conventions §9): roving tabindex, arrow-key
9
+ * selection and the checked/unchecked state machine are genuine behavior a
10
+ * `<div>` + `<input type="radio">` can't express on their own without
11
+ * reimplementing Base UI's composite-focus logic, so the two parts wrap
12
+ * `@base-ui/react/radio-group` (`RadioGroup`, imported and re-exported as
13
+ * `RadioGroupPrimitive`) and `@base-ui/react/radio` (`Radio`, imported as a
14
+ * namespace exposing `Radio.Root` / `Radio.Indicator` — matches the actual
15
+ * `export * as Radio from "./index.parts.js"` shape in node_modules, same
16
+ * pattern `avatar.tsx` uses for `@base-ui/react/avatar`). Arrow-key
17
+ * roving/selection, click-to-select, and the hidden native
18
+ * `<input type="radio">` (native form participation) all come from Base UI —
19
+ * none of it is reimplemented here.
20
+ *
21
+ * `"use client"` is intentionally omitted here, same reasoning as
22
+ * `avatar.tsx`: `@base-ui/react/radio-group`'s `RadioGroup` and
23
+ * `@base-ui/react/radio`'s `Radio.Root` / `Radio.Indicator` each carry their
24
+ * own `'use client'` directive at the compiled-source level (verified in
25
+ * `node_modules/@base-ui/react/{radio-group/RadioGroup.js,radio/root/RadioRoot.js,radio/indicator/RadioIndicator.js}`),
26
+ * so they are already client boundaries on their own. This wrapper file has
27
+ * no hooks/handlers of its own — it only forwards props into those parts —
28
+ * so per conventions §2 it can stay a plain (server-renderable) module; a
29
+ * Server Component tree can render a Client Component child without the
30
+ * parent re-declaring the directive. Confirmed via `pnpm typecheck` + the
31
+ * test suite; add the directive here only if that stops holding true.
32
+ *
33
+ * Layout: shadcn's reference implementation defaults `RadioGroup` to
34
+ * `"grid gap-3"`. This kit ships `"grid gap-2"` instead — a deliberate,
35
+ * spec-directed deviation to match this component family's spacing scale (a
36
+ * 16px control at `gap-2` == 8px reads as a tighter, denser Fluent list than
37
+ * shadcn's 12px gap). Callers needing shadcn's exact spacing can override via
38
+ * `className="gap-3"` (later utility wins through `cn`'s `tailwind-merge`).
39
+ *
40
+ * Checked indicator: shadcn fills a `lucide-react` `CircleIcon` positioned
41
+ * absolutely inside the indicator. Fluent 2's RadioGroup instead shows a
42
+ * brand-colored **ring** (the whole circle's border turns brand) with a
43
+ * small brand **dot** centered inside — no checkmark glyph. This
44
+ * implementation matches that: the item's border switches to
45
+ * `border-primary` when `data-checked` is present, and the indicator renders
46
+ * a plain `size-2 rounded-full bg-primary` `<span>` (flex-centered, no icon
47
+ * import needed — a filled circle needs no glyph, so pulling in
48
+ * `@fluentui/react-icons` for this would add a dependency for no visual
49
+ * gain). `Radio.Indicator` only mounts while the radio is checked (Base UI
50
+ * unmounts it otherwise, per `RadioIndicator.js`'s `shouldRender` check), so
51
+ * the dot itself needs no extra checked-conditional styling — but it does
52
+ * ramp its color alongside the ring (see below).
53
+ *
54
+ * Borders + interaction ramp: the unchecked ring outlines with Fluent's
55
+ * `NeutralStrokeAccessible` ramp — rest `#616161` (`border-stroke-accessible`),
56
+ * hover `#575757`, pressed `#4d4d4d` — the higher-contrast neutral spec for
57
+ * interactive control outlines (extracted from the Figma radio), NOT the
58
+ * lighter `border-input` grey the item previously used. When checked, the ring
59
+ * (border) and dot step through `CompoundBrandStroke`/`CompoundBrandForeground1`
60
+ * Hover/Pressed (`brand-70`/`brand-60`; dark hover `brand-80`), mirroring
61
+ * Button's per-theme brand ramp (conventions §4). The ring uses
62
+ * `data-[checked]:hover:`/`:active:` (which outrank the neutral hover/active
63
+ * border by specificity); the dot, having no `data-checked` of its own, rides
64
+ * the root's `group` hover/press instead.
65
+ *
66
+ * States: `data-checked`/`data-unchecked` and `data-disabled` are Base UI's
67
+ * own presence attributes on `Radio.Root`'s rendered `<span>` (see
68
+ * `RadioRootDataAttributes` in node_modules — boolean presence, not a
69
+ * `data-state="checked"` value pair like Radix), matched here via Tailwind's
70
+ * `data-[checked]:` / `data-[disabled]:` arbitrary-attribute variants (there
71
+ * is no native `:disabled` pseudo-class to reach for — the rendered element
72
+ * is a `<span role="radio">`, not a real `<input>`/`<button>`, so the
73
+ * opacity/pointer-events disabled recipe from conventions §4 is re-expressed
74
+ * against `data-[disabled]:` instead of `disabled:`). Focus, per conventions
75
+ * §4, stays the generic offset-ring recipe (not the field bottom-accent
76
+ * variant — a radio is a selectable control, not a typed-into field).
77
+ * `aria-invalid` is a bare ARIA attribute Base UI passes through untouched,
78
+ * so the standard `aria-invalid:` recipe applies as-is.
79
+ *
80
+ * Typing: Base UI's `RadioGroup`/`Radio.Root` are generic over the radio
81
+ * value type (`Value = any` upstream). `ComponentProps<typeof X>` on a
82
+ * generic function component collapses that parameter to `unknown` (it has
83
+ * no call site to infer from), which would force every consumer to cast in
84
+ * `onValueChange`. Both parts pin `Value` to `string` instead via each
85
+ * primitive's own namespace type (`RadioGroupPrimitive.Props<string>`,
86
+ * `Radio.Root.Props<string>` — available because Base UI declaration-merges
87
+ * a namespace onto each component, matching shadcn/Radix's own radio API,
88
+ * which is string-only, not generic) so callers get a plain, un-cast
89
+ * `value`/`onValueChange: (value: string, …) => void` surface.
90
+ */
91
+ declare function RadioGroup({ className, ...props }: RadioGroup$1.Props<string>): react.JSX.Element;
92
+ declare function RadioGroupItem({ className, ...props }: Radio.Root.Props<string>): react.JSX.Element;
93
+
94
+ export { RadioGroup, RadioGroupItem };
@@ -0,0 +1,65 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Radio } from "@base-ui/react/radio";
3
+ import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group";
4
+ import { cn } from "../../lib/utils.js";
5
+ function RadioGroup({
6
+ className,
7
+ ...props
8
+ }) {
9
+ return /* @__PURE__ */ jsx(
10
+ RadioGroupPrimitive,
11
+ {
12
+ "data-slot": "radio-group",
13
+ className: cn("grid gap-2", className),
14
+ ...props
15
+ }
16
+ );
17
+ }
18
+ function RadioGroupItem({
19
+ className,
20
+ ...props
21
+ }) {
22
+ return /* @__PURE__ */ jsx(
23
+ Radio.Root,
24
+ {
25
+ "data-slot": "radio-group-item",
26
+ className: cn(
27
+ // layout — Fluent 16px circle. `group` lets the checked dot (a child
28
+ // span) pick up the root's hover/press to ramp alongside the ring.
29
+ "group aspect-square size-4 shrink-0 cursor-pointer rounded-full border bg-background",
30
+ // motion
31
+ "outline-none transition-colors duration-fast ease-ease",
32
+ // unchecked — Fluent NeutralStrokeAccessible rest/hover/pressed ramp
33
+ "border-stroke-accessible hover:border-stroke-accessible-hover active:border-stroke-accessible-pressed",
34
+ // checked — Fluent brand ring (the dot itself lives in the indicator),
35
+ // stepping through CompoundBrandStroke Hover/Pressed; dark hover
36
+ // brightens to brand-80 (Button's per-theme ramp). These outrank the
37
+ // neutral hover/active border by specificity so the ring stays brand.
38
+ "data-[checked]:border-primary data-[checked]:hover:border-brand-70 data-[checked]:active:border-brand-60 dark:data-[checked]:hover:border-brand-80",
39
+ // disabled — opacity-based (conventions §4), re-expressed against
40
+ // Base UI's data-disabled presence attribute (this renders a
41
+ // <span>, not a native disableable element)
42
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
43
+ // focus — generic offset-ring recipe (conventions §4)
44
+ "focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
45
+ // invalid — shadcn aria-invalid treatment (conventions §4)
46
+ "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
47
+ className
48
+ ),
49
+ ...props,
50
+ children: /* @__PURE__ */ jsx(
51
+ Radio.Indicator,
52
+ {
53
+ "data-slot": "radio-group-indicator",
54
+ className: "flex items-center justify-center",
55
+ children: /* @__PURE__ */ jsx("span", { className: "size-2 rounded-full bg-primary transition-colors duration-fast ease-ease group-hover:bg-brand-70 group-active:bg-brand-60 dark:group-hover:bg-brand-80" })
56
+ }
57
+ )
58
+ }
59
+ );
60
+ }
61
+ export {
62
+ RadioGroup,
63
+ RadioGroupItem
64
+ };
65
+ //# sourceMappingURL=radio-group.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/radio-group.tsx"],"sourcesContent":["import { Radio } from \"@base-ui/react/radio\";\nimport { RadioGroup as RadioGroupPrimitive } from \"@base-ui/react/radio-group\";\n\nimport { cn } from \"../../lib/utils\";\n\n/**\n * RadioGroup / RadioGroupItem — Fluent 2-styled, shadcn-API radio group.\n *\n * This is a Base UI case (conventions §9): roving tabindex, arrow-key\n * selection and the checked/unchecked state machine are genuine behavior a\n * `<div>` + `<input type=\"radio\">` can't express on their own without\n * reimplementing Base UI's composite-focus logic, so the two parts wrap\n * `@base-ui/react/radio-group` (`RadioGroup`, imported and re-exported as\n * `RadioGroupPrimitive`) and `@base-ui/react/radio` (`Radio`, imported as a\n * namespace exposing `Radio.Root` / `Radio.Indicator` — matches the actual\n * `export * as Radio from \"./index.parts.js\"` shape in node_modules, same\n * pattern `avatar.tsx` uses for `@base-ui/react/avatar`). Arrow-key\n * roving/selection, click-to-select, and the hidden native\n * `<input type=\"radio\">` (native form participation) all come from Base UI —\n * none of it is reimplemented here.\n *\n * `\"use client\"` is intentionally omitted here, same reasoning as\n * `avatar.tsx`: `@base-ui/react/radio-group`'s `RadioGroup` and\n * `@base-ui/react/radio`'s `Radio.Root` / `Radio.Indicator` each carry their\n * own `'use client'` directive at the compiled-source level (verified in\n * `node_modules/@base-ui/react/{radio-group/RadioGroup.js,radio/root/RadioRoot.js,radio/indicator/RadioIndicator.js}`),\n * so they are already client boundaries on their own. This wrapper file has\n * no hooks/handlers of its own — it only forwards props into those parts —\n * so per conventions §2 it can stay a plain (server-renderable) module; a\n * Server Component tree can render a Client Component child without the\n * parent re-declaring the directive. Confirmed via `pnpm typecheck` + the\n * test suite; add the directive here only if that stops holding true.\n *\n * Layout: shadcn's reference implementation defaults `RadioGroup` to\n * `\"grid gap-3\"`. This kit ships `\"grid gap-2\"` instead — a deliberate,\n * spec-directed deviation to match this component family's spacing scale (a\n * 16px control at `gap-2` == 8px reads as a tighter, denser Fluent list than\n * shadcn's 12px gap). Callers needing shadcn's exact spacing can override via\n * `className=\"gap-3\"` (later utility wins through `cn`'s `tailwind-merge`).\n *\n * Checked indicator: shadcn fills a `lucide-react` `CircleIcon` positioned\n * absolutely inside the indicator. Fluent 2's RadioGroup instead shows a\n * brand-colored **ring** (the whole circle's border turns brand) with a\n * small brand **dot** centered inside — no checkmark glyph. This\n * implementation matches that: the item's border switches to\n * `border-primary` when `data-checked` is present, and the indicator renders\n * a plain `size-2 rounded-full bg-primary` `<span>` (flex-centered, no icon\n * import needed — a filled circle needs no glyph, so pulling in\n * `@fluentui/react-icons` for this would add a dependency for no visual\n * gain). `Radio.Indicator` only mounts while the radio is checked (Base UI\n * unmounts it otherwise, per `RadioIndicator.js`'s `shouldRender` check), so\n * the dot itself needs no extra checked-conditional styling — but it does\n * ramp its color alongside the ring (see below).\n *\n * Borders + interaction ramp: the unchecked ring outlines with Fluent's\n * `NeutralStrokeAccessible` ramp — rest `#616161` (`border-stroke-accessible`),\n * hover `#575757`, pressed `#4d4d4d` — the higher-contrast neutral spec for\n * interactive control outlines (extracted from the Figma radio), NOT the\n * lighter `border-input` grey the item previously used. When checked, the ring\n * (border) and dot step through `CompoundBrandStroke`/`CompoundBrandForeground1`\n * Hover/Pressed (`brand-70`/`brand-60`; dark hover `brand-80`), mirroring\n * Button's per-theme brand ramp (conventions §4). The ring uses\n * `data-[checked]:hover:`/`:active:` (which outrank the neutral hover/active\n * border by specificity); the dot, having no `data-checked` of its own, rides\n * the root's `group` hover/press instead.\n *\n * States: `data-checked`/`data-unchecked` and `data-disabled` are Base UI's\n * own presence attributes on `Radio.Root`'s rendered `<span>` (see\n * `RadioRootDataAttributes` in node_modules — boolean presence, not a\n * `data-state=\"checked\"` value pair like Radix), matched here via Tailwind's\n * `data-[checked]:` / `data-[disabled]:` arbitrary-attribute variants (there\n * is no native `:disabled` pseudo-class to reach for — the rendered element\n * is a `<span role=\"radio\">`, not a real `<input>`/`<button>`, so the\n * opacity/pointer-events disabled recipe from conventions §4 is re-expressed\n * against `data-[disabled]:` instead of `disabled:`). Focus, per conventions\n * §4, stays the generic offset-ring recipe (not the field bottom-accent\n * variant — a radio is a selectable control, not a typed-into field).\n * `aria-invalid` is a bare ARIA attribute Base UI passes through untouched,\n * so the standard `aria-invalid:` recipe applies as-is.\n *\n * Typing: Base UI's `RadioGroup`/`Radio.Root` are generic over the radio\n * value type (`Value = any` upstream). `ComponentProps<typeof X>` on a\n * generic function component collapses that parameter to `unknown` (it has\n * no call site to infer from), which would force every consumer to cast in\n * `onValueChange`. Both parts pin `Value` to `string` instead via each\n * primitive's own namespace type (`RadioGroupPrimitive.Props<string>`,\n * `Radio.Root.Props<string>` — available because Base UI declaration-merges\n * a namespace onto each component, matching shadcn/Radix's own radio API,\n * which is string-only, not generic) so callers get a plain, un-cast\n * `value`/`onValueChange: (value: string, …) => void` surface.\n */\nfunction RadioGroup({\n className,\n ...props\n}: RadioGroupPrimitive.Props<string>) {\n return (\n <RadioGroupPrimitive\n data-slot=\"radio-group\"\n className={cn(\"grid gap-2\", className)}\n {...props}\n />\n );\n}\n\nfunction RadioGroupItem({\n className,\n ...props\n}: Radio.Root.Props<string>) {\n return (\n <Radio.Root\n data-slot=\"radio-group-item\"\n className={cn(\n // layout — Fluent 16px circle. `group` lets the checked dot (a child\n // span) pick up the root's hover/press to ramp alongside the ring.\n \"group aspect-square size-4 shrink-0 cursor-pointer rounded-full border bg-background\",\n // motion\n \"outline-none transition-colors duration-fast ease-ease\",\n // unchecked — Fluent NeutralStrokeAccessible rest/hover/pressed ramp\n \"border-stroke-accessible hover:border-stroke-accessible-hover active:border-stroke-accessible-pressed\",\n // checked — Fluent brand ring (the dot itself lives in the indicator),\n // stepping through CompoundBrandStroke Hover/Pressed; dark hover\n // brightens to brand-80 (Button's per-theme ramp). These outrank the\n // neutral hover/active border by specificity so the ring stays brand.\n \"data-[checked]:border-primary data-[checked]:hover:border-brand-70 data-[checked]:active:border-brand-60 dark:data-[checked]:hover:border-brand-80\",\n // disabled — opacity-based (conventions §4), re-expressed against\n // Base UI's data-disabled presence attribute (this renders a\n // <span>, not a native disableable element)\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n // focus — generic offset-ring recipe (conventions §4)\n \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n // invalid — shadcn aria-invalid treatment (conventions §4)\n \"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40\",\n className\n )}\n {...props}\n >\n <Radio.Indicator\n data-slot=\"radio-group-indicator\"\n className=\"flex items-center justify-center\"\n >\n {/* dot — brand fill, ramping with the ring via the root's `group`\n hover/press (CompoundBrandForeground1 Hover/Pressed). */}\n <span className=\"size-2 rounded-full bg-primary transition-colors duration-fast ease-ease group-hover:bg-brand-70 group-active:bg-brand-60 dark:group-hover:bg-brand-80\" />\n </Radio.Indicator>\n </Radio.Root>\n );\n}\n\nexport { RadioGroup, RadioGroupItem };\n"],"mappings":"AAgGI;AAhGJ,SAAS,aAAa;AACtB,SAAS,cAAc,2BAA2B;AAElD,SAAS,UAAU;AAwFnB,SAAS,WAAW;AAAA,EAClB;AAAA,EACA,GAAG;AACL,GAAsC;AACpC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,cAAc,SAAS;AAAA,MACpC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA,GAAG;AACL,GAA6B;AAC3B,SACE;AAAA,IAAC,MAAM;AAAA,IAAN;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA;AAAA;AAAA,QAGT;AAAA;AAAA,QAEA;AAAA;AAAA,QAEA;AAAA;AAAA;AAAA;AAAA;AAAA,QAKA;AAAA;AAAA;AAAA;AAAA,QAIA;AAAA;AAAA,QAEA;AAAA;AAAA,QAEA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ;AAAA,QAAC,MAAM;AAAA,QAAN;AAAA,UACC,aAAU;AAAA,UACV,WAAU;AAAA,UAIV,8BAAC,UAAK,WAAU,0JAAyJ;AAAA;AAAA,MAC3K;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -0,0 +1,145 @@
1
+ import * as react from 'react';
2
+ import { ComponentProps } from 'react';
3
+ import { Select as Select$1 } from '@base-ui/react/select';
4
+
5
+ /**
6
+ * Select — Fluent 2-styled, shadcn-API select (dropdown listbox).
7
+ *
8
+ * This is the kit's first popup/overlay component, so the patterns set here
9
+ * (portal + positioner + popup surface, `shadow-16` flyout elevation, item
10
+ * highlight via Base UI `data-highlighted`) are the reference for Dialog,
11
+ * Tooltip, and Dropdown later.
12
+ *
13
+ * ## Base UI mapping (conventions §9)
14
+ * Behavior — focus management, portalling, open/close state, roving tabindex,
15
+ * type-ahead, collision-aware positioning — genuinely needs a primitive, so the
16
+ * parts wrap `@base-ui/react/select` (namespace import, matching the actual
17
+ * export shape in node_modules, exactly like `avatar.tsx`). shadcn part names
18
+ * are mapped onto Base UI's model:
19
+ *
20
+ * | Exported (shadcn name) | Base UI primitive |
21
+ * | ----------------------- | ---------------------------------------------------- |
22
+ * | `Select` | `Select.Root` |
23
+ * | `SelectGroup` | `Select.Group` |
24
+ * | `SelectValue` | `Select.Value` |
25
+ * | `SelectTrigger` | `Select.Trigger` (+ `Select.Icon` chevron appended) |
26
+ * | `SelectContent` | `Select.Portal` + `Select.Positioner` + `Select.Popup` + `Select.List` |
27
+ * | `SelectLabel` | `Select.GroupLabel` ← see divergence 1 |
28
+ * | `SelectItem` | `Select.Item` (+ `Select.ItemIndicator` + `Select.ItemText`) |
29
+ * | `SelectSeparator` | `Select.Separator` |
30
+ * | `SelectScrollUpButton` | `Select.ScrollUpArrow` |
31
+ * | `SelectScrollDownButton`| `Select.ScrollDownArrow` |
32
+ *
33
+ * ## Divergences from the shadcn/Radix Select API (all deliberate)
34
+ * 1. **`SelectLabel` maps to Base UI `Select.GroupLabel`, not `Select.Label`.**
35
+ * Base UI has *two* label parts: `Select.Label` labels the whole control
36
+ * (like a field `<label>`), while `Select.GroupLabel` is the heading inside a
37
+ * `Select.Group`. shadcn's `SelectLabel` is the group heading, so it maps to
38
+ * `GroupLabel`. Base UI's control-level `Select.Label` is intentionally not
39
+ * re-exported — pair the trigger with the kit's own `Label` component instead.
40
+ * `Label` is a separate registry item (`registry/items/label.json`) and is
41
+ * not a `registryDependency` of `select`, so install it explicitly:
42
+ * `npx shadcn@latest add <registry-url>/r/label.json`.
43
+ *
44
+ * **Labeling recipe.** Give the `Label` an `id` and the `SelectTrigger` its
45
+ * own `id`, then set `aria-labelledby="<label-id> <trigger-id>"` on the
46
+ * trigger (referencing *both*). Pointing only at the external label drops
47
+ * the chosen value from the accessible name; adding the trigger's own id
48
+ * folds the `SelectValue` text (the current selection) back in, so a screen
49
+ * reader announces "<label>, <selected value>". `htmlFor`/`for` can't be
50
+ * used here — the trigger renders a `<button>`, not a labelable form field —
51
+ * which is why the association is `aria-labelledby`, not a wrapping/`for`
52
+ * `<label>`. The Select preview page uses this pattern on every example.
53
+ * 2. **`SelectValue` shows the raw value unless `<Select>` gets an `items` prop.**
54
+ * Unlike Radix (where `SelectValue` mirrors the selected `SelectItem`'s text),
55
+ * Base UI's `Select.Value` renders the raw `value` by default. To display a
56
+ * friendly label, either pass `items` to `<Select>` (Root) — e.g.
57
+ * `items={[{ value: "apple", label: "Apple" }]}` — or pass a render function
58
+ * as `SelectValue`'s child: `<SelectValue>{(v) => labels[v]}</SelectValue>`.
59
+ * This is Base UI's model; the wrapper stays thin and does not paper over it.
60
+ * 3. **`SelectTrigger` sizes follow the kit's Button scale, not shadcn's.**
61
+ * shadcn ships `sm`/`default` at h-8/h-9; this kit maps Fluent's field sizes
62
+ * onto the Button height scale instead — `sm` 24px (`h-6`), `default` 32px
63
+ * (`h-8`, matches `Input`), `lg` 40px (`h-10`) — surfaced as `data-size`.
64
+ * 4. **`SelectContent` positions below the trigger (`alignItemWithTrigger=false`).**
65
+ * Base UI defaults to overlapping the trigger so the selected item's text lines
66
+ * up with the value (native-select behavior). A shadcn-style dropdown that opens
67
+ * beneath the field is the expected Fluent flyout, so this is forced off; the
68
+ * scroll arrows/`data-[side=none]` overlap edge cases go away with it.
69
+ *
70
+ * ## `"use client"` — required (integration-pass correction)
71
+ * Every Base UI Select part module does carry its own `'use client'`
72
+ * directive, so on that basis alone this wrapper could stay server-renderable
73
+ * (same reasoning as `avatar.tsx`). But `CheckmarkRegular`/`ChevronDownRegular`/
74
+ * `ChevronUpRegular` from `@fluentui/react-icons` break that: the package's
75
+ * shared icon-sizing module (`createFluentIcon.styles.js`) calls `@griffel/
76
+ * react`'s `__styles()` at module scope *without* its own `'use client'`
77
+ * directive, even though `__styles` itself is client-only. Rendering any of
78
+ * these icons from a Server Component pulls that module into the server's
79
+ * RSC graph, and `next build` (Turbopack) fails collecting page data with
80
+ * "Attempted to call __styles() from the server but __styles is on the
81
+ * client" — reproduced against `@fluentui/react-icons@2.0.333` /
82
+ * `@griffel/react@1.7.5`, and confirmed to affect every route that shares
83
+ * Turbopack's chunk for these icons, not just this one. `"use client"` here
84
+ * keeps the icon imports inside a client boundary so they're never evaluated
85
+ * on the server. `checkbox.tsx` carries the same fix for the same reason.
86
+ *
87
+ * ## data-slot note
88
+ * `Select` (Root) renders no DOM element of its own and its Base UI props type
89
+ * is strict (no `data-*` passthrough), so it carries no `data-slot`. Every part
90
+ * that renders an element does — `select-trigger`, `select-content`,
91
+ * `select-item`, etc. — which is what tests/consumers hook onto.
92
+ */
93
+ declare function Select<Value, Multiple extends boolean | undefined = false>(props: Select$1.Root.Props<Value, Multiple>): react.JSX.Element;
94
+ declare function SelectGroup({ className, ...props }: ComponentProps<typeof Select$1.Group>): react.JSX.Element;
95
+ declare function SelectValue({ className, ...props }: ComponentProps<typeof Select$1.Value>): react.JSX.Element;
96
+ /**
97
+ * Trigger — Fluent field look, styled to match `Input` (h-8, rounded-md,
98
+ * border-input, px-3, text-sm, flat at rest). Focus uses the sanctioned
99
+ * per-field deviation from conventions §4: a 2px brand underline painted with
100
+ * an inset box-shadow (no reflow) plus `border-primary`, and the `aria-invalid`
101
+ * treatment declared *after* focus so an invalid+focused field shows the
102
+ * destructive accent. The chevron is appended via `Select.Icon`; the trigger's
103
+ * `[&_svg]` rules size it (`size-4`) and mute it (`text-muted-foreground`).
104
+ */
105
+ declare function SelectTrigger({ className, children, size, ...props }: ComponentProps<typeof Select$1.Trigger> & {
106
+ /** Fluent field sizes on the Button height scale — see divergence 3. */
107
+ size?: "sm" | "default" | "lg";
108
+ }): react.JSX.Element;
109
+ /**
110
+ * Content — the floating flyout: `Portal` → `Positioner` → `Popup`, with the
111
+ * items in a scrollable `List` between hover-scroll arrows. Surface is
112
+ * `bg-popover` + `border` + `shadow-16` (Fluent flyout elevation, conventions
113
+ * §3.6), `rounded-md`, `min-w` matched to the trigger via Base UI's
114
+ * `--anchor-width`. A subtle scale+fade open/close animation rides Base UI's
115
+ * `data-starting-style`/`data-ending-style` hooks with token durations/easings.
116
+ */
117
+ declare function SelectContent({ className, children, sideOffset, align, side, ...props }: ComponentProps<typeof Select$1.Popup> & Pick<ComponentProps<typeof Select$1.Positioner>, "side" | "align" | "sideOffset">): react.JSX.Element;
118
+ /**
119
+ * Label — a heading for a `SelectGroup` (Base UI `Select.GroupLabel`), *not* a
120
+ * control-level field label (divergence 1). Small muted caption, Fluent style.
121
+ */
122
+ declare function SelectLabel({ className, ...props }: ComponentProps<typeof Select$1.GroupLabel>): react.JSX.Element;
123
+ /**
124
+ * Item — one option. Text via `ItemText`; the selected-state check
125
+ * (`CheckmarkRegular`) is absolutely positioned on the right (shadcn placement)
126
+ * inside `ItemIndicator`, which Base UI only mounts for the selected item.
127
+ * `rounded-md` (4px) matches Fluent's `Corner-radius/List/Default`. Highlight
128
+ * (keyboard focus or hover) uses `data-highlighted` → `bg-accent`
129
+ * (`#f0f0f0`) `text-accent-foreground`; Fluent's list-hover token is `#f5f5f5`
130
+ * (one grey step lighter), but the kit keeps `--accent` for token consistency
131
+ * with every other hover surface — the difference is imperceptible on a 32px
132
+ * row. Disabled items are muted + inert.
133
+ */
134
+ declare function SelectItem({ className, children, ...props }: ComponentProps<typeof Select$1.Item>): react.JSX.Element;
135
+ declare function SelectSeparator({ className, ...props }: ComponentProps<typeof Select$1.Separator>): react.JSX.Element;
136
+ /**
137
+ * ScrollUpButton / ScrollDownButton — Base UI hover-scroll arrows that Base UI
138
+ * only renders when the list overflows in that direction. Rendered as siblings
139
+ * of the `List` inside `SelectContent`, so consumers don't place them manually
140
+ * (shadcn parity — the export exists for API compatibility / manual use).
141
+ */
142
+ declare function SelectScrollUpButton({ className, ...props }: ComponentProps<typeof Select$1.ScrollUpArrow>): react.JSX.Element;
143
+ declare function SelectScrollDownButton({ className, ...props }: ComponentProps<typeof Select$1.ScrollDownArrow>): react.JSX.Element;
144
+
145
+ export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue };
@@ -0,0 +1,240 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { Select as SelectPrimitive } from "@base-ui/react/select";
4
+ import {
5
+ CheckmarkRegular,
6
+ ChevronDownRegular,
7
+ ChevronUpRegular
8
+ } from "@fluentui/react-icons";
9
+ import { cn } from "../../lib/utils.js";
10
+ function Select(props) {
11
+ return /* @__PURE__ */ jsx(SelectPrimitive.Root, { ...props });
12
+ }
13
+ function SelectGroup({
14
+ className,
15
+ ...props
16
+ }) {
17
+ return /* @__PURE__ */ jsx(
18
+ SelectPrimitive.Group,
19
+ {
20
+ "data-slot": "select-group",
21
+ className: cn(className),
22
+ ...props
23
+ }
24
+ );
25
+ }
26
+ function SelectValue({
27
+ className,
28
+ ...props
29
+ }) {
30
+ return /* @__PURE__ */ jsx(
31
+ SelectPrimitive.Value,
32
+ {
33
+ "data-slot": "select-value",
34
+ className: cn(className),
35
+ ...props
36
+ }
37
+ );
38
+ }
39
+ function SelectTrigger({
40
+ className,
41
+ children,
42
+ size = "default",
43
+ ...props
44
+ }) {
45
+ return /* @__PURE__ */ jsxs(
46
+ SelectPrimitive.Trigger,
47
+ {
48
+ "data-slot": "select-trigger",
49
+ "data-size": size,
50
+ className: cn(
51
+ // layout — Fluent field on the Button height scale (divergence 3);
52
+ // default is the 32px medium that matches Input. Resting bottom
53
+ // edge uses the darker NeutralStrokeAccessible (#616161) accent while
54
+ // the other sides stay border-input; focus (border-primary + inset
55
+ // underline) and aria-invalid (border-destructive) both override it.
56
+ "flex w-full items-center justify-between gap-2 rounded-md border border-input border-b-stroke-accessible bg-background py-1 whitespace-nowrap",
57
+ size === "sm" && "h-6 px-2 text-xs",
58
+ size === "default" && "h-8 px-3 text-sm",
59
+ size === "lg" && "h-10 px-4 text-base",
60
+ // placeholder text muted (Base UI sets data-placeholder when no value)
61
+ "data-[placeholder]:text-muted-foreground",
62
+ // keep a long value on one line, left-aligned
63
+ "*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:text-left",
64
+ // icon defaults — chevron sized + muted unless overridden
65
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
66
+ // motion — color + box-shadow so the focus accent animates (§4)
67
+ "outline-none transition-[color,box-shadow] duration-fast ease-ease",
68
+ // disabled — opacity read; Base UI emits both `disabled` + `data-disabled`
69
+ "disabled:pointer-events-none disabled:opacity-50 data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
70
+ // focus — Fluent bottom brand accent via inset box-shadow, no reflow (§4)
71
+ "focus-visible:border-primary focus-visible:shadow-[inset_0_-2px_0_0_var(--brand-80)] dark:focus-visible:shadow-[inset_0_-2px_0_0_var(--brand-100)]",
72
+ // invalid — shadcn aria-invalid treatment; after focus so it wins the border
73
+ "aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
74
+ "aria-invalid:focus-visible:shadow-[inset_0_-2px_0_0_var(--destructive)]",
75
+ className
76
+ ),
77
+ ...props,
78
+ children: [
79
+ children,
80
+ /* @__PURE__ */ jsx(SelectPrimitive.Icon, { children: /* @__PURE__ */ jsx(ChevronDownRegular, {}) })
81
+ ]
82
+ }
83
+ );
84
+ }
85
+ function SelectContent({
86
+ className,
87
+ children,
88
+ sideOffset = 4,
89
+ align = "start",
90
+ side = "bottom",
91
+ ...props
92
+ }) {
93
+ return /* @__PURE__ */ jsx(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsx(
94
+ SelectPrimitive.Positioner,
95
+ {
96
+ "data-slot": "select-positioner",
97
+ sideOffset,
98
+ align,
99
+ side,
100
+ alignItemWithTrigger: false,
101
+ className: "z-50 outline-none",
102
+ children: /* @__PURE__ */ jsxs(
103
+ SelectPrimitive.Popup,
104
+ {
105
+ "data-slot": "select-content",
106
+ className: cn(
107
+ "relative min-w-[var(--anchor-width)] origin-[var(--transform-origin)] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-16 outline-none",
108
+ // motion — subtle scale + fade on open (enter) / close (exit)
109
+ "transition-[opacity,scale] duration-fast ease-decelerate-mid",
110
+ "data-starting-style:scale-95 data-starting-style:opacity-0",
111
+ "data-ending-style:scale-95 data-ending-style:opacity-0 data-ending-style:ease-accelerate-mid",
112
+ className
113
+ ),
114
+ ...props,
115
+ children: [
116
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
117
+ /* @__PURE__ */ jsx(
118
+ SelectPrimitive.List,
119
+ {
120
+ "data-slot": "select-list",
121
+ className: "max-h-[var(--available-height)] overflow-y-auto overscroll-contain p-1",
122
+ children
123
+ }
124
+ ),
125
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
126
+ ]
127
+ }
128
+ )
129
+ }
130
+ ) });
131
+ }
132
+ function SelectLabel({
133
+ className,
134
+ ...props
135
+ }) {
136
+ return /* @__PURE__ */ jsx(
137
+ SelectPrimitive.GroupLabel,
138
+ {
139
+ "data-slot": "select-label",
140
+ className: cn(
141
+ "px-2 py-1.5 text-xs font-medium text-muted-foreground select-none",
142
+ className
143
+ ),
144
+ ...props
145
+ }
146
+ );
147
+ }
148
+ function SelectItem({
149
+ className,
150
+ children,
151
+ ...props
152
+ }) {
153
+ return /* @__PURE__ */ jsxs(
154
+ SelectPrimitive.Item,
155
+ {
156
+ "data-slot": "select-item",
157
+ className: cn(
158
+ // layout — Fluent 32px row, 4px list radius, px-2 with room on the
159
+ // right for the check
160
+ "relative flex h-8 w-full cursor-default items-center rounded-md pr-8 pl-2 text-sm outline-none select-none",
161
+ // rest text is NeutralForeground2, darkening to accent-foreground on
162
+ // highlight (Figma validation: Fluent list rows rest at #424242)
163
+ "text-foreground-2 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground",
164
+ // disabled item — muted + non-interactive
165
+ "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
166
+ // icons that a consumer puts inside the item text
167
+ "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
168
+ className
169
+ ),
170
+ ...props,
171
+ children: [
172
+ /* @__PURE__ */ jsx("span", { className: "absolute right-2 flex size-4 items-center justify-center", children: /* @__PURE__ */ jsx(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx(CheckmarkRegular, { className: "size-4" }) }) }),
173
+ /* @__PURE__ */ jsx(SelectPrimitive.ItemText, { children })
174
+ ]
175
+ }
176
+ );
177
+ }
178
+ function SelectSeparator({
179
+ className,
180
+ ...props
181
+ }) {
182
+ return /* @__PURE__ */ jsx(
183
+ SelectPrimitive.Separator,
184
+ {
185
+ "data-slot": "select-separator",
186
+ className: cn(
187
+ "pointer-events-none -mx-1 my-1 h-px bg-border",
188
+ className
189
+ ),
190
+ ...props
191
+ }
192
+ );
193
+ }
194
+ function SelectScrollUpButton({
195
+ className,
196
+ ...props
197
+ }) {
198
+ return /* @__PURE__ */ jsx(
199
+ SelectPrimitive.ScrollUpArrow,
200
+ {
201
+ "data-slot": "select-scroll-up-button",
202
+ className: cn(
203
+ "flex cursor-default items-center justify-center py-1 text-muted-foreground",
204
+ className
205
+ ),
206
+ ...props,
207
+ children: /* @__PURE__ */ jsx(ChevronUpRegular, { className: "size-4" })
208
+ }
209
+ );
210
+ }
211
+ function SelectScrollDownButton({
212
+ className,
213
+ ...props
214
+ }) {
215
+ return /* @__PURE__ */ jsx(
216
+ SelectPrimitive.ScrollDownArrow,
217
+ {
218
+ "data-slot": "select-scroll-down-button",
219
+ className: cn(
220
+ "flex cursor-default items-center justify-center py-1 text-muted-foreground",
221
+ className
222
+ ),
223
+ ...props,
224
+ children: /* @__PURE__ */ jsx(ChevronDownRegular, { className: "size-4" })
225
+ }
226
+ );
227
+ }
228
+ export {
229
+ Select,
230
+ SelectContent,
231
+ SelectGroup,
232
+ SelectItem,
233
+ SelectLabel,
234
+ SelectScrollDownButton,
235
+ SelectScrollUpButton,
236
+ SelectSeparator,
237
+ SelectTrigger,
238
+ SelectValue
239
+ };
240
+ //# sourceMappingURL=select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/ui/select.tsx"],"sourcesContent":["\"use client\";\n\nimport { Select as SelectPrimitive } from \"@base-ui/react/select\";\nimport {\n CheckmarkRegular,\n ChevronDownRegular,\n ChevronUpRegular,\n} from \"@fluentui/react-icons\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\n/**\n * Select — Fluent 2-styled, shadcn-API select (dropdown listbox).\n *\n * This is the kit's first popup/overlay component, so the patterns set here\n * (portal + positioner + popup surface, `shadow-16` flyout elevation, item\n * highlight via Base UI `data-highlighted`) are the reference for Dialog,\n * Tooltip, and Dropdown later.\n *\n * ## Base UI mapping (conventions §9)\n * Behavior — focus management, portalling, open/close state, roving tabindex,\n * type-ahead, collision-aware positioning — genuinely needs a primitive, so the\n * parts wrap `@base-ui/react/select` (namespace import, matching the actual\n * export shape in node_modules, exactly like `avatar.tsx`). shadcn part names\n * are mapped onto Base UI's model:\n *\n * | Exported (shadcn name) | Base UI primitive |\n * | ----------------------- | ---------------------------------------------------- |\n * | `Select` | `Select.Root` |\n * | `SelectGroup` | `Select.Group` |\n * | `SelectValue` | `Select.Value` |\n * | `SelectTrigger` | `Select.Trigger` (+ `Select.Icon` chevron appended) |\n * | `SelectContent` | `Select.Portal` + `Select.Positioner` + `Select.Popup` + `Select.List` |\n * | `SelectLabel` | `Select.GroupLabel` ← see divergence 1 |\n * | `SelectItem` | `Select.Item` (+ `Select.ItemIndicator` + `Select.ItemText`) |\n * | `SelectSeparator` | `Select.Separator` |\n * | `SelectScrollUpButton` | `Select.ScrollUpArrow` |\n * | `SelectScrollDownButton`| `Select.ScrollDownArrow` |\n *\n * ## Divergences from the shadcn/Radix Select API (all deliberate)\n * 1. **`SelectLabel` maps to Base UI `Select.GroupLabel`, not `Select.Label`.**\n * Base UI has *two* label parts: `Select.Label` labels the whole control\n * (like a field `<label>`), while `Select.GroupLabel` is the heading inside a\n * `Select.Group`. shadcn's `SelectLabel` is the group heading, so it maps to\n * `GroupLabel`. Base UI's control-level `Select.Label` is intentionally not\n * re-exported — pair the trigger with the kit's own `Label` component instead.\n * `Label` is a separate registry item (`registry/items/label.json`) and is\n * not a `registryDependency` of `select`, so install it explicitly:\n * `npx shadcn@latest add <registry-url>/r/label.json`.\n *\n * **Labeling recipe.** Give the `Label` an `id` and the `SelectTrigger` its\n * own `id`, then set `aria-labelledby=\"<label-id> <trigger-id>\"` on the\n * trigger (referencing *both*). Pointing only at the external label drops\n * the chosen value from the accessible name; adding the trigger's own id\n * folds the `SelectValue` text (the current selection) back in, so a screen\n * reader announces \"<label>, <selected value>\". `htmlFor`/`for` can't be\n * used here — the trigger renders a `<button>`, not a labelable form field —\n * which is why the association is `aria-labelledby`, not a wrapping/`for`\n * `<label>`. The Select preview page uses this pattern on every example.\n * 2. **`SelectValue` shows the raw value unless `<Select>` gets an `items` prop.**\n * Unlike Radix (where `SelectValue` mirrors the selected `SelectItem`'s text),\n * Base UI's `Select.Value` renders the raw `value` by default. To display a\n * friendly label, either pass `items` to `<Select>` (Root) — e.g.\n * `items={[{ value: \"apple\", label: \"Apple\" }]}` — or pass a render function\n * as `SelectValue`'s child: `<SelectValue>{(v) => labels[v]}</SelectValue>`.\n * This is Base UI's model; the wrapper stays thin and does not paper over it.\n * 3. **`SelectTrigger` sizes follow the kit's Button scale, not shadcn's.**\n * shadcn ships `sm`/`default` at h-8/h-9; this kit maps Fluent's field sizes\n * onto the Button height scale instead — `sm` 24px (`h-6`), `default` 32px\n * (`h-8`, matches `Input`), `lg` 40px (`h-10`) — surfaced as `data-size`.\n * 4. **`SelectContent` positions below the trigger (`alignItemWithTrigger=false`).**\n * Base UI defaults to overlapping the trigger so the selected item's text lines\n * up with the value (native-select behavior). A shadcn-style dropdown that opens\n * beneath the field is the expected Fluent flyout, so this is forced off; the\n * scroll arrows/`data-[side=none]` overlap edge cases go away with it.\n *\n * ## `\"use client\"` — required (integration-pass correction)\n * Every Base UI Select part module does carry its own `'use client'`\n * directive, so on that basis alone this wrapper could stay server-renderable\n * (same reasoning as `avatar.tsx`). But `CheckmarkRegular`/`ChevronDownRegular`/\n * `ChevronUpRegular` from `@fluentui/react-icons` break that: the package's\n * shared icon-sizing module (`createFluentIcon.styles.js`) calls `@griffel/\n * react`'s `__styles()` at module scope *without* its own `'use client'`\n * directive, even though `__styles` itself is client-only. Rendering any of\n * these icons from a Server Component pulls that module into the server's\n * RSC graph, and `next build` (Turbopack) fails collecting page data with\n * \"Attempted to call __styles() from the server but __styles is on the\n * client\" — reproduced against `@fluentui/react-icons@2.0.333` /\n * `@griffel/react@1.7.5`, and confirmed to affect every route that shares\n * Turbopack's chunk for these icons, not just this one. `\"use client\"` here\n * keeps the icon imports inside a client boundary so they're never evaluated\n * on the server. `checkbox.tsx` carries the same fix for the same reason.\n *\n * ## data-slot note\n * `Select` (Root) renders no DOM element of its own and its Base UI props type\n * is strict (no `data-*` passthrough), so it carries no `data-slot`. Every part\n * that renders an element does — `select-trigger`, `select-content`,\n * `select-item`, etc. — which is what tests/consumers hook onto.\n */\n\nfunction Select<Value, Multiple extends boolean | undefined = false>(\n props: SelectPrimitive.Root.Props<Value, Multiple>\n) {\n return <SelectPrimitive.Root {...props} />;\n}\n\nfunction SelectGroup({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Group>) {\n return (\n <SelectPrimitive.Group\n data-slot=\"select-group\"\n className={cn(className)}\n {...props}\n />\n );\n}\n\nfunction SelectValue({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Value>) {\n return (\n <SelectPrimitive.Value\n data-slot=\"select-value\"\n className={cn(className)}\n {...props}\n />\n );\n}\n\n/**\n * Trigger — Fluent field look, styled to match `Input` (h-8, rounded-md,\n * border-input, px-3, text-sm, flat at rest). Focus uses the sanctioned\n * per-field deviation from conventions §4: a 2px brand underline painted with\n * an inset box-shadow (no reflow) plus `border-primary`, and the `aria-invalid`\n * treatment declared *after* focus so an invalid+focused field shows the\n * destructive accent. The chevron is appended via `Select.Icon`; the trigger's\n * `[&_svg]` rules size it (`size-4`) and mute it (`text-muted-foreground`).\n */\nfunction SelectTrigger({\n className,\n children,\n size = \"default\",\n ...props\n}: ComponentProps<typeof SelectPrimitive.Trigger> & {\n /** Fluent field sizes on the Button height scale — see divergence 3. */\n size?: \"sm\" | \"default\" | \"lg\";\n}) {\n return (\n <SelectPrimitive.Trigger\n data-slot=\"select-trigger\"\n data-size={size}\n className={cn(\n // layout — Fluent field on the Button height scale (divergence 3);\n // default is the 32px medium that matches Input. Resting bottom\n // edge uses the darker NeutralStrokeAccessible (#616161) accent while\n // the other sides stay border-input; focus (border-primary + inset\n // underline) and aria-invalid (border-destructive) both override it.\n \"flex w-full items-center justify-between gap-2 rounded-md border border-input border-b-stroke-accessible bg-background py-1 whitespace-nowrap\",\n size === \"sm\" && \"h-6 px-2 text-xs\",\n size === \"default\" && \"h-8 px-3 text-sm\",\n size === \"lg\" && \"h-10 px-4 text-base\",\n // placeholder text muted (Base UI sets data-placeholder when no value)\n \"data-[placeholder]:text-muted-foreground\",\n // keep a long value on one line, left-aligned\n \"*:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:text-left\",\n // icon defaults — chevron sized + muted unless overridden\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground\",\n // motion — color + box-shadow so the focus accent animates (§4)\n \"outline-none transition-[color,box-shadow] duration-fast ease-ease\",\n // disabled — opacity read; Base UI emits both `disabled` + `data-disabled`\n \"disabled:pointer-events-none disabled:opacity-50 data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n // focus — Fluent bottom brand accent via inset box-shadow, no reflow (§4)\n \"focus-visible:border-primary focus-visible:shadow-[inset_0_-2px_0_0_var(--brand-80)] dark:focus-visible:shadow-[inset_0_-2px_0_0_var(--brand-100)]\",\n // invalid — shadcn aria-invalid treatment; after focus so it wins the border\n \"aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40\",\n \"aria-invalid:focus-visible:shadow-[inset_0_-2px_0_0_var(--destructive)]\",\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon>\n <ChevronDownRegular />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n );\n}\n\n/**\n * Content — the floating flyout: `Portal` → `Positioner` → `Popup`, with the\n * items in a scrollable `List` between hover-scroll arrows. Surface is\n * `bg-popover` + `border` + `shadow-16` (Fluent flyout elevation, conventions\n * §3.6), `rounded-md`, `min-w` matched to the trigger via Base UI's\n * `--anchor-width`. A subtle scale+fade open/close animation rides Base UI's\n * `data-starting-style`/`data-ending-style` hooks with token durations/easings.\n */\nfunction SelectContent({\n className,\n children,\n sideOffset = 4,\n align = \"start\",\n side = \"bottom\",\n ...props\n}: ComponentProps<typeof SelectPrimitive.Popup> &\n Pick<\n ComponentProps<typeof SelectPrimitive.Positioner>,\n \"side\" | \"align\" | \"sideOffset\"\n >) {\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Positioner\n data-slot=\"select-positioner\"\n sideOffset={sideOffset}\n align={align}\n side={side}\n alignItemWithTrigger={false}\n className=\"z-50 outline-none\"\n >\n <SelectPrimitive.Popup\n data-slot=\"select-content\"\n className={cn(\n \"relative min-w-[var(--anchor-width)] origin-[var(--transform-origin)] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-16 outline-none\",\n // motion — subtle scale + fade on open (enter) / close (exit)\n \"transition-[opacity,scale] duration-fast ease-decelerate-mid\",\n \"data-starting-style:scale-95 data-starting-style:opacity-0\",\n \"data-ending-style:scale-95 data-ending-style:opacity-0 data-ending-style:ease-accelerate-mid\",\n className\n )}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.List\n data-slot=\"select-list\"\n className=\"max-h-[var(--available-height)] overflow-y-auto overscroll-contain p-1\"\n >\n {children}\n </SelectPrimitive.List>\n <SelectScrollDownButton />\n </SelectPrimitive.Popup>\n </SelectPrimitive.Positioner>\n </SelectPrimitive.Portal>\n );\n}\n\n/**\n * Label — a heading for a `SelectGroup` (Base UI `Select.GroupLabel`), *not* a\n * control-level field label (divergence 1). Small muted caption, Fluent style.\n */\nfunction SelectLabel({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.GroupLabel>) {\n return (\n <SelectPrimitive.GroupLabel\n data-slot=\"select-label\"\n className={cn(\n \"px-2 py-1.5 text-xs font-medium text-muted-foreground select-none\",\n className\n )}\n {...props}\n />\n );\n}\n\n/**\n * Item — one option. Text via `ItemText`; the selected-state check\n * (`CheckmarkRegular`) is absolutely positioned on the right (shadcn placement)\n * inside `ItemIndicator`, which Base UI only mounts for the selected item.\n * `rounded-md` (4px) matches Fluent's `Corner-radius/List/Default`. Highlight\n * (keyboard focus or hover) uses `data-highlighted` → `bg-accent`\n * (`#f0f0f0`) `text-accent-foreground`; Fluent's list-hover token is `#f5f5f5`\n * (one grey step lighter), but the kit keeps `--accent` for token consistency\n * with every other hover surface — the difference is imperceptible on a 32px\n * row. Disabled items are muted + inert.\n */\nfunction SelectItem({\n className,\n children,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Item>) {\n return (\n <SelectPrimitive.Item\n data-slot=\"select-item\"\n className={cn(\n // layout — Fluent 32px row, 4px list radius, px-2 with room on the\n // right for the check\n \"relative flex h-8 w-full cursor-default items-center rounded-md pr-8 pl-2 text-sm outline-none select-none\",\n // rest text is NeutralForeground2, darkening to accent-foreground on\n // highlight (Figma validation: Fluent list rows rest at #424242)\n \"text-foreground-2 data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground\",\n // disabled item — muted + non-interactive\n \"data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n // icons that a consumer puts inside the item text\n \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n className\n )}\n {...props}\n >\n <span className=\"absolute right-2 flex size-4 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <CheckmarkRegular className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n );\n}\n\nfunction SelectSeparator({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.Separator>) {\n return (\n <SelectPrimitive.Separator\n data-slot=\"select-separator\"\n className={cn(\n \"pointer-events-none -mx-1 my-1 h-px bg-border\",\n className\n )}\n {...props}\n />\n );\n}\n\n/**\n * ScrollUpButton / ScrollDownButton — Base UI hover-scroll arrows that Base UI\n * only renders when the list overflows in that direction. Rendered as siblings\n * of the `List` inside `SelectContent`, so consumers don't place them manually\n * (shadcn parity — the export exists for API compatibility / manual use).\n */\nfunction SelectScrollUpButton({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {\n return (\n <SelectPrimitive.ScrollUpArrow\n data-slot=\"select-scroll-up-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1 text-muted-foreground\",\n className\n )}\n {...props}\n >\n <ChevronUpRegular className=\"size-4\" />\n </SelectPrimitive.ScrollUpArrow>\n );\n}\n\nfunction SelectScrollDownButton({\n className,\n ...props\n}: ComponentProps<typeof SelectPrimitive.ScrollDownArrow>) {\n return (\n <SelectPrimitive.ScrollDownArrow\n data-slot=\"select-scroll-down-button\"\n className={cn(\n \"flex cursor-default items-center justify-center py-1 text-muted-foreground\",\n className\n )}\n {...props}\n >\n <ChevronDownRegular className=\"size-4\" />\n </SelectPrimitive.ScrollDownArrow>\n );\n}\n\nexport {\n Select,\n SelectGroup,\n SelectValue,\n SelectTrigger,\n SelectContent,\n SelectLabel,\n SelectItem,\n SelectSeparator,\n SelectScrollUpButton,\n SelectScrollDownButton,\n};\n"],"mappings":"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","names":[]}