@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.
- package/LICENSE +21 -0
- package/README.md +69 -0
- package/dist/components/ui/accordion.d.ts +133 -0
- package/dist/components/ui/accordion.js +80 -0
- package/dist/components/ui/accordion.js.map +1 -0
- package/dist/components/ui/alert.d.ts +106 -0
- package/dist/components/ui/alert.js +73 -0
- package/dist/components/ui/alert.js.map +1 -0
- package/dist/components/ui/avatar.d.ts +42 -0
- package/dist/components/ui/avatar.js +55 -0
- package/dist/components/ui/avatar.js.map +1 -0
- package/dist/components/ui/badge.d.ts +36 -0
- package/dist/components/ui/badge.js +81 -0
- package/dist/components/ui/badge.js.map +1 -0
- package/dist/components/ui/breadcrumb.d.ts +53 -0
- package/dist/components/ui/breadcrumb.js +149 -0
- package/dist/components/ui/breadcrumb.js.map +1 -0
- package/dist/components/ui/button.d.ts +24 -0
- package/dist/components/ui/button.js +86 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/components/ui/card.d.ts +51 -0
- package/dist/components/ui/card.js +97 -0
- package/dist/components/ui/card.js.map +1 -0
- package/dist/components/ui/checkbox.d.ts +101 -0
- package/dist/components/ui/checkbox.js +57 -0
- package/dist/components/ui/checkbox.js.map +1 -0
- package/dist/components/ui/combobox.d.ts +212 -0
- package/dist/components/ui/combobox.js +236 -0
- package/dist/components/ui/combobox.js.map +1 -0
- package/dist/components/ui/command.d.ts +187 -0
- package/dist/components/ui/command.js +225 -0
- package/dist/components/ui/command.js.map +1 -0
- package/dist/components/ui/dialog.d.ts +117 -0
- package/dist/components/ui/dialog.js +165 -0
- package/dist/components/ui/dialog.js.map +1 -0
- package/dist/components/ui/dropdown-menu.d.ts +155 -0
- package/dist/components/ui/dropdown-menu.js +295 -0
- package/dist/components/ui/dropdown-menu.js.map +1 -0
- package/dist/components/ui/input.d.ts +44 -0
- package/dist/components/ui/input.js +43 -0
- package/dist/components/ui/input.js.map +1 -0
- package/dist/components/ui/label.d.ts +39 -0
- package/dist/components/ui/label.js +30 -0
- package/dist/components/ui/label.js.map +1 -0
- package/dist/components/ui/link.d.ts +62 -0
- package/dist/components/ui/link.js +61 -0
- package/dist/components/ui/link.js.map +1 -0
- package/dist/components/ui/multi-select.d.ts +115 -0
- package/dist/components/ui/multi-select.js +133 -0
- package/dist/components/ui/multi-select.js.map +1 -0
- package/dist/components/ui/pagination.d.ts +46 -0
- package/dist/components/ui/pagination.js +164 -0
- package/dist/components/ui/pagination.js.map +1 -0
- package/dist/components/ui/popover.d.ts +117 -0
- package/dist/components/ui/popover.js +62 -0
- package/dist/components/ui/popover.js.map +1 -0
- package/dist/components/ui/progress.d.ts +98 -0
- package/dist/components/ui/progress.js +67 -0
- package/dist/components/ui/progress.js.map +1 -0
- package/dist/components/ui/radio-group.d.ts +94 -0
- package/dist/components/ui/radio-group.js +65 -0
- package/dist/components/ui/radio-group.js.map +1 -0
- package/dist/components/ui/select.d.ts +145 -0
- package/dist/components/ui/select.js +240 -0
- package/dist/components/ui/select.js.map +1 -0
- package/dist/components/ui/separator.d.ts +43 -0
- package/dist/components/ui/separator.js +27 -0
- package/dist/components/ui/separator.js.map +1 -0
- package/dist/components/ui/skeleton.d.ts +81 -0
- package/dist/components/ui/skeleton.js +24 -0
- package/dist/components/ui/skeleton.js.map +1 -0
- package/dist/components/ui/spinner.d.ts +56 -0
- package/dist/components/ui/spinner.js +83 -0
- package/dist/components/ui/spinner.js.map +1 -0
- package/dist/components/ui/switch.d.ts +60 -0
- package/dist/components/ui/switch.js +63 -0
- package/dist/components/ui/switch.js.map +1 -0
- package/dist/components/ui/tabs.d.ts +107 -0
- package/dist/components/ui/tabs.js +102 -0
- package/dist/components/ui/tabs.js.map +1 -0
- package/dist/components/ui/textarea.d.ts +28 -0
- package/dist/components/ui/textarea.js +36 -0
- package/dist/components/ui/textarea.js.map +1 -0
- package/dist/components/ui/toast.d.ts +185 -0
- package/dist/components/ui/toast.js +181 -0
- package/dist/components/ui/toast.js.map +1 -0
- package/dist/components/ui/tooltip.d.ts +115 -0
- package/dist/components/ui/tooltip.js +72 -0
- package/dist/components/ui/tooltip.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.js +284 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/utils.d.ts +9 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/utils.js.map +1 -0
- package/package.json +77 -0
- package/src/styles/tokens.css +596 -0
- package/src/styles/tokens.test.ts +216 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/multi-select.tsx"],"sourcesContent":["\"use client\";\n\nimport { Combobox as ComboboxPrimitive } from \"@base-ui/react/combobox\";\nimport { DismissRegular } from \"@fluentui/react-icons\";\nimport type { ComponentProps, ReactNode } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\nimport {\n ComboboxContent,\n ComboboxEmpty,\n ComboboxGroup,\n ComboboxItem,\n ComboboxLabel,\n ComboboxList,\n ComboboxSeparator,\n} from \"./combobox\";\n\n/**\n * Multi Select — Fluent 2-styled multiple-selection combobox with a chips field.\n *\n * Built DIRECTLY on the kit's `Combobox` reference (`./combobox`). Base UI's\n * `Combobox.Root` already carries the multiple-selection engine — passing\n * `multiple` turns `value`/`onValueChange` into arrays and unlocks the chips\n * parts (`Combobox.Chips`/`Chip`/`ChipRemove`). This file's only NEW surface is\n * the **chips field** (`MultiSelectInput` + `MultiSelectChip`); everything on the\n * popup side is re-exported from `combobox.tsx` unchanged.\n *\n * ## Reuse model — what is new vs a pass-through\n * | Exported (kit name) | Source |\n * | --------------------- | --------------------------------------------------- |\n * | `MultiSelect` | `Combobox.Root` with `multiple` defaulted to `true` |\n * | `MultiSelectInput` | **NEW** chips field: `Combobox.Chips` (field chrome) wrapping a `Combobox.Value` chip flow + `Combobox.Input` |\n * | `MultiSelectChip` | **NEW** one selected-value chip: `Combobox.Chip` + `Combobox.ChipRemove` |\n * | `MultiSelectContent` | pass-through re-export of `ComboboxContent` |\n * | `MultiSelectList` | pass-through re-export of `ComboboxList` |\n * | `MultiSelectItem` | pass-through re-export of `ComboboxItem` |\n * | `MultiSelectGroup` | pass-through re-export of `ComboboxGroup` |\n * | `MultiSelectLabel` | pass-through re-export of `ComboboxLabel` |\n * | `MultiSelectEmpty` | pass-through re-export of `ComboboxEmpty` |\n * | `MultiSelectSeparator`| pass-through re-export of `ComboboxSeparator` |\n *\n * ## Divergences (all deliberate)\n * 1. **The popup parts are literal re-exports, so they keep their\n * `data-slot=\"combobox-…\"` values** — they ARE the Combobox parts, aliased for\n * a coherent `MultiSelect*` call site. Only the two parts this file owns get\n * `data-slot=\"multi-select-…\"` (`multi-select-input-wrapper`,\n * `multi-select-input`, `multi-select-chip`, `multi-select-chip-remove`). This\n * avoids forking identical popup markup and keeps the registry item lean\n * (`registryDependencies: [\"utils\", \"combobox\"]`, like `pagination` depends on\n * `button`). Selected items still render the right-side `CheckmarkRegular` from\n * `ComboboxItem` — in `multiple` mode Base UI mounts the indicator for every\n * selected option.\n * 2. **`MultiSelectInput` is NOT `ComboboxInput`.** `ComboboxInput` is the\n * single-line surface (h-8, one `<input>` + Clear + chevron). The chips field\n * is a wrapping token field: `min-h-8` + `flex-wrap` + `gap-1` + `py-1` so\n * chips reflow to multiple rows, with the text `<input>` sitting inline at the\n * end. It reuses `combobox-input-wrapper`'s field-chrome recipe verbatim — the\n * `border-input`/`border-b-stroke-accessible` rest edge, the\n * `has-[input:focus-visible]` bottom brand accent, the\n * `has-[input[aria-invalid]]` destructive form, the `has-[input:disabled]`\n * opacity — because focus/invalid/disabled all still land on the inner input.\n * 3. **No baked-in Clear or chevron `Trigger`.** The single-select field bakes a\n * `Combobox.Clear` + chevron in; a tags picker's affordances are the chips\n * themselves (each removable) and Backspace-clears-last, so the chips field\n * stays chrome-light. Open with focus + type or `ArrowDown`. Consumers who want\n * a clear-all/chevron can compose `@base-ui/react/combobox`'s `Clear`/`Trigger`\n * directly.\n * 4. **Chip visuals are Fluent Tag (Small, Filled), Badge-adjacent.** A chip is\n * `bg-secondary` `text-foreground-2`, `rounded-md`, `h-6`, `px-1.5`, `text-xs` — the\n * neutral filled look of `Badge variant=\"secondary\"` but sized for an inline\n * token (Badge is a static 20px caption chip; a removable token needs the extra\n * height + a trailing dismiss target). The remove button hover is\n * `text-destructive` to signal \"this deletes\", paired with the `DismissRegular`\n * glyph (not color alone — conventions §5).\n *\n * ## Chips wiring — what Base UI provides vs what is wired here\n * The chip flow is rendered from `Combobox.Value`'s render-function child, which\n * receives the live `selectedValue` array and re-renders on every selection — so\n * an UNCONTROLLED `MultiSelect` (the preview / RSC case) shows chips without any\n * consumer `useState`. Base UI owns the keyboard model for free:\n * - **Backspace on an empty input removes the last chip** (Base UI `ComboboxInput`).\n * - **ArrowLeft/Right move between chips; Backspace/Delete on a focused chip\n * removes it** (Base UI `ComboboxChip`).\n * - **Clicking a `ChipRemove` deselects that value and refocuses the input**\n * (Base UI `ComboboxChipRemove`).\n * - **The popup stays OPEN after selecting** in `multiple` mode (Base UI default),\n * so several tags can be picked in a row.\n * This file only styles those parts and maps each value to a chip.\n *\n * ## `\"use client\"` — required\n * `@fluentui/react-icons` forces it (the `DismissRegular` import): the package's\n * shared icon-sizing module calls `@griffel/react`'s `__styles()` at module scope\n * without its own directive, so importing an icon into a Server Component breaks\n * `next build` (conventions §9; same fix as `select.tsx`/`combobox.tsx`).\n */\n\nfunction MultiSelect<Value, Multiple extends boolean | undefined = true>({\n multiple,\n ...props\n}: ComboboxPrimitive.Root.Props<Value, Multiple>) {\n return (\n <ComboboxPrimitive.Root\n multiple={(multiple ?? true) as Multiple}\n {...props}\n />\n );\n}\n\n/**\n * Chip — one selected value, rendered from `MultiSelectInput`'s chip flow (or\n * composed by a caller who passes their own render child). `Combobox.Chip` holds\n * the label; the trailing `Combobox.ChipRemove` button deselects it. Base UI maps\n * a chip to `selectedValue[index]` via its composite-list order, so chips must be\n * rendered in selection order (which `Combobox.Value`'s array is).\n */\nfunction MultiSelectChip({\n className,\n children,\n ...props\n}: ComponentProps<typeof ComboboxPrimitive.Chip>) {\n return (\n <ComboboxPrimitive.Chip\n data-slot=\"multi-select-chip\"\n className={cn(\n // Fluent Tag (Small, Filled): 24px, #f5f5f5 fill, 4px radius\n // (rounded-md), Caption-1 text in NeutralForeground2 (text-foreground-2)\n // — exact token values from Figma validation pass 3, node 9112:10360.\n \"inline-flex h-6 items-center gap-1 rounded-md bg-secondary px-1.5 text-xs text-foreground-2 select-none\",\n // highlighted (chip keyboard focus) + disabled\n \"data-[highlighted]:bg-accent data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className\n )}\n {...props}\n >\n {children}\n <ComboboxPrimitive.ChipRemove\n data-slot=\"multi-select-chip-remove\"\n aria-label=\"Remove\"\n className={cn(\n \"-mr-0.5 flex size-4 shrink-0 items-center justify-center rounded-sm text-muted-foreground outline-none\",\n // hover reads destructive — this action deletes (paired with the glyph, not color alone)\n \"transition-colors duration-fast ease-ease hover:text-destructive\",\n \"focus-visible:ring-2 focus-visible:ring-ring\",\n \"[&_svg]:pointer-events-none [&_svg]:size-3\"\n )}\n >\n <DismissRegular />\n </ComboboxPrimitive.ChipRemove>\n </ComboboxPrimitive.Chip>\n );\n}\n\n/**\n * Input — the Fluent chips field (divergence 2). `Combobox.Chips` is the\n * field-chrome container (flex-wrap token row) holding the chip flow and the\n * inline text `<input>`. `children`, when given, is a render function\n * `(value) => ReactNode` that maps each selected value to its chip content —\n * use it to look up a label for `{ value, label }` items or to style the chip.\n * With no `children`, each value is rendered as a `MultiSelectChip` showing\n * `String(value)` (the flat-string case). `className`/`ref`/`...props` forward to\n * the inner `<input>`; style the field with `wrapperClassName`.\n */\nfunction MultiSelectInput({\n className,\n wrapperClassName,\n children,\n ...props\n}: Omit<ComponentProps<typeof ComboboxPrimitive.Input>, \"children\"> & {\n wrapperClassName?: string;\n children?: (value: unknown) => ReactNode;\n}) {\n return (\n <ComboboxPrimitive.Chips\n data-slot=\"multi-select-input-wrapper\"\n className={cn(\n // layout — wrapping token field. min-h-8 (chips reflow to rows), flex-wrap,\n // gap-1, py-1. Resting bottom edge uses NeutralStrokeAccessible; the other\n // sides stay border-input. Focus + aria-invalid override it (below).\n \"flex min-h-8 w-full flex-wrap items-center gap-1 rounded-md border border-input border-b-stroke-accessible bg-background px-1.5 py-1 text-sm\",\n // motion — color + box-shadow so the focus accent animates (§4)\n \"transition-[color,box-shadow] duration-fast ease-ease\",\n // focus — Fluent bottom brand accent via inset box-shadow, no reflow (§4).\n // has-[input:focus-visible] because focus is on the inner input.\n \"has-[input:focus-visible]:border-primary has-[input:focus-visible]:shadow-[inset_0_-2px_0_0_var(--brand-80)] dark:has-[input: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 \"has-[input[aria-invalid='true']]:border-destructive has-[input[aria-invalid='true']]:ring-destructive/20 dark:has-[input[aria-invalid='true']]:ring-destructive/40\",\n \"has-[input[aria-invalid='true']:focus-visible]:shadow-[inset_0_-2px_0_0_var(--destructive)]\",\n // disabled — opacity read when the whole control is disabled\n \"has-[input:disabled]:pointer-events-none has-[input:disabled]:opacity-50\",\n wrapperClassName\n )}\n >\n <ComboboxPrimitive.Value>\n {(selected: unknown) =>\n (Array.isArray(selected) ? selected : []).map((value, index) =>\n children ? (\n children(value)\n ) : (\n <MultiSelectChip key={index}>{String(value)}</MultiSelectChip>\n )\n )\n }\n </ComboboxPrimitive.Value>\n <ComboboxPrimitive.Input\n data-slot=\"multi-select-input\"\n className={cn(\n \"h-6 min-w-16 flex-1 bg-transparent px-1 outline-none\",\n \"placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground\",\n className\n )}\n {...props}\n />\n </ComboboxPrimitive.Chips>\n );\n}\n\n// Popup-side parts are the Combobox parts, aliased for a MultiSelect* call site\n// (divergence 1 — they keep their `data-slot=\"combobox-…\"`).\nconst MultiSelectContent = ComboboxContent;\nconst MultiSelectList = ComboboxList;\nconst MultiSelectItem = ComboboxItem;\nconst MultiSelectGroup = ComboboxGroup;\nconst MultiSelectLabel = ComboboxLabel;\nconst MultiSelectEmpty = ComboboxEmpty;\nconst MultiSelectSeparator = ComboboxSeparator;\n\nexport {\n MultiSelect,\n MultiSelectInput,\n MultiSelectChip,\n MultiSelectContent,\n MultiSelectList,\n MultiSelectItem,\n MultiSelectGroup,\n MultiSelectLabel,\n MultiSelectEmpty,\n MultiSelectSeparator,\n};\n"],"mappings":";AAqGI,cAoBA,YApBA;AAnGJ,SAAS,YAAY,yBAAyB;AAC9C,SAAS,sBAAsB;AAG/B,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAiFP,SAAS,YAAgE;AAAA,EACvE;AAAA,EACA,GAAG;AACL,GAAkD;AAChD,SACE;AAAA,IAAC,kBAAkB;AAAA,IAAlB;AAAA,MACC,UAAW,YAAY;AAAA,MACtB,GAAG;AAAA;AAAA,EACN;AAEJ;AASA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkD;AAChD,SACE;AAAA,IAAC,kBAAkB;AAAA,IAAlB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA;AAAA;AAAA;AAAA,QAIT;AAAA;AAAA,QAEA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,QACD;AAAA,UAAC,kBAAkB;AAAA,UAAlB;AAAA,YACC,aAAU;AAAA,YACV,cAAW;AAAA,YACX,WAAW;AAAA,cACT;AAAA;AAAA,cAEA;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,YAEA,8BAAC,kBAAe;AAAA;AAAA,QAClB;AAAA;AAAA;AAAA,EACF;AAEJ;AAYA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAGG;AACD,SACE;AAAA,IAAC,kBAAkB;AAAA,IAAlB;AAAA,MACC,aAAU;AAAA,MACV,WAAW;AAAA;AAAA;AAAA;AAAA,QAIT;AAAA;AAAA,QAEA;AAAA;AAAA;AAAA,QAGA;AAAA;AAAA,QAEA;AAAA,QACA;AAAA;AAAA,QAEA;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,4BAAC,kBAAkB,OAAlB,EACE,WAAC,cACC,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,GAAG;AAAA,UAAI,CAAC,OAAO,UACpD,WACE,SAAS,KAAK,IAEd,oBAAC,mBAA6B,iBAAO,KAAK,KAApB,KAAsB;AAAA,QAEhD,GAEJ;AAAA,QACA;AAAA,UAAC,kBAAkB;AAAA,UAAlB;AAAA,YACC,aAAU;AAAA,YACV,WAAW;AAAA,cACT;AAAA,cACA;AAAA,cACA;AAAA,YACF;AAAA,YACC,GAAG;AAAA;AAAA,QACN;AAAA;AAAA;AAAA,EACF;AAEJ;AAIA,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB;AACxB,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AACzB,MAAM,mBAAmB;AACzB,MAAM,mBAAmB;AACzB,MAAM,uBAAuB;","names":[]}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentProps } from 'react';
|
|
3
|
+
import { VariantProps } from 'class-variance-authority';
|
|
4
|
+
import { buttonVariants } from './button.js';
|
|
5
|
+
import 'class-variance-authority/types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Pagination — Fluent 2-styled, shadcn-API pagination family.
|
|
9
|
+
*
|
|
10
|
+
* Structure matches shadcn/ui's Pagination: `Pagination` (nav landmark),
|
|
11
|
+
* `PaginationContent` (list), `PaginationItem` (list item), `PaginationLink`
|
|
12
|
+
* (page control, styled via `buttonVariants`), `PaginationPrevious` /
|
|
13
|
+
* `PaginationNext` (labeled link + chevron), and `PaginationEllipsis`
|
|
14
|
+
* (decorative truncation marker). Every part is a plain function component —
|
|
15
|
+
* there is no open/close or selection state to manage, so this stays pure
|
|
16
|
+
* markup, same as `Card`.
|
|
17
|
+
*
|
|
18
|
+
* `PaginationLink` reuses `Button`'s `buttonVariants` (outline when
|
|
19
|
+
* `isActive`, ghost otherwise) so page controls read as part of the same
|
|
20
|
+
* button system instead of a bespoke look.
|
|
21
|
+
*
|
|
22
|
+
* Divergence from shadcn: shadcn's chevrons and the ellipsis dots come from
|
|
23
|
+
* `lucide-react`. This kit uses `@fluentui/react-icons` for iconography
|
|
24
|
+
* elsewhere, but importing it forces `"use client"` onto every file that
|
|
25
|
+
* touches it (see `docs/component-conventions.md` §9 — the icon package's
|
|
26
|
+
* sizing module calls `@griffel/react`'s `__styles()` at module scope without
|
|
27
|
+
* its own `"use client"`, which breaks `next build`'s RSC graph). Pagination
|
|
28
|
+
* has no state of its own and should stay a server component, so the
|
|
29
|
+
* chevrons/dots are inline `<svg>` instead — a deliberate, documented
|
|
30
|
+
* divergence from both shadcn (lucide) and the rest of this kit (Fluent
|
|
31
|
+
* icons).
|
|
32
|
+
*
|
|
33
|
+
* Server-safe: no `"use client"`, no hooks — the React import is type-only.
|
|
34
|
+
*/
|
|
35
|
+
declare function Pagination({ className, ...props }: ComponentProps<"nav">): react.JSX.Element;
|
|
36
|
+
declare function PaginationContent({ className, ...props }: ComponentProps<"ul">): react.JSX.Element;
|
|
37
|
+
declare function PaginationItem({ ...props }: ComponentProps<"li">): react.JSX.Element;
|
|
38
|
+
type PaginationLinkProps = {
|
|
39
|
+
isActive?: boolean;
|
|
40
|
+
} & Pick<VariantProps<typeof buttonVariants>, "size"> & ComponentProps<"a">;
|
|
41
|
+
declare function PaginationLink({ className, isActive, size, ...props }: PaginationLinkProps): react.JSX.Element;
|
|
42
|
+
declare function PaginationPrevious({ className, ...props }: ComponentProps<typeof PaginationLink>): react.JSX.Element;
|
|
43
|
+
declare function PaginationNext({ className, ...props }: ComponentProps<typeof PaginationLink>): react.JSX.Element;
|
|
44
|
+
declare function PaginationEllipsis({ className, ...props }: ComponentProps<"span">): react.JSX.Element;
|
|
45
|
+
|
|
46
|
+
export { Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../../lib/utils.js";
|
|
3
|
+
import { buttonVariants } from "./button.js";
|
|
4
|
+
function Pagination({ className, ...props }) {
|
|
5
|
+
return /* @__PURE__ */ jsx(
|
|
6
|
+
"nav",
|
|
7
|
+
{
|
|
8
|
+
role: "navigation",
|
|
9
|
+
"aria-label": "pagination",
|
|
10
|
+
"data-slot": "pagination",
|
|
11
|
+
className: cn("mx-auto flex w-full justify-center", className),
|
|
12
|
+
...props
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
function PaginationContent({ className, ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsx(
|
|
18
|
+
"ul",
|
|
19
|
+
{
|
|
20
|
+
"data-slot": "pagination-content",
|
|
21
|
+
className: cn("flex flex-row items-center gap-1", className),
|
|
22
|
+
...props
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
function PaginationItem({ ...props }) {
|
|
27
|
+
return /* @__PURE__ */ jsx("li", { "data-slot": "pagination-item", ...props });
|
|
28
|
+
}
|
|
29
|
+
function PaginationLink({
|
|
30
|
+
className,
|
|
31
|
+
isActive = false,
|
|
32
|
+
size = "icon",
|
|
33
|
+
...props
|
|
34
|
+
}) {
|
|
35
|
+
return /* @__PURE__ */ jsx(
|
|
36
|
+
"a",
|
|
37
|
+
{
|
|
38
|
+
"aria-current": isActive ? "page" : void 0,
|
|
39
|
+
"data-slot": "pagination-link",
|
|
40
|
+
"data-active": isActive,
|
|
41
|
+
className: cn(
|
|
42
|
+
buttonVariants({
|
|
43
|
+
variant: isActive ? "outline" : "ghost",
|
|
44
|
+
size
|
|
45
|
+
}),
|
|
46
|
+
className
|
|
47
|
+
),
|
|
48
|
+
...props
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
function PaginationPrevious({
|
|
53
|
+
className,
|
|
54
|
+
...props
|
|
55
|
+
}) {
|
|
56
|
+
return /* @__PURE__ */ jsxs(
|
|
57
|
+
PaginationLink,
|
|
58
|
+
{
|
|
59
|
+
"aria-label": "Go to previous page",
|
|
60
|
+
size: "default",
|
|
61
|
+
className: cn("gap-1 px-2.5 sm:pl-2.5", className),
|
|
62
|
+
...props,
|
|
63
|
+
children: [
|
|
64
|
+
/* @__PURE__ */ jsx(
|
|
65
|
+
"svg",
|
|
66
|
+
{
|
|
67
|
+
viewBox: "0 0 20 20",
|
|
68
|
+
fill: "none",
|
|
69
|
+
"aria-hidden": "true",
|
|
70
|
+
className: "size-4",
|
|
71
|
+
children: /* @__PURE__ */ jsx(
|
|
72
|
+
"path",
|
|
73
|
+
{
|
|
74
|
+
d: "M12.5 5L7.5 10L12.5 15",
|
|
75
|
+
stroke: "currentColor",
|
|
76
|
+
strokeWidth: "1.5",
|
|
77
|
+
strokeLinecap: "round",
|
|
78
|
+
strokeLinejoin: "round"
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
),
|
|
83
|
+
/* @__PURE__ */ jsx("span", { className: "hidden sm:block", children: "Previous" })
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
function PaginationNext({
|
|
89
|
+
className,
|
|
90
|
+
...props
|
|
91
|
+
}) {
|
|
92
|
+
return /* @__PURE__ */ jsxs(
|
|
93
|
+
PaginationLink,
|
|
94
|
+
{
|
|
95
|
+
"aria-label": "Go to next page",
|
|
96
|
+
size: "default",
|
|
97
|
+
className: cn("gap-1 px-2.5 sm:pr-2.5", className),
|
|
98
|
+
...props,
|
|
99
|
+
children: [
|
|
100
|
+
/* @__PURE__ */ jsx("span", { className: "hidden sm:block", children: "Next" }),
|
|
101
|
+
/* @__PURE__ */ jsx(
|
|
102
|
+
"svg",
|
|
103
|
+
{
|
|
104
|
+
viewBox: "0 0 20 20",
|
|
105
|
+
fill: "none",
|
|
106
|
+
"aria-hidden": "true",
|
|
107
|
+
className: "size-4",
|
|
108
|
+
children: /* @__PURE__ */ jsx(
|
|
109
|
+
"path",
|
|
110
|
+
{
|
|
111
|
+
d: "M7.5 5L12.5 10L7.5 15",
|
|
112
|
+
stroke: "currentColor",
|
|
113
|
+
strokeWidth: "1.5",
|
|
114
|
+
strokeLinecap: "round",
|
|
115
|
+
strokeLinejoin: "round"
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
)
|
|
120
|
+
]
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
function PaginationEllipsis({
|
|
125
|
+
className,
|
|
126
|
+
...props
|
|
127
|
+
}) {
|
|
128
|
+
return /* @__PURE__ */ jsxs(
|
|
129
|
+
"span",
|
|
130
|
+
{
|
|
131
|
+
"aria-hidden": "true",
|
|
132
|
+
"data-slot": "pagination-ellipsis",
|
|
133
|
+
className: cn("flex size-8 items-center justify-center", className),
|
|
134
|
+
...props,
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ jsxs(
|
|
137
|
+
"svg",
|
|
138
|
+
{
|
|
139
|
+
viewBox: "0 0 20 20",
|
|
140
|
+
fill: "none",
|
|
141
|
+
"aria-hidden": "true",
|
|
142
|
+
className: "size-4",
|
|
143
|
+
children: [
|
|
144
|
+
/* @__PURE__ */ jsx("circle", { cx: "4", cy: "10", r: "1.25", fill: "currentColor" }),
|
|
145
|
+
/* @__PURE__ */ jsx("circle", { cx: "10", cy: "10", r: "1.25", fill: "currentColor" }),
|
|
146
|
+
/* @__PURE__ */ jsx("circle", { cx: "16", cy: "10", r: "1.25", fill: "currentColor" })
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
),
|
|
150
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: "More pages" })
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
export {
|
|
156
|
+
Pagination,
|
|
157
|
+
PaginationContent,
|
|
158
|
+
PaginationEllipsis,
|
|
159
|
+
PaginationItem,
|
|
160
|
+
PaginationLink,
|
|
161
|
+
PaginationNext,
|
|
162
|
+
PaginationPrevious
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=pagination.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/pagination.tsx"],"sourcesContent":["import type { VariantProps } from \"class-variance-authority\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\nimport { buttonVariants } from \"./button\";\n\n/**\n * Pagination — Fluent 2-styled, shadcn-API pagination family.\n *\n * Structure matches shadcn/ui's Pagination: `Pagination` (nav landmark),\n * `PaginationContent` (list), `PaginationItem` (list item), `PaginationLink`\n * (page control, styled via `buttonVariants`), `PaginationPrevious` /\n * `PaginationNext` (labeled link + chevron), and `PaginationEllipsis`\n * (decorative truncation marker). Every part is a plain function component —\n * there is no open/close or selection state to manage, so this stays pure\n * markup, same as `Card`.\n *\n * `PaginationLink` reuses `Button`'s `buttonVariants` (outline when\n * `isActive`, ghost otherwise) so page controls read as part of the same\n * button system instead of a bespoke look.\n *\n * Divergence from shadcn: shadcn's chevrons and the ellipsis dots come from\n * `lucide-react`. This kit uses `@fluentui/react-icons` for iconography\n * elsewhere, but importing it forces `\"use client\"` onto every file that\n * touches it (see `docs/component-conventions.md` §9 — the icon package's\n * sizing module calls `@griffel/react`'s `__styles()` at module scope without\n * its own `\"use client\"`, which breaks `next build`'s RSC graph). Pagination\n * has no state of its own and should stay a server component, so the\n * chevrons/dots are inline `<svg>` instead — a deliberate, documented\n * divergence from both shadcn (lucide) and the rest of this kit (Fluent\n * icons).\n *\n * Server-safe: no `\"use client\"`, no hooks — the React import is type-only.\n */\n\nfunction Pagination({ className, ...props }: ComponentProps<\"nav\">) {\n return (\n <nav\n role=\"navigation\"\n aria-label=\"pagination\"\n data-slot=\"pagination\"\n className={cn(\"mx-auto flex w-full justify-center\", className)}\n {...props}\n />\n );\n}\n\nfunction PaginationContent({ className, ...props }: ComponentProps<\"ul\">) {\n return (\n <ul\n data-slot=\"pagination-content\"\n className={cn(\"flex flex-row items-center gap-1\", className)}\n {...props}\n />\n );\n}\n\nfunction PaginationItem({ ...props }: ComponentProps<\"li\">) {\n return <li data-slot=\"pagination-item\" {...props} />;\n}\n\ntype PaginationLinkProps = {\n isActive?: boolean;\n} & Pick<VariantProps<typeof buttonVariants>, \"size\"> &\n ComponentProps<\"a\">;\n\nfunction PaginationLink({\n className,\n isActive = false,\n size = \"icon\",\n ...props\n}: PaginationLinkProps) {\n return (\n <a\n aria-current={isActive ? \"page\" : undefined}\n data-slot=\"pagination-link\"\n data-active={isActive}\n className={cn(\n buttonVariants({\n variant: isActive ? \"outline\" : \"ghost\",\n size,\n }),\n className\n )}\n {...props}\n />\n );\n}\n\nfunction PaginationPrevious({\n className,\n ...props\n}: ComponentProps<typeof PaginationLink>) {\n return (\n <PaginationLink\n aria-label=\"Go to previous page\"\n size=\"default\"\n className={cn(\"gap-1 px-2.5 sm:pl-2.5\", className)}\n {...props}\n >\n <svg\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4\"\n >\n <path\n d=\"M12.5 5L7.5 10L12.5 15\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n <span className=\"hidden sm:block\">Previous</span>\n </PaginationLink>\n );\n}\n\nfunction PaginationNext({\n className,\n ...props\n}: ComponentProps<typeof PaginationLink>) {\n return (\n <PaginationLink\n aria-label=\"Go to next page\"\n size=\"default\"\n className={cn(\"gap-1 px-2.5 sm:pr-2.5\", className)}\n {...props}\n >\n <span className=\"hidden sm:block\">Next</span>\n <svg\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4\"\n >\n <path\n d=\"M7.5 5L12.5 10L7.5 15\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </PaginationLink>\n );\n}\n\nfunction PaginationEllipsis({\n className,\n ...props\n}: ComponentProps<\"span\">) {\n return (\n <span\n aria-hidden=\"true\"\n data-slot=\"pagination-ellipsis\"\n className={cn(\"flex size-8 items-center justify-center\", className)}\n {...props}\n >\n <svg\n viewBox=\"0 0 20 20\"\n fill=\"none\"\n aria-hidden=\"true\"\n className=\"size-4\"\n >\n <circle cx=\"4\" cy=\"10\" r=\"1.25\" fill=\"currentColor\" />\n <circle cx=\"10\" cy=\"10\" r=\"1.25\" fill=\"currentColor\" />\n <circle cx=\"16\" cy=\"10\" r=\"1.25\" fill=\"currentColor\" />\n </svg>\n <span className=\"sr-only\">More pages</span>\n </span>\n );\n}\n\nexport {\n Pagination,\n PaginationContent,\n PaginationItem,\n PaginationLink,\n PaginationPrevious,\n PaginationNext,\n PaginationEllipsis,\n};\n"],"mappings":"AAqCI,cAyDA,YAzDA;AAlCJ,SAAS,UAAU;AACnB,SAAS,sBAAsB;AA+B/B,SAAS,WAAW,EAAE,WAAW,GAAG,MAAM,GAA0B;AAClE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAW;AAAA,MACX,aAAU;AAAA,MACV,WAAW,GAAG,sCAAsC,SAAS;AAAA,MAC5D,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,kBAAkB,EAAE,WAAW,GAAG,MAAM,GAAyB;AACxE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,oCAAoC,SAAS;AAAA,MAC1D,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,eAAe,EAAE,GAAG,MAAM,GAAyB;AAC1D,SAAO,oBAAC,QAAG,aAAU,mBAAmB,GAAG,OAAO;AACpD;AAOA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA,WAAW;AAAA,EACX,OAAO;AAAA,EACP,GAAG;AACL,GAAwB;AACtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,gBAAc,WAAW,SAAS;AAAA,MAClC,aAAU;AAAA,MACV,eAAa;AAAA,MACb,WAAW;AAAA,QACT,eAAe;AAAA,UACb,SAAS,WAAW,YAAY;AAAA,UAChC;AAAA,QACF,CAAC;AAAA,QACD;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA0C;AACxC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAW;AAAA,MACX,MAAK;AAAA,MACL,WAAW,GAAG,0BAA0B,SAAS;AAAA,MAChD,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,eAAY;AAAA,YACZ,WAAU;AAAA,YAEV;AAAA,cAAC;AAAA;AAAA,gBACC,GAAE;AAAA,gBACF,QAAO;AAAA,gBACP,aAAY;AAAA,gBACZ,eAAc;AAAA,gBACd,gBAAe;AAAA;AAAA,YACjB;AAAA;AAAA,QACF;AAAA,QACA,oBAAC,UAAK,WAAU,mBAAkB,sBAAQ;AAAA;AAAA;AAAA,EAC5C;AAEJ;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA,GAAG;AACL,GAA0C;AACxC,SACE;AAAA,IAAC;AAAA;AAAA,MACC,cAAW;AAAA,MACX,MAAK;AAAA,MACL,WAAW,GAAG,0BAA0B,SAAS;AAAA,MAChD,GAAG;AAAA,MAEJ;AAAA,4BAAC,UAAK,WAAU,mBAAkB,kBAAI;AAAA,QACtC;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,eAAY;AAAA,YACZ,WAAU;AAAA,YAEV;AAAA,cAAC;AAAA;AAAA,gBACC,GAAE;AAAA,gBACF,QAAO;AAAA,gBACP,aAAY;AAAA,gBACZ,eAAc;AAAA,gBACd,gBAAe;AAAA;AAAA,YACjB;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,SAAS,mBAAmB;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,GAA2B;AACzB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAY;AAAA,MACZ,aAAU;AAAA,MACV,WAAW,GAAG,2CAA2C,SAAS;AAAA,MACjE,GAAG;AAAA,MAEJ;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,eAAY;AAAA,YACZ,WAAU;AAAA,YAEV;AAAA,kCAAC,YAAO,IAAG,KAAI,IAAG,MAAK,GAAE,QAAO,MAAK,gBAAe;AAAA,cACpD,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,QAAO,MAAK,gBAAe;AAAA,cACrD,oBAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,QAAO,MAAK,gBAAe;AAAA;AAAA;AAAA,QACvD;AAAA,QACA,oBAAC,UAAK,WAAU,WAAU,wBAAU;AAAA;AAAA;AAAA,EACtC;AAEJ;","names":[]}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentProps } from 'react';
|
|
3
|
+
import { Popover as Popover$1 } from '@base-ui/react/popover';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Popover — Fluent 2-styled, shadcn-API popover (non-modal floating panel
|
|
7
|
+
* anchored to a trigger, for rich content — forms, menus, previews — that
|
|
8
|
+
* isn't a single-purpose listbox or tooltip).
|
|
9
|
+
*
|
|
10
|
+
* This is the kit's second popup/overlay component; it reuses the
|
|
11
|
+
* portal → positioner → popup structure and motion recipe `select.tsx`
|
|
12
|
+
* established (conventions §9) rather than inventing a new shape.
|
|
13
|
+
*
|
|
14
|
+
* ## Base UI mapping (conventions §9)
|
|
15
|
+
* Behavior — focus management, portalling, open/close state, collision-aware
|
|
16
|
+
* positioning, outside-press/Escape dismissal — genuinely needs a primitive,
|
|
17
|
+
* so the parts wrap `@base-ui/react/popover` (namespace import, matching the
|
|
18
|
+
* actual `export * as Popover from "./index.parts.js"` shape in node_modules,
|
|
19
|
+
* exactly like `select.tsx`). shadcn part names are mapped onto Base UI's
|
|
20
|
+
* model:
|
|
21
|
+
*
|
|
22
|
+
* | Exported (shadcn name) | Base UI primitive |
|
|
23
|
+
* | ----------------------- | ---------------------------------------------------- |
|
|
24
|
+
* | `Popover` | `Popover.Root` |
|
|
25
|
+
* | `PopoverTrigger` | `Popover.Trigger` |
|
|
26
|
+
* | `PopoverContent` | `Popover.Portal` + `Popover.Positioner` + `Popover.Popup` composed |
|
|
27
|
+
*
|
|
28
|
+
* `Popover.Arrow` / `Popover.Title` / `Popover.Description` / `Popover.Close`
|
|
29
|
+
* / `Popover.Backdrop` / `Popover.Viewport` exist in Base UI but are out of
|
|
30
|
+
* scope for this thin wrapper (no arrow ships by default per spec, and the
|
|
31
|
+
* shadcn Popover API itself has no title/description/close parts) — reach
|
|
32
|
+
* for `@base-ui/react/popover` directly if a consumer needs one of those.
|
|
33
|
+
*
|
|
34
|
+
* ## Divergences from the shadcn/Radix Popover API (all deliberate)
|
|
35
|
+
* 1. **No `PopoverAnchor` export.** Radix ships a dedicated `Popover.Anchor`
|
|
36
|
+
* part you wrap around an arbitrary element to anchor the content
|
|
37
|
+
* somewhere other than the trigger. Base UI has no equivalent part —
|
|
38
|
+
* positioning against a different element is instead a plain `anchor`
|
|
39
|
+
* prop on `Popover.Positioner` (`Element | VirtualElement |
|
|
40
|
+
* RefObject<Element | null> | (() => Element | VirtualElement | null)`,
|
|
41
|
+
* confirmed in `positioner/PopoverPositioner.d.ts` via
|
|
42
|
+
* `UseAnchorPositioningSharedParameters`). Re-exposing that as its own
|
|
43
|
+
* "Anchor" component would have nothing to render (no DOM wrapper needed
|
|
44
|
+
* around the target element), so `PopoverContent` instead accepts an
|
|
45
|
+
* `anchor` prop that forwards straight to the `Positioner`: pass a ref to
|
|
46
|
+
* the element you want to anchor against instead of wrapping it.
|
|
47
|
+
* 2. **Composition uses Base UI's `render` prop, not `asChild`.**
|
|
48
|
+
* `Popover.Trigger` renders its own `<button>` (Base UI's model — there is
|
|
49
|
+
* no Slot-style boolean). `PopoverPrimitive.Trigger.Props` already includes
|
|
50
|
+
* Base UI's `render` prop, so no extra plumbing is needed to point the
|
|
51
|
+
* trigger at another element (e.g. the kit's `Button`):
|
|
52
|
+
* `<PopoverTrigger render={<Button variant="outline">Open</Button>} />`.
|
|
53
|
+
* This is the direct Base UI analogue of shadcn's
|
|
54
|
+
* `<PopoverTrigger asChild><Button /></PopoverTrigger>`, same reasoning
|
|
55
|
+
* `tooltip.tsx` and `dropdown-menu.tsx` document for their own triggers.
|
|
56
|
+
* 3. **The popup's role is `dialog` (non-modal), not the Radix default.**
|
|
57
|
+
* Base UI's `Popover.Popup` always renders `role="dialog"` (confirmed in
|
|
58
|
+
* `popup/PopoverPopup.js`) and `Popover.Trigger` sets
|
|
59
|
+
* `aria-haspopup="dialog"` + `aria-expanded` + `aria-controls`
|
|
60
|
+
* accordingly. `Popover.Root`'s `modal` prop defaults to `false` (no
|
|
61
|
+
* `aria-modal`, no scroll lock, outside interaction stays live) and is
|
|
62
|
+
* left at that default here — Radix's Popover is non-modal by default
|
|
63
|
+
* too, so behavior matches even though this wrapper doesn't set the prop
|
|
64
|
+
* itself. Pass `modal` through `<Popover>` (it forwards to `Popover.Root`)
|
|
65
|
+
* if a consumer needs modal behavior.
|
|
66
|
+
* 4. **`sideOffset` defaults to `4`, not Base UI's `0`.** Same shadcn-parity
|
|
67
|
+
* override `select.tsx` makes for `SelectContent`; `align="center"` and
|
|
68
|
+
* `side="bottom"` are already Base UI's own defaults, restated here as
|
|
69
|
+
* explicit defaults for clarity and so `PopoverContent`'s JSDoc is the one
|
|
70
|
+
* place all three live.
|
|
71
|
+
* 5. **`PopoverContent` needs an accessible name from the consumer.** Because
|
|
72
|
+
* the popup is forced to `role="dialog"` (divergence 3), axe-core's
|
|
73
|
+
* `aria-dialog-name` rule fails if it has neither `aria-label` nor
|
|
74
|
+
* `aria-labelledby` — unlike Radix's Popover.Content, which is a plain
|
|
75
|
+
* (unroled) div and has no such requirement. This wrapper doesn't ship a
|
|
76
|
+
* `PopoverTitle`/heading part (out of scope, matching the shadcn API
|
|
77
|
+
* surface), so give `PopoverContent` an explicit `aria-label` (e.g.
|
|
78
|
+
* `aria-label="Edit dimensions"`) or point `aria-labelledby` at a heading
|
|
79
|
+
* rendered inside it. `popover.test.tsx` and the preview page both do
|
|
80
|
+
* this on every example.
|
|
81
|
+
*
|
|
82
|
+
* ## `"use client"` — intentionally omitted
|
|
83
|
+
* Every Base UI Popover part this file uses (`Root`, `Trigger`, `Portal`,
|
|
84
|
+
* `Positioner`, `Popup`) carries its own `'use client'` directive at the
|
|
85
|
+
* source level (verified in the compiled package output, same check
|
|
86
|
+
* `avatar.tsx` documents), so they're already client boundaries on their
|
|
87
|
+
* own. This wrapper has no hooks/handlers and — unlike `select.tsx` /
|
|
88
|
+
* `checkbox.tsx` — no `@fluentui/react-icons` import (no arrow renders by
|
|
89
|
+
* default), so none of the triggers in conventions §2/§9 that would force
|
|
90
|
+
* `"use client"` apply here. The file stays a plain, server-renderable
|
|
91
|
+
* module per conventions §2: a Server Component tree can render these
|
|
92
|
+
* Client Component children without the parent re-declaring the directive.
|
|
93
|
+
* Confirmed via `pnpm typecheck` + the test suite; add the directive here
|
|
94
|
+
* only if that stops holding true.
|
|
95
|
+
*
|
|
96
|
+
* ## data-slot note
|
|
97
|
+
* `Popover` (Root) renders no DOM element of its own (same as `Select`) so it
|
|
98
|
+
* carries no `data-slot`. Every part that renders an element does —
|
|
99
|
+
* `popover-trigger`, `popover-positioner`, `popover-content` — which is what
|
|
100
|
+
* tests/consumers hook onto.
|
|
101
|
+
*/
|
|
102
|
+
declare function Popover(props: Popover$1.Root.Props): react.JSX.Element;
|
|
103
|
+
declare function PopoverTrigger({ className, ...props }: Popover$1.Trigger.Props): react.JSX.Element;
|
|
104
|
+
/**
|
|
105
|
+
* Content — the floating panel: `Portal` → `Positioner` → `Popup`. Surface is
|
|
106
|
+
* `bg-popover` + `border` + `shadow-16` (Fluent flyout elevation, conventions
|
|
107
|
+
* §3.6), `rounded-md`, `w-72 p-4` (shadcn parity default size for prose/form
|
|
108
|
+
* content — override with `className` for a differently sized panel). A
|
|
109
|
+
* subtle scale+fade open/close animation rides Base UI's
|
|
110
|
+
* `data-starting-style`/`data-ending-style` hooks with the same token
|
|
111
|
+
* durations/easings `SelectContent` uses. No arrow by default (divergence
|
|
112
|
+
* table above) — `origin-[var(--transform-origin)]` keeps the scale
|
|
113
|
+
* animation's pivot correct regardless of which side the popup lands on.
|
|
114
|
+
*/
|
|
115
|
+
declare function PopoverContent({ className, children, sideOffset, align, side, anchor, ...props }: ComponentProps<typeof Popover$1.Popup> & Pick<ComponentProps<typeof Popover$1.Positioner>, "side" | "align" | "sideOffset" | "anchor">): react.JSX.Element;
|
|
116
|
+
|
|
117
|
+
export { Popover, PopoverContent, PopoverTrigger };
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Popover as PopoverPrimitive } from "@base-ui/react/popover";
|
|
3
|
+
import { cn } from "../../lib/utils.js";
|
|
4
|
+
function Popover(props) {
|
|
5
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Root, { ...props });
|
|
6
|
+
}
|
|
7
|
+
function PopoverTrigger({
|
|
8
|
+
className,
|
|
9
|
+
...props
|
|
10
|
+
}) {
|
|
11
|
+
return /* @__PURE__ */ jsx(
|
|
12
|
+
PopoverPrimitive.Trigger,
|
|
13
|
+
{
|
|
14
|
+
"data-slot": "popover-trigger",
|
|
15
|
+
className: cn(className),
|
|
16
|
+
...props
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
function PopoverContent({
|
|
21
|
+
className,
|
|
22
|
+
children,
|
|
23
|
+
sideOffset = 4,
|
|
24
|
+
align = "center",
|
|
25
|
+
side = "bottom",
|
|
26
|
+
anchor,
|
|
27
|
+
...props
|
|
28
|
+
}) {
|
|
29
|
+
return /* @__PURE__ */ jsx(PopoverPrimitive.Portal, { children: /* @__PURE__ */ jsx(
|
|
30
|
+
PopoverPrimitive.Positioner,
|
|
31
|
+
{
|
|
32
|
+
"data-slot": "popover-positioner",
|
|
33
|
+
sideOffset,
|
|
34
|
+
align,
|
|
35
|
+
side,
|
|
36
|
+
anchor,
|
|
37
|
+
className: "z-50 outline-none",
|
|
38
|
+
children: /* @__PURE__ */ jsx(
|
|
39
|
+
PopoverPrimitive.Popup,
|
|
40
|
+
{
|
|
41
|
+
"data-slot": "popover-content",
|
|
42
|
+
className: cn(
|
|
43
|
+
"w-72 origin-[var(--transform-origin)] rounded-md border bg-popover p-4 text-popover-foreground shadow-16 outline-none",
|
|
44
|
+
// motion — subtle scale + fade on open (enter) / close (exit)
|
|
45
|
+
"transition-[opacity,scale] duration-fast ease-decelerate-mid",
|
|
46
|
+
"data-starting-style:scale-95 data-starting-style:opacity-0",
|
|
47
|
+
"data-ending-style:scale-95 data-ending-style:opacity-0 data-ending-style:ease-accelerate-mid",
|
|
48
|
+
className
|
|
49
|
+
),
|
|
50
|
+
...props,
|
|
51
|
+
children
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
) });
|
|
56
|
+
}
|
|
57
|
+
export {
|
|
58
|
+
Popover,
|
|
59
|
+
PopoverContent,
|
|
60
|
+
PopoverTrigger
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=popover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/popover.tsx"],"sourcesContent":["import { Popover as PopoverPrimitive } from \"@base-ui/react/popover\";\nimport type { ComponentProps } from \"react\";\n\nimport { cn } from \"../../lib/utils\";\n\n/**\n * Popover — Fluent 2-styled, shadcn-API popover (non-modal floating panel\n * anchored to a trigger, for rich content — forms, menus, previews — that\n * isn't a single-purpose listbox or tooltip).\n *\n * This is the kit's second popup/overlay component; it reuses the\n * portal → positioner → popup structure and motion recipe `select.tsx`\n * established (conventions §9) rather than inventing a new shape.\n *\n * ## Base UI mapping (conventions §9)\n * Behavior — focus management, portalling, open/close state, collision-aware\n * positioning, outside-press/Escape dismissal — genuinely needs a primitive,\n * so the parts wrap `@base-ui/react/popover` (namespace import, matching the\n * actual `export * as Popover from \"./index.parts.js\"` shape in node_modules,\n * exactly like `select.tsx`). shadcn part names are mapped onto Base UI's\n * model:\n *\n * | Exported (shadcn name) | Base UI primitive |\n * | ----------------------- | ---------------------------------------------------- |\n * | `Popover` | `Popover.Root` |\n * | `PopoverTrigger` | `Popover.Trigger` |\n * | `PopoverContent` | `Popover.Portal` + `Popover.Positioner` + `Popover.Popup` composed |\n *\n * `Popover.Arrow` / `Popover.Title` / `Popover.Description` / `Popover.Close`\n * / `Popover.Backdrop` / `Popover.Viewport` exist in Base UI but are out of\n * scope for this thin wrapper (no arrow ships by default per spec, and the\n * shadcn Popover API itself has no title/description/close parts) — reach\n * for `@base-ui/react/popover` directly if a consumer needs one of those.\n *\n * ## Divergences from the shadcn/Radix Popover API (all deliberate)\n * 1. **No `PopoverAnchor` export.** Radix ships a dedicated `Popover.Anchor`\n * part you wrap around an arbitrary element to anchor the content\n * somewhere other than the trigger. Base UI has no equivalent part —\n * positioning against a different element is instead a plain `anchor`\n * prop on `Popover.Positioner` (`Element | VirtualElement |\n * RefObject<Element | null> | (() => Element | VirtualElement | null)`,\n * confirmed in `positioner/PopoverPositioner.d.ts` via\n * `UseAnchorPositioningSharedParameters`). Re-exposing that as its own\n * \"Anchor\" component would have nothing to render (no DOM wrapper needed\n * around the target element), so `PopoverContent` instead accepts an\n * `anchor` prop that forwards straight to the `Positioner`: pass a ref to\n * the element you want to anchor against instead of wrapping it.\n * 2. **Composition uses Base UI's `render` prop, not `asChild`.**\n * `Popover.Trigger` renders its own `<button>` (Base UI's model — there is\n * no Slot-style boolean). `PopoverPrimitive.Trigger.Props` already includes\n * Base UI's `render` prop, so no extra plumbing is needed to point the\n * trigger at another element (e.g. the kit's `Button`):\n * `<PopoverTrigger render={<Button variant=\"outline\">Open</Button>} />`.\n * This is the direct Base UI analogue of shadcn's\n * `<PopoverTrigger asChild><Button /></PopoverTrigger>`, same reasoning\n * `tooltip.tsx` and `dropdown-menu.tsx` document for their own triggers.\n * 3. **The popup's role is `dialog` (non-modal), not the Radix default.**\n * Base UI's `Popover.Popup` always renders `role=\"dialog\"` (confirmed in\n * `popup/PopoverPopup.js`) and `Popover.Trigger` sets\n * `aria-haspopup=\"dialog\"` + `aria-expanded` + `aria-controls`\n * accordingly. `Popover.Root`'s `modal` prop defaults to `false` (no\n * `aria-modal`, no scroll lock, outside interaction stays live) and is\n * left at that default here — Radix's Popover is non-modal by default\n * too, so behavior matches even though this wrapper doesn't set the prop\n * itself. Pass `modal` through `<Popover>` (it forwards to `Popover.Root`)\n * if a consumer needs modal behavior.\n * 4. **`sideOffset` defaults to `4`, not Base UI's `0`.** Same shadcn-parity\n * override `select.tsx` makes for `SelectContent`; `align=\"center\"` and\n * `side=\"bottom\"` are already Base UI's own defaults, restated here as\n * explicit defaults for clarity and so `PopoverContent`'s JSDoc is the one\n * place all three live.\n * 5. **`PopoverContent` needs an accessible name from the consumer.** Because\n * the popup is forced to `role=\"dialog\"` (divergence 3), axe-core's\n * `aria-dialog-name` rule fails if it has neither `aria-label` nor\n * `aria-labelledby` — unlike Radix's Popover.Content, which is a plain\n * (unroled) div and has no such requirement. This wrapper doesn't ship a\n * `PopoverTitle`/heading part (out of scope, matching the shadcn API\n * surface), so give `PopoverContent` an explicit `aria-label` (e.g.\n * `aria-label=\"Edit dimensions\"`) or point `aria-labelledby` at a heading\n * rendered inside it. `popover.test.tsx` and the preview page both do\n * this on every example.\n *\n * ## `\"use client\"` — intentionally omitted\n * Every Base UI Popover part this file uses (`Root`, `Trigger`, `Portal`,\n * `Positioner`, `Popup`) carries its own `'use client'` directive at the\n * source level (verified in the compiled package output, same check\n * `avatar.tsx` documents), so they're already client boundaries on their\n * own. This wrapper has no hooks/handlers and — unlike `select.tsx` /\n * `checkbox.tsx` — no `@fluentui/react-icons` import (no arrow renders by\n * default), so none of the triggers in conventions §2/§9 that would force\n * `\"use client\"` apply here. The file stays a plain, server-renderable\n * module per conventions §2: a Server Component tree can render these\n * Client Component children without the parent re-declaring the directive.\n * Confirmed via `pnpm typecheck` + the test suite; add the directive here\n * only if that stops holding true.\n *\n * ## data-slot note\n * `Popover` (Root) renders no DOM element of its own (same as `Select`) so it\n * carries no `data-slot`. Every part that renders an element does —\n * `popover-trigger`, `popover-positioner`, `popover-content` — which is what\n * tests/consumers hook onto.\n */\n\nfunction Popover(props: PopoverPrimitive.Root.Props) {\n return <PopoverPrimitive.Root {...props} />;\n}\n\nfunction PopoverTrigger({\n className,\n ...props\n}: PopoverPrimitive.Trigger.Props) {\n return (\n <PopoverPrimitive.Trigger\n data-slot=\"popover-trigger\"\n className={cn(className)}\n {...props}\n />\n );\n}\n\n/**\n * Content — the floating panel: `Portal` → `Positioner` → `Popup`. Surface is\n * `bg-popover` + `border` + `shadow-16` (Fluent flyout elevation, conventions\n * §3.6), `rounded-md`, `w-72 p-4` (shadcn parity default size for prose/form\n * content — override with `className` for a differently sized panel). A\n * subtle scale+fade open/close animation rides Base UI's\n * `data-starting-style`/`data-ending-style` hooks with the same token\n * durations/easings `SelectContent` uses. No arrow by default (divergence\n * table above) — `origin-[var(--transform-origin)]` keeps the scale\n * animation's pivot correct regardless of which side the popup lands on.\n */\nfunction PopoverContent({\n className,\n children,\n sideOffset = 4,\n align = \"center\",\n side = \"bottom\",\n anchor,\n ...props\n}: ComponentProps<typeof PopoverPrimitive.Popup> &\n Pick<\n ComponentProps<typeof PopoverPrimitive.Positioner>,\n \"side\" | \"align\" | \"sideOffset\" | \"anchor\"\n >) {\n return (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Positioner\n data-slot=\"popover-positioner\"\n sideOffset={sideOffset}\n align={align}\n side={side}\n anchor={anchor}\n className=\"z-50 outline-none\"\n >\n <PopoverPrimitive.Popup\n data-slot=\"popover-content\"\n className={cn(\n \"w-72 origin-[var(--transform-origin)] rounded-md border bg-popover p-4 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 {children}\n </PopoverPrimitive.Popup>\n </PopoverPrimitive.Positioner>\n </PopoverPrimitive.Portal>\n );\n}\n\nexport { Popover, PopoverTrigger, PopoverContent };\n"],"mappings":"AAwGS;AAxGT,SAAS,WAAW,wBAAwB;AAG5C,SAAS,UAAU;AAoGnB,SAAS,QAAQ,OAAoC;AACnD,SAAO,oBAAC,iBAAiB,MAAjB,EAAuB,GAAG,OAAO;AAC3C;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA,GAAG;AACL,GAAmC;AACjC,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,SAAS;AAAA,MACtB,GAAG;AAAA;AAAA,EACN;AAEJ;AAaA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,OAAO;AAAA,EACP;AAAA,EACA,GAAG;AACL,GAIK;AACH,SACE,oBAAC,iBAAiB,QAAjB,EACC;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,aAAU;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAU;AAAA,MAEV;AAAA,QAAC,iBAAiB;AAAA,QAAjB;AAAA,UACC,aAAU;AAAA,UACV,WAAW;AAAA,YACT;AAAA;AAAA,YAEA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UACC,GAAG;AAAA,UAEH;AAAA;AAAA,MACH;AAAA;AAAA,EACF,GACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ComponentProps } from 'react';
|
|
3
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
4
|
+
import { Progress as Progress$1 } from '@base-ui/react/progress';
|
|
5
|
+
import { VariantProps } from 'class-variance-authority';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Progress — Fluent 2-styled, shadcn-API progress bar.
|
|
9
|
+
*
|
|
10
|
+
* Base UI ships a Progress primitive (`@base-ui/react/progress`, imported as
|
|
11
|
+
* a namespace exposing `Root` / `Track` / `Indicator` / `Label` / `Value`,
|
|
12
|
+
* matching the actual export shape in node_modules — same pattern as
|
|
13
|
+
* `avatar.tsx`). This is the batch's Base UI case (conventions §9): value→
|
|
14
|
+
* percentage math, `role="progressbar"`, `aria-valuemin`/`aria-valuemax`/
|
|
15
|
+
* `aria-valuenow`/`aria-valuetext` wiring, and indeterminate detection
|
|
16
|
+
* (`aria-valuenow` correctly omitted when `value` is `null`/`undefined`) are
|
|
17
|
+
* exactly the kind of genuine behavior a primitive should own rather than
|
|
18
|
+
* hand-rolling ARIA math. `Root`, `Track`, and `Indicator` are composed
|
|
19
|
+
* internally into a single `Progress` export to match shadcn's flat API
|
|
20
|
+
* (`<Progress value={33} />`) — the sub-parts are not re-exported, since the
|
|
21
|
+
* spec calls for one component, not shadcn's newer multi-part variant.
|
|
22
|
+
*
|
|
23
|
+
* `"use client"` is intentionally omitted, mirroring `avatar.tsx`'s
|
|
24
|
+
* reasoning: Base UI's Root/Track/Indicator modules each carry their own
|
|
25
|
+
* `'use client'` directive at the source level, so they are already client
|
|
26
|
+
* boundaries on their own. This wrapper file has no hooks/handlers of its
|
|
27
|
+
* own — it only forwards props and branches on a plain value comparison — so
|
|
28
|
+
* it stays a plain (server-renderable) module per conventions §2. Confirmed
|
|
29
|
+
* via `pnpm typecheck` + the test suite.
|
|
30
|
+
*
|
|
31
|
+
* Aesthetics follow Fluent 2's ProgressBar, which is thin — 2px (`h-0.5`),
|
|
32
|
+
* not shadcn's 8px `h-2` default. This is a deliberate, documented deviation
|
|
33
|
+
* from the shadcn reference; consumers who want the shadcn-thick bar (or any
|
|
34
|
+
* other height) can override via `className` (`cn` + tailwind-merge resolve
|
|
35
|
+
* the conflict, last utility wins). Track is `bg-secondary` (flat neutral
|
|
36
|
+
* fill) with `rounded-full overflow-hidden`; the indicator is `bg-primary`,
|
|
37
|
+
* also `rounded-full`.
|
|
38
|
+
*
|
|
39
|
+
* Intent variants: Fluent's ProgressBar ships a `State` axis (Default/Success/
|
|
40
|
+
* Error/Warning), so `Progress` exposes a matching `variant` prop
|
|
41
|
+
* (`default`/`success`/`warning`/`destructive`) via `progressVariants` — a
|
|
42
|
+
* `cva` on the indicator sub-part, the same precedent `spinner.tsx` sets by
|
|
43
|
+
* putting its `cva` on the inner glyph. `success` (`bg-success` `#107c10`) and
|
|
44
|
+
* `warning` (`bg-warning` `#da3b01`) are exact hex matches to Fluent's
|
|
45
|
+
* Success/Warning `State`. `destructive` reuses `bg-destructive` (`#d13438`)
|
|
46
|
+
* rather than Fluent's filled-status `#c50f1f`: this kit standardizes on one
|
|
47
|
+
* destructive red across Badge/Progress/Label per the single-red policy
|
|
48
|
+
* (docs/design/tokens-research.md §12.9), keeping consistency over a one-off
|
|
49
|
+
* fifth red token. The indicator width is driven by Base UI's own computed
|
|
50
|
+
* `style.width` percentage (`ProgressIndicator` reads `value`/`min`/`max`
|
|
51
|
+
* from context and sets `width: ${percent}%` — this is "the cleaner" of the
|
|
52
|
+
* two width strategies the spec allows: it needs no manual percent math on
|
|
53
|
+
* our side, unlike shadcn's classic `translateX(-${100 - value}%)` recipe).
|
|
54
|
+
* `transition-[width]` (not `transition-all`/`transform`, since Base UI
|
|
55
|
+
* animates `width` directly) plus the token duration/easing pair animates
|
|
56
|
+
* value changes; reduced motion is handled automatically by the token layer
|
|
57
|
+
* (conventions §3.5) since `duration-normal`/`ease-ease` are token-driven.
|
|
58
|
+
*
|
|
59
|
+
* Indeterminate (`value` is `null`/undefined): Fluent's sliding segment. The
|
|
60
|
+
* indicator renders a `w-1/3` segment driven by the token-layer
|
|
61
|
+
* `--animate-progress-indeterminate` keyframes (tokens.css): it travels from
|
|
62
|
+
* fully off-track left (`translate: -100%` of its own width) to fully
|
|
63
|
+
* off-track right (`300%`), clipped by the root's `overflow-hidden`.
|
|
64
|
+
*
|
|
65
|
+
* Under `prefers-reduced-motion` the slide is fully stopped via
|
|
66
|
+
* `motion-reduce:animate-none` (same call as `skeleton.tsx`, not `spinner.tsx`'s
|
|
67
|
+
* slow-down): the pulse carries no information a reduced-motion user would
|
|
68
|
+
* lose by holding it still — the indeterminate/busy state is conveyed by the
|
|
69
|
+
* `role="progressbar"` + omitted `aria-valuenow` to assistive tech and by the
|
|
70
|
+
* bar's presence to sighted users — and a persistently animating region is
|
|
71
|
+
* exactly what `prefers-reduced-motion` asks apps to avoid. `motion-reduce:
|
|
72
|
+
* animate-none` is a plain Tailwind utility (not a `duration-*` token), so it
|
|
73
|
+
* isn't covered by the automatic duration collapse `tokens.css` applies and
|
|
74
|
+
* has to be declared here explicitly.
|
|
75
|
+
*
|
|
76
|
+
* `role="progressbar"` requires an accessible name; Base UI does not default
|
|
77
|
+
* one. Pass `aria-label` (forwarded straight through to the root via
|
|
78
|
+
* `...props`) or compose Base UI's own `Progress.Label` alongside this
|
|
79
|
+
* component — consumers must supply one or the other.
|
|
80
|
+
*/
|
|
81
|
+
declare const progressVariants: (props?: ({
|
|
82
|
+
variant?: "default" | "destructive" | "success" | "warning" | null | undefined;
|
|
83
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
84
|
+
declare function Progress({ className, value, variant, size, ...props }: Omit<ComponentProps<typeof Progress$1.Root>, "value"> & VariantProps<typeof progressVariants> & {
|
|
85
|
+
/**
|
|
86
|
+
* 0–100 (relative to `min`/`max`, both default 0/100). Omit or pass `null`
|
|
87
|
+
* for the indeterminate state — Base UI's Root then correctly omits
|
|
88
|
+
* `aria-valuenow` and this wrapper renders the pulsing stand-in indicator.
|
|
89
|
+
*/
|
|
90
|
+
value?: number | null;
|
|
91
|
+
/**
|
|
92
|
+
* Fluent ProgressBar `Size` axis: `default` = Medium (2px track),
|
|
93
|
+
* `lg` = Large (4px) — surfaced by the pass-1 Figma validation.
|
|
94
|
+
*/
|
|
95
|
+
size?: "default" | "lg";
|
|
96
|
+
}): react.JSX.Element;
|
|
97
|
+
|
|
98
|
+
export { Progress, progressVariants };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Progress as ProgressPrimitive } from "@base-ui/react/progress";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { cn } from "../../lib/utils.js";
|
|
5
|
+
const progressVariants = cva(
|
|
6
|
+
"h-full rounded-full transition-[width] duration-normal ease-ease",
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: "bg-primary",
|
|
11
|
+
success: "bg-success",
|
|
12
|
+
warning: "bg-warning",
|
|
13
|
+
destructive: "bg-destructive"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
defaultVariants: {
|
|
17
|
+
variant: "default"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
function Progress({
|
|
22
|
+
className,
|
|
23
|
+
value,
|
|
24
|
+
variant = "default",
|
|
25
|
+
size = "default",
|
|
26
|
+
...props
|
|
27
|
+
}) {
|
|
28
|
+
return /* @__PURE__ */ jsx(
|
|
29
|
+
ProgressPrimitive.Root,
|
|
30
|
+
{
|
|
31
|
+
"data-slot": "progress",
|
|
32
|
+
"data-variant": variant,
|
|
33
|
+
"data-size": size,
|
|
34
|
+
value: value ?? null,
|
|
35
|
+
className: cn(
|
|
36
|
+
"relative w-full overflow-hidden rounded-full bg-secondary",
|
|
37
|
+
size === "lg" ? "h-1" : "h-0.5",
|
|
38
|
+
className
|
|
39
|
+
),
|
|
40
|
+
...props,
|
|
41
|
+
children: /* @__PURE__ */ jsx(
|
|
42
|
+
ProgressPrimitive.Track,
|
|
43
|
+
{
|
|
44
|
+
"data-slot": "progress-track",
|
|
45
|
+
className: "relative h-full w-full",
|
|
46
|
+
children: /* @__PURE__ */ jsx(
|
|
47
|
+
ProgressPrimitive.Indicator,
|
|
48
|
+
{
|
|
49
|
+
"data-slot": "progress-indicator",
|
|
50
|
+
className: cn(
|
|
51
|
+
progressVariants({ variant }),
|
|
52
|
+
// Fluent indeterminate: the token-layer keyframes slide the 1/3
|
|
53
|
+
// segment from off-track left to off-track right (root clips).
|
|
54
|
+
value == null && "w-1/3 animate-progress-indeterminate motion-reduce:animate-none"
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
export {
|
|
64
|
+
Progress,
|
|
65
|
+
progressVariants
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=progress.js.map
|