@photon-ai/pho-ui 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/dist/chunks/basic-page-C50WUzYV.js +238 -0
  2. package/dist/chunks/basic-page-C50WUzYV.js.map +1 -0
  3. package/dist/chunks/card-9cGnv-VD.js.map +1 -1
  4. package/dist/chunks/{close-button-Bq9f-H15.js → close-button-B8gF5UNk.js} +3 -3
  5. package/dist/chunks/close-button-B8gF5UNk.js.map +1 -0
  6. package/dist/chunks/dialog-Ba0UUE5g.js +155 -0
  7. package/dist/chunks/dialog-Ba0UUE5g.js.map +1 -0
  8. package/dist/chunks/{sidebar-BCqq58hV.js → sidebar-DGpEKxOn.js} +3 -3
  9. package/dist/chunks/{sidebar-BCqq58hV.js.map → sidebar-DGpEKxOn.js.map} +1 -1
  10. package/dist/chunks/use-press-pulse-8iorQPsh.js +62 -0
  11. package/dist/chunks/use-press-pulse-8iorQPsh.js.map +1 -0
  12. package/dist/components/badge.js +46 -31
  13. package/dist/components/badge.js.map +1 -1
  14. package/dist/components/button.js +1 -1
  15. package/dist/components/checkbox.js +1 -1
  16. package/dist/components/dialog.js +1 -1
  17. package/dist/components/select.js +1 -1
  18. package/dist/index.js +36 -36
  19. package/dist/sections/basic-page.js +8 -0
  20. package/dist/sections/sidebar.js +1 -1
  21. package/dist/src/components/badge/badge.d.ts +34 -8
  22. package/dist/src/components/badge/index.d.ts +1 -1
  23. package/dist/src/components/card/card.d.ts +2 -2
  24. package/dist/src/components/dialog/dialog.d.ts +16 -1
  25. package/dist/src/index.d.ts +1 -1
  26. package/dist/src/sections/basic-page/basic-page.d.ts +270 -0
  27. package/dist/src/sections/basic-page/index.d.ts +1 -0
  28. package/dist/src/sections/sidebar/sidebar.d.ts +1 -1
  29. package/dist/src/utils/use-press-pulse.d.ts +15 -11
  30. package/dist/utils.js +1 -1
  31. package/package.json +4 -4
  32. package/src/styles/theme.css +20 -0
  33. package/dist/chunks/close-button-Bq9f-H15.js.map +0 -1
  34. package/dist/chunks/dialog-DolPKFGS.js +0 -141
  35. package/dist/chunks/dialog-DolPKFGS.js.map +0 -1
  36. package/dist/chunks/settings-B0vhLoMi.js +0 -134
  37. package/dist/chunks/settings-B0vhLoMi.js.map +0 -1
  38. package/dist/chunks/use-press-pulse-CMwPTOR2.js +0 -44
  39. package/dist/chunks/use-press-pulse-CMwPTOR2.js.map +0 -1
  40. package/dist/sections/settings.js +0 -8
  41. package/dist/src/sections/settings/index.d.ts +0 -1
  42. package/dist/src/sections/settings/settings.d.ts +0 -170
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog-Ba0UUE5g.js","names":[],"sources":["../../src/components/dialog/dialog.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ComponentProps,\n type ElementType,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n} from \"react\";\nimport { Dialog as BaseDialog } from \"@base-ui/react/dialog\";\nimport { cn } from \"../../utils/cn\";\nimport { Button, type ButtonProps } from \"../button/button\";\nimport { CloseButton } from \"../button/close-button\";\n\n/** Override Base UI's `string | (state) => string` className with plain string. */\ntype StyledProps<T extends ElementType> = Omit<\n ComponentProps<T>,\n \"className\"\n> & {\n className?: string;\n};\n\n/* ========================== Async pending context ========================== */\n\n/** Imperative actions exposed by Base UI's `actionsRef`. */\ninterface RootActions {\n unmount: () => void;\n close: () => void;\n}\n\ninterface DialogPendingContextValue {\n /** True while a `Dialog.Action` promise is in flight. */\n pending: boolean;\n beginPending: () => void;\n endPending: () => void;\n /** Close the dialog imperatively (used by `Dialog.Action` on resolve). */\n close: () => void;\n}\n\nconst DialogPendingContext = createContext<DialogPendingContextValue | null>(\n null,\n);\n\n/**\n * Whether the surrounding dialog has a `Dialog.Action` promise in flight —\n * use it to disable secondary actions (Cancel etc.) while work is pending.\n * Returns `false` outside a `Dialog.Root`.\n */\nexport function useDialogPending(): boolean {\n return useContext(DialogPendingContext)?.pending ?? false;\n}\n\ntype RootProps = ComponentProps<typeof BaseDialog.Root>;\n\n/**\n * `Dialog.Root` with async awareness: while a `Dialog.Action` promise is\n * pending, every close request (outside press, Escape, `Dialog.Close`) is\n * cancelled so the dialog stays open until the work settles. Props pass\n * through to Base UI's `Dialog.Root` unchanged.\n */\nfunction Root({ onOpenChange, actionsRef, ...props }: RootProps) {\n const [pending, setPending] = useState(false);\n // Guard reads a ref so a resolve → close() in the same tick isn't blocked\n // by a not-yet-flushed state update.\n const pendingRef = useRef(false);\n const internalActionsRef = useRef<RootActions | null>(null);\n\n // Keep a caller-supplied actionsRef working alongside our internal one.\n useEffect(() => {\n if (!actionsRef) return;\n actionsRef.current = internalActionsRef.current;\n return () => {\n actionsRef.current = null;\n };\n }, [actionsRef]);\n\n const handleOpenChange = useCallback<NonNullable<RootProps[\"onOpenChange\"]>>(\n (open, eventDetails) => {\n if (!open && pendingRef.current) {\n eventDetails.cancel();\n return;\n }\n onOpenChange?.(open, eventDetails);\n },\n [onOpenChange],\n );\n\n const contextValue = useMemo<DialogPendingContextValue>(\n () => ({\n pending,\n beginPending: () => {\n pendingRef.current = true;\n setPending(true);\n },\n endPending: () => {\n pendingRef.current = false;\n setPending(false);\n },\n close: () => internalActionsRef.current?.close(),\n }),\n [pending],\n );\n\n return (\n <DialogPendingContext.Provider value={contextValue}>\n <BaseDialog.Root\n actionsRef={internalActionsRef}\n onOpenChange={handleOpenChange}\n {...props}\n />\n </DialogPendingContext.Provider>\n );\n}\n\nconst Trigger = BaseDialog.Trigger;\nconst Portal = BaseDialog.Portal;\nconst Close = BaseDialog.Close;\n\n/* ============================== Dialog.Action ============================== */\n\nexport interface DialogActionProps extends Omit<ButtonProps, \"onClick\"> {\n /**\n * Confirm handler. Return a promise to keep the dialog open while it runs:\n * the button shows `loading`, all dismissal is locked, and the dialog\n * closes when the promise resolves. On rejection the dialog stays open —\n * surface errors inside the handler. A non-promise return closes\n * immediately, like `Dialog.Close`.\n */\n onClick?: (\n event: ReactMouseEvent<HTMLButtonElement>,\n ) => void | Promise<unknown>;\n}\n\nfunction isThenable(value: unknown): value is Promise<unknown> {\n return (\n value != null && typeof (value as { then?: unknown }).then === \"function\"\n );\n}\n\n/**\n * The confirm button of an action row, with native promise support — a\n * `Button` that runs its (possibly async) `onClick` and closes the dialog\n * when the work settles successfully.\n */\nfunction Action({ onClick, loading, disabled, ...props }: DialogActionProps) {\n const pendingContext = useContext(DialogPendingContext);\n const [busy, setBusy] = useState(false);\n const mountedRef = useRef(true);\n\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n function handleClick(event: ReactMouseEvent<HTMLButtonElement>) {\n if (busy || loading) return;\n const result = onClick?.(event);\n if (!isThenable(result)) {\n pendingContext?.close();\n return;\n }\n setBusy(true);\n pendingContext?.beginPending();\n result.then(\n () => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n pendingContext?.close();\n },\n (error: unknown) => {\n pendingContext?.endPending();\n if (mountedRef.current) setBusy(false);\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV !== \"production\"\n ) {\n console.error(\"Dialog.Action: async onClick rejected —\", error);\n }\n },\n );\n }\n\n const inert = busy || loading;\n return (\n <Button\n {...props}\n disabled={disabled || inert}\n loading={inert}\n onClick={handleClick}\n />\n );\n}\n\nfunction Backdrop({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Backdrop>) {\n return (\n <BaseDialog.Backdrop\n className={cn(\n \"bg-pho-overlay fixed inset-0 z-50 transition-opacity duration-200 ease-out\",\n \"data-[ending-style]:opacity-0 data-[ending-style]:duration-150 data-[starting-style]:opacity-0\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Popup({ className, ...props }: StyledProps<typeof BaseDialog.Popup>) {\n return (\n <BaseDialog.Popup\n className={cn(\n // Floating layer: bg-pho-primary + border-pho-secondary hairline, elevation kept.\n \"border-pho-secondary bg-pho-primary shadow-pho-xl fixed top-1/2 left-1/2 z-50 w-[calc(100%-2rem)] max-w-lg -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-lg border outline-none\",\n // Opacity + scale only — leave translate centering alone (no transition-all).\n \"transition-[opacity,scale] duration-200 ease-out\",\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]:duration-150\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Title({ className, ...props }: StyledProps<typeof BaseDialog.Title>) {\n return (\n <BaseDialog.Title\n className={cn(\n \"text-pho-primary font-display text-display-sm font-medium text-balance\",\n className,\n )}\n {...props}\n />\n );\n}\n\nfunction Description({\n className,\n ...props\n}: StyledProps<typeof BaseDialog.Description>) {\n return (\n <BaseDialog.Description\n className={cn(\n \"text-pho-description text-display-xs font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface ContentProps extends Omit<\n StyledProps<typeof BaseDialog.Popup>,\n \"title\"\n> {\n /** Heading rendered in the panel header. */\n title?: ReactNode;\n /** Supporting text under the title. */\n description?: ReactNode;\n /**\n * Consequence bullets rendered as a list at the top of the body — one item\n * per outcome (what is deleted, what survives, who loses access). Use on\n * destructive confirms where the one-line description undersells the\n * impact; keep each item to a single short sentence. Wrap the load-bearing\n * figure in `<strong>` (\"<strong>3 members</strong> lose access\") — the\n * list styles it (secondary ink, medium weight); no classes needed.\n */\n consequences?: ReactNode[];\n /**\n * Final cautionary line under `consequences` — error ink at description\n * size (e.g. \"It cannot be undone. Please be certain.\"). Reserve it for\n * irreversible actions; keep it short.\n */\n warning?: ReactNode;\n /**\n * Footer action row (Cancel / Confirm, etc.). Iron rule: when `actions` is\n * set, the header close button is never shown — dismiss via the actions.\n */\n actions?: ReactNode;\n /**\n * Header close control. Only applies when `actions` is absent.\n * @default true\n */\n showClose?: boolean;\n children?: ReactNode;\n}\n\n/**\n * Convenience panel: renders the portal, backdrop, and styled popup with an\n * optional header (title/description + close) and optional action row. For\n * full control, compose the parts directly (`Dialog.Portal` /\n * `Dialog.Backdrop` / `Dialog.Popup`).\n */\nfunction Content({\n title,\n description,\n consequences,\n warning,\n actions,\n showClose = true,\n children,\n className,\n ...props\n}: ContentProps) {\n // Iron rule: action dialogs dismiss via their actions — never a header X.\n const showCloseButton = actions == null && showClose;\n const hasHeader = Boolean(title || description || showCloseButton);\n const hasConsequences = consequences != null && consequences.length > 0;\n const hasBody =\n hasConsequences || warning != null || children != null || actions != null;\n\n return (\n <Portal>\n <Backdrop />\n <Popup className={className} {...props}>\n {hasHeader && (\n <div className=\"flex flex-col gap-1 px-6 pt-6\">\n {(title || showCloseButton) && (\n // Title row height = title only. Close is out of flow, centered\n // on the row, and may paint outside it (no clip, no stretch).\n <div className=\"relative\">\n {title ? (\n <Title className={showCloseButton ? \"pr-12\" : undefined}>\n {title}\n </Title>\n ) : (\n <div className=\"h-[1.625rem]\" aria-hidden=\"true\" />\n )}\n {showCloseButton && (\n <Close\n render={\n <CloseButton className=\"absolute top-1/2 right-0 z-10 -translate-y-1/2\" />\n }\n />\n )}\n </div>\n )}\n {description && <Description>{description}</Description>}\n </div>\n )}\n {hasBody && (\n <div className=\"flex flex-col gap-5 px-6 py-5\">\n {hasConsequences && (\n <ul className=\"text-pho-description text-md [&_strong]:text-pho-secondary space-y-1 [&_strong]:font-medium\">\n {consequences.map((item, index) => (\n // Hand-drawn marker: a 4px dot on the first line's center —\n // quieter than the browser disc, ink tracks the text.\n <li\n key={index}\n className=\"relative pl-4 before:absolute before:top-2.5 before:left-1 before:size-1 before:rounded-full before:bg-current\"\n >\n {item}\n </li>\n ))}\n </ul>\n )}\n {warning != null && (\n <p className=\"text-pho-error text-display-xs font-medium\">\n {warning}\n </p>\n )}\n {children}\n {actions != null && (\n <div className=\"flex justify-end gap-2\">{actions}</div>\n )}\n </div>\n )}\n </Popup>\n </Portal>\n );\n}\n\n/**\n * Modal dialog built on Base UI `Dialog`. Controlled or uncontrolled via\n * `Dialog.Root` (`open` / `onOpenChange` / `defaultOpen`). `Dialog.Action`\n * adds native promise support: an async confirm keeps the dialog open and\n * undismissable until the work resolves.\n */\nexport const Dialog = {\n Root,\n Trigger,\n Portal,\n Backdrop,\n Popup,\n Title,\n Description,\n Close,\n Action,\n Content,\n};\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { t as a } from "./cn-DTiB6ek_.js";
3
3
  import { n as b, r as y } from "./link-provider-9TFNyDqO.js";
4
- import { d as N } from "./close-button-Bq9f-H15.js";
4
+ import { d as N } from "./close-button-B8gF5UNk.js";
5
5
  import { t as h } from "./createReactComponent-BqCmnqfX.js";
6
6
  import { n as l } from "./avatar-CiAvJNNs.js";
7
7
  import { createContext as I, isValidElement as R, useContext as E } from "react";
@@ -31,7 +31,7 @@ var A = [["path", {
31
31
  }, Y = a(f, v.base), S = {
32
32
  base: "mb-6 px-2",
33
33
  sm: "mb-3 px-0"
34
- }, T = "outline-pho-brand flex min-h-8 w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-base transition-colors focus-visible:outline-2 focus-visible:-outline-offset-1", D = "bg-pho-primary text-pho-primary ring-pho-secondary font-medium ring-1 ring-inset *:data-icon:text-pho-primary", B = a("text-pho-secondary *:data-icon:text-pho-secondary", "hover:bg-pho-primary hover:text-pho-primary hover:*:data-icon:text-pho-primary"), x = I("base");
34
+ }, T = "outline-pho-brand flex min-h-9 w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-base transition-colors focus-visible:outline-2 focus-visible:-outline-offset-1", D = "bg-pho-primary text-pho-primary ring-pho-secondary font-medium ring-1 ring-inset *:data-icon:text-pho-primary", B = a("text-pho-secondary *:data-icon:text-pho-secondary", "hover:bg-pho-primary hover:text-pho-primary hover:*:data-icon:text-pho-primary"), x = I("base");
35
35
  function M({ className: r, inset: e = "base", ...o }) {
36
36
  return /* @__PURE__ */ t(x.Provider, {
37
37
  value: e,
@@ -174,4 +174,4 @@ export {
174
174
  S as t
175
175
  };
176
176
 
177
- //# sourceMappingURL=sidebar-BCqq58hV.js.map
177
+ //# sourceMappingURL=sidebar-DGpEKxOn.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-BCqq58hV.js","names":["__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowUpRight.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconDots.mjs","../../src/sections/sidebar/sidebar.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M17 7l-10 10\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M8 7l9 0l0 9\", \"key\": \"svg-1\" }]];\nconst IconArrowUpRight = createReactComponent(\"outline\", \"arrow-up-right\", \"ArrowUpRight\", __iconNode);\n\nexport { __iconNode, IconArrowUpRight as default };\n//# sourceMappingURL=IconArrowUpRight.mjs.map\n","/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M4 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M18 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-2\" }]];\nconst IconDots = createReactComponent(\"outline\", \"dots\", \"Dots\", __iconNode);\n\nexport { __iconNode, IconDots as default };\n//# sourceMappingURL=IconDots.mjs.map\n","import {\n createContext,\n isValidElement,\n useContext,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type ComponentProps,\n type FC,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { IconArrowUpRight, IconDots } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils/cn\";\nimport { isReactComponent } from \"../../utils/is-react-component\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\nimport { Avatar } from \"../../components/avatar\";\nimport { buttonVariants } from \"../../components/button\";\n\n/**\n * Sidebar — Pho's first SECTION: a composed app rail, not a micro component.\n * It encodes the navigation rail used across Photon surfaces (the Pho docs\n * site, the dashboard): a sticky full-height column with a brand header, a\n * scrollable stack of titled nav groups, and a pinned footer that usually\n * carries the account row.\n *\n * Sections stay presentational — no router, no data fetching, no theme\n * plumbing. Links render through the host's `LinkProvider` (same contract as\n * `ButtonLink`), state arrives via props (`active`), and interactive footers\n * compose with other Pho parts (e.g. wrap `Sidebar.AccountRow` in a\n * `Menu.Trigger render={...}` to open an account menu).\n *\n * `Root` takes `inset` (`base` | `sm`, default `base`) for the rail's outer\n * padding and header spacing — prefer that over host-app class overrides.\n */\n\n/* ------------------------------- class map ------------------------------- */\n\n/** The rail itself — sticky, full-height, hairline right edge (no inset). */\nexport const SIDEBAR_ROOT =\n \"border-pho-secondary bg-pho-page sticky top-0 flex h-dvh w-64 shrink-0 flex-col border-r\";\n\n/** Outer inset on `Root` — `base` is the docs/default rail; `sm` is tighter. */\nexport const SIDEBAR_ROOT_INSET = {\n base: \"px-4 pt-5 pb-4\",\n sm: \"px-3 pt-4 pb-3\",\n} as const;\n\n/** `SIDEBAR_ROOT` with the default `base` inset — one string for docs chrome. */\nexport const SIDEBAR_ROOT_BASE = cn(SIDEBAR_ROOT, SIDEBAR_ROOT_INSET.base);\n\n/** Header spacing paired with `Root`'s `inset`. */\nexport const SIDEBAR_HEADER_INSET = {\n base: \"mb-6 px-2\",\n sm: \"mb-3 px-0\",\n} as const;\n\nexport type SidebarInset = keyof typeof SIDEBAR_ROOT_INSET;\n\n/** A nav row at rest and on hover. Active/inactive inks split below. */\nexport const SIDEBAR_ITEM =\n \"outline-pho-brand flex min-h-8 w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-base transition-colors focus-visible:outline-2 focus-visible:-outline-offset-1\";\n\n/**\n * Selected row — lifted onto the primary surface with the site hairline.\n * The icon carries the same ink as the label so the pair reads as one unit.\n */\nexport const SIDEBAR_ITEM_ACTIVE =\n \"bg-pho-primary text-pho-primary ring-pho-secondary font-medium ring-1 ring-inset *:data-icon:text-pho-primary\";\n\n/**\n * Resting row — secondary ink (75%). Hover lifts onto the primary surface\n * (same plane as the active chip, without the ring) so the wash stays quiet\n * on `pho-page`. Icon tracks the label's ink at every state.\n */\nexport const SIDEBAR_ITEM_INACTIVE = cn(\n \"text-pho-secondary *:data-icon:text-pho-secondary\",\n \"hover:bg-pho-primary hover:text-pho-primary hover:*:data-icon:text-pho-primary\",\n);\n\nconst SidebarInsetContext = createContext<SidebarInset>(\"base\");\n\n/* --------------------------------- frame --------------------------------- */\n\ninterface RootProps extends ComponentProps<\"aside\"> {\n /** Outer padding + header spacing. Defaults to `base`. */\n inset?: SidebarInset;\n ref?: Ref<HTMLElement>;\n}\n\n/** The rail — a sticky, full-height `<aside>` with the hairline right edge. */\nfunction Root({ className, inset = \"base\", ...props }: RootProps) {\n return (\n <SidebarInsetContext.Provider value={inset}>\n <aside\n className={cn(SIDEBAR_ROOT, SIDEBAR_ROOT_INSET[inset], className)}\n {...props}\n data-inset={inset}\n />\n </SidebarInsetContext.Provider>\n );\n}\n\n/** Brand slot at the top of the rail — logo, wordmark, workspace switcher. */\nfunction Header({ className, ...props }: ComponentProps<\"div\">) {\n const inset = useContext(SidebarInsetContext);\n return (\n <div\n className={cn(\n \"flex items-center gap-2.5\",\n SIDEBAR_HEADER_INSET[inset],\n className,\n )}\n {...props}\n />\n );\n}\n\n/** The scrollable middle — a stack of `Sidebar.Group`s. */\nfunction Nav({ className, ...props }: ComponentProps<\"nav\">) {\n return (\n <nav\n className={cn(\"flex flex-1 flex-col gap-6 overflow-y-auto\", className)}\n {...props}\n />\n );\n}\n\n/** One titled cluster of nav rows: a `GroupLabel` followed by a `List`. */\nfunction Group({ className, ...props }: ComponentProps<\"div\">) {\n return <div className={className} {...props} />;\n}\n\n/** The cluster's caption — description ink, regular weight. */\nfunction GroupLabel({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\n \"text-pho-description mb-2 px-2 text-xs font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface ListProps extends ComponentProps<\"ul\"> {\n /** Lay the rows out in two columns — for long, flat registries. */\n columns?: boolean;\n}\n\n/** The rows of a group. `columns` switches to a two-column grid. */\nfunction List({ className, columns, ...props }: ListProps) {\n return (\n <ul\n className={cn(\n // list-none/m-0/p-0 shield the rail from host prose styles.\n \"m-0 list-none p-0 *:m-0\",\n columns\n ? \"grid grid-cols-2 gap-x-2 gap-y-0.5\"\n : \"flex flex-col gap-0.5\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Pinned bottom cluster — docs link, account row, theme toggle. */\nfunction Footer({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div className={cn(\"mt-4 flex flex-col gap-0.5\", className)} {...props} />\n );\n}\n\n/* --------------------------------- item ---------------------------------- */\n\n/** An icon slot — a component (`IconBook`) or element (`<IconBook />`). */\ntype Slottable = ReactNode | FC<{ className?: string }>;\n\nfunction renderIcon(icon: Slottable): ReactNode {\n if (icon == null || icon === false) return null;\n let content: ReactNode = null;\n if (isReactComponent(icon)) {\n const Icon = icon;\n content = <Icon />;\n } else if (isValidElement(icon)) {\n content = icon;\n }\n if (content == null) return null;\n return (\n <span\n data-icon\n className=\"pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-4 [&>svg]:shrink-0\"\n >\n {content}\n </span>\n );\n}\n\ninterface ItemBaseProps {\n /** Slot before the label — a component (`IconBook`) or element. */\n icon?: Slottable;\n /** Marks the row as the current destination (adds `aria-current=\"page\"`). */\n active?: boolean;\n children?: ReactNode;\n className?: string;\n}\n\nexport interface SidebarItemLinkProps\n extends\n ItemBaseProps,\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof ItemBaseProps> {\n /** Destination — rendered through the host's `LinkProvider`. */\n href: string;\n /** Leaves the app: opens in a new tab and renders a ↗ cue. */\n external?: boolean;\n}\n\nexport interface SidebarItemButtonProps\n extends\n ItemBaseProps,\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ItemBaseProps> {\n href?: undefined;\n external?: undefined;\n}\n\nexport type SidebarItemProps = SidebarItemLinkProps | SidebarItemButtonProps;\n\n/**\n * A nav row — a link when `href` is given (rendered through the host's\n * `LinkProvider`), otherwise a button. `active` lifts the row onto the\n * primary surface; `external` opens a new tab and appends a ↗ cue.\n */\nfunction Item({\n icon,\n active,\n className,\n children,\n href,\n external,\n ...rest\n}: SidebarItemProps) {\n const Link = useLinkComponent();\n const rowClass = cn(\n SIDEBAR_ITEM,\n active ? SIDEBAR_ITEM_ACTIVE : SIDEBAR_ITEM_INACTIVE,\n className,\n );\n const label = <span className=\"min-w-0 flex-1 truncate\">{children}</span>;\n\n if (href !== undefined) {\n return (\n <li>\n <Link\n href={href}\n aria-current={active ? \"page\" : undefined}\n {...(external && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n {...(rest as AnchorHTMLAttributes<HTMLAnchorElement>)}\n className={rowClass}\n >\n {renderIcon(icon)}\n {label}\n {external && (\n <>\n {renderIcon(<IconArrowUpRight aria-hidden />)}\n <span className=\"sr-only\">(opens in a new tab)</span>\n </>\n )}\n </Link>\n </li>\n );\n }\n\n return (\n <li>\n <button\n type=\"button\"\n aria-current={active ? \"page\" : undefined}\n {...(rest as ButtonHTMLAttributes<HTMLButtonElement>)}\n className={rowClass}\n >\n {renderIcon(icon)}\n {label}\n </button>\n </li>\n );\n}\n\n/* ------------------------------ account row ------------------------------ */\n\n/**\n * Whole-row account trigger. The row itself stays visually quiet — it only\n * carries the `group` state (hover/press/popup-open) and the focus ring;\n * all visual feedback renders on the ⋯ circle via `group-*` classes.\n */\nconst ACCOUNT_ROW =\n \"group outline-pho-brand flex w-full cursor-pointer items-center gap-2 rounded-base p-2 text-left focus-visible:outline-2 focus-visible:outline-offset-2\";\n\n/** Avatar initials: first + last word initial, else the first character. */\nfunction initialsFrom(name: string): string {\n const words = name.split(/\\s+/).filter(Boolean);\n const first = words[0]?.[0] ?? name[0] ?? \"?\";\n const last = words.length >= 2 ? (words[words.length - 1]?.[0] ?? \"\") : \"\";\n return (first + last).toUpperCase();\n}\n\nexport interface SidebarAccountRowProps extends Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"children\"\n> {\n /** Display name — also the source for fallback initials. */\n name: string;\n /** Avatar image URL; falls back to initials while loading or on error. */\n avatarSrc?: string;\n /** Override the derived initials. */\n initials?: string;\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * The account chip pinned to the rail's footer — an xs avatar, the name, and\n * a decorative ⋯ circle. The WHOLE row is one button, but the row is only the\n * control — the circle is the indicator: hover, press, and menu-open feedback\n * all render on the ⋯ (a span wearing the stock secondary-circle button\n * classes), driven by the row's `group` state, so it reads as a button\n * without nesting one.\n *\n * It renders a plain `<button>` and forwards every prop, so it slots straight\n * into a menu: `<Menu.Trigger render={<Sidebar.AccountRow name=\"…\" />} />` —\n * Base UI's `data-popup-open` / `data-pressed` states light up the circle.\n */\nfunction AccountRow({\n name,\n avatarSrc,\n initials,\n className,\n ...props\n}: SidebarAccountRowProps) {\n return (\n <button type=\"button\" className={cn(ACCOUNT_ROW, className)} {...props}>\n <Avatar.Root size=\"xs\">\n {avatarSrc && <Avatar.Image src={avatarSrc} alt=\"\" />}\n <Avatar.Fallback>{initials ?? initialsFrom(name)}</Avatar.Fallback>\n </Avatar.Root>\n <span className=\"text-pho-primary min-w-0 flex-1 truncate text-base\">\n {name}\n </span>\n <span\n aria-hidden\n className={buttonVariants({\n variant: \"outlined\",\n size: \"sm\",\n shape: \"circle\",\n className:\n \"group-hover:bg-pho-primary-hover group-hover:text-pho-secondary-hover group-data-[popup-open]:bg-pho-primary-hover group-data-[popup-open]:text-pho-secondary-hover p-1 group-data-[pressed]:scale-[0.97]\",\n })}\n >\n <IconDots className=\"size-4\" />\n </span>\n </button>\n );\n}\n\n/* -------------------------------- assembly ------------------------------- */\n\n/**\n * The composed sidebar rail. Assemble the frame parts and fill them with\n * rows; wire interactivity by composing other Pho parts around them:\n *\n * ```tsx\n * <Sidebar.Root>\n * <Sidebar.Header>…brand…</Sidebar.Header>\n * <Sidebar.Nav>\n * <Sidebar.Group>\n * <Sidebar.GroupLabel>Pages</Sidebar.GroupLabel>\n * <Sidebar.List>\n * <Sidebar.Item href=\"/\" icon={IconHome} active>\n * Overview\n * </Sidebar.Item>\n * </Sidebar.List>\n * </Sidebar.Group>\n * </Sidebar.Nav>\n * <Sidebar.Footer>\n * <Menu.Root>\n * <Menu.Trigger render={<Sidebar.AccountRow name=\"Ada Lovelace\" />} />\n * …\n * </Menu.Root>\n * </Sidebar.Footer>\n * </Sidebar.Root>\n * ```\n */\nexport const Sidebar = {\n Root,\n Header,\n Nav,\n Group,\n GroupLabel,\n List,\n Item,\n Footer,\n AccountRow,\n};\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
1
+ {"version":3,"file":"sidebar-DGpEKxOn.js","names":["__iconNode"],"sources":["../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowUpRight.mjs","../../../../node_modules/.pnpm/@tabler+icons-react@3.44.0_react@19.2.7/node_modules/@tabler/icons-react/dist/esm/icons/IconDots.mjs","../../src/sections/sidebar/sidebar.tsx"],"sourcesContent":["/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M17 7l-10 10\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M8 7l9 0l0 9\", \"key\": \"svg-1\" }]];\nconst IconArrowUpRight = createReactComponent(\"outline\", \"arrow-up-right\", \"ArrowUpRight\", __iconNode);\n\nexport { __iconNode, IconArrowUpRight as default };\n//# sourceMappingURL=IconArrowUpRight.mjs.map\n","/**\n * @license @tabler/icons-react v3.44.0 - MIT\n *\n * This source code is licensed under the MIT license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createReactComponent from '../createReactComponent.mjs';\n\nconst __iconNode = [[\"path\", { \"d\": \"M4 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-0\" }], [\"path\", { \"d\": \"M11 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-1\" }], [\"path\", { \"d\": \"M18 12a1 1 0 1 0 2 0a1 1 0 1 0 -2 0\", \"key\": \"svg-2\" }]];\nconst IconDots = createReactComponent(\"outline\", \"dots\", \"Dots\", __iconNode);\n\nexport { __iconNode, IconDots as default };\n//# sourceMappingURL=IconDots.mjs.map\n","import {\n createContext,\n isValidElement,\n useContext,\n type AnchorHTMLAttributes,\n type ButtonHTMLAttributes,\n type ComponentProps,\n type FC,\n type ReactNode,\n type Ref,\n} from \"react\";\nimport { IconArrowUpRight, IconDots } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils/cn\";\nimport { isReactComponent } from \"../../utils/is-react-component\";\nimport { useLinkComponent } from \"../../utils/link-provider\";\nimport { Avatar } from \"../../components/avatar\";\nimport { buttonVariants } from \"../../components/button\";\n\n/**\n * Sidebar — Pho's first SECTION: a composed app rail, not a micro component.\n * It encodes the navigation rail used across Photon surfaces (the Pho docs\n * site, the dashboard): a sticky full-height column with a brand header, a\n * scrollable stack of titled nav groups, and a pinned footer that usually\n * carries the account row.\n *\n * Sections stay presentational — no router, no data fetching, no theme\n * plumbing. Links render through the host's `LinkProvider` (same contract as\n * `ButtonLink`), state arrives via props (`active`), and interactive footers\n * compose with other Pho parts (e.g. wrap `Sidebar.AccountRow` in a\n * `Menu.Trigger render={...}` to open an account menu).\n *\n * `Root` takes `inset` (`base` | `sm`, default `base`) for the rail's outer\n * padding and header spacing — prefer that over host-app class overrides.\n */\n\n/* ------------------------------- class map ------------------------------- */\n\n/** The rail itself — sticky, full-height, hairline right edge (no inset). */\nexport const SIDEBAR_ROOT =\n \"border-pho-secondary bg-pho-page sticky top-0 flex h-dvh w-64 shrink-0 flex-col border-r\";\n\n/** Outer inset on `Root` — `base` is the docs/default rail; `sm` is tighter. */\nexport const SIDEBAR_ROOT_INSET = {\n base: \"px-4 pt-5 pb-4\",\n sm: \"px-3 pt-4 pb-3\",\n} as const;\n\n/** `SIDEBAR_ROOT` with the default `base` inset — one string for docs chrome. */\nexport const SIDEBAR_ROOT_BASE = cn(SIDEBAR_ROOT, SIDEBAR_ROOT_INSET.base);\n\n/** Header spacing paired with `Root`'s `inset`. */\nexport const SIDEBAR_HEADER_INSET = {\n base: \"mb-6 px-2\",\n sm: \"mb-3 px-0\",\n} as const;\n\nexport type SidebarInset = keyof typeof SIDEBAR_ROOT_INSET;\n\n/** A nav row at rest and on hover. Active/inactive inks split below. */\nexport const SIDEBAR_ITEM =\n \"outline-pho-brand flex min-h-9 w-full cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-left text-base transition-colors focus-visible:outline-2 focus-visible:-outline-offset-1\";\n\n/**\n * Selected row — lifted onto the primary surface with the site hairline.\n * The icon carries the same ink as the label so the pair reads as one unit.\n */\nexport const SIDEBAR_ITEM_ACTIVE =\n \"bg-pho-primary text-pho-primary ring-pho-secondary font-medium ring-1 ring-inset *:data-icon:text-pho-primary\";\n\n/**\n * Resting row — secondary ink (75%). Hover lifts onto the primary surface\n * (same plane as the active chip, without the ring) so the wash stays quiet\n * on `pho-page`. Icon tracks the label's ink at every state.\n */\nexport const SIDEBAR_ITEM_INACTIVE = cn(\n \"text-pho-secondary *:data-icon:text-pho-secondary\",\n \"hover:bg-pho-primary hover:text-pho-primary hover:*:data-icon:text-pho-primary\",\n);\n\nconst SidebarInsetContext = createContext<SidebarInset>(\"base\");\n\n/* --------------------------------- frame --------------------------------- */\n\ninterface RootProps extends ComponentProps<\"aside\"> {\n /** Outer padding + header spacing. Defaults to `base`. */\n inset?: SidebarInset;\n ref?: Ref<HTMLElement>;\n}\n\n/** The rail — a sticky, full-height `<aside>` with the hairline right edge. */\nfunction Root({ className, inset = \"base\", ...props }: RootProps) {\n return (\n <SidebarInsetContext.Provider value={inset}>\n <aside\n className={cn(SIDEBAR_ROOT, SIDEBAR_ROOT_INSET[inset], className)}\n {...props}\n data-inset={inset}\n />\n </SidebarInsetContext.Provider>\n );\n}\n\n/** Brand slot at the top of the rail — logo, wordmark, workspace switcher. */\nfunction Header({ className, ...props }: ComponentProps<\"div\">) {\n const inset = useContext(SidebarInsetContext);\n return (\n <div\n className={cn(\n \"flex items-center gap-2.5\",\n SIDEBAR_HEADER_INSET[inset],\n className,\n )}\n {...props}\n />\n );\n}\n\n/** The scrollable middle — a stack of `Sidebar.Group`s. */\nfunction Nav({ className, ...props }: ComponentProps<\"nav\">) {\n return (\n <nav\n className={cn(\"flex flex-1 flex-col gap-6 overflow-y-auto\", className)}\n {...props}\n />\n );\n}\n\n/** One titled cluster of nav rows: a `GroupLabel` followed by a `List`. */\nfunction Group({ className, ...props }: ComponentProps<\"div\">) {\n return <div className={className} {...props} />;\n}\n\n/** The cluster's caption — description ink, regular weight. */\nfunction GroupLabel({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div\n className={cn(\n \"text-pho-description mb-2 px-2 text-xs font-normal\",\n className,\n )}\n {...props}\n />\n );\n}\n\ninterface ListProps extends ComponentProps<\"ul\"> {\n /** Lay the rows out in two columns — for long, flat registries. */\n columns?: boolean;\n}\n\n/** The rows of a group. `columns` switches to a two-column grid. */\nfunction List({ className, columns, ...props }: ListProps) {\n return (\n <ul\n className={cn(\n // list-none/m-0/p-0 shield the rail from host prose styles.\n \"m-0 list-none p-0 *:m-0\",\n columns\n ? \"grid grid-cols-2 gap-x-2 gap-y-0.5\"\n : \"flex flex-col gap-0.5\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Pinned bottom cluster — docs link, account row, theme toggle. */\nfunction Footer({ className, ...props }: ComponentProps<\"div\">) {\n return (\n <div className={cn(\"mt-4 flex flex-col gap-0.5\", className)} {...props} />\n );\n}\n\n/* --------------------------------- item ---------------------------------- */\n\n/** An icon slot — a component (`IconBook`) or element (`<IconBook />`). */\ntype Slottable = ReactNode | FC<{ className?: string }>;\n\nfunction renderIcon(icon: Slottable): ReactNode {\n if (icon == null || icon === false) return null;\n let content: ReactNode = null;\n if (isReactComponent(icon)) {\n const Icon = icon;\n content = <Icon />;\n } else if (isValidElement(icon)) {\n content = icon;\n }\n if (content == null) return null;\n return (\n <span\n data-icon\n className=\"pointer-events-none inline-flex shrink-0 items-center [&>svg]:size-4 [&>svg]:shrink-0\"\n >\n {content}\n </span>\n );\n}\n\ninterface ItemBaseProps {\n /** Slot before the label — a component (`IconBook`) or element. */\n icon?: Slottable;\n /** Marks the row as the current destination (adds `aria-current=\"page\"`). */\n active?: boolean;\n children?: ReactNode;\n className?: string;\n}\n\nexport interface SidebarItemLinkProps\n extends\n ItemBaseProps,\n Omit<AnchorHTMLAttributes<HTMLAnchorElement>, keyof ItemBaseProps> {\n /** Destination — rendered through the host's `LinkProvider`. */\n href: string;\n /** Leaves the app: opens in a new tab and renders a ↗ cue. */\n external?: boolean;\n}\n\nexport interface SidebarItemButtonProps\n extends\n ItemBaseProps,\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof ItemBaseProps> {\n href?: undefined;\n external?: undefined;\n}\n\nexport type SidebarItemProps = SidebarItemLinkProps | SidebarItemButtonProps;\n\n/**\n * A nav row — a link when `href` is given (rendered through the host's\n * `LinkProvider`), otherwise a button. `active` lifts the row onto the\n * primary surface; `external` opens a new tab and appends a ↗ cue.\n */\nfunction Item({\n icon,\n active,\n className,\n children,\n href,\n external,\n ...rest\n}: SidebarItemProps) {\n const Link = useLinkComponent();\n const rowClass = cn(\n SIDEBAR_ITEM,\n active ? SIDEBAR_ITEM_ACTIVE : SIDEBAR_ITEM_INACTIVE,\n className,\n );\n const label = <span className=\"min-w-0 flex-1 truncate\">{children}</span>;\n\n if (href !== undefined) {\n return (\n <li>\n <Link\n href={href}\n aria-current={active ? \"page\" : undefined}\n {...(external && { target: \"_blank\", rel: \"noopener noreferrer\" })}\n {...(rest as AnchorHTMLAttributes<HTMLAnchorElement>)}\n className={rowClass}\n >\n {renderIcon(icon)}\n {label}\n {external && (\n <>\n {renderIcon(<IconArrowUpRight aria-hidden />)}\n <span className=\"sr-only\">(opens in a new tab)</span>\n </>\n )}\n </Link>\n </li>\n );\n }\n\n return (\n <li>\n <button\n type=\"button\"\n aria-current={active ? \"page\" : undefined}\n {...(rest as ButtonHTMLAttributes<HTMLButtonElement>)}\n className={rowClass}\n >\n {renderIcon(icon)}\n {label}\n </button>\n </li>\n );\n}\n\n/* ------------------------------ account row ------------------------------ */\n\n/**\n * Whole-row account trigger. The row itself stays visually quiet — it only\n * carries the `group` state (hover/press/popup-open) and the focus ring;\n * all visual feedback renders on the ⋯ circle via `group-*` classes.\n */\nconst ACCOUNT_ROW =\n \"group outline-pho-brand flex w-full cursor-pointer items-center gap-2 rounded-base p-2 text-left focus-visible:outline-2 focus-visible:outline-offset-2\";\n\n/** Avatar initials: first + last word initial, else the first character. */\nfunction initialsFrom(name: string): string {\n const words = name.split(/\\s+/).filter(Boolean);\n const first = words[0]?.[0] ?? name[0] ?? \"?\";\n const last = words.length >= 2 ? (words[words.length - 1]?.[0] ?? \"\") : \"\";\n return (first + last).toUpperCase();\n}\n\nexport interface SidebarAccountRowProps extends Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"children\"\n> {\n /** Display name — also the source for fallback initials. */\n name: string;\n /** Avatar image URL; falls back to initials while loading or on error. */\n avatarSrc?: string;\n /** Override the derived initials. */\n initials?: string;\n ref?: Ref<HTMLButtonElement>;\n}\n\n/**\n * The account chip pinned to the rail's footer — an xs avatar, the name, and\n * a decorative ⋯ circle. The WHOLE row is one button, but the row is only the\n * control — the circle is the indicator: hover, press, and menu-open feedback\n * all render on the ⋯ (a span wearing the stock secondary-circle button\n * classes), driven by the row's `group` state, so it reads as a button\n * without nesting one.\n *\n * It renders a plain `<button>` and forwards every prop, so it slots straight\n * into a menu: `<Menu.Trigger render={<Sidebar.AccountRow name=\"…\" />} />` —\n * Base UI's `data-popup-open` / `data-pressed` states light up the circle.\n */\nfunction AccountRow({\n name,\n avatarSrc,\n initials,\n className,\n ...props\n}: SidebarAccountRowProps) {\n return (\n <button type=\"button\" className={cn(ACCOUNT_ROW, className)} {...props}>\n <Avatar.Root size=\"xs\">\n {avatarSrc && <Avatar.Image src={avatarSrc} alt=\"\" />}\n <Avatar.Fallback>{initials ?? initialsFrom(name)}</Avatar.Fallback>\n </Avatar.Root>\n <span className=\"text-pho-primary min-w-0 flex-1 truncate text-base\">\n {name}\n </span>\n <span\n aria-hidden\n className={buttonVariants({\n variant: \"outlined\",\n size: \"sm\",\n shape: \"circle\",\n className:\n \"group-hover:bg-pho-primary-hover group-hover:text-pho-secondary-hover group-data-[popup-open]:bg-pho-primary-hover group-data-[popup-open]:text-pho-secondary-hover p-1 group-data-[pressed]:scale-[0.97]\",\n })}\n >\n <IconDots className=\"size-4\" />\n </span>\n </button>\n );\n}\n\n/* -------------------------------- assembly ------------------------------- */\n\n/**\n * The composed sidebar rail. Assemble the frame parts and fill them with\n * rows; wire interactivity by composing other Pho parts around them:\n *\n * ```tsx\n * <Sidebar.Root>\n * <Sidebar.Header>…brand…</Sidebar.Header>\n * <Sidebar.Nav>\n * <Sidebar.Group>\n * <Sidebar.GroupLabel>Pages</Sidebar.GroupLabel>\n * <Sidebar.List>\n * <Sidebar.Item href=\"/\" icon={IconHome} active>\n * Overview\n * </Sidebar.Item>\n * </Sidebar.List>\n * </Sidebar.Group>\n * </Sidebar.Nav>\n * <Sidebar.Footer>\n * <Menu.Root>\n * <Menu.Trigger render={<Sidebar.AccountRow name=\"Ada Lovelace\" />} />\n * …\n * </Menu.Root>\n * </Sidebar.Footer>\n * </Sidebar.Root>\n * ```\n */\nexport const Sidebar = {\n Root,\n Header,\n Nav,\n Group,\n GroupLabel,\n List,\n Item,\n Footer,\n AccountRow,\n};\n"],"x_google_ignoreList":[0,1],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ "use client";
2
+ import { useCallback as u, useEffect as w, useRef as f } from "react";
3
+ import { useAnimationControls as E } from "motion/react";
4
+ var L = {
5
+ type: "spring",
6
+ stiffness: 700,
7
+ damping: 32,
8
+ mass: 0.06
9
+ }, R = 0.96;
10
+ function S(l) {
11
+ const p = l?.scale ?? 0.96, t = l?.disabled ?? !1, s = l?.transition ?? L, n = E(), i = f(!1), d = f(null), r = f(null);
12
+ w(() => () => r.current?.(), []);
13
+ const o = u(() => {
14
+ t || (i.current = !0, d.current = n.start({
15
+ scale: p,
16
+ transition: s
17
+ }));
18
+ }, [
19
+ n,
20
+ t,
21
+ p,
22
+ s
23
+ ]), c = u(async () => {
24
+ if (!i.current) return;
25
+ i.current = !1;
26
+ const e = d.current;
27
+ await e, !(i.current || d.current !== e) && n.start({
28
+ scale: 1,
29
+ transition: s
30
+ });
31
+ }, [n, s]);
32
+ return {
33
+ pulse: u(() => {
34
+ o(), c();
35
+ }, [o, c]),
36
+ motionProps: {
37
+ initial: !1,
38
+ animate: n,
39
+ onPointerDown: u((e) => {
40
+ if (t || e.button !== 0 || !e.isPrimary) return;
41
+ o(), r.current?.();
42
+ const a = (m) => {
43
+ m.pointerId === e.pointerId && (r.current?.(), c());
44
+ };
45
+ window.addEventListener("pointerup", a), window.addEventListener("pointercancel", a), r.current = () => {
46
+ window.removeEventListener("pointerup", a), window.removeEventListener("pointercancel", a), r.current = null;
47
+ };
48
+ }, [
49
+ t,
50
+ o,
51
+ c
52
+ ])
53
+ }
54
+ };
55
+ }
56
+ export {
57
+ L as n,
58
+ S as r,
59
+ R as t
60
+ };
61
+
62
+ //# sourceMappingURL=use-press-pulse-8iorQPsh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-press-pulse-8iorQPsh.js","names":[],"sources":["../../src/utils/use-press-pulse.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport { useAnimationControls, type Transition } from \"motion/react\";\n\n/**\n * Press feedback for selection controls (Select trigger, Checkbox…) — the same\n * spring family as Button's effect press, and the same pointer-following\n * behavior: press in on pointer-down, stay compressed while held, spring back\n * on release. One deliberate refinement over a bare `whileTap`: a fast tap\n * never truncates the press-in leg — it always reaches full depth before\n * springing back, so even the quickest click reads as a complete tick.\n */\nexport const CONTROL_PRESS_SPRING = {\n type: \"spring\",\n stiffness: 700,\n damping: 32,\n mass: 0.06,\n} as const;\n\n/** Default press depth — shallow; each control can tune its own. */\nexport const CONTROL_PRESS_SCALE = 0.96;\n\n/**\n * Pointer-following press driven by Motion controls. Spread `motionProps` onto\n * a `motion.*` element (via Base UI `render`): pointer-down (primary button)\n * compresses and holds; release springs back once the press-in leg has\n * finished. Release is tracked on `window`, so dragging off the control before\n * letting go still restores it.\n */\nexport function usePressPulse(opts?: {\n scale?: number;\n disabled?: boolean;\n /** Spring override for both legs of the press. @default CONTROL_PRESS_SPRING */\n transition?: Transition;\n}) {\n const scale = opts?.scale ?? CONTROL_PRESS_SCALE;\n const disabled = opts?.disabled ?? false;\n const transition = opts?.transition ?? CONTROL_PRESS_SPRING;\n const controls = useAnimationControls();\n const pressed = useRef(false);\n const pressIn = useRef<Promise<unknown> | null>(null);\n const removeListeners = useRef<(() => void) | null>(null);\n\n useEffect(() => () => removeListeners.current?.(), []);\n\n const press = useCallback(() => {\n if (disabled) return;\n pressed.current = true;\n pressIn.current = controls.start({ scale, transition });\n }, [controls, disabled, scale, transition]);\n\n const release = useCallback(async () => {\n if (!pressed.current) return;\n pressed.current = false;\n const leg = pressIn.current;\n // Let the press-in leg play out in full before springing back, so a tap\n // shorter than the spring still shows the whole press.\n await leg;\n // A re-press started while we waited — its own release will restore.\n if (pressed.current || pressIn.current !== leg) return;\n void controls.start({ scale: 1, transition });\n }, [controls, transition]);\n\n /** Programmatic one-shot pulse (press in, then spring back). */\n const pulse = useCallback(() => {\n press();\n void release();\n }, [press, release]);\n\n const onPointerDown = useCallback(\n (event: { button: number; pointerId: number; isPrimary: boolean }) => {\n if (disabled || event.button !== 0 || !event.isPrimary) return;\n press();\n // The pointer may be released anywhere (including off the control after\n // dragging away), so listen on window rather than the element — but only\n // for the pointer that started this press, so another finger lifting\n // elsewhere doesn't spring the control back early.\n removeListeners.current?.();\n const end = (e: PointerEvent) => {\n if (e.pointerId !== event.pointerId) return;\n removeListeners.current?.();\n void release();\n };\n window.addEventListener(\"pointerup\", end);\n window.addEventListener(\"pointercancel\", end);\n removeListeners.current = () => {\n window.removeEventListener(\"pointerup\", end);\n window.removeEventListener(\"pointercancel\", end);\n removeListeners.current = null;\n };\n },\n [disabled, press, release],\n );\n\n return {\n pulse,\n motionProps: { initial: false as const, animate: controls, onPointerDown },\n };\n}\n"],"mappings":";;;AAWA,IAAa,IAAuB;AAAA,EAClC,MAAM;AAAA,EACN,WAAW;AAAA,EACX,SAAS;AAAA,EACT,MAAM;AACR,GAGa,IAAsB;AASnC,SAAgB,EAAc,GAK3B;AACD,QAAM,IAAQ,GAAM,SAAA,MACd,IAAW,GAAM,YAAY,IAC7B,IAAa,GAAM,cAAc,GACjC,IAAW,EAAqB,GAChC,IAAU,EAAO,EAAK,GACtB,IAAU,EAAgC,IAAI,GAC9C,IAAkB,EAA4B,IAAI;AAExD,EAAA,EAAA,MAAA,MAAsB,EAAgB,UAAU,GAAG,CAAC,CAAC;AAErD,QAAM,IAAQ,EAAA,MAAkB;AAC9B,IAAI,MACJ,EAAQ,UAAU,IAClB,EAAQ,UAAU,EAAS,MAAM;AAAA,MAAE,OAAA;AAAA,MAAO,YAAA;AAAA,IAAW,CAAC;AAAA,EACxD,GAAG;AAAA,IAAC;AAAA,IAAU;AAAA,IAAU;AAAA,IAAO;AAAA,EAAU,CAAC,GAEpC,IAAU,EAAY,YAAY;AACtC,QAAI,CAAC,EAAQ,QAAS;AACtB,IAAA,EAAQ,UAAU;AAClB,UAAM,IAAM,EAAQ;AAKpB,IAFA,MAAM,GAEF,EAAA,EAAQ,WAAW,EAAQ,YAAY,MAC3C,EAAc,MAAM;AAAA,MAAE,OAAO;AAAA,MAAG,YAAA;AAAA,IAAW,CAAC;AAAA,EAC9C,GAAG,CAAC,GAAU,CAAU,CAAC;AAiCzB,SAAO;AAAA,IACL,OA/BY,EAAA,MAAkB;AAC9B,MAAA,EAAM,GACN,EAAa;AAAA,IACf,GAAG,CAAC,GAAO,CAAO,CA4BhB;AAAA,IACA,aAAa;AAAA,MAAE,SAAS;AAAA,MAAgB,SAAS;AAAA,MAAU,eA3BvC,EAAA,CACnB,MAAqE;AACpE,YAAI,KAAY,EAAM,WAAW,KAAK,CAAC,EAAM,UAAW;AACxD,QAAA,EAAM,GAKN,EAAgB,UAAU;AAC1B,cAAM,IAAA,CAAO,MAAoB;AAC/B,UAAI,EAAE,cAAc,EAAM,cAC1B,EAAgB,UAAU,GAC1B,EAAa;AAAA,QACf;AACA,eAAO,iBAAiB,aAAa,CAAG,GACxC,OAAO,iBAAiB,iBAAiB,CAAG,GAC5C,EAAgB,UAAA,MAAgB;AAC9B,iBAAO,oBAAoB,aAAa,CAAG,GAC3C,OAAO,oBAAoB,iBAAiB,CAAG,GAC/C,EAAgB,UAAU;AAAA,QAC5B;AAAA,MACF,GACA;AAAA,QAAC;AAAA,QAAU;AAAA,QAAO;AAAA,MAAO,CAKkC;AAAA,IAAc;AAAA,EAC3E;AACF"}
@@ -1,59 +1,74 @@
1
1
  "use client";
2
- import { t as a } from "../chunks/cn-DTiB6ek_.js";
3
- import { t as i } from "../chunks/resolve-variant-CcD8iG5l.js";
2
+ import { t as s } from "../chunks/cn-DTiB6ek_.js";
3
+ import { t as a } from "../chunks/resolve-variant-CcD8iG5l.js";
4
4
  import "react";
5
- import { jsx as o } from "react/jsx-runtime";
6
- var l = a("inline-flex shrink-0 items-center whitespace-nowrap rounded-full font-medium", "bg-current/10 ring-1 ring-current/20 ring-inset"), c = {
5
+ import { jsx as l } from "react/jsx-runtime";
6
+ var p = "inline-flex shrink-0 items-center whitespace-nowrap rounded-full font-medium", d = "bg-current/10 ring-1 ring-current/20 ring-inset", h = {
7
+ xs: {
8
+ classes: "h-4 gap-0.5 px-1.5 text-[10px] leading-none",
9
+ description: "Extra small — 16px; inline next to 14px labels (plan chips)"
10
+ },
7
11
  sm: {
8
- classes: "gap-0.5 px-1.5 py-px text-xs",
9
- description: "Small — dense rows, table cells, inline with tight text"
12
+ classes: "h-5 gap-0.5 px-2 text-xs leading-none",
13
+ description: "Small — 20px; dense rows, table cells"
10
14
  },
11
15
  md: {
12
- classes: "gap-1 px-2 py-0.5 text-xs",
13
- description: "Medium — the default"
16
+ classes: "h-6 gap-1 px-2.5 text-xs leading-none",
17
+ description: "Medium — 24px; the default"
14
18
  }
15
- }, d = {
19
+ }, c = {
16
20
  gray: {
17
- classes: "text-pho-secondary",
18
- description: "Neutral — the low-signal default"
21
+ high: "bg-pho-inverse text-pho-inverse",
22
+ low: "text-pho-secondary",
23
+ description: "Neutral — the low-signal default (solid inverse)"
24
+ },
25
+ muted: {
26
+ high: "bg-pho-secondary text-pho-primary",
27
+ low: "text-pho-description",
28
+ description: "Muted — soft solid surface for quieter labels (Free, Shared)"
19
29
  },
20
30
  brand: {
21
- classes: "text-pho-brand",
31
+ high: "bg-pho-brand-solid text-pho-on-brand",
32
+ low: "text-pho-brand",
22
33
  description: "Brand — plan tiers, feature flags, highlights"
23
34
  },
24
35
  success: {
25
- classes: "text-pho-success",
36
+ high: "bg-pho-success-ink text-pho-on-brand",
37
+ low: "text-pho-success",
26
38
  description: "Success — healthy, live, complete"
27
39
  },
28
40
  warning: {
29
- classes: "text-pho-warning",
41
+ high: "bg-pho-warning-ink text-pho-on-brand",
42
+ low: "text-pho-warning",
30
43
  description: "Warning — needs attention, degraded"
31
44
  },
32
45
  error: {
33
- classes: "text-pho-error",
46
+ high: "bg-pho-error-ink text-pho-on-brand",
47
+ low: "text-pho-error",
34
48
  description: "Error — failed, blocked, over limit"
35
49
  }
36
50
  };
37
- function p(e) {
38
- const { color: s = "gray", size: t = "md", className: r } = e ?? {};
39
- return a(l, i(c, t), i(d, s), r);
51
+ function g(r) {
52
+ const { color: t = "gray", contrast: n = "high", size: i = "md", className: o } = r ?? {}, e = c[t];
53
+ return s(p, a(h, i), n === "low" ? s(d, e?.low) : e?.high, o);
40
54
  }
41
- function g({ color: e, size: s, className: t, children: r, ...n }) {
42
- return /* @__PURE__ */ o("span", {
43
- className: a(p({
44
- color: e,
45
- size: s
46
- }), t),
47
- ...n,
48
- children: r
55
+ function x({ color: r, contrast: t, size: n, className: i, children: o, ...e }) {
56
+ return /* @__PURE__ */ l("span", {
57
+ className: s(g({
58
+ color: r,
59
+ contrast: t,
60
+ size: n
61
+ }), i),
62
+ ...e,
63
+ children: o
49
64
  });
50
65
  }
51
- g.displayName = "Badge";
66
+ x.displayName = "Badge";
52
67
  export {
53
- d as BADGE_COLORS,
54
- c as BADGE_SIZES,
55
- g as Badge,
56
- p as badgeVariants
68
+ c as BADGE_COLORS,
69
+ h as BADGE_SIZES,
70
+ x as Badge,
71
+ g as badgeVariants
57
72
  };
58
73
 
59
74
  //# sourceMappingURL=badge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"badge.js","names":[],"sources":["../../src/components/badge/badge.tsx"],"sourcesContent":["import { type ComponentProps } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant, type VariantMap } from \"../../utils/resolve-variant\";\n\n/**\n * Design notes (Geist-aligned):\n * - ONE color axis, a tight semantic set (`gray` / `brand` / `success` /\n * `warning` / `error`). Untitled UI's `type` triplication (modern / pill /\n * badge-color) is dropped: a Badge is always the soft \"accent\" material.\n * - The color axis only sets the *text* token; the fill and hairline ring\n * derive from `currentColor` at low opacity, so every color shares one recipe\n * and no per-color background/ring token has to exist.\n * - TWO sizes (`sm` / `md`, default `md`). A badge is inherently small.\n * - The richer Untitled features (dot, icon, avatar, count, dismiss button) are\n * deliberately left out — a dismissible or selectable chip is a Tag, not a\n * Badge, and a badge that triggers an action is a Button.\n */\n\n/** Shared material: pill shape + the currentColor-derived accent fill and ring. */\nconst BADGE_BASE = cn(\n \"inline-flex shrink-0 items-center whitespace-nowrap rounded-full font-medium\",\n \"bg-current/10 ring-1 ring-current/20 ring-inset\",\n);\n\n/** Size axis — padding, gap, and label size. */\nexport const BADGE_SIZES = {\n sm: {\n classes: \"gap-0.5 px-1.5 py-px text-xs\",\n description: \"Small — dense rows, table cells, inline with tight text\",\n },\n md: {\n classes: \"gap-1 px-2 py-0.5 text-xs\",\n description: \"Medium — the default\",\n },\n} satisfies VariantMap;\n\n/** Color axis — a closed semantic set; each key tints text, fill, and ring. */\nexport const BADGE_COLORS = {\n gray: {\n classes: \"text-pho-secondary\",\n description: \"Neutral — the low-signal default\",\n },\n brand: {\n classes: \"text-pho-brand\",\n description: \"Brand — plan tiers, feature flags, highlights\",\n },\n success: {\n classes: \"text-pho-success\",\n description: \"Success — healthy, live, complete\",\n },\n warning: {\n classes: \"text-pho-warning\",\n description: \"Warning — needs attention, degraded\",\n },\n error: {\n classes: \"text-pho-error\",\n description: \"Error — failed, blocked, over limit\",\n },\n} satisfies VariantMap;\n\nexport type BadgeSize = keyof typeof BADGE_SIZES;\nexport type BadgeColor = keyof typeof BADGE_COLORS;\n\n/** Compose the full class string for a badge — exported for reuse/testing. */\nexport function badgeVariants(opts?: {\n color?: BadgeColor;\n size?: BadgeSize;\n className?: string;\n}): string {\n const { color = \"gray\", size = \"md\", className } = opts ?? {};\n return cn(\n BADGE_BASE,\n resolveVariant(BADGE_SIZES, size),\n resolveVariant(BADGE_COLORS, color),\n className,\n );\n}\n\ninterface BadgeBaseProps {\n /** Semantic color. @default \"gray\" */\n color?: BadgeColor;\n /** Size variant. @default \"md\" */\n size?: BadgeSize;\n}\n\nexport interface BadgeProps\n extends BadgeBaseProps, Omit<ComponentProps<\"span\">, keyof BadgeBaseProps> {}\n\n/**\n * Badge — a small, non-interactive status label: a plan tier (`Pro`), a state\n * (`Live`, `Failed`), a count. It's a plain `<span>`, so it never takes focus or\n * handles clicks — for a dismissible or selectable chip reach for a `Tag`, and\n * for a standalone action use a `Button`. Let `color` carry the meaning and keep\n * the label to a word or two.\n */\nexport function Badge({\n color,\n size,\n className,\n children,\n ...props\n}: BadgeProps) {\n return (\n <span className={cn(badgeVariants({ color, size }), className)} {...props}>\n {children}\n </span>\n );\n}\n\nBadge.displayName = \"Badge\";\n"],"mappings":";;;;;AAmBA,IAAM,IAAa,EACjB,gFACA,iDACF,GAGa,IAAc;AAAA,EACzB,IAAI;AAAA,IACF,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,IAAI;AAAA,IACF,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AACF,GAGa,IAAe;AAAA,EAC1B,MAAM;AAAA,IACJ,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AACF;AAMA,SAAgB,EAAc,GAInB;AACT,QAAM,EAAE,OAAA,IAAQ,QAAQ,MAAA,IAAO,MAAM,WAAA,EAAA,IAAc,KAAQ,CAAC;AAC5D,SAAO,EACL,GACA,EAAe,GAAa,CAAI,GAChC,EAAe,GAAc,CAAK,GAClC,CACF;AACF;AAmBA,SAAgB,EAAM,EACpB,OAAA,GACA,MAAA,GACA,WAAA,GACA,UAAA,GACA,GAAG,EAAA,GACU;AACb,SACE,gBAAA,EAAC,QAAD;AAAA,IAAM,WAAW,EAAG,EAAc;AAAA,MAAE,OAAA;AAAA,MAAO,MAAA;AAAA,IAAK,CAAC,GAAG,CAAS;AAAA,IAAG,GAAI;AAAA,IACjE,UAAA;AAAA,EACG,CAAA;AAEV;AAEA,EAAM,cAAc"}
1
+ {"version":3,"file":"badge.js","names":[],"sources":["../../src/components/badge/badge.tsx"],"sourcesContent":["import { type ComponentProps } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant, type VariantMap } from \"../../utils/resolve-variant\";\n\n/**\n * Design notes (Geist-aligned):\n * - ONE color axis, a tight semantic set (`gray` / `muted` / `brand` /\n * `success` / `warning` / `error`). Untitled UI's `type` triplication\n * (modern / pill / badge-color) is dropped.\n * - TWO contrasts (`high` / `low`, default `high`). High is the solid state\n * fill — the site's \"Most Popular\" pill — pairing each color's ink with\n * flipping on-ink content. Low is the soft accent material: fill and\n * hairline ring derive from `currentColor` at low opacity, so every color\n * shares one recipe.\n * - THREE sizes (`xs` / `sm` / `md`, default `md`). A badge is inherently small.\n * - The richer Untitled features (dot, icon, avatar, count, dismiss button) are\n * deliberately left out — a dismissible or selectable chip is a Tag, not a\n * Badge, and a badge that triggers an action is a Button.\n */\n\nconst BADGE_BASE =\n \"inline-flex shrink-0 items-center whitespace-nowrap rounded-full font-medium\";\n\n/** Low-contrast material — tint and hairline derived from the color's text token. */\nconst LOW_MATERIAL = \"bg-current/10 ring-1 ring-current/20 ring-inset\";\n\n/**\n * Size axis — fixed heights on a 4px step (16 / 20 / 24) so the ladder stays\n * proportional. Horizontal padding and type scale with each step; vertical\n * centering comes from `items-center` on the base (no `py`).\n */\nexport const BADGE_SIZES = {\n xs: {\n classes: \"h-4 gap-0.5 px-1.5 text-[10px] leading-none\",\n description: \"Extra small — 16px; inline next to 14px labels (plan chips)\",\n },\n sm: {\n classes: \"h-5 gap-0.5 px-2 text-xs leading-none\",\n description: \"Small — 20px; dense rows, table cells\",\n },\n md: {\n classes: \"h-6 gap-1 px-2.5 text-xs leading-none\",\n description: \"Medium — 24px; the default\",\n },\n} satisfies VariantMap;\n\n/**\n * Color axis — a closed semantic set with one recipe per contrast. `high`\n * fills with the state ink (text flips with it per mode); `low` tints text\n * only and lets `LOW_MATERIAL` derive fill and ring from it.\n */\nexport const BADGE_COLORS = {\n gray: {\n high: \"bg-pho-inverse text-pho-inverse\",\n low: \"text-pho-secondary\",\n description: \"Neutral — the low-signal default (solid inverse)\",\n },\n muted: {\n high: \"bg-pho-secondary text-pho-primary\",\n low: \"text-pho-description\",\n description: \"Muted — soft solid surface for quieter labels (Free, Shared)\",\n },\n brand: {\n high: \"bg-pho-brand-solid text-pho-on-brand\",\n low: \"text-pho-brand\",\n description: \"Brand — plan tiers, feature flags, highlights\",\n },\n success: {\n high: \"bg-pho-success-ink text-pho-on-brand\",\n low: \"text-pho-success\",\n description: \"Success — healthy, live, complete\",\n },\n warning: {\n high: \"bg-pho-warning-ink text-pho-on-brand\",\n low: \"text-pho-warning\",\n description: \"Warning — needs attention, degraded\",\n },\n error: {\n high: \"bg-pho-error-ink text-pho-on-brand\",\n low: \"text-pho-error\",\n description: \"Error — failed, blocked, over limit\",\n },\n} satisfies Record<string, { high: string; low: string; description: string }>;\n\nexport type BadgeSize = keyof typeof BADGE_SIZES;\nexport type BadgeColor = keyof typeof BADGE_COLORS;\nexport type BadgeContrast = \"high\" | \"low\";\n\n/** Compose the full class string for a badge — exported for reuse/testing. */\nexport function badgeVariants(opts?: {\n color?: BadgeColor;\n contrast?: BadgeContrast;\n size?: BadgeSize;\n className?: string;\n}): string {\n const {\n color = \"gray\",\n contrast = \"high\",\n size = \"md\",\n className,\n } = opts ?? {};\n const def = BADGE_COLORS[color] as\n (typeof BADGE_COLORS)[BadgeColor] | undefined;\n return cn(\n BADGE_BASE,\n resolveVariant(BADGE_SIZES, size),\n contrast === \"low\" ? cn(LOW_MATERIAL, def?.low) : def?.high,\n className,\n );\n}\n\ninterface BadgeBaseProps {\n /** Semantic color. @default \"gray\" */\n color?: BadgeColor;\n /** Solid state fill (`high`) or the soft currentColor tint (`low`). @default \"high\" */\n contrast?: BadgeContrast;\n /** Size variant. @default \"md\" */\n size?: BadgeSize;\n}\n\nexport interface BadgeProps\n extends BadgeBaseProps, Omit<ComponentProps<\"span\">, keyof BadgeBaseProps> {}\n\n/**\n * Badge — a small, non-interactive status label: a plan tier (`Pro`), a state\n * (`Live`, `Failed`), a count. It's a plain `<span>`, so it never takes focus or\n * handles clicks — for a dismissible or selectable chip reach for a `Tag`, and\n * for a standalone action use a `Button`. Let `color` carry the meaning and keep\n * the label to a word or two.\n */\nexport function Badge({\n color,\n contrast,\n size,\n className,\n children,\n ...props\n}: BadgeProps) {\n return (\n <span\n className={cn(badgeVariants({ color, contrast, size }), className)}\n {...props}\n >\n {children}\n </span>\n );\n}\n\nBadge.displayName = \"Badge\";\n"],"mappings":";;;;;AAoBA,IAAM,IACJ,gFAGI,IAAe,mDAOR,IAAc;AAAA,EACzB,IAAI;AAAA,IACF,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,IAAI;AAAA,IACF,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,IAAI;AAAA,IACF,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AACF,GAOa,IAAe;AAAA,EAC1B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AACF;AAOA,SAAgB,EAAc,GAKnB;AACT,QAAM,EACJ,OAAA,IAAQ,QACR,UAAA,IAAW,QACX,MAAA,IAAO,MACP,WAAA,EAAA,IACE,KAAQ,CAAC,GACP,IAAM,EAAa,CAAA;AAEzB,SAAO,EACL,GACA,EAAe,GAAa,CAAI,GAChC,MAAa,QAAQ,EAAG,GAAc,GAAK,GAAG,IAAI,GAAK,MACvD,CACF;AACF;AAqBA,SAAgB,EAAM,EACpB,OAAA,GACA,UAAA,GACA,MAAA,GACA,WAAA,GACA,UAAA,GACA,GAAG,EAAA,GACU;AACb,SACE,gBAAA,EAAC,QAAD;AAAA,IACE,WAAW,EAAG,EAAc;AAAA,MAAE,OAAA;AAAA,MAAO,UAAA;AAAA,MAAU,MAAA;AAAA,IAAK,CAAC,GAAG,CAAS;AAAA,IACjE,GAAI;AAAA,IAEH,UAAA;AAAA,EACG,CAAA;AAEV;AAEA,EAAM,cAAc"}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { a, c as s, d as n, f as o, i as T, l as B, n as u, o as e, r as f, s as S, t as i, u as E } from "../chunks/close-button-Bq9f-H15.js";
2
+ import { a, c as s, d as n, f as o, i as T, l as B, n as u, o as e, r as f, s as S, t as i, u as E } from "../chunks/close-button-B8gF5UNk.js";
3
3
  export {
4
4
  u as BUTTON_COLORS,
5
5
  f as BUTTON_SHAPES,
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { t as o } from "../chunks/cn-DTiB6ek_.js";
3
- import { r as p } from "../chunks/use-press-pulse-CMwPTOR2.js";
3
+ import { r as p } from "../chunks/use-press-pulse-8iorQPsh.js";
4
4
  import { t as u } from "../chunks/createReactComponent-BqCmnqfX.js";
5
5
  import { t as b } from "../chunks/IconCheck-D2WuculQ.js";
6
6
  import "react";
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { n as i, t as o } from "../chunks/dialog-DolPKFGS.js";
2
+ import { n as i, t as o } from "../chunks/dialog-Ba0UUE5g.js";
3
3
  export {
4
4
  o as Dialog,
5
5
  i as useDialogPending
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { t as a } from "../chunks/cn-DTiB6ek_.js";
3
- import { r as p } from "../chunks/use-press-pulse-CMwPTOR2.js";
3
+ import { r as p } from "../chunks/use-press-pulse-8iorQPsh.js";
4
4
  import { t as u } from "../chunks/IconCheck-D2WuculQ.js";
5
5
  import { createContext as m, useContext as g } from "react";
6
6
  import { jsx as r } from "react/jsx-runtime";
package/dist/index.js CHANGED
@@ -1,38 +1,39 @@
1
1
  "use client";
2
- import { t } from "./chunks/cn-DTiB6ek_.js";
3
- import { n as o, r, t as S } from "./chunks/link-provider-9TFNyDqO.js";
4
- import { t as E } from "./chunks/resolve-variant-CcD8iG5l.js";
5
- import { n as i, r as _, t as m } from "./chunks/use-press-pulse-CMwPTOR2.js";
2
+ import { t as s } from "./chunks/cn-DTiB6ek_.js";
3
+ import { n as o, r, t as n } from "./chunks/link-provider-9TFNyDqO.js";
4
+ import { t as i } from "./chunks/resolve-variant-CcD8iG5l.js";
5
+ import { n as _, r as m, t as A } from "./chunks/use-press-pulse-8iorQPsh.js";
6
6
  import "./utils.js";
7
- import { a as e, c as A, d as B, f as O, i as f, l as p, n as u, o as C, r as N, s as D, t as L, u as c } from "./chunks/close-button-Bq9f-H15.js";
8
- import { a as l, c as U, i as V, n as d, o as G, r as g, s as k, t as F } from "./chunks/sidebar-BCqq58hV.js";
9
- import { t as b } from "./chunks/input-CxS7ndpb.js";
10
- import { t as H } from "./chunks/input-group-D6dlma8k.js";
11
- import { n as x, t as W } from "./chunks/card-9cGnv-VD.js";
12
- import { n as j, t as q } from "./chunks/dialog-DolPKFGS.js";
13
- import { i as y, n as z, r as J, t as K } from "./chunks/settings-B0vhLoMi.js";
7
+ import { a as B, c as R, d as e, f as O, i as f, l as p, n as C, o as u, r as D, s as N, t as P, u as L } from "./chunks/close-button-B8gF5UNk.js";
8
+ import { a as l, c as U, i as V, n as d, o as G, r as g, s as k, t as F } from "./chunks/sidebar-DGpEKxOn.js";
9
+ import { i as b, n as v, r as H, t as Z } from "./chunks/basic-page-C50WUzYV.js";
10
+ import { t as W } from "./chunks/input-CxS7ndpb.js";
11
+ import { t as j } from "./chunks/input-group-D6dlma8k.js";
12
+ import { n as w, t as y } from "./chunks/card-9cGnv-VD.js";
13
+ import { n as J, t as K } from "./chunks/dialog-Ba0UUE5g.js";
14
14
  export {
15
- u as BUTTON_COLORS,
16
- N as BUTTON_SHAPES,
15
+ Z as BASIC_PAGE_CALLOUT,
16
+ v as BASIC_PAGE_CARD,
17
+ H as BASIC_PAGE_ROW,
18
+ C as BUTTON_COLORS,
19
+ D as BUTTON_SHAPES,
17
20
  f as BUTTON_SIZES,
18
- e as BUTTON_VARIANTS,
19
- C as Button,
20
- D as ButtonLink,
21
- W as CARD_SURFACE,
22
- m as CONTROL_PRESS_SCALE,
23
- i as CONTROL_PRESS_SPRING,
24
- x as Card,
25
- L as CloseButton,
26
- q as Dialog,
27
- A as EFFECT_BUTTON_SIZES,
21
+ B as BUTTON_VARIANTS,
22
+ b as BasicPage,
23
+ u as Button,
24
+ N as ButtonLink,
25
+ y as CARD_SURFACE,
26
+ A as CONTROL_PRESS_SCALE,
27
+ _ as CONTROL_PRESS_SPRING,
28
+ w as Card,
29
+ P as CloseButton,
30
+ K as Dialog,
31
+ R as EFFECT_BUTTON_SIZES,
28
32
  p as EffectButton,
29
- c as EffectButtonLink,
30
- b as Input,
31
- H as InputGroup,
32
- S as LinkProvider,
33
- K as SETTINGS_CALLOUT,
34
- z as SETTINGS_CARD,
35
- J as SETTINGS_ROW,
33
+ L as EffectButtonLink,
34
+ W as Input,
35
+ j as InputGroup,
36
+ n as LinkProvider,
36
37
  F as SIDEBAR_HEADER_INSET,
37
38
  d as SIDEBAR_ITEM,
38
39
  g as SIDEBAR_ITEM_ACTIVE,
@@ -40,14 +41,13 @@ export {
40
41
  l as SIDEBAR_ROOT,
41
42
  G as SIDEBAR_ROOT_BASE,
42
43
  k as SIDEBAR_ROOT_INSET,
43
- y as Settings,
44
44
  U as Sidebar,
45
- B as buttonVariants,
46
- t as cn,
45
+ e as buttonVariants,
46
+ s as cn,
47
47
  O as effectButtonVariants,
48
48
  r as isReactComponent,
49
- E as resolveVariant,
50
- j as useDialogPending,
49
+ i as resolveVariant,
50
+ J as useDialogPending,
51
51
  o as useLinkComponent,
52
- _ as usePressPulse
52
+ m as usePressPulse
53
53
  };
@@ -0,0 +1,8 @@
1
+ "use client";
2
+ import { i as a, n as s, r as _, t as C } from "../chunks/basic-page-C50WUzYV.js";
3
+ export {
4
+ C as BASIC_PAGE_CALLOUT,
5
+ s as BASIC_PAGE_CARD,
6
+ _ as BASIC_PAGE_ROW,
7
+ a as BasicPage
8
+ };
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { a as I, c as _, i as A, n as R, o as S, r as a, s, t as T } from "../chunks/sidebar-BCqq58hV.js";
2
+ import { a as I, c as _, i as A, n as R, o as S, r as a, s, t as T } from "../chunks/sidebar-DGpEKxOn.js";
3
3
  export {
4
4
  T as SIDEBAR_HEADER_INSET,
5
5
  R as SIDEBAR_ITEM,
@@ -1,6 +1,14 @@
1
1
  import { ComponentProps } from 'react';
2
- /** Size axis — padding, gap, and label size. */
2
+ /**
3
+ * Size axis — fixed heights on a 4px step (16 / 20 / 24) so the ladder stays
4
+ * proportional. Horizontal padding and type scale with each step; vertical
5
+ * centering comes from `items-center` on the base (no `py`).
6
+ */
3
7
  export declare const BADGE_SIZES: {
8
+ xs: {
9
+ classes: string;
10
+ description: string;
11
+ };
4
12
  sm: {
5
13
  classes: string;
6
14
  description: string;
@@ -10,40 +18,58 @@ export declare const BADGE_SIZES: {
10
18
  description: string;
11
19
  };
12
20
  };
13
- /** Color axis — a closed semantic set; each key tints text, fill, and ring. */
21
+ /**
22
+ * Color axis — a closed semantic set with one recipe per contrast. `high`
23
+ * fills with the state ink (text flips with it per mode); `low` tints text
24
+ * only and lets `LOW_MATERIAL` derive fill and ring from it.
25
+ */
14
26
  export declare const BADGE_COLORS: {
15
27
  gray: {
16
- classes: string;
28
+ high: string;
29
+ low: string;
30
+ description: string;
31
+ };
32
+ muted: {
33
+ high: string;
34
+ low: string;
17
35
  description: string;
18
36
  };
19
37
  brand: {
20
- classes: string;
38
+ high: string;
39
+ low: string;
21
40
  description: string;
22
41
  };
23
42
  success: {
24
- classes: string;
43
+ high: string;
44
+ low: string;
25
45
  description: string;
26
46
  };
27
47
  warning: {
28
- classes: string;
48
+ high: string;
49
+ low: string;
29
50
  description: string;
30
51
  };
31
52
  error: {
32
- classes: string;
53
+ high: string;
54
+ low: string;
33
55
  description: string;
34
56
  };
35
57
  };
36
58
  export type BadgeSize = keyof typeof BADGE_SIZES;
37
59
  export type BadgeColor = keyof typeof BADGE_COLORS;
60
+ export type BadgeContrast = "high" | "low";
38
61
  /** Compose the full class string for a badge — exported for reuse/testing. */
39
62
  export declare function badgeVariants(opts?: {
40
63
  color?: BadgeColor;
64
+ contrast?: BadgeContrast;
41
65
  size?: BadgeSize;
42
66
  className?: string;
43
67
  }): string;
44
68
  interface BadgeBaseProps {
45
69
  /** Semantic color. @default "gray" */
46
70
  color?: BadgeColor;
71
+ /** Solid state fill (`high`) or the soft currentColor tint (`low`). @default "high" */
72
+ contrast?: BadgeContrast;
47
73
  /** Size variant. @default "md" */
48
74
  size?: BadgeSize;
49
75
  }
@@ -56,7 +82,7 @@ export interface BadgeProps extends BadgeBaseProps, Omit<ComponentProps<"span">,
56
82
  * for a standalone action use a `Button`. Let `color` carry the meaning and keep
57
83
  * the label to a word or two.
58
84
  */
59
- export declare function Badge({ color, size, className, children, ...props }: BadgeProps): import("react").JSX.Element;
85
+ export declare function Badge({ color, contrast, size, className, children, ...props }: BadgeProps): import("react").JSX.Element;
60
86
  export declare namespace Badge {
61
87
  var displayName: string;
62
88
  }
@@ -1 +1 @@
1
- export { Badge, badgeVariants, BADGE_SIZES, BADGE_COLORS, type BadgeProps, type BadgeSize, type BadgeColor, } from './badge';
1
+ export { Badge, badgeVariants, BADGE_SIZES, BADGE_COLORS, type BadgeProps, type BadgeSize, type BadgeColor, type BadgeContrast, } from './badge';