@dirstack/ui 1.0.0 → 1.1.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 (38) hide show
  1. package/dist/components/button.d.ts.map +1 -1
  2. package/dist/components/button.js +2 -1
  3. package/dist/components/button.js.map +1 -1
  4. package/dist/components/dialog.d.ts +12 -12
  5. package/dist/components/dialog.d.ts.map +1 -1
  6. package/dist/components/dialog.js +9 -7
  7. package/dist/components/dialog.js.map +1 -1
  8. package/dist/components/form-section.js +1 -1
  9. package/dist/components/form-section.js.map +1 -1
  10. package/dist/components/form.js +2 -2
  11. package/dist/components/form.js.map +1 -1
  12. package/dist/components/input.d.ts +1 -1
  13. package/dist/components/input.d.ts.map +1 -1
  14. package/dist/components/input.js +2 -1
  15. package/dist/components/input.js.map +1 -1
  16. package/dist/components/menu.js +4 -4
  17. package/dist/components/menu.js.map +1 -1
  18. package/dist/components/nav.js +1 -1
  19. package/dist/components/nav.js.map +1 -1
  20. package/dist/components/section-header.d.ts +6 -6
  21. package/dist/components/section-header.js +5 -5
  22. package/dist/components/section-header.js.map +1 -1
  23. package/dist/components/select.js +2 -2
  24. package/dist/components/select.js.map +1 -1
  25. package/dist/components/stat-strip.js +3 -3
  26. package/dist/components/stat-strip.js.map +1 -1
  27. package/dist/components/tabs.d.ts.map +1 -1
  28. package/dist/components/tabs.js +2 -1
  29. package/dist/components/tabs.js.map +1 -1
  30. package/dist/components/toaster.d.ts.map +1 -1
  31. package/dist/components/toaster.js +7 -1
  32. package/dist/components/toaster.js.map +1 -1
  33. package/dist/lib/classes.d.ts +10 -0
  34. package/dist/lib/classes.d.ts.map +1 -1
  35. package/dist/lib/classes.js +11 -1
  36. package/dist/lib/classes.js.map +1 -1
  37. package/dist/styles.css +24 -0
  38. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"button.d.ts","names":[],"sources":["../../src/components/button.tsx"],"mappings":";;;;;cAQM,4CAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAoCR,cAAc,KAAK,UAAU,+CACvC,oBAAoB,kBACpB,KAAK,oBAAoB;;;;EAIvB;;;;EAKA,SAAS;;;;EAKT,SAAS;;iBAGJ,SACP,UACA,WACA,UACA,QACA,WACA,QACA,QACA,SACA,MACA,OACA,UACG,QACF,8BAAW,+CAAA"}
1
+ {"version":3,"file":"button.d.ts","names":[],"sources":["../../src/components/button.tsx"],"mappings":";;;;;cASM,4CAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAoCR,cAAc,KAAK,UAAU,+CACvC,oBAAoB,kBACpB,KAAK,oBAAoB;;;;EAIvB;;;;EAKA,SAAS;;;;EAKT,SAAS;;iBAGJ,SACP,UACA,WACA,UACA,QACA,WACA,QACA,QACA,SACA,MACA,OACA,UACG,QACF,8BAAW,+CAAA"}
@@ -1,5 +1,6 @@
1
1
  import { cn, variants } from "../lib/variants.js";
2
2
  import { slot } from "../lib/slot.js";
3
+ import { controlTextClasses } from "../lib/classes.js";
3
4
  import { LoaderIcon } from "../lib/icons.js";
4
5
  import { interactiveVariants } from "../lib/interactive.js";
5
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -8,7 +9,7 @@ import { useRender } from "@base-ui/react/use-render";
8
9
  import { Children, isValidElement } from "react";
9
10
  //#region src/components/button.tsx
10
11
  const buttonVariants = variants({
11
- base: ["group/button inline-flex items-center justify-center font-medium text-control text-start rounded-md overflow-clip select-none hover:z-10", "disabled:opacity-60 disabled:pointer-events-none aria-disabled:opacity-60 aria-disabled:pointer-events-none"],
12
+ base: [`group/button inline-flex items-center justify-center font-medium ${controlTextClasses} text-start rounded-md overflow-clip select-none hover:z-10`, "disabled:opacity-60 disabled:pointer-events-none aria-disabled:opacity-60 aria-disabled:pointer-events-none"],
12
13
  variants: {
13
14
  variant: {
14
15
  primary: "text-background bg-foreground hover:opacity-90",
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":[],"sources":["../../src/components/button.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { Children, isValidElement, type ReactNode } from \"react\"\nimport { LoaderIcon } from \"~/lib/icons\"\nimport { interactiveVariants } from \"~/lib/interactive\"\nimport { slot } from \"~/lib/slot\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst buttonVariants = variants({\n base: [\n \"group/button inline-flex items-center justify-center font-medium text-control text-start rounded-md overflow-clip select-none hover:z-10\",\n \"disabled:opacity-60 disabled:pointer-events-none aria-disabled:opacity-60 aria-disabled:pointer-events-none\",\n ],\n\n variants: {\n variant: {\n primary: \"text-background bg-foreground hover:opacity-90\",\n secondary: \"bg-card text-secondary-foreground\",\n soft: \"bg-muted text-secondary-foreground hover:bg-muted/75 hover:text-foreground hover:outline-none\",\n ghost:\n \"text-secondary-foreground hover:bg-foreground/5 hover:text-foreground hover:outline-none\",\n danger: \"bg-danger text-white hover:bg-danger/90\",\n },\n size: {\n sm: \"px-2 py-1 gap-[0.66ch]\",\n // The default control height. A floor rather than a fixed height, so a row that leads\n // with something taller than the label (the sidebar's 20px avatar) still grows.\n md: \"min-h-control px-3 py-2 gap-[0.75ch]\",\n lg: \"px-3.5 py-2.5 gap-[1ch] rounded-lg sm:text-sm/tight\",\n },\n },\n\n defaultVariants: {\n variant: \"primary\",\n size: \"md\",\n },\n})\n\nconst buttonAffixClasses =\n \"shrink-0 first:-ml-[0.21425em] last:-mr-[0.21425em] [svg]:my-[0.077em] [svg]:size-[1.1em]\"\n\n/** Hidden while the button is pending, so only the spinner reads as content. */\nconst buttonPendingClasses = \"group-data-pending/button:text-transparent\"\n\nexport type ButtonProps = Omit<useRender.ComponentProps<\"button\">, \"size\" | \"prefix\"> &\n VariantProps<typeof buttonVariants> &\n Pick<VariantProps<typeof interactiveVariants>, \"hover\" | \"focus\"> & {\n /**\n * If set to `true`, the button will be rendered in the pending state.\n */\n isPending?: boolean\n\n /**\n * The slot to be rendered before the label.\n */\n prefix?: ReactNode\n\n /**\n * The slot to be rendered after the label.\n */\n suffix?: ReactNode\n }\n\nfunction Button({\n children,\n className,\n disabled,\n render,\n isPending,\n prefix,\n suffix,\n variant,\n size,\n hover = true,\n focus = true,\n ...rest\n}: ButtonProps) {\n const props = mergeProps<\"button\">(\n {\n disabled: disabled || isPending,\n \"aria-busy\": isPending || undefined,\n className: cn(\n interactiveVariants({ hover, focus, bordered: variant === \"secondary\" }),\n buttonVariants({ variant, size, className }),\n ),\n children: (\n <>\n {slot(prefix && isPending ? <LoaderIcon className=\"animate-spin\" /> : prefix, {\n className: buttonAffixClasses,\n })}\n\n {Children.count(children) > 0 &&\n slot(isValidElement(children) ? children : <span>{children}</span>, {\n className: cn(\n \"flex-1 truncate only:text-center has-[div]:contents\",\n buttonPendingClasses,\n ),\n })}\n\n {slot(suffix, { className: cn(buttonAffixClasses, buttonPendingClasses) })}\n\n {!prefix && !!isPending && <LoaderIcon className=\"absolute size-[1.25em] animate-spin\" />}\n </>\n ),\n },\n rest,\n )\n\n // `data-pending` drives the label and suffix fade; it sits outside `mergeProps`, whose\n // button props type has no room for a custom data attribute.\n return useRender({\n defaultTagName: \"button\",\n render,\n props: { \"data-pending\": isPending || undefined, ...props },\n })\n}\n\nexport { Button, buttonVariants }\n"],"mappings":";;;;;;;;;AAQA,MAAM,iBAAiB,SAAS;CAC9B,MAAM,CACJ,4IACA,6GACF;CAEA,UAAU;EACR,SAAS;GACP,SAAS;GACT,WAAW;GACX,MAAM;GACN,OACE;GACF,QAAQ;EACV;EACA,MAAM;GACJ,IAAI;GAGJ,IAAI;GACJ,IAAI;EACN;CACF;CAEA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CAAC;AAED,MAAM,qBACJ;;AAGF,MAAM,uBAAuB;AAqB7B,SAAS,OAAO,EACd,UACA,WACA,UACA,QACA,WACA,QACA,QACA,SACA,MACA,QAAQ,MACR,QAAQ,MACR,GAAG,QACW;CACd,MAAM,QAAQ,WACZ;EACE,UAAU,YAAY;EACtB,aAAa,aAAa,KAAA;EAC1B,WAAW,GACT,oBAAoB;GAAE;GAAO;GAAO,UAAU,YAAY;EAAY,CAAC,GACvE,eAAe;GAAE;GAAS;GAAM;EAAU,CAAC,CAC7C;EACA,UACE,qBAAA,UAAA,EAAA,UAAA;GACG,KAAK,UAAU,YAAY,oBAAC,YAAD,EAAY,WAAU,eAAgB,CAAA,IAAI,QAAQ,EAC5E,WAAW,mBACb,CAAC;GAEA,SAAS,MAAM,QAAQ,IAAI,KAC1B,KAAK,eAAe,QAAQ,IAAI,WAAW,oBAAC,QAAD,EAAO,SAAe,CAAA,GAAG,EAClE,WAAW,GACT,uDACA,oBACF,EACF,CAAC;GAEF,KAAK,QAAQ,EAAE,WAAW,GAAG,oBAAoB,oBAAoB,EAAE,CAAC;GAExE,CAAC,UAAU,CAAC,CAAC,aAAa,oBAAC,YAAD,EAAY,WAAU,sCAAuC,CAAA;EACxF,EAAA,CAAA;CAEN,GACA,IACF;CAIA,OAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO;GAAE,gBAAgB,aAAa,KAAA;GAAW,GAAG;EAAM;CAC5D,CAAC;AACH"}
1
+ {"version":3,"file":"button.js","names":[],"sources":["../../src/components/button.tsx"],"sourcesContent":["import { mergeProps } from \"@base-ui/react\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { Children, isValidElement, type ReactNode } from \"react\"\nimport { controlTextClasses } from \"~/lib/classes\"\nimport { LoaderIcon } from \"~/lib/icons\"\nimport { interactiveVariants } from \"~/lib/interactive\"\nimport { slot } from \"~/lib/slot\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst buttonVariants = variants({\n base: [\n `group/button inline-flex items-center justify-center font-medium ${controlTextClasses} text-start rounded-md overflow-clip select-none hover:z-10`,\n \"disabled:opacity-60 disabled:pointer-events-none aria-disabled:opacity-60 aria-disabled:pointer-events-none\",\n ],\n\n variants: {\n variant: {\n primary: \"text-background bg-foreground hover:opacity-90\",\n secondary: \"bg-card text-secondary-foreground\",\n soft: \"bg-muted text-secondary-foreground hover:bg-muted/75 hover:text-foreground hover:outline-none\",\n ghost:\n \"text-secondary-foreground hover:bg-foreground/5 hover:text-foreground hover:outline-none\",\n danger: \"bg-danger text-white hover:bg-danger/90\",\n },\n size: {\n sm: \"px-2 py-1 gap-[0.66ch]\",\n // The default control height. A floor rather than a fixed height, so a row that leads\n // with something taller than the label (the sidebar's 20px avatar) still grows.\n md: \"min-h-control px-3 py-2 gap-[0.75ch]\",\n lg: \"px-3.5 py-2.5 gap-[1ch] rounded-lg sm:text-sm/tight\",\n },\n },\n\n defaultVariants: {\n variant: \"primary\",\n size: \"md\",\n },\n})\n\nconst buttonAffixClasses =\n \"shrink-0 first:-ml-[0.21425em] last:-mr-[0.21425em] [svg]:my-[0.077em] [svg]:size-[1.1em]\"\n\n/** Hidden while the button is pending, so only the spinner reads as content. */\nconst buttonPendingClasses = \"group-data-pending/button:text-transparent\"\n\nexport type ButtonProps = Omit<useRender.ComponentProps<\"button\">, \"size\" | \"prefix\"> &\n VariantProps<typeof buttonVariants> &\n Pick<VariantProps<typeof interactiveVariants>, \"hover\" | \"focus\"> & {\n /**\n * If set to `true`, the button will be rendered in the pending state.\n */\n isPending?: boolean\n\n /**\n * The slot to be rendered before the label.\n */\n prefix?: ReactNode\n\n /**\n * The slot to be rendered after the label.\n */\n suffix?: ReactNode\n }\n\nfunction Button({\n children,\n className,\n disabled,\n render,\n isPending,\n prefix,\n suffix,\n variant,\n size,\n hover = true,\n focus = true,\n ...rest\n}: ButtonProps) {\n const props = mergeProps<\"button\">(\n {\n disabled: disabled || isPending,\n \"aria-busy\": isPending || undefined,\n className: cn(\n interactiveVariants({ hover, focus, bordered: variant === \"secondary\" }),\n buttonVariants({ variant, size, className }),\n ),\n children: (\n <>\n {slot(prefix && isPending ? <LoaderIcon className=\"animate-spin\" /> : prefix, {\n className: buttonAffixClasses,\n })}\n\n {Children.count(children) > 0 &&\n slot(isValidElement(children) ? children : <span>{children}</span>, {\n className: cn(\n \"flex-1 truncate only:text-center has-[div]:contents\",\n buttonPendingClasses,\n ),\n })}\n\n {slot(suffix, { className: cn(buttonAffixClasses, buttonPendingClasses) })}\n\n {!prefix && !!isPending && <LoaderIcon className=\"absolute size-[1.25em] animate-spin\" />}\n </>\n ),\n },\n rest,\n )\n\n // `data-pending` drives the label and suffix fade; it sits outside `mergeProps`, whose\n // button props type has no room for a custom data attribute.\n return useRender({\n defaultTagName: \"button\",\n render,\n props: { \"data-pending\": isPending || undefined, ...props },\n })\n}\n\nexport { Button, buttonVariants }\n"],"mappings":";;;;;;;;;;AASA,MAAM,iBAAiB,SAAS;CAC9B,MAAM,CACJ,oEAAoE,mBAAmB,8DACvF,6GACF;CAEA,UAAU;EACR,SAAS;GACP,SAAS;GACT,WAAW;GACX,MAAM;GACN,OACE;GACF,QAAQ;EACV;EACA,MAAM;GACJ,IAAI;GAGJ,IAAI;GACJ,IAAI;EACN;CACF;CAEA,iBAAiB;EACf,SAAS;EACT,MAAM;CACR;AACF,CAAC;AAED,MAAM,qBACJ;;AAGF,MAAM,uBAAuB;AAqB7B,SAAS,OAAO,EACd,UACA,WACA,UACA,QACA,WACA,QACA,QACA,SACA,MACA,QAAQ,MACR,QAAQ,MACR,GAAG,QACW;CACd,MAAM,QAAQ,WACZ;EACE,UAAU,YAAY;EACtB,aAAa,aAAa,KAAA;EAC1B,WAAW,GACT,oBAAoB;GAAE;GAAO;GAAO,UAAU,YAAY;EAAY,CAAC,GACvE,eAAe;GAAE;GAAS;GAAM;EAAU,CAAC,CAC7C;EACA,UACE,qBAAA,UAAA,EAAA,UAAA;GACG,KAAK,UAAU,YAAY,oBAAC,YAAD,EAAY,WAAU,eAAgB,CAAA,IAAI,QAAQ,EAC5E,WAAW,mBACb,CAAC;GAEA,SAAS,MAAM,QAAQ,IAAI,KAC1B,KAAK,eAAe,QAAQ,IAAI,WAAW,oBAAC,QAAD,EAAO,SAAe,CAAA,GAAG,EAClE,WAAW,GACT,uDACA,oBACF,EACF,CAAC;GAEF,KAAK,QAAQ,EAAE,WAAW,GAAG,oBAAoB,oBAAoB,EAAE,CAAC;GAExE,CAAC,UAAU,CAAC,CAAC,aAAa,oBAAC,YAAD,EAAY,WAAU,sCAAuC,CAAA;EACxF,EAAA,CAAA;CAEN,GACA,IACF;CAIA,OAAO,UAAU;EACf,gBAAgB;EAChB;EACA,OAAO;GAAE,gBAAgB,aAAa,KAAA;GAAW,GAAG;EAAM;CAC5D,CAAC;AACH"}
@@ -26,16 +26,16 @@ declare const dialogContentVariants: import("tailwind-variants").TVReturnType<{
26
26
  * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.
27
27
  */
28
28
  fixed: {
29
- true: "top-[10vh] max-h-[calc(90vh-2rem)] [[role=dialog]~&]:top-[15vh] [[role=dialog]~&]:max-h-[calc(85vh-2rem)]";
30
- false: "top-1/2 -translate-y-1/2 max-h-[calc(100vh-2rem)]";
29
+ true: "sm:top-[10vh] sm:max-h-[calc(90vh-2rem)] sm:[[role=dialog]~&]:top-[15vh] sm:[[role=dialog]~&]:max-h-[calc(85vh-2rem)]";
30
+ false: "sm:top-1/2 sm:-translate-y-1/2 sm:max-h-[calc(100vh-2rem)]";
31
31
  };
32
32
  /**
33
33
  * Drop the dialog's own padding and gap so sections can run edge to edge and draw their
34
34
  * own borders, e.g. a bordered header over a scrolling body over a bordered footer.
35
35
  */
36
36
  flush: {
37
- true: "gap-0 p-0";
38
- false: "gap-6 p-6";
37
+ true: "gap-0 p-0 max-sm:pb-[env(safe-area-inset-bottom)]";
38
+ false: "gap-6 p-6 max-sm:pb-[calc(1.5rem+env(safe-area-inset-bottom))]";
39
39
  };
40
40
  }, undefined, string[], {
41
41
  size: {
@@ -55,16 +55,16 @@ declare const dialogContentVariants: import("tailwind-variants").TVReturnType<{
55
55
  * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.
56
56
  */
57
57
  fixed: {
58
- true: "top-[10vh] max-h-[calc(90vh-2rem)] [[role=dialog]~&]:top-[15vh] [[role=dialog]~&]:max-h-[calc(85vh-2rem)]";
59
- false: "top-1/2 -translate-y-1/2 max-h-[calc(100vh-2rem)]";
58
+ true: "sm:top-[10vh] sm:max-h-[calc(90vh-2rem)] sm:[[role=dialog]~&]:top-[15vh] sm:[[role=dialog]~&]:max-h-[calc(85vh-2rem)]";
59
+ false: "sm:top-1/2 sm:-translate-y-1/2 sm:max-h-[calc(100vh-2rem)]";
60
60
  };
61
61
  /**
62
62
  * Drop the dialog's own padding and gap so sections can run edge to edge and draw their
63
63
  * own borders, e.g. a bordered header over a scrolling body over a bordered footer.
64
64
  */
65
65
  flush: {
66
- true: "gap-0 p-0";
67
- false: "gap-6 p-6";
66
+ true: "gap-0 p-0 max-sm:pb-[env(safe-area-inset-bottom)]";
67
+ false: "gap-6 p-6 max-sm:pb-[calc(1.5rem+env(safe-area-inset-bottom))]";
68
68
  };
69
69
  }, undefined, import("tailwind-variants").TVReturnTypeLike<{
70
70
  size: {
@@ -84,16 +84,16 @@ declare const dialogContentVariants: import("tailwind-variants").TVReturnType<{
84
84
  * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.
85
85
  */
86
86
  fixed: {
87
- true: "top-[10vh] max-h-[calc(90vh-2rem)] [[role=dialog]~&]:top-[15vh] [[role=dialog]~&]:max-h-[calc(85vh-2rem)]";
88
- false: "top-1/2 -translate-y-1/2 max-h-[calc(100vh-2rem)]";
87
+ true: "sm:top-[10vh] sm:max-h-[calc(90vh-2rem)] sm:[[role=dialog]~&]:top-[15vh] sm:[[role=dialog]~&]:max-h-[calc(85vh-2rem)]";
88
+ false: "sm:top-1/2 sm:-translate-y-1/2 sm:max-h-[calc(100vh-2rem)]";
89
89
  };
90
90
  /**
91
91
  * Drop the dialog's own padding and gap so sections can run edge to edge and draw their
92
92
  * own borders, e.g. a bordered header over a scrolling body over a bordered footer.
93
93
  */
94
94
  flush: {
95
- true: "gap-0 p-0";
96
- false: "gap-6 p-6";
95
+ true: "gap-0 p-0 max-sm:pb-[env(safe-area-inset-bottom)]";
96
+ false: "gap-6 p-6 max-sm:pb-[calc(1.5rem+env(safe-area-inset-bottom))]";
97
97
  };
98
98
  }, undefined>>;
99
99
  type DialogContentProps = Omit<Dialog$1.Popup.Props, "className"> & VariantProps<typeof dialogContentVariants> & {
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.d.ts","names":[],"sources":["../../src/components/dialog.tsx"],"mappings":";;;;;;cAcM,eAAM,SAAA;cACN,eAAa,SAAA;cACb,6BAAW,0BAAA,8BAAA,gDAAA,cAAA;cACX,mCAAiB,0BAAA,8BAAA,sDAAA,cAAA;cAiBjB,mDAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAiDtB,qBAAqB,KAAK,SAAgB,MAAM,sBACnD,oBAAoB;EAClB;;;;;EAMA;;iBAGK,gBACP,WACA,UACA,MACA,OACA,OACA,cACG,SACF,qCAAkB,IAAA;cAsBf,kDAAoB;;;;;;;;;;;;;;;;;;;;;;;;;KAYrB,oBAAoB,KAAK,sBAAsB,2CAClD,oBAAoB;EAClB,OAAO;EACP,cAAc;;;;;;;iBAQT,eACP,OACA,aACA,UACA,WACA,aACG,SACF,oCAAiB,IAAA;cAgBd,kDAAoB;;;;;;;;;;;;;;;;;;;;;;;;;KAcrB,oBAAoB,wBAAwB,oBAAoB;iBAE5D,eAAe,WAAW,aAAa,SAAS,oCAAiB,IAAA;iBAIjE,iBAAiB,SAAS,sBAAsB,0BAAO,IAAA"}
1
+ {"version":3,"file":"dialog.d.ts","names":[],"sources":["../../src/components/dialog.tsx"],"mappings":";;;;;;cAcM,eAAM,SAAA;cACN,eAAa,SAAA;cACb,6BAAW,0BAAA,8BAAA,gDAAA,cAAA;cACX,mCAAiB,0BAAA,8BAAA,sDAAA,cAAA;cAiBjB,mDAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAqDtB,qBAAqB,KAAK,SAAgB,MAAM,sBACnD,oBAAoB;EAClB;;;;;EAMA;;iBAGK,gBACP,WACA,UACA,MACA,OACA,OACA,cACG,SACF,qCAAkB,IAAA;cAsBf,kDAAoB;;;;;;;;;;;;;;;;;;;;;;;;;KAYrB,oBAAoB,KAAK,sBAAsB,2CAClD,oBAAoB;EAClB,OAAO;EACP,cAAc;;;;;;;iBAQT,eACP,OACA,aACA,UACA,WACA,aACG,SACF,oCAAiB,IAAA;cAgBd,kDAAoB;;;;;;;;;;;;;;;;;;;;;;;;;KAcrB,oBAAoB,wBAAwB,oBAAoB;iBAE5D,eAAe,WAAW,aAAa,SAAS,oCAAiB,IAAA;iBAIjE,iBAAiB,SAAS,sBAAsB,0BAAO,IAAA"}
@@ -19,11 +19,13 @@ function DialogOverlay({ className, ...props }) {
19
19
  }
20
20
  const dialogContentVariants = variants({
21
21
  base: [
22
- "fixed left-1/2 z-50 grid w-[calc(100vw-2rem)] -translate-x-1/2 overflow-y-auto",
23
- "border bg-card shadow-sm rounded-xl",
22
+ "fixed z-50 grid overflow-y-auto border bg-card shadow-sm",
23
+ "max-sm:inset-x-0 max-sm:bottom-0 max-sm:max-h-[calc(100dvh-3rem)] max-sm:rounded-t-2xl max-sm:border-b-0",
24
+ "sm:left-1/2 sm:w-[calc(100vw-2rem)] sm:-translate-x-1/2 sm:rounded-xl",
24
25
  "data-open:animate-in data-closed:animate-out",
25
26
  "data-open:fade-in-0 data-closed:fade-out-0",
26
- "data-open:slide-in-from-bottom-4 data-closed:slide-out-to-bottom-4"
27
+ "data-open:slide-in-from-bottom-4 data-closed:slide-out-to-bottom-4",
28
+ "max-sm:data-open:slide-in-from-bottom-8 max-sm:data-closed:slide-out-to-bottom-8"
27
29
  ],
28
30
  variants: {
29
31
  size: {
@@ -43,16 +45,16 @@ const dialogContentVariants = variants({
43
45
  * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.
44
46
  */
45
47
  fixed: {
46
- true: "top-[10vh] max-h-[calc(90vh-2rem)] [[role=dialog]~&]:top-[15vh] [[role=dialog]~&]:max-h-[calc(85vh-2rem)]",
47
- false: "top-1/2 -translate-y-1/2 max-h-[calc(100vh-2rem)]"
48
+ true: "sm:top-[10vh] sm:max-h-[calc(90vh-2rem)] sm:[[role=dialog]~&]:top-[15vh] sm:[[role=dialog]~&]:max-h-[calc(85vh-2rem)]",
49
+ false: "sm:top-1/2 sm:-translate-y-1/2 sm:max-h-[calc(100vh-2rem)]"
48
50
  },
49
51
  /**
50
52
  * Drop the dialog's own padding and gap so sections can run edge to edge and draw their
51
53
  * own borders, e.g. a bordered header over a scrolling body over a bordered footer.
52
54
  */
53
55
  flush: {
54
- true: "gap-0 p-0",
55
- false: "gap-6 p-6"
56
+ true: "gap-0 p-0 max-sm:pb-[env(safe-area-inset-bottom)]",
57
+ false: "gap-6 p-6 max-sm:pb-[calc(1.5rem+env(safe-area-inset-bottom))]"
56
58
  }
57
59
  },
58
60
  defaultVariants: {
@@ -1 +1 @@
1
- {"version":3,"file":"dialog.js","names":["DialogPrimitive"],"sources":["../../src/components/dialog.tsx"],"sourcesContent":["\"use client\"\n\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\"\nimport type { ComponentProps, ReactNode } from \"react\"\nimport { Button } from \"~/components/button\"\nimport {\n SectionHeader,\n SectionHeaderBody,\n SectionHeaderDescription,\n SectionHeaderTitle,\n} from \"~/components/section-header\"\nimport { XIcon } from \"~/lib/icons\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst Dialog = DialogPrimitive.Root\nconst DialogTrigger = DialogPrimitive.Trigger\nconst DialogTitle = DialogPrimitive.Title\nconst DialogDescription = DialogPrimitive.Description\n\n/** The dashed, blurred backdrop behind the dialog. Rendered by `DialogContent`. */\nfunction DialogOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) {\n return (\n <DialogPrimitive.Backdrop\n className={cn(\n \"fixed inset-0 z-50 bg-dashed backdrop-blur-xs\",\n \"data-open:animate-in data-closed:animate-out\",\n \"data-open:fade-in-0 data-closed:fade-out-0\",\n className,\n )}\n {...props}\n />\n )\n}\n\nconst dialogContentVariants = variants({\n base: [\n \"fixed left-1/2 z-50 grid w-[calc(100vw-2rem)] -translate-x-1/2 overflow-y-auto\",\n \"border bg-card shadow-sm rounded-xl\",\n \"data-open:animate-in data-closed:animate-out\",\n \"data-open:fade-in-0 data-closed:fade-out-0\",\n \"data-open:slide-in-from-bottom-4 data-closed:slide-out-to-bottom-4\",\n ],\n\n variants: {\n size: {\n xs: \"max-w-xs\",\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n xl: \"max-w-xl\",\n \"2xl\": \"max-w-2xl\",\n \"3xl\": \"max-w-3xl\",\n \"4xl\": \"max-w-4xl\",\n \"5xl\": \"max-w-5xl\",\n },\n\n /**\n * Pin the dialog near the top of the viewport instead of centering it, so its height can\n * change without the whole thing jumping. A dialog stacked on top of another one\n * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.\n */\n fixed: {\n true: \"top-[10vh] max-h-[calc(90vh-2rem)] [[role=dialog]~&]:top-[15vh] [[role=dialog]~&]:max-h-[calc(85vh-2rem)]\",\n false: \"top-1/2 -translate-y-1/2 max-h-[calc(100vh-2rem)]\",\n },\n\n /**\n * Drop the dialog's own padding and gap so sections can run edge to edge and draw their\n * own borders, e.g. a bordered header over a scrolling body over a bordered footer.\n */\n flush: {\n true: \"gap-0 p-0\",\n false: \"gap-6 p-6\",\n },\n },\n\n defaultVariants: {\n size: \"md\",\n fixed: true,\n flush: false,\n },\n})\n\ntype DialogContentProps = Omit<DialogPrimitive.Popup.Props, \"className\"> &\n VariantProps<typeof dialogContentVariants> & {\n className?: string\n\n /**\n * Hide the close button in the top right corner, for a dialog that must be dismissed\n * through one of its own actions.\n */\n hideClose?: boolean\n }\n\nfunction DialogContent({\n className,\n children,\n size,\n fixed,\n flush,\n hideClose,\n ...props\n}: DialogContentProps) {\n return (\n <DialogPrimitive.Portal>\n <DialogOverlay />\n\n <DialogPrimitive.Popup\n className={dialogContentVariants({ size, fixed, flush, className })}\n {...props}\n >\n {children}\n\n {!hideClose && (\n <DialogPrimitive.Close\n render={<Button variant=\"ghost\" size=\"sm\" aria-label=\"Close\" prefix={<XIcon />} />}\n className=\"absolute top-3 right-3\"\n />\n )}\n </DialogPrimitive.Popup>\n </DialogPrimitive.Portal>\n )\n}\n\nconst dialogHeaderVariants = variants({\n variants: {\n /**\n * Give the header its own hairline and padding, for a `flush` dialog whose body scrolls\n * under it. The extra right padding clears the dialog's close button.\n */\n bordered: {\n true: \"border-b px-6 py-5 pr-14\",\n },\n },\n})\n\ntype DialogHeaderProps = Omit<ComponentProps<typeof SectionHeader>, \"title\" | \"description\"> &\n VariantProps<typeof dialogHeaderVariants> & {\n title: ReactNode\n description?: ReactNode\n }\n\n/**\n * The standard dialog heading: a card-scale `SectionHeader` whose title and description are wired to\n * Base UI's `DialogTitle` / `DialogDescription` for accessibility. Extra children render after\n * them.\n */\nfunction DialogHeader({\n title,\n description,\n bordered,\n className,\n children,\n ...props\n}: DialogHeaderProps) {\n return (\n <SectionHeader size=\"card\" className={dialogHeaderVariants({ bordered, className })} {...props}>\n <SectionHeaderBody>\n <DialogTitle render={<SectionHeaderTitle />}>{title}</DialogTitle>\n\n {description && (\n <DialogDescription render={<SectionHeaderDescription />}>{description}</DialogDescription>\n )}\n </SectionHeaderBody>\n\n {children}\n </SectionHeader>\n )\n}\n\nconst dialogFooterVariants = variants({\n base: \"flex flex-col-reverse flex-wrap gap-x-2 gap-y-4 sm:flex-row sm:justify-end\",\n\n variants: {\n /**\n * Give the footer its own hairline and padding, for a `flush` dialog where the body\n * scrolls behind it.\n */\n bordered: {\n true: \"border-t px-6 py-4\",\n },\n },\n})\n\ntype DialogFooterProps = ComponentProps<\"div\"> & VariantProps<typeof dialogFooterVariants>\n\nfunction DialogFooter({ className, bordered, ...props }: DialogFooterProps) {\n return <div className={dialogFooterVariants({ bordered, className })} {...props} />\n}\n\nfunction DialogClose({ ...props }: ComponentProps<typeof Button>) {\n return <DialogPrimitive.Close render={<Button variant=\"secondary\" {...props} />} />\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n}\n"],"mappings":";;;;;;;;AAcA,MAAM,SAASA,SAAgB;AAC/B,MAAM,gBAAgBA,SAAgB;AACtC,MAAM,cAAcA,SAAgB;AACpC,MAAM,oBAAoBA,SAAgB;;AAG1C,SAAS,cAAc,EAAE,WAAW,GAAG,SAAyC;CAC9E,OACE,oBAACA,SAAgB,UAAjB;EACE,WAAW,GACT,iDACA,gDACA,8CACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,wBAAwB,SAAS;CACrC,MAAM;EACJ;EACA;EACA;EACA;EACA;CACF;CAEA,UAAU;EACR,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,OAAO;GACP,OAAO;GACP,OAAO;GACP,OAAO;EACT;;;;;;EAOA,OAAO;GACL,MAAM;GACN,OAAO;EACT;;;;;EAMA,OAAO;GACL,MAAM;GACN,OAAO;EACT;CACF;CAEA,iBAAiB;EACf,MAAM;EACN,OAAO;EACP,OAAO;CACT;AACF,CAAC;AAaD,SAAS,cAAc,EACrB,WACA,UACA,MACA,OACA,OACA,WACA,GAAG,SACkB;CACrB,OACE,qBAACA,SAAgB,QAAjB,EAAA,UAAA,CACE,oBAAC,eAAD,CAAgB,CAAA,GAEhB,qBAACA,SAAgB,OAAjB;EACE,WAAW,sBAAsB;GAAE;GAAM;GAAO;GAAO;EAAU,CAAC;EAClE,GAAI;EAFN,UAAA,CAIG,UAEA,CAAC,aACA,oBAACA,SAAgB,OAAjB;GACE,QAAQ,oBAAC,QAAD;IAAQ,SAAQ;IAAQ,MAAK;IAAK,cAAW;IAAQ,QAAQ,oBAAC,OAAD,CAAQ,CAAA;GAAI,CAAA;GACjF,WAAU;EACX,CAAA,CAEkB;CACD,CAAA,CAAA,EAAA,CAAA;AAE5B;AAEA,MAAM,uBAAuB,SAAS,EACpC,UAAU;;;;;AAKR,UAAU,EACR,MAAM,2BACR,EACF,EACF,CAAC;;;;;;AAaD,SAAS,aAAa,EACpB,OACA,aACA,UACA,WACA,UACA,GAAG,SACiB;CACpB,OACE,qBAAC,eAAD;EAAe,MAAK;EAAO,WAAW,qBAAqB;GAAE;GAAU;EAAU,CAAC;EAAG,GAAI;EAAzF,UAAA,CACE,qBAAC,mBAAD,EAAA,UAAA,CACE,oBAAC,aAAD;GAAa,QAAQ,oBAAC,oBAAD,CAAqB,CAAA;GAAI,UAAA;EAAmB,CAAA,GAEhE,eACC,oBAAC,mBAAD;GAAmB,QAAQ,oBAAC,0BAAD,CAA2B,CAAA;GAAI,UAAA;EAA+B,CAAA,CAE1E,EAAA,CAAA,GAElB,QACY;;AAEnB;AAEA,MAAM,uBAAuB,SAAS;CACpC,MAAM;CAEN,UAAU;;;;;AAKR,UAAU,EACR,MAAM,qBACR,EACF;AACF,CAAC;AAID,SAAS,aAAa,EAAE,WAAW,UAAU,GAAG,SAA4B;CAC1E,OAAO,oBAAC,OAAD;EAAK,WAAW,qBAAqB;GAAE;GAAU;EAAU,CAAC;EAAG,GAAI;CAAQ,CAAA;AACpF;AAEA,SAAS,YAAY,EAAE,GAAG,SAAwC;CAChE,OAAO,oBAACA,SAAgB,OAAjB,EAAuB,QAAQ,oBAAC,QAAD;EAAQ,SAAQ;EAAY,GAAI;CAAQ,CAAA,EAAI,CAAA;AACpF"}
1
+ {"version":3,"file":"dialog.js","names":["DialogPrimitive"],"sources":["../../src/components/dialog.tsx"],"sourcesContent":["\"use client\"\n\nimport { Dialog as DialogPrimitive } from \"@base-ui/react/dialog\"\nimport type { ComponentProps, ReactNode } from \"react\"\nimport { Button } from \"~/components/button\"\nimport {\n SectionHeader,\n SectionHeaderBody,\n SectionHeaderDescription,\n SectionHeaderTitle,\n} from \"~/components/section-header\"\nimport { XIcon } from \"~/lib/icons\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst Dialog = DialogPrimitive.Root\nconst DialogTrigger = DialogPrimitive.Trigger\nconst DialogTitle = DialogPrimitive.Title\nconst DialogDescription = DialogPrimitive.Description\n\n/** The dashed, blurred backdrop behind the dialog. Rendered by `DialogContent`. */\nfunction DialogOverlay({ className, ...props }: DialogPrimitive.Backdrop.Props) {\n return (\n <DialogPrimitive.Backdrop\n className={cn(\n \"fixed inset-0 z-50 bg-dashed backdrop-blur-xs\",\n \"data-open:animate-in data-closed:animate-out\",\n \"data-open:fade-in-0 data-closed:fade-out-0\",\n className,\n )}\n {...props}\n />\n )\n}\n\nconst dialogContentVariants = variants({\n base: [\n \"fixed z-50 grid overflow-y-auto border bg-card shadow-sm\",\n // Under `sm` the dialog is a bottom sheet: full width, pinned to the bottom edge,\n // padded past the home indicator.\n \"max-sm:inset-x-0 max-sm:bottom-0 max-sm:max-h-[calc(100dvh-3rem)] max-sm:rounded-t-2xl max-sm:border-b-0\",\n \"sm:left-1/2 sm:w-[calc(100vw-2rem)] sm:-translate-x-1/2 sm:rounded-xl\",\n \"data-open:animate-in data-closed:animate-out\",\n \"data-open:fade-in-0 data-closed:fade-out-0\",\n \"data-open:slide-in-from-bottom-4 data-closed:slide-out-to-bottom-4\",\n \"max-sm:data-open:slide-in-from-bottom-8 max-sm:data-closed:slide-out-to-bottom-8\",\n ],\n\n variants: {\n size: {\n xs: \"max-w-xs\",\n sm: \"max-w-sm\",\n md: \"max-w-md\",\n lg: \"max-w-lg\",\n xl: \"max-w-xl\",\n \"2xl\": \"max-w-2xl\",\n \"3xl\": \"max-w-3xl\",\n \"4xl\": \"max-w-4xl\",\n \"5xl\": \"max-w-5xl\",\n },\n\n /**\n * Pin the dialog near the top of the viewport instead of centering it, so its height can\n * change without the whole thing jumping. A dialog stacked on top of another one\n * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.\n */\n fixed: {\n true: \"sm:top-[10vh] sm:max-h-[calc(90vh-2rem)] sm:[[role=dialog]~&]:top-[15vh] sm:[[role=dialog]~&]:max-h-[calc(85vh-2rem)]\",\n false: \"sm:top-1/2 sm:-translate-y-1/2 sm:max-h-[calc(100vh-2rem)]\",\n },\n\n /**\n * Drop the dialog's own padding and gap so sections can run edge to edge and draw their\n * own borders, e.g. a bordered header over a scrolling body over a bordered footer.\n */\n flush: {\n true: \"gap-0 p-0 max-sm:pb-[env(safe-area-inset-bottom)]\",\n false: \"gap-6 p-6 max-sm:pb-[calc(1.5rem+env(safe-area-inset-bottom))]\",\n },\n },\n\n defaultVariants: {\n size: \"md\",\n fixed: true,\n flush: false,\n },\n})\n\ntype DialogContentProps = Omit<DialogPrimitive.Popup.Props, \"className\"> &\n VariantProps<typeof dialogContentVariants> & {\n className?: string\n\n /**\n * Hide the close button in the top right corner, for a dialog that must be dismissed\n * through one of its own actions.\n */\n hideClose?: boolean\n }\n\nfunction DialogContent({\n className,\n children,\n size,\n fixed,\n flush,\n hideClose,\n ...props\n}: DialogContentProps) {\n return (\n <DialogPrimitive.Portal>\n <DialogOverlay />\n\n <DialogPrimitive.Popup\n className={dialogContentVariants({ size, fixed, flush, className })}\n {...props}\n >\n {children}\n\n {!hideClose && (\n <DialogPrimitive.Close\n render={<Button variant=\"ghost\" size=\"sm\" aria-label=\"Close\" prefix={<XIcon />} />}\n className=\"absolute top-3 right-3\"\n />\n )}\n </DialogPrimitive.Popup>\n </DialogPrimitive.Portal>\n )\n}\n\nconst dialogHeaderVariants = variants({\n variants: {\n /**\n * Give the header its own hairline and padding, for a `flush` dialog whose body scrolls\n * under it. The extra right padding clears the dialog's close button.\n */\n bordered: {\n true: \"border-b px-6 py-5 pr-14\",\n },\n },\n})\n\ntype DialogHeaderProps = Omit<ComponentProps<typeof SectionHeader>, \"title\" | \"description\"> &\n VariantProps<typeof dialogHeaderVariants> & {\n title: ReactNode\n description?: ReactNode\n }\n\n/**\n * The standard dialog heading: a card-scale `SectionHeader` whose title and description are wired to\n * Base UI's `DialogTitle` / `DialogDescription` for accessibility. Extra children render after\n * them.\n */\nfunction DialogHeader({\n title,\n description,\n bordered,\n className,\n children,\n ...props\n}: DialogHeaderProps) {\n return (\n <SectionHeader size=\"card\" className={dialogHeaderVariants({ bordered, className })} {...props}>\n <SectionHeaderBody>\n <DialogTitle render={<SectionHeaderTitle />}>{title}</DialogTitle>\n\n {description && (\n <DialogDescription render={<SectionHeaderDescription />}>{description}</DialogDescription>\n )}\n </SectionHeaderBody>\n\n {children}\n </SectionHeader>\n )\n}\n\nconst dialogFooterVariants = variants({\n base: \"flex flex-col-reverse flex-wrap gap-x-2 gap-y-4 sm:flex-row sm:justify-end\",\n\n variants: {\n /**\n * Give the footer its own hairline and padding, for a `flush` dialog where the body\n * scrolls behind it.\n */\n bordered: {\n true: \"border-t px-6 py-4\",\n },\n },\n})\n\ntype DialogFooterProps = ComponentProps<\"div\"> & VariantProps<typeof dialogFooterVariants>\n\nfunction DialogFooter({ className, bordered, ...props }: DialogFooterProps) {\n return <div className={dialogFooterVariants({ bordered, className })} {...props} />\n}\n\nfunction DialogClose({ ...props }: ComponentProps<typeof Button>) {\n return <DialogPrimitive.Close render={<Button variant=\"secondary\" {...props} />} />\n}\n\nexport {\n Dialog,\n DialogClose,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n}\n"],"mappings":";;;;;;;;AAcA,MAAM,SAASA,SAAgB;AAC/B,MAAM,gBAAgBA,SAAgB;AACtC,MAAM,cAAcA,SAAgB;AACpC,MAAM,oBAAoBA,SAAgB;;AAG1C,SAAS,cAAc,EAAE,WAAW,GAAG,SAAyC;CAC9E,OACE,oBAACA,SAAgB,UAAjB;EACE,WAAW,GACT,iDACA,gDACA,8CACA,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,MAAM,wBAAwB,SAAS;CACrC,MAAM;EACJ;EAGA;EACA;EACA;EACA;EACA;EACA;CACF;CAEA,UAAU;EACR,MAAM;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,OAAO;GACP,OAAO;GACP,OAAO;GACP,OAAO;EACT;;;;;;EAOA,OAAO;GACL,MAAM;GACN,OAAO;EACT;;;;;EAMA,OAAO;GACL,MAAM;GACN,OAAO;EACT;CACF;CAEA,iBAAiB;EACf,MAAM;EACN,OAAO;EACP,OAAO;CACT;AACF,CAAC;AAaD,SAAS,cAAc,EACrB,WACA,UACA,MACA,OACA,OACA,WACA,GAAG,SACkB;CACrB,OACE,qBAACA,SAAgB,QAAjB,EAAA,UAAA,CACE,oBAAC,eAAD,CAAgB,CAAA,GAEhB,qBAACA,SAAgB,OAAjB;EACE,WAAW,sBAAsB;GAAE;GAAM;GAAO;GAAO;EAAU,CAAC;EAClE,GAAI;EAFN,UAAA,CAIG,UAEA,CAAC,aACA,oBAACA,SAAgB,OAAjB;GACE,QAAQ,oBAAC,QAAD;IAAQ,SAAQ;IAAQ,MAAK;IAAK,cAAW;IAAQ,QAAQ,oBAAC,OAAD,CAAQ,CAAA;GAAI,CAAA;GACjF,WAAU;EACX,CAAA,CAEkB;CACD,CAAA,CAAA,EAAA,CAAA;AAE5B;AAEA,MAAM,uBAAuB,SAAS,EACpC,UAAU;;;;;AAKR,UAAU,EACR,MAAM,2BACR,EACF,EACF,CAAC;;;;;;AAaD,SAAS,aAAa,EACpB,OACA,aACA,UACA,WACA,UACA,GAAG,SACiB;CACpB,OACE,qBAAC,eAAD;EAAe,MAAK;EAAO,WAAW,qBAAqB;GAAE;GAAU;EAAU,CAAC;EAAG,GAAI;EAAzF,UAAA,CACE,qBAAC,mBAAD,EAAA,UAAA,CACE,oBAAC,aAAD;GAAa,QAAQ,oBAAC,oBAAD,CAAqB,CAAA;GAAI,UAAA;EAAmB,CAAA,GAEhE,eACC,oBAAC,mBAAD;GAAmB,QAAQ,oBAAC,0BAAD,CAA2B,CAAA;GAAI,UAAA;EAA+B,CAAA,CAE1E,EAAA,CAAA,GAElB,QACY;;AAEnB;AAEA,MAAM,uBAAuB,SAAS;CACpC,MAAM;CAEN,UAAU;;;;;AAKR,UAAU,EACR,MAAM,qBACR,EACF;AACF,CAAC;AAID,SAAS,aAAa,EAAE,WAAW,UAAU,GAAG,SAA4B;CAC1E,OAAO,oBAAC,OAAD;EAAK,WAAW,qBAAqB;GAAE;GAAU;EAAU,CAAC;EAAG,GAAI;CAAQ,CAAA;AACpF;AAEA,SAAS,YAAY,EAAE,GAAG,SAAwC;CAChE,OAAO,oBAACA,SAAgB,OAAjB,EAAuB,QAAQ,oBAAC,QAAD;EAAQ,SAAQ;EAAY,GAAI;CAAQ,CAAA,EAAI,CAAA;AACpF"}
@@ -18,7 +18,7 @@ function FormSection({ id, title, description, actions, footer, className, child
18
18
  children: /* @__PURE__ */ jsxs(Fragment, { children: [
19
19
  (title || actions) && /* @__PURE__ */ jsx(SectionHeader, {
20
20
  size: "panel",
21
- className: "py-4",
21
+ className: "py-4 max-sm:flex-col max-sm:items-stretch",
22
22
  title,
23
23
  description,
24
24
  actions
@@ -1 +1 @@
1
- {"version":3,"file":"form-section.js","names":[],"sources":["../../src/components/form-section.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\"\nimport type { ReactNode } from \"react\"\nimport { SectionHeader } from \"~/components/section-header\"\nimport { cn } from \"~/lib/variants\"\n\ntype FormSectionProps = Omit<useRender.ComponentProps<\"section\">, \"title\"> & {\n id?: string\n /**\n * Optional heading. Leave it out inside the settings dialog, whose header owns the title.\n */\n title?: ReactNode\n description?: ReactNode\n actions?: ReactNode\n /**\n * Right-aligned actions after the rows, e.g. a save button. Rendered as the last row.\n */\n footer?: ReactNode\n}\n\n/**\n * A block of settings: one padded container whose children (optional heading, the rows,\n * optional footer) stack with hairlines between them. Renders as a `<form>` via `render`\n * when the rows are fields, so the form is the only wrapper.\n */\nexport function FormSection({\n id,\n title,\n description,\n actions,\n footer,\n className,\n children,\n render,\n ...props\n}: FormSectionProps) {\n return useRender({\n render,\n defaultTagName: \"section\",\n props: {\n id,\n className: cn(\"flex flex-col divide-y px-5 md:px-6\", className),\n children: (\n <>\n {(title || actions) && (\n <SectionHeader\n size=\"panel\"\n className=\"py-4\"\n title={title}\n description={description}\n actions={actions}\n />\n )}\n\n {children}\n\n {footer && <div className=\"flex justify-end py-5\">{footer}</div>}\n </>\n ),\n ...props,\n },\n })\n}\n"],"mappings":";;;;;;;;;;AAwBA,SAAgB,YAAY,EAC1B,IACA,OACA,aACA,SACA,QACA,WACA,UACA,QACA,GAAG,SACgB;CACnB,OAAO,UAAU;EACf;EACA,gBAAgB;EAChB,OAAO;GACL;GACA,WAAW,GAAG,uCAAuC,SAAS;GAC9D,UACE,qBAAA,UAAA,EAAA,UAAA;KACI,SAAS,YACT,oBAAC,eAAD;KACE,MAAK;KACL,WAAU;KACH;KACM;KACJ;IACV,CAAA;IAGF;IAEA,UAAU,oBAAC,OAAD;KAAK,WAAU;KAAyB,UAAA;IAAY,CAAA;GAC/D,EAAA,CAAA;GAEJ,GAAG;EACL;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"form-section.js","names":[],"sources":["../../src/components/form-section.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\"\nimport type { ReactNode } from \"react\"\nimport { SectionHeader } from \"~/components/section-header\"\nimport { cn } from \"~/lib/variants\"\n\ntype FormSectionProps = Omit<useRender.ComponentProps<\"section\">, \"title\"> & {\n id?: string\n /**\n * Optional heading. Leave it out inside the settings dialog, whose header owns the title.\n */\n title?: ReactNode\n description?: ReactNode\n actions?: ReactNode\n /**\n * Right-aligned actions after the rows, e.g. a save button. Rendered as the last row.\n */\n footer?: ReactNode\n}\n\n/**\n * A block of settings: one padded container whose children (optional heading, the rows,\n * optional footer) stack with hairlines between them. Renders as a `<form>` via `render`\n * when the rows are fields, so the form is the only wrapper.\n */\nexport function FormSection({\n id,\n title,\n description,\n actions,\n footer,\n className,\n children,\n render,\n ...props\n}: FormSectionProps) {\n return useRender({\n render,\n defaultTagName: \"section\",\n props: {\n id,\n className: cn(\"flex flex-col divide-y px-5 md:px-6\", className),\n children: (\n <>\n {(title || actions) && (\n <SectionHeader\n size=\"panel\"\n className=\"py-4 max-sm:flex-col max-sm:items-stretch\"\n title={title}\n description={description}\n actions={actions}\n />\n )}\n\n {children}\n\n {footer && <div className=\"flex justify-end py-5\">{footer}</div>}\n </>\n ),\n ...props,\n },\n })\n}\n"],"mappings":";;;;;;;;;;AAwBA,SAAgB,YAAY,EAC1B,IACA,OACA,aACA,SACA,QACA,WACA,UACA,QACA,GAAG,SACgB;CACnB,OAAO,UAAU;EACf;EACA,gBAAgB;EAChB,OAAO;GACL;GACA,WAAW,GAAG,uCAAuC,SAAS;GAC9D,UACE,qBAAA,UAAA,EAAA,UAAA;KACI,SAAS,YACT,oBAAC,eAAD;KACE,MAAK;KACL,WAAU;KACH;KACM;KACJ;IACV,CAAA;IAGF;IAEA,UAAU,oBAAC,OAAD;KAAK,WAAU;KAAyB,UAAA;IAAY,CAAA;GAC/D,EAAA,CAAA;GAEJ,GAAG;EACL;CACF,CAAC;AACH"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/variants.js";
3
+ import { controlTextClasses, descriptionClasses } from "../lib/classes.js";
3
4
  import { Stack } from "./stack.js";
4
- import { descriptionClasses } from "../lib/classes.js";
5
5
  import { Label } from "./label.js";
6
6
  import { jsx } from "react/jsx-runtime";
7
7
  import { useRender } from "@base-ui/react/use-render";
@@ -77,7 +77,7 @@ function FormMessage({ className, children, ...props }) {
77
77
  if (!body) return null;
78
78
  return /* @__PURE__ */ jsx("p", {
79
79
  id: formMessageId,
80
- className: cn("text-control font-medium text-danger", className),
80
+ className: cn(`${controlTextClasses} font-medium text-danger`, className),
81
81
  ...props,
82
82
  children: body
83
83
  });
@@ -1 +1 @@
1
- {"version":3,"file":"form.js","names":[],"sources":["../../src/components/form.tsx"],"sourcesContent":["\"use client\"\n\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { type ComponentProps, createContext, useContext, useId } from \"react\"\nimport {\n Controller,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n FormProvider,\n useFormContext,\n} from \"react-hook-form\"\nimport { Label } from \"~/components/label\"\nimport { Stack } from \"~/components/stack\"\nimport { descriptionClasses } from \"~/lib/classes\"\nimport { cn } from \"~/lib/variants\"\n\nconst Form = FormProvider\n\ninterface FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> {\n name: TName\n}\n\nconst FormFieldContext = createContext<FormFieldContextValue | null>(null)\n\nfunction FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformedValues = TFieldValues,\n>({ ...props }: ControllerProps<TFieldValues, TName, TTransformedValues>) {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nfunction useFormField() {\n const fieldContext = useContext(FormFieldContext)\n const itemContext = useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n if (!itemContext) {\n throw new Error(\"useFormField should be used within <FormItem>\")\n }\n\n const fieldState = getFieldState(fieldContext.name, formState)\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ninterface FormItemContextValue {\n id: string\n}\n\nconst FormItemContext = createContext<FormItemContextValue | null>(null)\n\nfunction FormItem({ direction = \"column\", ...props }: ComponentProps<typeof Stack>) {\n const id = useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <Stack direction={direction} {...props} />\n </FormItemContext.Provider>\n )\n}\n\nfunction FormLabel({ ...props }: ComponentProps<typeof Label>) {\n const { formItemId } = useFormField()\n\n return <Label htmlFor={formItemId} {...props} />\n}\n\nfunction FormControl({ children, render, ...props }: useRender.ComponentProps<\"div\">) {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n // Renders *as* its single child (the form field), merging id/aria onto it —\n // the Base UI equivalent of Radix's `<Slot>`.\n return useRender({\n render: render ?? (children as useRender.RenderProp),\n props: {\n id: formItemId,\n \"aria-describedby\": !error ? formDescriptionId : `${formDescriptionId} ${formMessageId}`,\n \"aria-invalid\": !!error,\n ...props,\n },\n })\n}\n\nfunction FormDescription({ className, ...props }: ComponentProps<\"p\">) {\n const { formDescriptionId } = useFormField()\n\n return <p id={formDescriptionId} className={cn(descriptionClasses, className)} {...props} />\n}\n\nfunction FormMessage({ className, children, ...props }: ComponentProps<\"p\">) {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message) : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n id={formMessageId}\n className={cn(\"text-control font-medium text-danger\", className)}\n {...props}\n >\n {body}\n </p>\n )\n}\n\nexport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n useFormField,\n}\n"],"mappings":";;;;;;;;;;AAiBA,MAAM,OAAO;AASb,MAAM,mBAAmB,cAA4C,IAAI;AAEzE,SAAS,UAIP,EAAE,GAAG,SAAmE;CACxE,OACE,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO,EAAE,MAAM,MAAM,KAAK;EACnD,UAAA,oBAAC,YAAD,EAAY,GAAI,MAAQ,CAAA;CACC,CAAA;AAE/B;AAEA,SAAS,eAAe;CACtB,MAAM,eAAe,WAAW,gBAAgB;CAChD,MAAM,cAAc,WAAW,eAAe;CAC9C,MAAM,EAAE,eAAe,cAAc,eAAe;CAEpD,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,gDAAgD;CAGlE,IAAI,CAAC,aACH,MAAM,IAAI,MAAM,+CAA+C;CAGjE,MAAM,aAAa,cAAc,aAAa,MAAM,SAAS;CAC7D,MAAM,EAAE,OAAO;CAEf,OAAO;EACL;EACA,MAAM,aAAa;EACnB,YAAY,GAAG,GAAG;EAClB,mBAAmB,GAAG,GAAG;EACzB,eAAe,GAAG,GAAG;EACrB,GAAG;CACL;AACF;AAMA,MAAM,kBAAkB,cAA2C,IAAI;AAEvE,SAAS,SAAS,EAAE,YAAY,UAAU,GAAG,SAAuC;CAClF,MAAM,KAAK,MAAM;CAEjB,OACE,oBAAC,gBAAgB,UAAjB;EAA0B,OAAO,EAAE,GAAG;EACpC,UAAA,oBAAC,OAAD;GAAkB;GAAW,GAAI;EAAQ,CAAA;CACjB,CAAA;AAE9B;AAEA,SAAS,UAAU,EAAE,GAAG,SAAuC;CAC7D,MAAM,EAAE,eAAe,aAAa;CAEpC,OAAO,oBAAC,OAAD;EAAO,SAAS;EAAY,GAAI;CAAQ,CAAA;AACjD;AAEA,SAAS,YAAY,EAAE,UAAU,QAAQ,GAAG,SAA0C;CACpF,MAAM,EAAE,OAAO,YAAY,mBAAmB,kBAAkB,aAAa;CAI7E,OAAO,UAAU;EACf,QAAQ,UAAW;EACnB,OAAO;GACL,IAAI;GACJ,oBAAoB,CAAC,QAAQ,oBAAoB,GAAG,kBAAkB,GAAG;GACzE,gBAAgB,CAAC,CAAC;GAClB,GAAG;EACL;CACF,CAAC;AACH;AAEA,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAA8B;CACrE,MAAM,EAAE,sBAAsB,aAAa;CAE3C,OAAO,oBAAC,KAAD;EAAG,IAAI;EAAmB,WAAW,GAAG,oBAAoB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC7F;AAEA,SAAS,YAAY,EAAE,WAAW,UAAU,GAAG,SAA8B;CAC3E,MAAM,EAAE,OAAO,kBAAkB,aAAa;CAC9C,MAAM,OAAO,QAAQ,OAAO,OAAO,OAAO,IAAI;CAE9C,IAAI,CAAC,MACH,OAAO;CAGT,OACE,oBAAC,KAAD;EACE,IAAI;EACJ,WAAW,GAAG,wCAAwC,SAAS;EAC/D,GAAI;EAEH,UAAA;CACA,CAAA;AAEP"}
1
+ {"version":3,"file":"form.js","names":[],"sources":["../../src/components/form.tsx"],"sourcesContent":["\"use client\"\n\nimport { useRender } from \"@base-ui/react/use-render\"\nimport { type ComponentProps, createContext, useContext, useId } from \"react\"\nimport {\n Controller,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n FormProvider,\n useFormContext,\n} from \"react-hook-form\"\nimport { Label } from \"~/components/label\"\nimport { Stack } from \"~/components/stack\"\nimport { controlTextClasses, descriptionClasses } from \"~/lib/classes\"\nimport { cn } from \"~/lib/variants\"\n\nconst Form = FormProvider\n\ninterface FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> {\n name: TName\n}\n\nconst FormFieldContext = createContext<FormFieldContextValue | null>(null)\n\nfunction FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n TTransformedValues = TFieldValues,\n>({ ...props }: ControllerProps<TFieldValues, TName, TTransformedValues>) {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n )\n}\n\nfunction useFormField() {\n const fieldContext = useContext(FormFieldContext)\n const itemContext = useContext(FormItemContext)\n const { getFieldState, formState } = useFormContext()\n\n if (!fieldContext) {\n throw new Error(\"useFormField should be used within <FormField>\")\n }\n\n if (!itemContext) {\n throw new Error(\"useFormField should be used within <FormItem>\")\n }\n\n const fieldState = getFieldState(fieldContext.name, formState)\n const { id } = itemContext\n\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n }\n}\n\ninterface FormItemContextValue {\n id: string\n}\n\nconst FormItemContext = createContext<FormItemContextValue | null>(null)\n\nfunction FormItem({ direction = \"column\", ...props }: ComponentProps<typeof Stack>) {\n const id = useId()\n\n return (\n <FormItemContext.Provider value={{ id }}>\n <Stack direction={direction} {...props} />\n </FormItemContext.Provider>\n )\n}\n\nfunction FormLabel({ ...props }: ComponentProps<typeof Label>) {\n const { formItemId } = useFormField()\n\n return <Label htmlFor={formItemId} {...props} />\n}\n\nfunction FormControl({ children, render, ...props }: useRender.ComponentProps<\"div\">) {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField()\n\n // Renders *as* its single child (the form field), merging id/aria onto it —\n // the Base UI equivalent of Radix's `<Slot>`.\n return useRender({\n render: render ?? (children as useRender.RenderProp),\n props: {\n id: formItemId,\n \"aria-describedby\": !error ? formDescriptionId : `${formDescriptionId} ${formMessageId}`,\n \"aria-invalid\": !!error,\n ...props,\n },\n })\n}\n\nfunction FormDescription({ className, ...props }: ComponentProps<\"p\">) {\n const { formDescriptionId } = useFormField()\n\n return <p id={formDescriptionId} className={cn(descriptionClasses, className)} {...props} />\n}\n\nfunction FormMessage({ className, children, ...props }: ComponentProps<\"p\">) {\n const { error, formMessageId } = useFormField()\n const body = error ? String(error?.message) : children\n\n if (!body) {\n return null\n }\n\n return (\n <p\n id={formMessageId}\n className={cn(`${controlTextClasses} font-medium text-danger`, className)}\n {...props}\n >\n {body}\n </p>\n )\n}\n\nexport {\n Form,\n FormControl,\n FormDescription,\n FormField,\n FormItem,\n FormLabel,\n FormMessage,\n useFormField,\n}\n"],"mappings":";;;;;;;;;;AAiBA,MAAM,OAAO;AASb,MAAM,mBAAmB,cAA4C,IAAI;AAEzE,SAAS,UAIP,EAAE,GAAG,SAAmE;CACxE,OACE,oBAAC,iBAAiB,UAAlB;EAA2B,OAAO,EAAE,MAAM,MAAM,KAAK;EACnD,UAAA,oBAAC,YAAD,EAAY,GAAI,MAAQ,CAAA;CACC,CAAA;AAE/B;AAEA,SAAS,eAAe;CACtB,MAAM,eAAe,WAAW,gBAAgB;CAChD,MAAM,cAAc,WAAW,eAAe;CAC9C,MAAM,EAAE,eAAe,cAAc,eAAe;CAEpD,IAAI,CAAC,cACH,MAAM,IAAI,MAAM,gDAAgD;CAGlE,IAAI,CAAC,aACH,MAAM,IAAI,MAAM,+CAA+C;CAGjE,MAAM,aAAa,cAAc,aAAa,MAAM,SAAS;CAC7D,MAAM,EAAE,OAAO;CAEf,OAAO;EACL;EACA,MAAM,aAAa;EACnB,YAAY,GAAG,GAAG;EAClB,mBAAmB,GAAG,GAAG;EACzB,eAAe,GAAG,GAAG;EACrB,GAAG;CACL;AACF;AAMA,MAAM,kBAAkB,cAA2C,IAAI;AAEvE,SAAS,SAAS,EAAE,YAAY,UAAU,GAAG,SAAuC;CAClF,MAAM,KAAK,MAAM;CAEjB,OACE,oBAAC,gBAAgB,UAAjB;EAA0B,OAAO,EAAE,GAAG;EACpC,UAAA,oBAAC,OAAD;GAAkB;GAAW,GAAI;EAAQ,CAAA;CACjB,CAAA;AAE9B;AAEA,SAAS,UAAU,EAAE,GAAG,SAAuC;CAC7D,MAAM,EAAE,eAAe,aAAa;CAEpC,OAAO,oBAAC,OAAD;EAAO,SAAS;EAAY,GAAI;CAAQ,CAAA;AACjD;AAEA,SAAS,YAAY,EAAE,UAAU,QAAQ,GAAG,SAA0C;CACpF,MAAM,EAAE,OAAO,YAAY,mBAAmB,kBAAkB,aAAa;CAI7E,OAAO,UAAU;EACf,QAAQ,UAAW;EACnB,OAAO;GACL,IAAI;GACJ,oBAAoB,CAAC,QAAQ,oBAAoB,GAAG,kBAAkB,GAAG;GACzE,gBAAgB,CAAC,CAAC;GAClB,GAAG;EACL;CACF,CAAC;AACH;AAEA,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAA8B;CACrE,MAAM,EAAE,sBAAsB,aAAa;CAE3C,OAAO,oBAAC,KAAD;EAAG,IAAI;EAAmB,WAAW,GAAG,oBAAoB,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC7F;AAEA,SAAS,YAAY,EAAE,WAAW,UAAU,GAAG,SAA8B;CAC3E,MAAM,EAAE,OAAO,kBAAkB,aAAa;CAC9C,MAAM,OAAO,QAAQ,OAAO,OAAO,OAAO,IAAI;CAE9C,IAAI,CAAC,MACH,OAAO;CAGT,OACE,oBAAC,KAAD;EACE,IAAI;EACJ,WAAW,GAAG,GAAG,mBAAmB,2BAA2B,SAAS;EACxE,GAAI;EAEH,UAAA;CACA,CAAA;AAEP"}
@@ -7,7 +7,7 @@ declare const inputVariants: import("tailwind-variants").TVReturnType<{
7
7
  md: "px-3 py-2 rounded-md";
8
8
  lg: "px-4 py-2.5 rounded-lg sm:text-sm";
9
9
  };
10
- }, undefined, "appearance-none min-h-0 w-full self-stretch bg-card text-foreground text-control break-words disabled:text-secondary-foreground/50", {
10
+ }, undefined, "appearance-none min-h-0 w-full self-stretch bg-card text-foreground text-(length:--text-control) leading-(--text-control--line-height) break-words disabled:text-secondary-foreground/50", {
11
11
  hover: {
12
12
  true: "not-disabled:cursor-pointer hover:not-disabled:outline-[3px] hover:not-disabled:outline-border/50";
13
13
  };
@@ -1 +1 @@
1
- {"version":3,"file":"input.d.ts","names":[],"sources":["../../src/components/input.tsx"],"mappings":";;;cAIM,2CAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoBd,aAAa,KAAK,mCAAmC,oBAAoB;iBAErE,QAAQ,WAAW,OAAO,OAAO,SAAS,SAAS,6BAAU,IAAA"}
1
+ {"version":3,"file":"input.d.ts","names":[],"sources":["../../src/components/input.tsx"],"mappings":";;;cAKM,2CAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoBd,aAAa,KAAK,mCAAmC,oBAAoB;iBAErE,QAAQ,WAAW,OAAO,OAAO,SAAS,SAAS,6BAAU,IAAA"}
@@ -1,10 +1,11 @@
1
1
  import { cn, variants } from "../lib/variants.js";
2
+ import { controlTextClasses } from "../lib/classes.js";
2
3
  import { interactiveVariants } from "../lib/interactive.js";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  //#region src/components/input.tsx
5
6
  const inputVariants = variants({
6
7
  extend: interactiveVariants,
7
- base: "appearance-none min-h-0 w-full self-stretch bg-card text-foreground text-control break-words disabled:text-secondary-foreground/50",
8
+ base: `appearance-none min-h-0 w-full self-stretch bg-card text-foreground ${controlTextClasses} break-words disabled:text-secondary-foreground/50`,
8
9
  variants: { size: {
9
10
  sm: "px-2 py-1 font-normal rounded-md",
10
11
  md: "px-3 py-2 rounded-md",
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","names":[],"sources":["../../src/components/input.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\"\nimport { interactiveVariants } from \"~/lib/interactive\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst inputVariants = variants({\n extend: interactiveVariants,\n base: \"appearance-none min-h-0 w-full self-stretch bg-card text-foreground text-control break-words disabled:text-secondary-foreground/50\",\n\n variants: {\n size: {\n sm: \"px-2 py-1 font-normal rounded-md\",\n md: \"px-3 py-2 rounded-md\",\n lg: \"px-4 py-2.5 rounded-lg sm:text-sm\",\n },\n },\n\n defaultVariants: {\n hover: false,\n focus: true,\n bordered: true,\n size: \"md\",\n },\n})\n\ntype InputProps = Omit<ComponentProps<\"input\">, \"size\"> & VariantProps<typeof inputVariants>\n\nfunction Input({ className, hover, focus, size, ...props }: InputProps) {\n return <input className={cn(inputVariants({ hover, focus, size }), className)} {...props} />\n}\n\nexport { Input, inputVariants }\n"],"mappings":";;;;AAIA,MAAM,gBAAgB,SAAS;CAC7B,QAAQ;CACR,MAAM;CAEN,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,EACF;CAEA,iBAAiB;EACf,OAAO;EACP,OAAO;EACP,UAAU;EACV,MAAM;CACR;AACF,CAAC;AAID,SAAS,MAAM,EAAE,WAAW,OAAO,OAAO,MAAM,GAAG,SAAqB;CACtE,OAAO,oBAAC,SAAD;EAAO,WAAW,GAAG,cAAc;GAAE;GAAO;GAAO;EAAK,CAAC,GAAG,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC7F"}
1
+ {"version":3,"file":"input.js","names":[],"sources":["../../src/components/input.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\"\nimport { controlTextClasses } from \"~/lib/classes\"\nimport { interactiveVariants } from \"~/lib/interactive\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst inputVariants = variants({\n extend: interactiveVariants,\n base: `appearance-none min-h-0 w-full self-stretch bg-card text-foreground ${controlTextClasses} break-words disabled:text-secondary-foreground/50`,\n\n variants: {\n size: {\n sm: \"px-2 py-1 font-normal rounded-md\",\n md: \"px-3 py-2 rounded-md\",\n lg: \"px-4 py-2.5 rounded-lg sm:text-sm\",\n },\n },\n\n defaultVariants: {\n hover: false,\n focus: true,\n bordered: true,\n size: \"md\",\n },\n})\n\ntype InputProps = Omit<ComponentProps<\"input\">, \"size\"> & VariantProps<typeof inputVariants>\n\nfunction Input({ className, hover, focus, size, ...props }: InputProps) {\n return <input className={cn(inputVariants({ hover, focus, size }), className)} {...props} />\n}\n\nexport { Input, inputVariants }\n"],"mappings":";;;;;AAKA,MAAM,gBAAgB,SAAS;CAC7B,QAAQ;CACR,MAAM,uEAAuE,mBAAmB;CAEhG,UAAU,EACR,MAAM;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,EACF;CAEA,iBAAiB;EACf,OAAO;EACP,OAAO;EACP,UAAU;EACV,MAAM;CACR;AACF,CAAC;AAID,SAAS,MAAM,EAAE,WAAW,OAAO,OAAO,MAAM,GAAG,SAAqB;CACtE,OAAO,oBAAC,SAAD;EAAO,WAAW,GAAG,cAAc;GAAE;GAAO;GAAO;EAAK,CAAC,GAAG,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC7F"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../lib/variants.js";
3
+ import { controlTextClasses, eyebrowClasses, popoverAnimationClasses } from "../lib/classes.js";
3
4
  import { CheckIcon, CircleIcon } from "../lib/icons.js";
4
- import { eyebrowClasses, popoverAnimationClasses } from "../lib/classes.js";
5
5
  import { Kbd } from "./kbd.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { Menu as Menu$1 } from "@base-ui/react/menu";
@@ -24,13 +24,13 @@ function MenuContent({ className, sideOffset = 4, align, side, ...props }) {
24
24
  }
25
25
  function MenuItem({ className, inset, ...props }) {
26
26
  return /* @__PURE__ */ jsx(Menu$1.Item, {
27
- className: cn("relative flex m-0 cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-control outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0", inset && "pl-8", className),
27
+ className: cn(`relative flex m-0 cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 pointer-coarse:min-h-10 ${controlTextClasses} outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0`, inset && "pl-8", className),
28
28
  ...props
29
29
  });
30
30
  }
31
31
  function MenuCheckboxItem({ className, children, checked, ...props }) {
32
32
  return /* @__PURE__ */ jsxs(Menu$1.CheckboxItem, {
33
- className: cn("relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-control outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50", className),
33
+ className: cn(`relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 pointer-coarse:min-h-10 ${controlTextClasses} outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50`, className),
34
34
  checked,
35
35
  ...props,
36
36
  children: [/* @__PURE__ */ jsx("span", {
@@ -41,7 +41,7 @@ function MenuCheckboxItem({ className, children, checked, ...props }) {
41
41
  }
42
42
  function MenuRadioItem({ className, children, ...props }) {
43
43
  return /* @__PURE__ */ jsxs(Menu$1.RadioItem, {
44
- className: cn("relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-control outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50", className),
44
+ className: cn(`relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 pointer-coarse:min-h-10 ${controlTextClasses} outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50`, className),
45
45
  ...props,
46
46
  children: [/* @__PURE__ */ jsx("span", {
47
47
  className: "absolute left-2 flex size-3.5 items-center justify-center",
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","names":["MenuPrimitive"],"sources":["../../src/components/menu.tsx"],"sourcesContent":["\"use client\"\n\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\nimport type { ComponentProps } from \"react\"\nimport { Kbd } from \"~/components/kbd\"\nimport { eyebrowClasses, popoverAnimationClasses } from \"~/lib/classes\"\nimport { CheckIcon, CircleIcon } from \"~/lib/icons\"\nimport { cn } from \"~/lib/variants\"\n\nconst Menu = MenuPrimitive.Root\nconst MenuTrigger = MenuPrimitive.Trigger\nconst MenuGroup = MenuPrimitive.Group\nconst MenuRadioGroup = MenuPrimitive.RadioGroup\n\nfunction MenuContent({\n className,\n sideOffset = 4,\n align,\n side,\n ...props\n}: MenuPrimitive.Popup.Props &\n Pick<MenuPrimitive.Positioner.Props, \"align\" | \"side\" | \"sideOffset\">) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.Positioner\n sideOffset={sideOffset}\n align={align}\n side={side}\n className=\"isolate z-50\"\n >\n <MenuPrimitive.Popup\n className={cn(\n \"min-w-40 flex flex-col rounded-md border bg-popover p-1 text-popover-foreground shadow-sm backdrop-blur-xs\",\n popoverAnimationClasses,\n className,\n )}\n {...props}\n />\n </MenuPrimitive.Positioner>\n </MenuPrimitive.Portal>\n )\n}\n\nfunction MenuItem({\n className,\n inset,\n ...props\n}: MenuPrimitive.Item.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.Item\n className={cn(\n \"relative flex m-0 cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-control outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0\",\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: MenuPrimitive.CheckboxItem.Props) {\n return (\n <MenuPrimitive.CheckboxItem\n className={cn(\n \"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-control outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50\",\n className,\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <MenuPrimitive.CheckboxItemIndicator>\n <CheckIcon />\n </MenuPrimitive.CheckboxItemIndicator>\n </span>\n {children}\n </MenuPrimitive.CheckboxItem>\n )\n}\n\nfunction MenuRadioItem({ className, children, ...props }: MenuPrimitive.RadioItem.Props) {\n return (\n <MenuPrimitive.RadioItem\n className={cn(\n \"relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-control outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <MenuPrimitive.RadioItemIndicator>\n <CircleIcon className=\"fill-current size-2\" />\n </MenuPrimitive.RadioItemIndicator>\n </span>\n {children}\n </MenuPrimitive.RadioItem>\n )\n}\n\nfunction MenuGroupLabel({\n className,\n inset,\n ...props\n}: MenuPrimitive.GroupLabel.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.GroupLabel\n className={cn(\"px-2 pt-1.5 pb-1\", eyebrowClasses, inset && \"pl-8\", className)}\n {...props}\n />\n )\n}\n\nfunction MenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {\n return (\n <MenuPrimitive.Separator className={cn(\"-mx-1 my-1 h-px bg-border\", className)} {...props} />\n )\n}\n\nfunction MenuShortcut({ className, ...props }: ComponentProps<typeof Kbd>) {\n return <Kbd className={cn(\"ml-auto\", className)} {...props} />\n}\n\nexport {\n Menu,\n MenuCheckboxItem,\n MenuContent,\n MenuGroup,\n MenuItem,\n MenuGroupLabel,\n MenuRadioGroup,\n MenuRadioItem,\n MenuSeparator,\n MenuShortcut,\n MenuTrigger,\n}\n"],"mappings":";;;;;;;;AASA,MAAM,OAAOA,OAAc;AAC3B,MAAM,cAAcA,OAAc;AAClC,MAAM,YAAYA,OAAc;AAChC,MAAM,iBAAiBA,OAAc;AAErC,SAAS,YAAY,EACnB,WACA,aAAa,GACb,OACA,MACA,GAAG,SAEoE;CACvE,OACE,oBAACA,OAAc,QAAf,EAAA,UACE,oBAACA,OAAc,YAAf;EACc;EACL;EACD;EACN,WAAU;EAEV,UAAA,oBAACA,OAAc,OAAf;GACE,WAAW,GACT,8GACA,yBACA,SACF;GACA,GAAI;EACL,CAAA;CACuB,CAAA,EACN,CAAA;AAE1B;AAEA,SAAS,SAAS,EAChB,WACA,OACA,GAAG,SAGF;CACD,OACE,oBAACA,OAAc,MAAf;EACE,WAAW,GACT,8PACA,SAAS,QACT,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,UACA,SACA,GAAG,SACgC;CACnC,OACE,qBAACA,OAAc,cAAf;EACE,WAAW,GACT,yNACA,SACF;EACS;EACT,GAAI;EANN,UAAA,CAQE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACA,OAAc,uBAAf,EAAA,UACE,oBAAC,WAAD,CAAY,CAAA,EACuB,CAAA;EACjC,CAAA,GACL,QACyB;;AAEhC;AAEA,SAAS,cAAc,EAAE,WAAW,UAAU,GAAG,SAAwC;CACvF,OACE,qBAACA,OAAc,WAAf;EACE,WAAW,GACT,yNACA,SACF;EACA,GAAI;EALN,UAAA,CAOE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACA,OAAc,oBAAf,EAAA,UACE,oBAAC,YAAD,EAAY,WAAU,sBAAuB,CAAA,EACb,CAAA;EAC9B,CAAA,GACL,QACsB;;AAE7B;AAEA,SAAS,eAAe,EACtB,WACA,OACA,GAAG,SAGF;CACD,OACE,oBAACA,OAAc,YAAf;EACE,WAAW,GAAG,oBAAoB,gBAAgB,SAAS,QAAQ,SAAS;EAC5E,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EAAE,WAAW,GAAG,SAAwC;CAC7E,OACE,oBAACA,OAAc,WAAf;EAAyB,WAAW,GAAG,6BAA6B,SAAS;EAAG,GAAI;CAAQ,CAAA;AAEhG;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAqC;CACzE,OAAO,oBAAC,KAAD;EAAK,WAAW,GAAG,WAAW,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC/D"}
1
+ {"version":3,"file":"menu.js","names":["MenuPrimitive"],"sources":["../../src/components/menu.tsx"],"sourcesContent":["\"use client\"\n\nimport { Menu as MenuPrimitive } from \"@base-ui/react/menu\"\nimport type { ComponentProps } from \"react\"\nimport { Kbd } from \"~/components/kbd\"\nimport { controlTextClasses, eyebrowClasses, popoverAnimationClasses } from \"~/lib/classes\"\nimport { CheckIcon, CircleIcon } from \"~/lib/icons\"\nimport { cn } from \"~/lib/variants\"\n\nconst Menu = MenuPrimitive.Root\nconst MenuTrigger = MenuPrimitive.Trigger\nconst MenuGroup = MenuPrimitive.Group\nconst MenuRadioGroup = MenuPrimitive.RadioGroup\n\nfunction MenuContent({\n className,\n sideOffset = 4,\n align,\n side,\n ...props\n}: MenuPrimitive.Popup.Props &\n Pick<MenuPrimitive.Positioner.Props, \"align\" | \"side\" | \"sideOffset\">) {\n return (\n <MenuPrimitive.Portal>\n <MenuPrimitive.Positioner\n sideOffset={sideOffset}\n align={align}\n side={side}\n className=\"isolate z-50\"\n >\n <MenuPrimitive.Popup\n className={cn(\n \"min-w-40 flex flex-col rounded-md border bg-popover p-1 text-popover-foreground shadow-sm backdrop-blur-xs\",\n popoverAnimationClasses,\n className,\n )}\n {...props}\n />\n </MenuPrimitive.Positioner>\n </MenuPrimitive.Portal>\n )\n}\n\nfunction MenuItem({\n className,\n inset,\n ...props\n}: MenuPrimitive.Item.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.Item\n className={cn(\n `relative flex m-0 cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 pointer-coarse:min-h-10 ${controlTextClasses} outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0`,\n inset && \"pl-8\",\n className,\n )}\n {...props}\n />\n )\n}\n\nfunction MenuCheckboxItem({\n className,\n children,\n checked,\n ...props\n}: MenuPrimitive.CheckboxItem.Props) {\n return (\n <MenuPrimitive.CheckboxItem\n className={cn(\n `relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 pointer-coarse:min-h-10 ${controlTextClasses} outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50`,\n className,\n )}\n checked={checked}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <MenuPrimitive.CheckboxItemIndicator>\n <CheckIcon />\n </MenuPrimitive.CheckboxItemIndicator>\n </span>\n {children}\n </MenuPrimitive.CheckboxItem>\n )\n}\n\nfunction MenuRadioItem({ className, children, ...props }: MenuPrimitive.RadioItem.Props) {\n return (\n <MenuPrimitive.RadioItem\n className={cn(\n `relative flex cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 pointer-coarse:min-h-10 ${controlTextClasses} outline-hidden focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50`,\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <MenuPrimitive.RadioItemIndicator>\n <CircleIcon className=\"fill-current size-2\" />\n </MenuPrimitive.RadioItemIndicator>\n </span>\n {children}\n </MenuPrimitive.RadioItem>\n )\n}\n\nfunction MenuGroupLabel({\n className,\n inset,\n ...props\n}: MenuPrimitive.GroupLabel.Props & {\n inset?: boolean\n}) {\n return (\n <MenuPrimitive.GroupLabel\n className={cn(\"px-2 pt-1.5 pb-1\", eyebrowClasses, inset && \"pl-8\", className)}\n {...props}\n />\n )\n}\n\nfunction MenuSeparator({ className, ...props }: MenuPrimitive.Separator.Props) {\n return (\n <MenuPrimitive.Separator className={cn(\"-mx-1 my-1 h-px bg-border\", className)} {...props} />\n )\n}\n\nfunction MenuShortcut({ className, ...props }: ComponentProps<typeof Kbd>) {\n return <Kbd className={cn(\"ml-auto\", className)} {...props} />\n}\n\nexport {\n Menu,\n MenuCheckboxItem,\n MenuContent,\n MenuGroup,\n MenuItem,\n MenuGroupLabel,\n MenuRadioGroup,\n MenuRadioItem,\n MenuSeparator,\n MenuShortcut,\n MenuTrigger,\n}\n"],"mappings":";;;;;;;;AASA,MAAM,OAAOA,OAAc;AAC3B,MAAM,cAAcA,OAAc;AAClC,MAAM,YAAYA,OAAc;AAChC,MAAM,iBAAiBA,OAAc;AAErC,SAAS,YAAY,EACnB,WACA,aAAa,GACb,OACA,MACA,GAAG,SAEoE;CACvE,OACE,oBAACA,OAAc,QAAf,EAAA,UACE,oBAACA,OAAc,YAAf;EACc;EACL;EACD;EACN,WAAU;EAEV,UAAA,oBAACA,OAAc,OAAf;GACE,WAAW,GACT,8GACA,yBACA,SACF;GACA,GAAI;EACL,CAAA;CACuB,CAAA,EACN,CAAA;AAE1B;AAEA,SAAS,SAAS,EAChB,WACA,OACA,GAAG,SAGF;CACD,OACE,oBAACA,OAAc,MAAf;EACE,WAAW,GACT,kHAAkH,mBAAmB,0JACrI,SAAS,QACT,SACF;EACA,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,iBAAiB,EACxB,WACA,UACA,SACA,GAAG,SACgC;CACnC,OACE,qBAACA,OAAc,cAAf;EACE,WAAW,GACT,6GAA6G,mBAAmB,0HAChI,SACF;EACS;EACT,GAAI;EANN,UAAA,CAQE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACA,OAAc,uBAAf,EAAA,UACE,oBAAC,WAAD,CAAY,CAAA,EACuB,CAAA;EACjC,CAAA,GACL,QACyB;;AAEhC;AAEA,SAAS,cAAc,EAAE,WAAW,UAAU,GAAG,SAAwC;CACvF,OACE,qBAACA,OAAc,WAAf;EACE,WAAW,GACT,6GAA6G,mBAAmB,0HAChI,SACF;EACA,GAAI;EALN,UAAA,CAOE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACA,OAAc,oBAAf,EAAA,UACE,oBAAC,YAAD,EAAY,WAAU,sBAAuB,CAAA,EACb,CAAA;EAC9B,CAAA,GACL,QACsB;;AAE7B;AAEA,SAAS,eAAe,EACtB,WACA,OACA,GAAG,SAGF;CACD,OACE,oBAACA,OAAc,YAAf;EACE,WAAW,GAAG,oBAAoB,gBAAgB,SAAS,QAAQ,SAAS;EAC5E,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,cAAc,EAAE,WAAW,GAAG,SAAwC;CAC7E,OACE,oBAACA,OAAc,WAAf;EAAyB,WAAW,GAAG,6BAA6B,SAAS;EAAG,GAAI;CAAQ,CAAA;AAEhG;AAEA,SAAS,aAAa,EAAE,WAAW,GAAG,SAAqC;CACzE,OAAO,oBAAC,KAAD;EAAK,WAAW,GAAG,WAAW,SAAS;EAAG,GAAI;CAAQ,CAAA;AAC/D"}
@@ -41,7 +41,7 @@ const navAffixClasses = "[&>*:first-child]:ml-0 [&>*:last-child]:mr-0";
41
41
  const navItem = variants({
42
42
  base: "w-full justify-start gap-2.5 px-2.5",
43
43
  variants: { variant: {
44
- link: ["py-2 text-muted-foreground text-sm/tight hover:bg-foreground/3 hover:text-foreground [&>svg:first-child]:ml-0.5 [&>svg]:mr-0.5 [&>svg]:size-4 [&>svg]:shrink-0", "data-[status=active]:bg-foreground/5 data-[status=active]:text-foreground data-[status=active]:hover:bg-foreground/5"],
44
+ link: ["py-2 pointer-coarse:min-h-11 text-muted-foreground text-sm/tight hover:bg-foreground/3 hover:text-foreground [&>svg:first-child]:ml-0.5 [&>svg]:mr-0.5 [&>svg]:size-4 [&>svg]:shrink-0", "data-[status=active]:bg-foreground/5 data-[status=active]:text-foreground data-[status=active]:hover:bg-foreground/5"],
45
45
  bordered: [navAffixClasses, "border-border bg-card hover:bg-card hover:border-ring"],
46
46
  flat: navAffixClasses
47
47
  } },
@@ -1 +1 @@
1
- {"version":3,"file":"nav.js","names":[],"sources":["../../src/components/nav.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\"\nimport { eyebrowClasses } from \"~/lib/classes\"\nimport { cn, variants } from \"~/lib/variants\"\n\nexport function Nav({ className, ...props }: ComponentProps<\"nav\">) {\n return <nav className={cn(\"flex flex-col gap-0.5 px-3 py-2\", className)} {...props} />\n}\n\n/**\n * Muted group label above a run of nav links.\n */\nexport function NavLabel({ className, ...props }: ComponentProps<\"p\">) {\n return <p className={cn(\"px-2.5 pt-1 pb-1.5\", eyebrowClasses, className)} {...props} />\n}\n\n/**\n * The affixes of a nav row that leads with its own visual (an avatar, a skeleton) sit flush\n * against the row's inset, so the Button's optical pull-in is zeroed on both ends.\n */\nconst navAffixClasses = \"[&>*:first-child]:ml-0 [&>*:last-child]:mr-0\"\n\n/**\n * The one nav row, applied to a `ghost` `md` `Button`: every item starts from the same width,\n * inset and gap, and each variant is the shape on top of it.\n *\n * `link` — a nav link or a settings tab: muted at rest, full color on hover, and a flat darker\n * tint with dark text when active. The 16px icon sits centered in a 20px box, so labels start on\n * the same column as a row that leads with a 20px avatar (10px inset + 20px avatar + 10px gap).\n * The active state keys off `data-status=\"active\"`, which router links set on their own and plain\n * buttons set by hand, so the active color always wins over the resting one. Its tints are flat\n * foreground over the canvas, so hover and active share the canvas hue exactly.\n *\n * `bordered` — a bordered row on a card surface, for a row that leads with its own visual and\n * opens a menu.\n *\n * `flat` — the same row without the border or the surface.\n */\nexport const navItem = variants({\n base: \"w-full justify-start gap-2.5 px-2.5\",\n\n variants: {\n variant: {\n link: [\n \"py-2 text-muted-foreground text-sm/tight hover:bg-foreground/3 hover:text-foreground [&>svg:first-child]:ml-0.5 [&>svg]:mr-0.5 [&>svg]:size-4 [&>svg]:shrink-0\",\n \"data-[status=active]:bg-foreground/5 data-[status=active]:text-foreground data-[status=active]:hover:bg-foreground/5\",\n ],\n bordered: [navAffixClasses, \"border-border bg-card hover:bg-card hover:border-ring\"],\n flat: navAffixClasses,\n },\n },\n\n defaultVariants: {\n variant: \"link\",\n },\n})\n"],"mappings":";;;;AAIA,SAAgB,IAAI,EAAE,WAAW,GAAG,SAAgC;CAClE,OAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,mCAAmC,SAAS;EAAG,GAAI;CAAQ,CAAA;AACvF;;;;AAKA,SAAgB,SAAS,EAAE,WAAW,GAAG,SAA8B;CACrE,OAAO,oBAAC,KAAD;EAAG,WAAW,GAAG,sBAAsB,gBAAgB,SAAS;EAAG,GAAI;CAAQ,CAAA;AACxF;;;;;AAMA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;AAkBxB,MAAa,UAAU,SAAS;CAC9B,MAAM;CAEN,UAAU,EACR,SAAS;EACP,MAAM,CACJ,kKACA,sHACF;EACA,UAAU,CAAC,iBAAiB,uDAAuD;EACnF,MAAM;CACR,EACF;CAEA,iBAAiB,EACf,SAAS,OACX;AACF,CAAC"}
1
+ {"version":3,"file":"nav.js","names":[],"sources":["../../src/components/nav.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\"\nimport { eyebrowClasses } from \"~/lib/classes\"\nimport { cn, variants } from \"~/lib/variants\"\n\nexport function Nav({ className, ...props }: ComponentProps<\"nav\">) {\n return <nav className={cn(\"flex flex-col gap-0.5 px-3 py-2\", className)} {...props} />\n}\n\n/**\n * Muted group label above a run of nav links.\n */\nexport function NavLabel({ className, ...props }: ComponentProps<\"p\">) {\n return <p className={cn(\"px-2.5 pt-1 pb-1.5\", eyebrowClasses, className)} {...props} />\n}\n\n/**\n * The affixes of a nav row that leads with its own visual (an avatar, a skeleton) sit flush\n * against the row's inset, so the Button's optical pull-in is zeroed on both ends.\n */\nconst navAffixClasses = \"[&>*:first-child]:ml-0 [&>*:last-child]:mr-0\"\n\n/**\n * The one nav row, applied to a `ghost` `md` `Button`: every item starts from the same width,\n * inset and gap, and each variant is the shape on top of it.\n *\n * `link` — a nav link or a settings tab: muted at rest, full color on hover, and a flat darker\n * tint with dark text when active. The 16px icon sits centered in a 20px box, so labels start on\n * the same column as a row that leads with a 20px avatar (10px inset + 20px avatar + 10px gap).\n * The active state keys off `data-status=\"active\"`, which router links set on their own and plain\n * buttons set by hand, so the active color always wins over the resting one. Its tints are flat\n * foreground over the canvas, so hover and active share the canvas hue exactly.\n *\n * `bordered` — a bordered row on a card surface, for a row that leads with its own visual and\n * opens a menu.\n *\n * `flat` — the same row without the border or the surface.\n */\nexport const navItem = variants({\n base: \"w-full justify-start gap-2.5 px-2.5\",\n\n variants: {\n variant: {\n link: [\n \"py-2 pointer-coarse:min-h-11 text-muted-foreground text-sm/tight hover:bg-foreground/3 hover:text-foreground [&>svg:first-child]:ml-0.5 [&>svg]:mr-0.5 [&>svg]:size-4 [&>svg]:shrink-0\",\n \"data-[status=active]:bg-foreground/5 data-[status=active]:text-foreground data-[status=active]:hover:bg-foreground/5\",\n ],\n bordered: [navAffixClasses, \"border-border bg-card hover:bg-card hover:border-ring\"],\n flat: navAffixClasses,\n },\n },\n\n defaultVariants: {\n variant: \"link\",\n },\n})\n"],"mappings":";;;;AAIA,SAAgB,IAAI,EAAE,WAAW,GAAG,SAAgC;CAClE,OAAO,oBAAC,OAAD;EAAK,WAAW,GAAG,mCAAmC,SAAS;EAAG,GAAI;CAAQ,CAAA;AACvF;;;;AAKA,SAAgB,SAAS,EAAE,WAAW,GAAG,SAA8B;CACrE,OAAO,oBAAC,KAAD;EAAG,WAAW,GAAG,sBAAsB,gBAAgB,SAAS;EAAG,GAAI;CAAQ,CAAA;AACxF;;;;;AAMA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;AAkBxB,MAAa,UAAU,SAAS;CAC9B,MAAM;CAEN,UAAU,EACR,SAAS;EACP,MAAM,CACJ,0LACA,sHACF;EACA,UAAU,CAAC,iBAAiB,uDAAuD;EACnF,MAAM;CACR,EACF;CAEA,iBAAiB,EACf,SAAS,OACX;AACF,CAAC"}
@@ -10,8 +10,8 @@ declare const sectionHeaderVariants: import("tailwind-variants").TVReturnType<{
10
10
  center: "justify-center text-center";
11
11
  };
12
12
  size: {
13
- page: "gap-y-3 gap-x-6 lg:gap-x-12";
14
- card: "gap-y-2 gap-x-6";
13
+ page: "gap-y-3 gap-x-6 max-sm:flex-col max-sm:items-stretch lg:gap-x-12";
14
+ card: "gap-y-2 gap-x-6 max-sm:flex-col max-sm:items-stretch";
15
15
  panel: "gap-y-2 gap-x-6";
16
16
  hero: "gap-y-3 gap-x-6 lg:gap-x-12";
17
17
  };
@@ -25,8 +25,8 @@ declare const sectionHeaderVariants: import("tailwind-variants").TVReturnType<{
25
25
  center: "justify-center text-center";
26
26
  };
27
27
  size: {
28
- page: "gap-y-3 gap-x-6 lg:gap-x-12";
29
- card: "gap-y-2 gap-x-6";
28
+ page: "gap-y-3 gap-x-6 max-sm:flex-col max-sm:items-stretch lg:gap-x-12";
29
+ card: "gap-y-2 gap-x-6 max-sm:flex-col max-sm:items-stretch";
30
30
  panel: "gap-y-2 gap-x-6";
31
31
  hero: "gap-y-3 gap-x-6 lg:gap-x-12";
32
32
  };
@@ -40,8 +40,8 @@ declare const sectionHeaderVariants: import("tailwind-variants").TVReturnType<{
40
40
  center: "justify-center text-center";
41
41
  };
42
42
  size: {
43
- page: "gap-y-3 gap-x-6 lg:gap-x-12";
44
- card: "gap-y-2 gap-x-6";
43
+ page: "gap-y-3 gap-x-6 max-sm:flex-col max-sm:items-stretch lg:gap-x-12";
44
+ card: "gap-y-2 gap-x-6 max-sm:flex-col max-sm:items-stretch";
45
45
  panel: "gap-y-2 gap-x-6";
46
46
  hero: "gap-y-3 gap-x-6 lg:gap-x-12";
47
47
  };
@@ -1,7 +1,7 @@
1
1
  import { cn, variants } from "../lib/variants.js";
2
+ import { descriptionClasses } from "../lib/classes.js";
2
3
  import { Stack } from "./stack.js";
3
4
  import { Heading } from "./heading.js";
4
- import { descriptionClasses } from "../lib/classes.js";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useRender } from "@base-ui/react/use-render";
7
7
  import { createContext, use } from "react";
@@ -14,8 +14,8 @@ const sectionHeaderVariants = variants({
14
14
  center: "justify-center text-center"
15
15
  },
16
16
  size: {
17
- page: "gap-y-3 gap-x-6 lg:gap-x-12",
18
- card: "gap-y-2 gap-x-6",
17
+ page: "gap-y-3 gap-x-6 max-sm:flex-col max-sm:items-stretch lg:gap-x-12",
18
+ card: "gap-y-2 gap-x-6 max-sm:flex-col max-sm:items-stretch",
19
19
  panel: "gap-y-2 gap-x-6",
20
20
  hero: "gap-y-3 gap-x-6 lg:gap-x-12"
21
21
  },
@@ -135,9 +135,9 @@ function SectionHeaderDescription({ className, ...props }) {
135
135
  * truncates instead of squeezing the buttons.
136
136
  */
137
137
  function SectionHeaderActions({ className, ...props }) {
138
- const { wrap } = use(SectionHeaderContext);
138
+ const { size, wrap } = use(SectionHeaderContext);
139
139
  return /* @__PURE__ */ jsx(Stack, {
140
- className: cn("-my-0.5", !wrap && "shrink-0", className),
140
+ className: cn("-my-0.5", !wrap && "shrink-0", size === "page" && "max-sm:flex-row-reverse max-sm:justify-end", className),
141
141
  ...props
142
142
  });
143
143
  }
@@ -1 +1 @@
1
- {"version":3,"file":"section-header.js","names":[],"sources":["../../src/components/section-header.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\"\nimport { type ComponentProps, createContext, type ReactNode, use } from \"react\"\nimport { Heading, type HeadingProps } from \"~/components/heading\"\nimport { Stack } from \"~/components/stack\"\nimport { descriptionClasses } from \"~/lib/classes\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst sectionHeaderVariants = variants({\n base: \"flex items-center w-full min-w-0\",\n\n variants: {\n alignment: {\n left: \"justify-between text-start\",\n center: \"justify-center text-center\",\n },\n size: {\n page: \"gap-y-3 gap-x-6 lg:gap-x-12\",\n card: \"gap-y-2 gap-x-6\",\n panel: \"gap-y-2 gap-x-6\",\n hero: \"gap-y-3 gap-x-6 lg:gap-x-12\",\n },\n wrap: {\n true: \"flex-wrap\",\n false: \"flex-nowrap\",\n },\n },\n\n defaultVariants: {\n alignment: \"left\",\n wrap: true,\n },\n})\n\ntype SectionHeaderSize = NonNullable<VariantProps<typeof sectionHeaderVariants>[\"size\"]>\n\n/**\n * The title each header scale gets, alongside the spacing the variant above gives it: `page`\n * for a route heading, `card` for a standalone card, `panel` for a dashboard or list panel,\n * `hero` for the centered auth and callback screens. The `as` entry keeps the heading outline\n * intact — one `<h1>` per route, `<h2>` for everything nested inside it.\n */\nconst sectionHeaderTitles = {\n page: { size: \"h3\", as: \"h1\" },\n card: { size: \"h4\", as: \"h2\" },\n panel: { size: \"h5\", as: \"h2\" },\n hero: { size: \"h2\", as: \"h1\" },\n} as const satisfies Record<SectionHeaderSize, { size: HeadingProps[\"size\"]; as: string }>\n\nconst SectionHeaderContext = createContext<{ size: SectionHeaderSize; wrap: boolean }>({\n size: \"page\",\n wrap: true,\n})\n\ntype SectionHeaderProps = Omit<useRender.ComponentProps<\"div\">, \"title\"> &\n Omit<VariantProps<typeof sectionHeaderVariants>, \"wrap\"> & {\n /**\n * Keep the title block and the actions on one line instead of wrapping them.\n */\n wrap?: boolean\n /**\n * Title block. Given any of `title`/`description`/`leading`/`actions`, the header renders\n * its own `SectionHeaderBody` (empty if there is nothing but actions, so they still sit right);\n * leave them all out to compose the body by hand, e.g. an entity header with dot-joined\n * meta or the dashboard greeting.\n */\n title?: ReactNode\n description?: ReactNode\n actions?: ReactNode\n /**\n * Leading visual beside the title, e.g. an entity avatar.\n */\n leading?: ReactNode\n }\n\n/**\n * The one header for every surface in the app: pages, cards, list panels, dialogs and settings\n * sections. Pass `title`/`description`/`actions` for the standard block, or compose\n * `SectionHeaderBody` + `SectionHeaderActions` as children when the content is bespoke.\n */\nfunction SectionHeader({\n className,\n alignment = \"left\",\n size = \"page\",\n wrap = true,\n title,\n description,\n actions,\n leading,\n children,\n render,\n ...props\n}: SectionHeaderProps) {\n const element = useRender({\n render,\n defaultTagName: \"div\",\n props: {\n className: cn(sectionHeaderVariants({ alignment, size, wrap, className })),\n children: (\n <>\n {(title || description || leading || actions) && (\n <SectionHeaderBody\n leading={leading}\n className={cn(alignment === \"center\" && \"justify-center\")}\n >\n {title && <SectionHeaderTitle>{title}</SectionHeaderTitle>}\n {description && <SectionHeaderDescription>{description}</SectionHeaderDescription>}\n </SectionHeaderBody>\n )}\n\n {actions && <SectionHeaderActions>{actions}</SectionHeaderActions>}\n\n {children}\n </>\n ),\n ...props,\n },\n })\n\n return <SectionHeaderContext value={{ size, wrap }}>{element}</SectionHeaderContext>\n}\n\n/**\n * The page title. Its visual size and semantic level both follow the header's `size`, so a\n * page heading stays the route's single `<h1>` while cards and panels render `<h2>`s. Pass\n * `size`/`as` to override either one on its own.\n */\nfunction SectionHeaderTitle({ size, as, ...props }: HeadingProps) {\n const preset = sectionHeaderTitles[use(SectionHeaderContext).size]\n\n return <Heading size={size ?? preset.size} as={as ?? preset.as} {...props} />\n}\n\ntype SectionHeaderBodyProps = ComponentProps<\"div\"> & {\n /**\n * Leading visual, e.g. an entity avatar.\n */\n leading?: ReactNode\n}\n\n/**\n * The one title block for every header in the app (pages, cards, dialogs, settings sections):\n * an optional leading visual beside a column of `SectionHeaderTitle` + `SectionHeaderDescription`. Change the\n * spacing here and it changes everywhere.\n */\nfunction SectionHeaderBody({ leading, children, className, ...props }: SectionHeaderBodyProps) {\n return (\n <div className={cn(\"flex min-w-0 flex-1 items-center gap-3\", className)} {...props}>\n {leading}\n <div className=\"flex min-w-0 flex-col gap-1.5\">{children}</div>\n </div>\n )\n}\n\n/**\n * The muted line under a title. Wraps by default; pass `truncate` for one-line entity meta.\n */\nfunction SectionHeaderDescription({ className, ...props }: ComponentProps<\"p\">) {\n return <p className={cn(descriptionClasses, className)} {...props} />\n}\n\n/**\n * Right-aligned actions. Stops shrinking when the header is `wrap={false}`, so a long title\n * truncates instead of squeezing the buttons.\n */\nfunction SectionHeaderActions({ className, ...props }: ComponentProps<typeof Stack>) {\n const { wrap } = use(SectionHeaderContext)\n\n return <Stack className={cn(\"-my-0.5\", !wrap && \"shrink-0\", className)} {...props} />\n}\n\nexport {\n SectionHeader,\n SectionHeaderTitle,\n SectionHeaderBody,\n SectionHeaderDescription,\n SectionHeaderActions,\n}\n"],"mappings":";;;;;;;;AAOA,MAAM,wBAAwB,SAAS;CACrC,MAAM;CAEN,UAAU;EACR,WAAW;GACT,MAAM;GACN,QAAQ;EACV;EACA,MAAM;GACJ,MAAM;GACN,MAAM;GACN,OAAO;GACP,MAAM;EACR;EACA,MAAM;GACJ,MAAM;GACN,OAAO;EACT;CACF;CAEA,iBAAiB;EACf,WAAW;EACX,MAAM;CACR;AACF,CAAC;;;;;;;AAUD,MAAM,sBAAsB;CAC1B,MAAM;EAAE,MAAM;EAAM,IAAI;CAAK;CAC7B,MAAM;EAAE,MAAM;EAAM,IAAI;CAAK;CAC7B,OAAO;EAAE,MAAM;EAAM,IAAI;CAAK;CAC9B,MAAM;EAAE,MAAM;EAAM,IAAI;CAAK;AAC/B;AAEA,MAAM,uBAAuB,cAA0D;CACrF,MAAM;CACN,MAAM;AACR,CAAC;;;;;;AA4BD,SAAS,cAAc,EACrB,WACA,YAAY,QACZ,OAAO,QACP,OAAO,MACP,OACA,aACA,SACA,SACA,UACA,QACA,GAAG,SACkB;CACrB,MAAM,UAAU,UAAU;EACxB;EACA,gBAAgB;EAChB,OAAO;GACL,WAAW,GAAG,sBAAsB;IAAE;IAAW;IAAM;IAAM;GAAU,CAAC,CAAC;GACzE,UACE,qBAAA,UAAA,EAAA,UAAA;KACI,SAAS,eAAe,WAAW,YACnC,qBAAC,mBAAD;KACW;KACT,WAAW,GAAG,cAAc,YAAY,gBAAgB;KAF1D,UAAA,CAIG,SAAS,oBAAC,oBAAD,EAAA,UAAqB,MAA0B,CAAA,GACxD,eAAe,oBAAC,0BAAD,EAAA,UAA2B,YAAsC,CAAA,CAChE;;IAGpB,WAAW,oBAAC,sBAAD,EAAA,UAAuB,QAA8B,CAAA;IAEhE;GACD,EAAA,CAAA;GAEJ,GAAG;EACL;CACF,CAAC;CAED,OAAO,oBAAC,sBAAD;EAAsB,OAAO;GAAE;GAAM;EAAK;EAAI,UAAA;CAA8B,CAAA;AACrF;;;;;;AAOA,SAAS,mBAAmB,EAAE,MAAM,IAAI,GAAG,SAAuB;CAChE,MAAM,SAAS,oBAAoB,IAAI,oBAAoB,CAAC,CAAC;CAE7D,OAAO,oBAAC,SAAD;EAAS,MAAM,QAAQ,OAAO;EAAM,IAAI,MAAM,OAAO;EAAI,GAAI;CAAQ,CAAA;AAC9E;;;;;;AAcA,SAAS,kBAAkB,EAAE,SAAS,UAAU,WAAW,GAAG,SAAiC;CAC7F,OACE,qBAAC,OAAD;EAAK,WAAW,GAAG,0CAA0C,SAAS;EAAG,GAAI;EAA7E,UAAA,CACG,SACD,oBAAC,OAAD;GAAK,WAAU;GAAiC;EAAc,CAAA,CAC3D;;AAET;;;;AAKA,SAAS,yBAAyB,EAAE,WAAW,GAAG,SAA8B;CAC9E,OAAO,oBAAC,KAAD;EAAG,WAAW,GAAG,oBAAoB,SAAS;EAAG,GAAI;CAAQ,CAAA;AACtE;;;;;AAMA,SAAS,qBAAqB,EAAE,WAAW,GAAG,SAAuC;CACnF,MAAM,EAAE,SAAS,IAAI,oBAAoB;CAEzC,OAAO,oBAAC,OAAD;EAAO,WAAW,GAAG,WAAW,CAAC,QAAQ,YAAY,SAAS;EAAG,GAAI;CAAQ,CAAA;AACtF"}
1
+ {"version":3,"file":"section-header.js","names":[],"sources":["../../src/components/section-header.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\"\nimport { type ComponentProps, createContext, type ReactNode, use } from \"react\"\nimport { Heading, type HeadingProps } from \"~/components/heading\"\nimport { Stack } from \"~/components/stack\"\nimport { descriptionClasses } from \"~/lib/classes\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst sectionHeaderVariants = variants({\n base: \"flex items-center w-full min-w-0\",\n\n variants: {\n alignment: {\n left: \"justify-between text-start\",\n center: \"justify-center text-center\",\n },\n size: {\n page: \"gap-y-3 gap-x-6 max-sm:flex-col max-sm:items-stretch lg:gap-x-12\",\n card: \"gap-y-2 gap-x-6 max-sm:flex-col max-sm:items-stretch\",\n panel: \"gap-y-2 gap-x-6\",\n hero: \"gap-y-3 gap-x-6 lg:gap-x-12\",\n },\n wrap: {\n true: \"flex-wrap\",\n false: \"flex-nowrap\",\n },\n },\n\n defaultVariants: {\n alignment: \"left\",\n wrap: true,\n },\n})\n\ntype SectionHeaderSize = NonNullable<VariantProps<typeof sectionHeaderVariants>[\"size\"]>\n\n/**\n * The title each header scale gets, alongside the spacing the variant above gives it: `page`\n * for a route heading, `card` for a standalone card, `panel` for a dashboard or list panel,\n * `hero` for the centered auth and callback screens. The `as` entry keeps the heading outline\n * intact — one `<h1>` per route, `<h2>` for everything nested inside it.\n */\nconst sectionHeaderTitles = {\n page: { size: \"h3\", as: \"h1\" },\n card: { size: \"h4\", as: \"h2\" },\n panel: { size: \"h5\", as: \"h2\" },\n hero: { size: \"h2\", as: \"h1\" },\n} as const satisfies Record<SectionHeaderSize, { size: HeadingProps[\"size\"]; as: string }>\n\nconst SectionHeaderContext = createContext<{ size: SectionHeaderSize; wrap: boolean }>({\n size: \"page\",\n wrap: true,\n})\n\ntype SectionHeaderProps = Omit<useRender.ComponentProps<\"div\">, \"title\"> &\n Omit<VariantProps<typeof sectionHeaderVariants>, \"wrap\"> & {\n /**\n * Keep the title block and the actions on one line instead of wrapping them.\n */\n wrap?: boolean\n /**\n * Title block. Given any of `title`/`description`/`leading`/`actions`, the header renders\n * its own `SectionHeaderBody` (empty if there is nothing but actions, so they still sit right);\n * leave them all out to compose the body by hand, e.g. an entity header with dot-joined\n * meta or the dashboard greeting.\n */\n title?: ReactNode\n description?: ReactNode\n actions?: ReactNode\n /**\n * Leading visual beside the title, e.g. an entity avatar.\n */\n leading?: ReactNode\n }\n\n/**\n * The one header for every surface in the app: pages, cards, list panels, dialogs and settings\n * sections. Pass `title`/`description`/`actions` for the standard block, or compose\n * `SectionHeaderBody` + `SectionHeaderActions` as children when the content is bespoke.\n */\nfunction SectionHeader({\n className,\n alignment = \"left\",\n size = \"page\",\n wrap = true,\n title,\n description,\n actions,\n leading,\n children,\n render,\n ...props\n}: SectionHeaderProps) {\n const element = useRender({\n render,\n defaultTagName: \"div\",\n props: {\n className: cn(sectionHeaderVariants({ alignment, size, wrap, className })),\n children: (\n <>\n {(title || description || leading || actions) && (\n <SectionHeaderBody\n leading={leading}\n className={cn(alignment === \"center\" && \"justify-center\")}\n >\n {title && <SectionHeaderTitle>{title}</SectionHeaderTitle>}\n {description && <SectionHeaderDescription>{description}</SectionHeaderDescription>}\n </SectionHeaderBody>\n )}\n\n {actions && <SectionHeaderActions>{actions}</SectionHeaderActions>}\n\n {children}\n </>\n ),\n ...props,\n },\n })\n\n return <SectionHeaderContext value={{ size, wrap }}>{element}</SectionHeaderContext>\n}\n\n/**\n * The page title. Its visual size and semantic level both follow the header's `size`, so a\n * page heading stays the route's single `<h1>` while cards and panels render `<h2>`s. Pass\n * `size`/`as` to override either one on its own.\n */\nfunction SectionHeaderTitle({ size, as, ...props }: HeadingProps) {\n const preset = sectionHeaderTitles[use(SectionHeaderContext).size]\n\n return <Heading size={size ?? preset.size} as={as ?? preset.as} {...props} />\n}\n\ntype SectionHeaderBodyProps = ComponentProps<\"div\"> & {\n /**\n * Leading visual, e.g. an entity avatar.\n */\n leading?: ReactNode\n}\n\n/**\n * The one title block for every header in the app (pages, cards, dialogs, settings sections):\n * an optional leading visual beside a column of `SectionHeaderTitle` + `SectionHeaderDescription`. Change the\n * spacing here and it changes everywhere.\n */\nfunction SectionHeaderBody({ leading, children, className, ...props }: SectionHeaderBodyProps) {\n return (\n <div className={cn(\"flex min-w-0 flex-1 items-center gap-3\", className)} {...props}>\n {leading}\n <div className=\"flex min-w-0 flex-col gap-1.5\">{children}</div>\n </div>\n )\n}\n\n/**\n * The muted line under a title. Wraps by default; pass `truncate` for one-line entity meta.\n */\nfunction SectionHeaderDescription({ className, ...props }: ComponentProps<\"p\">) {\n return <p className={cn(descriptionClasses, className)} {...props} />\n}\n\n/**\n * Right-aligned actions. Stops shrinking when the header is `wrap={false}`, so a long title\n * truncates instead of squeezing the buttons.\n */\nfunction SectionHeaderActions({ className, ...props }: ComponentProps<typeof Stack>) {\n const { size, wrap } = use(SectionHeaderContext)\n\n return (\n <Stack\n className={cn(\n \"-my-0.5\",\n !wrap && \"shrink-0\",\n // Stacked under a page title, the trailing (primary) action leads the row.\n size === \"page\" && \"max-sm:flex-row-reverse max-sm:justify-end\",\n className,\n )}\n {...props}\n />\n )\n}\n\nexport {\n SectionHeader,\n SectionHeaderTitle,\n SectionHeaderBody,\n SectionHeaderDescription,\n SectionHeaderActions,\n}\n"],"mappings":";;;;;;;;AAOA,MAAM,wBAAwB,SAAS;CACrC,MAAM;CAEN,UAAU;EACR,WAAW;GACT,MAAM;GACN,QAAQ;EACV;EACA,MAAM;GACJ,MAAM;GACN,MAAM;GACN,OAAO;GACP,MAAM;EACR;EACA,MAAM;GACJ,MAAM;GACN,OAAO;EACT;CACF;CAEA,iBAAiB;EACf,WAAW;EACX,MAAM;CACR;AACF,CAAC;;;;;;;AAUD,MAAM,sBAAsB;CAC1B,MAAM;EAAE,MAAM;EAAM,IAAI;CAAK;CAC7B,MAAM;EAAE,MAAM;EAAM,IAAI;CAAK;CAC7B,OAAO;EAAE,MAAM;EAAM,IAAI;CAAK;CAC9B,MAAM;EAAE,MAAM;EAAM,IAAI;CAAK;AAC/B;AAEA,MAAM,uBAAuB,cAA0D;CACrF,MAAM;CACN,MAAM;AACR,CAAC;;;;;;AA4BD,SAAS,cAAc,EACrB,WACA,YAAY,QACZ,OAAO,QACP,OAAO,MACP,OACA,aACA,SACA,SACA,UACA,QACA,GAAG,SACkB;CACrB,MAAM,UAAU,UAAU;EACxB;EACA,gBAAgB;EAChB,OAAO;GACL,WAAW,GAAG,sBAAsB;IAAE;IAAW;IAAM;IAAM;GAAU,CAAC,CAAC;GACzE,UACE,qBAAA,UAAA,EAAA,UAAA;KACI,SAAS,eAAe,WAAW,YACnC,qBAAC,mBAAD;KACW;KACT,WAAW,GAAG,cAAc,YAAY,gBAAgB;KAF1D,UAAA,CAIG,SAAS,oBAAC,oBAAD,EAAA,UAAqB,MAA0B,CAAA,GACxD,eAAe,oBAAC,0BAAD,EAAA,UAA2B,YAAsC,CAAA,CAChE;;IAGpB,WAAW,oBAAC,sBAAD,EAAA,UAAuB,QAA8B,CAAA;IAEhE;GACD,EAAA,CAAA;GAEJ,GAAG;EACL;CACF,CAAC;CAED,OAAO,oBAAC,sBAAD;EAAsB,OAAO;GAAE;GAAM;EAAK;EAAI,UAAA;CAA8B,CAAA;AACrF;;;;;;AAOA,SAAS,mBAAmB,EAAE,MAAM,IAAI,GAAG,SAAuB;CAChE,MAAM,SAAS,oBAAoB,IAAI,oBAAoB,CAAC,CAAC;CAE7D,OAAO,oBAAC,SAAD;EAAS,MAAM,QAAQ,OAAO;EAAM,IAAI,MAAM,OAAO;EAAI,GAAI;CAAQ,CAAA;AAC9E;;;;;;AAcA,SAAS,kBAAkB,EAAE,SAAS,UAAU,WAAW,GAAG,SAAiC;CAC7F,OACE,qBAAC,OAAD;EAAK,WAAW,GAAG,0CAA0C,SAAS;EAAG,GAAI;EAA7E,UAAA,CACG,SACD,oBAAC,OAAD;GAAK,WAAU;GAAiC;EAAc,CAAA,CAC3D;;AAET;;;;AAKA,SAAS,yBAAyB,EAAE,WAAW,GAAG,SAA8B;CAC9E,OAAO,oBAAC,KAAD;EAAG,WAAW,GAAG,oBAAoB,SAAS;EAAG,GAAI;CAAQ,CAAA;AACtE;;;;;AAMA,SAAS,qBAAqB,EAAE,WAAW,GAAG,SAAuC;CACnF,MAAM,EAAE,MAAM,SAAS,IAAI,oBAAoB;CAE/C,OACE,oBAAC,OAAD;EACE,WAAW,GACT,WACA,CAAC,QAAQ,YAET,SAAS,UAAU,8CACnB,SACF;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { cn, variants } from "../lib/variants.js";
3
+ import { controlTextClasses, popoverAnimationClasses } from "../lib/classes.js";
3
4
  import { CheckIcon, ChevronDownIcon, ChevronUpIcon, ChevronsUpDownIcon } from "../lib/icons.js";
4
- import { popoverAnimationClasses } from "../lib/classes.js";
5
5
  import { inputVariants } from "./input.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { Select as Select$1 } from "@base-ui/react/select";
@@ -74,7 +74,7 @@ function SelectLabel({ className, ...props }) {
74
74
  function SelectItem({ className, children, label, ...props }) {
75
75
  return /* @__PURE__ */ jsxs(Select$1.Item, {
76
76
  label: label ?? (typeof children === "string" ? children : void 0),
77
- className: cn("relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-control text-secondary-foreground outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50", className),
77
+ className: cn(`relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 pointer-coarse:min-h-10 ${controlTextClasses} text-secondary-foreground outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50`, className),
78
78
  ...props,
79
79
  children: [/* @__PURE__ */ jsx("span", {
80
80
  className: "absolute left-2 flex size-3.5 items-center justify-center",
@@ -1 +1 @@
1
- {"version":3,"file":"select.js","names":["SelectPrimitive"],"sources":["../../src/components/select.tsx"],"sourcesContent":["\"use client\"\n\nimport { Select as SelectPrimitive } from \"@base-ui/react/select\"\nimport { inputVariants } from \"~/components/input\"\nimport { popoverAnimationClasses } from \"~/lib/classes\"\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon, ChevronsUpDownIcon } from \"~/lib/icons\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst Select = SelectPrimitive.Root\nconst SelectGroup = SelectPrimitive.Group\nconst SelectValue = SelectPrimitive.Value\n\nfunction SelectTrigger({\n children,\n className,\n hover = true,\n focus = true,\n size,\n ...props\n}: SelectPrimitive.Trigger.Props & VariantProps<typeof inputVariants>) {\n return (\n <SelectPrimitive.Trigger\n className={cn(\n inputVariants({ hover, focus, size }),\n \"flex items-center justify-between\",\n className,\n )}\n {...props}\n >\n <span className=\"truncate\">{children}</span>\n\n <SelectPrimitive.Icon\n render={<ChevronsUpDownIcon className=\"ml-1 size-4 shrink-0 opacity-50\" />}\n />\n </SelectPrimitive.Trigger>\n )\n}\n\nfunction SelectScrollUpButton({ className, ...props }: SelectPrimitive.ScrollUpArrow.Props) {\n return (\n <SelectPrimitive.ScrollUpArrow\n className={cn(\"flex cursor-pointer items-center justify-center py-1\", className)}\n {...props}\n >\n <ChevronUpIcon />\n </SelectPrimitive.ScrollUpArrow>\n )\n}\n\nfunction SelectScrollDownButton({ className, ...props }: SelectPrimitive.ScrollDownArrow.Props) {\n return (\n <SelectPrimitive.ScrollDownArrow\n className={cn(\"flex cursor-pointer items-center justify-center py-1\", className)}\n {...props}\n >\n <ChevronDownIcon />\n </SelectPrimitive.ScrollDownArrow>\n )\n}\n\nconst selectScrollButtonVariants = variants({\n base: \"absolute inset-x-0 z-10 bg-background animate-in fade-in-0 duration-300\",\n variants: {\n position: {\n top: \"top-0 mask-b-from-0\",\n bottom: \"bottom-0 mask-t-from-0\",\n },\n },\n})\n\nfunction SelectContent({\n className,\n children,\n align,\n side,\n sideOffset = 4,\n alignItemWithTrigger = false,\n ...props\n}: SelectPrimitive.Popup.Props &\n Pick<\n SelectPrimitive.Positioner.Props,\n \"align\" | \"side\" | \"sideOffset\" | \"alignItemWithTrigger\"\n >) {\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Positioner\n sideOffset={sideOffset}\n align={align}\n side={side}\n alignItemWithTrigger={alignItemWithTrigger}\n className=\"isolate z-50\"\n >\n <SelectPrimitive.Popup\n className={cn(\n \"relative z-50 isolate max-h-(--available-height) min-w-(--anchor-width) overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md backdrop-blur-xs\",\n !alignItemWithTrigger && popoverAnimationClasses,\n className,\n )}\n {...props}\n >\n <SelectScrollUpButton className={selectScrollButtonVariants({ position: \"top\" })} />\n <SelectPrimitive.List className=\"p-1\">{children}</SelectPrimitive.List>\n <SelectScrollDownButton className={selectScrollButtonVariants({ position: \"bottom\" })} />\n </SelectPrimitive.Popup>\n </SelectPrimitive.Positioner>\n </SelectPrimitive.Portal>\n )\n}\n\nfunction SelectLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props) {\n return (\n <SelectPrimitive.GroupLabel\n className={cn(\"px-2 py-1.5 text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction SelectItem({ className, children, label, ...props }: SelectPrimitive.Item.Props) {\n return (\n <SelectPrimitive.Item\n label={label ?? (typeof children === \"string\" ? children : undefined)}\n className={cn(\n \"relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-control text-secondary-foreground outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n )\n}\n\nfunction SelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) {\n return (\n <SelectPrimitive.Separator className={cn(\"-mx-1 my-1 h-px bg-border\", className)} {...props} />\n )\n}\n\nexport {\n Select,\n SelectGroup,\n SelectValue,\n SelectTrigger,\n SelectContent,\n SelectLabel,\n SelectItem,\n SelectSeparator,\n SelectScrollUpButton,\n SelectScrollDownButton,\n}\n"],"mappings":";;;;;;;;AAQA,MAAM,SAASA,SAAgB;AAC/B,MAAM,cAAcA,SAAgB;AACpC,MAAM,cAAcA,SAAgB;AAEpC,SAAS,cAAc,EACrB,UACA,WACA,QAAQ,MACR,QAAQ,MACR,MACA,GAAG,SACkE;CACrE,OACE,qBAACA,SAAgB,SAAjB;EACE,WAAW,GACT,cAAc;GAAE;GAAO;GAAO;EAAK,CAAC,GACpC,qCACA,SACF;EACA,GAAI;EANN,UAAA,CAQE,oBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA,GAE3C,oBAACA,SAAgB,MAAjB,EACE,QAAQ,oBAAC,oBAAD,EAAoB,WAAU,kCAAmC,CAAA,EAC1E,CAAA,CACsB;;AAE7B;AAEA,SAAS,qBAAqB,EAAE,WAAW,GAAG,SAA8C;CAC1F,OACE,oBAACA,SAAgB,eAAjB;EACE,WAAW,GAAG,wDAAwD,SAAS;EAC/E,GAAI;EAEJ,UAAA,oBAAC,eAAD,CAAgB,CAAA;CACa,CAAA;AAEnC;AAEA,SAAS,uBAAuB,EAAE,WAAW,GAAG,SAAgD;CAC9F,OACE,oBAACA,SAAgB,iBAAjB;EACE,WAAW,GAAG,wDAAwD,SAAS;EAC/E,GAAI;EAEJ,UAAA,oBAAC,iBAAD,CAAkB,CAAA;CACa,CAAA;AAErC;AAEA,MAAM,6BAA6B,SAAS;CAC1C,MAAM;CACN,UAAU,EACR,UAAU;EACR,KAAK;EACL,QAAQ;CACV,EACF;AACF,CAAC;AAED,SAAS,cAAc,EACrB,WACA,UACA,OACA,MACA,aAAa,GACb,uBAAuB,OACvB,GAAG,SAKA;CACH,OACE,oBAACA,SAAgB,QAAjB,EAAA,UACE,oBAACA,SAAgB,YAAjB;EACc;EACL;EACD;EACgB;EACtB,WAAU;EAEV,UAAA,qBAACA,SAAgB,OAAjB;GACE,WAAW,GACT,2KACA,CAAC,wBAAwB,yBACzB,SACF;GACA,GAAI;GANN,UAAA;IAQE,oBAAC,sBAAD,EAAsB,WAAW,2BAA2B,EAAE,UAAU,MAAM,CAAC,EAAI,CAAA;IACnF,oBAACA,SAAgB,MAAjB;KAAsB,WAAU;KAAO;IAA+B,CAAA;IACtE,oBAAC,wBAAD,EAAwB,WAAW,2BAA2B,EAAE,UAAU,SAAS,CAAC,EAAI,CAAA;GACnE;;CACG,CAAA,EACN,CAAA;AAE5B;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2C;CAC9E,OACE,oBAACA,SAAgB,YAAjB;EACE,WAAW,GAAG,mCAAmC,SAAS;EAC1D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAAE,WAAW,UAAU,OAAO,GAAG,SAAqC;CACxF,OACE,qBAACA,SAAgB,MAAjB;EACE,OAAO,UAAU,OAAO,aAAa,WAAW,WAAW,KAAA;EAC3D,WAAW,GACT,wPACA,SACF;EACA,GAAI;EANN,UAAA,CAQE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACA,SAAgB,eAAjB,EAAA,UACE,oBAAC,WAAD,EAAW,WAAU,SAAU,CAAA,EACF,CAAA;EAC3B,CAAA,GACN,oBAACA,SAAgB,UAAjB,EAA2B,SAAmC,CAAA,CAC1C;;AAE1B;AAEA,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAA0C;CACjF,OACE,oBAACA,SAAgB,WAAjB;EAA2B,WAAW,GAAG,6BAA6B,SAAS;EAAG,GAAI;CAAQ,CAAA;AAElG"}
1
+ {"version":3,"file":"select.js","names":["SelectPrimitive"],"sources":["../../src/components/select.tsx"],"sourcesContent":["\"use client\"\n\nimport { Select as SelectPrimitive } from \"@base-ui/react/select\"\nimport { inputVariants } from \"~/components/input\"\nimport { controlTextClasses, popoverAnimationClasses } from \"~/lib/classes\"\nimport { CheckIcon, ChevronDownIcon, ChevronUpIcon, ChevronsUpDownIcon } from \"~/lib/icons\"\nimport { variants, cn, type VariantProps } from \"~/lib/variants\"\n\nconst Select = SelectPrimitive.Root\nconst SelectGroup = SelectPrimitive.Group\nconst SelectValue = SelectPrimitive.Value\n\nfunction SelectTrigger({\n children,\n className,\n hover = true,\n focus = true,\n size,\n ...props\n}: SelectPrimitive.Trigger.Props & VariantProps<typeof inputVariants>) {\n return (\n <SelectPrimitive.Trigger\n className={cn(\n inputVariants({ hover, focus, size }),\n \"flex items-center justify-between\",\n className,\n )}\n {...props}\n >\n <span className=\"truncate\">{children}</span>\n\n <SelectPrimitive.Icon\n render={<ChevronsUpDownIcon className=\"ml-1 size-4 shrink-0 opacity-50\" />}\n />\n </SelectPrimitive.Trigger>\n )\n}\n\nfunction SelectScrollUpButton({ className, ...props }: SelectPrimitive.ScrollUpArrow.Props) {\n return (\n <SelectPrimitive.ScrollUpArrow\n className={cn(\"flex cursor-pointer items-center justify-center py-1\", className)}\n {...props}\n >\n <ChevronUpIcon />\n </SelectPrimitive.ScrollUpArrow>\n )\n}\n\nfunction SelectScrollDownButton({ className, ...props }: SelectPrimitive.ScrollDownArrow.Props) {\n return (\n <SelectPrimitive.ScrollDownArrow\n className={cn(\"flex cursor-pointer items-center justify-center py-1\", className)}\n {...props}\n >\n <ChevronDownIcon />\n </SelectPrimitive.ScrollDownArrow>\n )\n}\n\nconst selectScrollButtonVariants = variants({\n base: \"absolute inset-x-0 z-10 bg-background animate-in fade-in-0 duration-300\",\n variants: {\n position: {\n top: \"top-0 mask-b-from-0\",\n bottom: \"bottom-0 mask-t-from-0\",\n },\n },\n})\n\nfunction SelectContent({\n className,\n children,\n align,\n side,\n sideOffset = 4,\n alignItemWithTrigger = false,\n ...props\n}: SelectPrimitive.Popup.Props &\n Pick<\n SelectPrimitive.Positioner.Props,\n \"align\" | \"side\" | \"sideOffset\" | \"alignItemWithTrigger\"\n >) {\n return (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Positioner\n sideOffset={sideOffset}\n align={align}\n side={side}\n alignItemWithTrigger={alignItemWithTrigger}\n className=\"isolate z-50\"\n >\n <SelectPrimitive.Popup\n className={cn(\n \"relative z-50 isolate max-h-(--available-height) min-w-(--anchor-width) overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md backdrop-blur-xs\",\n !alignItemWithTrigger && popoverAnimationClasses,\n className,\n )}\n {...props}\n >\n <SelectScrollUpButton className={selectScrollButtonVariants({ position: \"top\" })} />\n <SelectPrimitive.List className=\"p-1\">{children}</SelectPrimitive.List>\n <SelectScrollDownButton className={selectScrollButtonVariants({ position: \"bottom\" })} />\n </SelectPrimitive.Popup>\n </SelectPrimitive.Positioner>\n </SelectPrimitive.Portal>\n )\n}\n\nfunction SelectLabel({ className, ...props }: SelectPrimitive.GroupLabel.Props) {\n return (\n <SelectPrimitive.GroupLabel\n className={cn(\"px-2 py-1.5 text-sm font-medium\", className)}\n {...props}\n />\n )\n}\n\nfunction SelectItem({ className, children, label, ...props }: SelectPrimitive.Item.Props) {\n return (\n <SelectPrimitive.Item\n label={label ?? (typeof children === \"string\" ? children : undefined)}\n className={cn(\n `relative flex w-full cursor-pointer select-none items-center rounded-sm py-1.5 pl-8 pr-2 pointer-coarse:min-h-10 ${controlTextClasses} text-secondary-foreground outline-none focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50`,\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex size-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <CheckIcon className=\"size-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n )\n}\n\nfunction SelectSeparator({ className, ...props }: SelectPrimitive.Separator.Props) {\n return (\n <SelectPrimitive.Separator className={cn(\"-mx-1 my-1 h-px bg-border\", className)} {...props} />\n )\n}\n\nexport {\n Select,\n SelectGroup,\n SelectValue,\n SelectTrigger,\n SelectContent,\n SelectLabel,\n SelectItem,\n SelectSeparator,\n SelectScrollUpButton,\n SelectScrollDownButton,\n}\n"],"mappings":";;;;;;;;AAQA,MAAM,SAASA,SAAgB;AAC/B,MAAM,cAAcA,SAAgB;AACpC,MAAM,cAAcA,SAAgB;AAEpC,SAAS,cAAc,EACrB,UACA,WACA,QAAQ,MACR,QAAQ,MACR,MACA,GAAG,SACkE;CACrE,OACE,qBAACA,SAAgB,SAAjB;EACE,WAAW,GACT,cAAc;GAAE;GAAO;GAAO;EAAK,CAAC,GACpC,qCACA,SACF;EACA,GAAI;EANN,UAAA,CAQE,oBAAC,QAAD;GAAM,WAAU;GAAY;EAAe,CAAA,GAE3C,oBAACA,SAAgB,MAAjB,EACE,QAAQ,oBAAC,oBAAD,EAAoB,WAAU,kCAAmC,CAAA,EAC1E,CAAA,CACsB;;AAE7B;AAEA,SAAS,qBAAqB,EAAE,WAAW,GAAG,SAA8C;CAC1F,OACE,oBAACA,SAAgB,eAAjB;EACE,WAAW,GAAG,wDAAwD,SAAS;EAC/E,GAAI;EAEJ,UAAA,oBAAC,eAAD,CAAgB,CAAA;CACa,CAAA;AAEnC;AAEA,SAAS,uBAAuB,EAAE,WAAW,GAAG,SAAgD;CAC9F,OACE,oBAACA,SAAgB,iBAAjB;EACE,WAAW,GAAG,wDAAwD,SAAS;EAC/E,GAAI;EAEJ,UAAA,oBAAC,iBAAD,CAAkB,CAAA;CACa,CAAA;AAErC;AAEA,MAAM,6BAA6B,SAAS;CAC1C,MAAM;CACN,UAAU,EACR,UAAU;EACR,KAAK;EACL,QAAQ;CACV,EACF;AACF,CAAC;AAED,SAAS,cAAc,EACrB,WACA,UACA,OACA,MACA,aAAa,GACb,uBAAuB,OACvB,GAAG,SAKA;CACH,OACE,oBAACA,SAAgB,QAAjB,EAAA,UACE,oBAACA,SAAgB,YAAjB;EACc;EACL;EACD;EACgB;EACtB,WAAU;EAEV,UAAA,qBAACA,SAAgB,OAAjB;GACE,WAAW,GACT,2KACA,CAAC,wBAAwB,yBACzB,SACF;GACA,GAAI;GANN,UAAA;IAQE,oBAAC,sBAAD,EAAsB,WAAW,2BAA2B,EAAE,UAAU,MAAM,CAAC,EAAI,CAAA;IACnF,oBAACA,SAAgB,MAAjB;KAAsB,WAAU;KAAO;IAA+B,CAAA;IACtE,oBAAC,wBAAD,EAAwB,WAAW,2BAA2B,EAAE,UAAU,SAAS,CAAC,EAAI,CAAA;GACnE;;CACG,CAAA,EACN,CAAA;AAE5B;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAA2C;CAC9E,OACE,oBAACA,SAAgB,YAAjB;EACE,WAAW,GAAG,mCAAmC,SAAS;EAC1D,GAAI;CACL,CAAA;AAEL;AAEA,SAAS,WAAW,EAAE,WAAW,UAAU,OAAO,GAAG,SAAqC;CACxF,OACE,qBAACA,SAAgB,MAAjB;EACE,OAAO,UAAU,OAAO,aAAa,WAAW,WAAW,KAAA;EAC3D,WAAW,GACT,oHAAoH,mBAAmB,kJACvI,SACF;EACA,GAAI;EANN,UAAA,CAQE,oBAAC,QAAD;GAAM,WAAU;GACd,UAAA,oBAACA,SAAgB,eAAjB,EAAA,UACE,oBAAC,WAAD,EAAW,WAAU,SAAU,CAAA,EACF,CAAA;EAC3B,CAAA,GACN,oBAACA,SAAgB,UAAjB,EAA2B,SAAmC,CAAA,CAC1C;;AAE1B;AAEA,SAAS,gBAAgB,EAAE,WAAW,GAAG,SAA0C;CACjF,OACE,oBAACA,SAAgB,WAAjB;EAA2B,WAAW,GAAG,6BAA6B,SAAS;EAAG,GAAI;CAAQ,CAAA;AAElG"}
@@ -31,19 +31,19 @@ function StatStripItem({ label, value, format, hint, selected, render, className
31
31
  className: cn("relative min-w-0 flex-1 rounded-lg border border-transparent px-4 py-3 text-start", "before:absolute before:inset-y-2 before:-left-px before:w-px before:bg-border first:before:hidden max-sm:before:hidden", "group-data-[variant=plain]/strip:data-selected:before:hidden group-data-[variant=plain]/strip:[[data-selected]+&]:before:hidden", "group-data-[variant=track]/strip:before:-left-[8px]", "[&:is(button)]:hover:bg-foreground/3", "group-data-[variant=plain]/strip:rounded-none group-data-[variant=plain]/strip:px-5 group-data-[variant=plain]/strip:py-4 group-data-[variant=plain]/strip:before:inset-y-0 group-data-[variant=plain]/strip:before:left-0", "group-data-[variant=plain]/strip:data-selected:bg-muted", "group-data-[variant=track]/strip:data-selected:border-border group-data-[variant=track]/strip:data-selected:bg-card group-data-[variant=track]/strip:data-selected:shadow-xs", "group-data-[variant=track]/strip:not-data-selected:[&_[data-value]]:text-muted-foreground", "group-data-[variant=track]/strip:[&:is(button)]:hover:not-data-selected:bg-card/60", className),
32
32
  children: /* @__PURE__ */ jsxs(Fragment, { children: [
33
33
  /* @__PURE__ */ jsx("p", {
34
- className: "truncate text-muted-foreground text-sm",
34
+ className: "text-muted-foreground text-sm sm:truncate",
35
35
  children: label
36
36
  }),
37
37
  /* @__PURE__ */ jsx("p", {
38
38
  "data-value": true,
39
- className: "mt-0.5 truncate font-display font-semibold text-2xl tabular-nums",
39
+ className: "mt-0.5 truncate font-display font-semibold text-xl tabular-nums sm:text-2xl",
40
40
  children: /* @__PURE__ */ jsx(AnimatedNumber, {
41
41
  value,
42
42
  format
43
43
  })
44
44
  }),
45
45
  hint && /* @__PURE__ */ jsx("p", {
46
- className: "truncate text-muted-foreground text-xs",
46
+ className: "text-muted-foreground text-xs sm:truncate",
47
47
  children: hint
48
48
  })
49
49
  ] }),
@@ -1 +1 @@
1
- {"version":3,"file":"stat-strip.js","names":[],"sources":["../../src/components/stat-strip.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\"\nimport type { Format } from \"@number-flow/react\"\nimport type { ComponentProps } from \"react\"\nimport { AnimatedNumber } from \"~/components/animated-number\"\nimport { cardSurfaceClasses } from \"~/components/card\"\nimport { cn, variants, type VariantProps } from \"~/lib/variants\"\n\nconst stripVariants = variants({\n base: \"group/strip grid grid-cols-2 gap-y-1 max-sm:[&>*:last-child:nth-child(odd)]:col-span-2 sm:flex sm:flex-wrap sm:gap-y-0\",\n\n variants: {\n variant: {\n // A white card of figures, divided by full-height hairlines.\n plain: cardSurfaceClasses,\n // A canvas-toned track where the selected figure sits on a raised card, like a\n // segmented control; for strips that drive the panel beside them.\n // 13px gap: a 1px divider then sits 6px from the card on either side, matching the 6px inset.\n track: \"rounded-xl bg-background p-1.5 sm:gap-x-[13px]\",\n },\n },\n\n defaultVariants: {\n variant: \"plain\",\n },\n})\n\ntype StatStripProps = ComponentProps<\"div\"> & VariantProps<typeof stripVariants>\n\nfunction StatStrip({ className, variant, ...props }: StatStripProps) {\n return (\n <div\n data-variant={variant ?? \"plain\"}\n className={cn(stripVariants({ variant, className }))}\n {...props}\n />\n )\n}\n\ntype StatStripItemProps = Omit<useRender.ComponentProps<\"div\">, \"children\"> & {\n label: string\n value: string | number\n format?: Format\n hint?: string\n /**\n * Marks the item as the one driving the panel beside it. Pass `render={<button ... />}`\n * to make it selectable.\n */\n selected?: boolean\n}\n\nfunction StatStripItem({\n label,\n value,\n format,\n hint,\n selected,\n render,\n className,\n ...props\n}: StatStripItemProps) {\n return useRender({\n render,\n defaultTagName: \"div\",\n props: {\n \"data-selected\": selected || undefined,\n className: cn(\n // The border is always laid out and only colored when selected, so toggling\n // never shifts the row.\n \"relative min-w-0 flex-1 rounded-lg border border-transparent px-4 py-3 text-start\",\n // Hairline divider between neighbours. The plain strip hides it around the\n // selected fill; the track keeps it, centered in the gap between cards.\n \"before:absolute before:inset-y-2 before:-left-px before:w-px before:bg-border first:before:hidden max-sm:before:hidden\",\n \"group-data-[variant=plain]/strip:data-selected:before:hidden group-data-[variant=plain]/strip:[[data-selected]+&]:before:hidden\",\n // Offsets are measured from the padding box, so the 1px border is added to land\n // exactly halfway across the 13px gap.\n \"group-data-[variant=track]/strip:before:-left-[8px]\",\n \"[&:is(button)]:hover:bg-foreground/3\",\n // Plain card: roomier cells, full-height dividers, selected item on a soft fill.\n \"group-data-[variant=plain]/strip:rounded-none group-data-[variant=plain]/strip:px-5 group-data-[variant=plain]/strip:py-4 group-data-[variant=plain]/strip:before:inset-y-0 group-data-[variant=plain]/strip:before:left-0\",\n \"group-data-[variant=plain]/strip:data-selected:bg-muted\",\n // Track: the selected item is a raised card; unselected figures recede.\n \"group-data-[variant=track]/strip:data-selected:border-border group-data-[variant=track]/strip:data-selected:bg-card group-data-[variant=track]/strip:data-selected:shadow-xs\",\n \"group-data-[variant=track]/strip:not-data-selected:[&_[data-value]]:text-muted-foreground\",\n \"group-data-[variant=track]/strip:[&:is(button)]:hover:not-data-selected:bg-card/60\",\n className,\n ),\n children: (\n <>\n <p className=\"truncate text-muted-foreground text-sm\">{label}</p>\n\n <p\n data-value\n className=\"mt-0.5 truncate font-display font-semibold text-2xl tabular-nums\"\n >\n <AnimatedNumber value={value} format={format} />\n </p>\n\n {hint && <p className=\"truncate text-muted-foreground text-xs\">{hint}</p>}\n </>\n ),\n ...props,\n },\n })\n}\n\nexport { StatStrip, StatStripItem }\n"],"mappings":";;;;;;AAOA,MAAM,gBAAgB,SAAS;CAC7B,MAAM;CAEN,UAAU,EACR,SAAS;EAEP,OAAO;EAIP,OAAO;CACT,EACF;CAEA,iBAAiB,EACf,SAAS,QACX;AACF,CAAC;AAID,SAAS,UAAU,EAAE,WAAW,SAAS,GAAG,SAAyB;CACnE,OACE,oBAAC,OAAD;EACE,gBAAc,WAAW;EACzB,WAAW,GAAG,cAAc;GAAE;GAAS;EAAU,CAAC,CAAC;EACnD,GAAI;CACL,CAAA;AAEL;AAcA,SAAS,cAAc,EACrB,OACA,OACA,QACA,MACA,UACA,QACA,WACA,GAAG,SACkB;CACrB,OAAO,UAAU;EACf;EACA,gBAAgB;EAChB,OAAO;GACL,iBAAiB,YAAY,KAAA;GAC7B,WAAW,GAGT,qFAGA,0HACA,mIAGA,uDACA,wCAEA,8NACA,2DAEA,gLACA,6FACA,sFACA,SACF;GACA,UACE,qBAAA,UAAA,EAAA,UAAA;IACE,oBAAC,KAAD;KAAG,WAAU;KAA0C,UAAA;IAAS,CAAA;IAEhE,oBAAC,KAAD;KACE,cAAA;KACA,WAAU;KAEV,UAAA,oBAAC,gBAAD;MAAuB;MAAe;KAAS,CAAA;IAC9C,CAAA;IAEF,QAAQ,oBAAC,KAAD;KAAG,WAAU;KAA0C,UAAA;IAAQ,CAAA;GACxE,EAAA,CAAA;GAEJ,GAAG;EACL;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"stat-strip.js","names":[],"sources":["../../src/components/stat-strip.tsx"],"sourcesContent":["import { useRender } from \"@base-ui/react/use-render\"\nimport type { Format } from \"@number-flow/react\"\nimport type { ComponentProps } from \"react\"\nimport { AnimatedNumber } from \"~/components/animated-number\"\nimport { cardSurfaceClasses } from \"~/components/card\"\nimport { cn, variants, type VariantProps } from \"~/lib/variants\"\n\nconst stripVariants = variants({\n base: \"group/strip grid grid-cols-2 gap-y-1 max-sm:[&>*:last-child:nth-child(odd)]:col-span-2 sm:flex sm:flex-wrap sm:gap-y-0\",\n\n variants: {\n variant: {\n // A white card of figures, divided by full-height hairlines.\n plain: cardSurfaceClasses,\n // A canvas-toned track where the selected figure sits on a raised card, like a\n // segmented control; for strips that drive the panel beside them.\n // 13px gap: a 1px divider then sits 6px from the card on either side, matching the 6px inset.\n track: \"rounded-xl bg-background p-1.5 sm:gap-x-[13px]\",\n },\n },\n\n defaultVariants: {\n variant: \"plain\",\n },\n})\n\ntype StatStripProps = ComponentProps<\"div\"> & VariantProps<typeof stripVariants>\n\nfunction StatStrip({ className, variant, ...props }: StatStripProps) {\n return (\n <div\n data-variant={variant ?? \"plain\"}\n className={cn(stripVariants({ variant, className }))}\n {...props}\n />\n )\n}\n\ntype StatStripItemProps = Omit<useRender.ComponentProps<\"div\">, \"children\"> & {\n label: string\n value: string | number\n format?: Format\n hint?: string\n /**\n * Marks the item as the one driving the panel beside it. Pass `render={<button ... />}`\n * to make it selectable.\n */\n selected?: boolean\n}\n\nfunction StatStripItem({\n label,\n value,\n format,\n hint,\n selected,\n render,\n className,\n ...props\n}: StatStripItemProps) {\n return useRender({\n render,\n defaultTagName: \"div\",\n props: {\n \"data-selected\": selected || undefined,\n className: cn(\n // The border is always laid out and only colored when selected, so toggling\n // never shifts the row.\n \"relative min-w-0 flex-1 rounded-lg border border-transparent px-4 py-3 text-start\",\n // Hairline divider between neighbours. The plain strip hides it around the\n // selected fill; the track keeps it, centered in the gap between cards.\n \"before:absolute before:inset-y-2 before:-left-px before:w-px before:bg-border first:before:hidden max-sm:before:hidden\",\n \"group-data-[variant=plain]/strip:data-selected:before:hidden group-data-[variant=plain]/strip:[[data-selected]+&]:before:hidden\",\n // Offsets are measured from the padding box, so the 1px border is added to land\n // exactly halfway across the 13px gap.\n \"group-data-[variant=track]/strip:before:-left-[8px]\",\n \"[&:is(button)]:hover:bg-foreground/3\",\n // Plain card: roomier cells, full-height dividers, selected item on a soft fill.\n \"group-data-[variant=plain]/strip:rounded-none group-data-[variant=plain]/strip:px-5 group-data-[variant=plain]/strip:py-4 group-data-[variant=plain]/strip:before:inset-y-0 group-data-[variant=plain]/strip:before:left-0\",\n \"group-data-[variant=plain]/strip:data-selected:bg-muted\",\n // Track: the selected item is a raised card; unselected figures recede.\n \"group-data-[variant=track]/strip:data-selected:border-border group-data-[variant=track]/strip:data-selected:bg-card group-data-[variant=track]/strip:data-selected:shadow-xs\",\n \"group-data-[variant=track]/strip:not-data-selected:[&_[data-value]]:text-muted-foreground\",\n \"group-data-[variant=track]/strip:[&:is(button)]:hover:not-data-selected:bg-card/60\",\n className,\n ),\n children: (\n <>\n <p className=\"text-muted-foreground text-sm sm:truncate\">{label}</p>\n\n <p\n data-value\n className=\"mt-0.5 truncate font-display font-semibold text-xl tabular-nums sm:text-2xl\"\n >\n <AnimatedNumber value={value} format={format} />\n </p>\n\n {hint && <p className=\"text-muted-foreground text-xs sm:truncate\">{hint}</p>}\n </>\n ),\n ...props,\n },\n })\n}\n\nexport { StatStrip, StatStripItem }\n"],"mappings":";;;;;;AAOA,MAAM,gBAAgB,SAAS;CAC7B,MAAM;CAEN,UAAU,EACR,SAAS;EAEP,OAAO;EAIP,OAAO;CACT,EACF;CAEA,iBAAiB,EACf,SAAS,QACX;AACF,CAAC;AAID,SAAS,UAAU,EAAE,WAAW,SAAS,GAAG,SAAyB;CACnE,OACE,oBAAC,OAAD;EACE,gBAAc,WAAW;EACzB,WAAW,GAAG,cAAc;GAAE;GAAS;EAAU,CAAC,CAAC;EACnD,GAAI;CACL,CAAA;AAEL;AAcA,SAAS,cAAc,EACrB,OACA,OACA,QACA,MACA,UACA,QACA,WACA,GAAG,SACkB;CACrB,OAAO,UAAU;EACf;EACA,gBAAgB;EAChB,OAAO;GACL,iBAAiB,YAAY,KAAA;GAC7B,WAAW,GAGT,qFAGA,0HACA,mIAGA,uDACA,wCAEA,8NACA,2DAEA,gLACA,6FACA,sFACA,SACF;GACA,UACE,qBAAA,UAAA,EAAA,UAAA;IACE,oBAAC,KAAD;KAAG,WAAU;KAA6C,UAAA;IAAS,CAAA;IAEnE,oBAAC,KAAD;KACE,cAAA;KACA,WAAU;KAEV,UAAA,oBAAC,gBAAD;MAAuB;MAAe;KAAS,CAAA;IAC9C,CAAA;IAEF,QAAQ,oBAAC,KAAD;KAAG,WAAU;KAA6C,UAAA;IAAQ,CAAA;GAC3E,EAAA,CAAA;GAEJ,GAAG;EACL;CACF,CAAC;AACH"}
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.d.ts","names":[],"sources":["../../src/components/tabs.tsx"],"mappings":";;;cAOM,sBAAI,0BAAA,8BAAA,wCAAA,cAAA;cAEJ,8CAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyDjB,gBAAgB,OAAc,KAAK,QAAQ,oBAAoB;iBAE3D,WAAW,WAAW,UAAU,YAA0B,SAAS,gCAAa,IAAA;iBAchF,cAAc,cAAc,SAAS,OAAc,IAAI,wBAAK,IAAA"}
1
+ {"version":3,"file":"tabs.d.ts","names":[],"sources":["../../src/components/tabs.tsx"],"mappings":";;;cAQM,sBAAI,0BAAA,8BAAA,wCAAA,cAAA;cAEJ,8CAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAyDjB,gBAAgB,OAAc,KAAK,QAAQ,oBAAoB;iBAE3D,WAAW,WAAW,UAAU,YAA0B,SAAS,gCAAa,IAAA;iBAchF,cAAc,cAAc,SAAS,OAAc,IAAI,wBAAK,IAAA"}
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { cn, variants } from "../lib/variants.js";
3
+ import { controlTextClasses } from "../lib/classes.js";
3
4
  import { interactiveVariants } from "../lib/interactive.js";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
6
  import { createContext, useContext } from "react";
@@ -16,7 +17,7 @@ const tabsListVariants = variants({
16
17
  segmented: {
17
18
  list: "h-control justify-center rounded-md border bg-card p-[3px]",
18
19
  indicator: "rounded-[3px] bg-muted",
19
- trigger: "rounded-[3px] px-2.5 py-[5px] text-control"
20
+ trigger: `rounded-[3px] px-2.5 py-[5px] ${controlTextClasses}`
20
21
  },
21
22
  plain: {
22
23
  list: "gap-0.5",
@@ -1 +1 @@
1
- {"version":3,"file":"tabs.js","names":["TabsPrimitive"],"sources":["../../src/components/tabs.tsx"],"sourcesContent":["\"use client\"\n\nimport { Tabs as TabsPrimitive } from \"@base-ui/react/tabs\"\nimport { createContext, useContext } from \"react\"\nimport { interactiveVariants } from \"~/lib/interactive\"\nimport { cn, variants, type VariantProps } from \"~/lib/variants\"\n\nconst Tabs = TabsPrimitive.Root\n\nconst tabsListVariants = variants({\n slots: {\n list: \"relative inline-flex items-center text-muted-foreground\",\n indicator:\n \"absolute top-1/2 left-0 z-0 h-[var(--active-tab-height)] w-[var(--active-tab-width)] -translate-y-1/2 translate-x-[var(--active-tab-left)] rounded-md transition-[translate,width] duration-500 ease-out-expo\",\n trigger: cn(\n interactiveVariants({ focus: true }),\n \"relative z-10 inline-flex items-center justify-center whitespace-nowrap rounded-md font-medium disabled:pointer-events-none disabled:opacity-50 hover:text-foreground data-active:text-foreground\",\n ),\n },\n\n variants: {\n variant: {\n // Segmented control, sized like an `md` Button so it sits flush beside one in a header:\n // the same 13px text, the same `--spacing-control` height, and a 6px outer radius over a\n // 3px inset (so the inner pill radius is 3px).\n segmented: {\n list: \"h-control justify-center rounded-md border bg-card p-[3px]\",\n indicator: \"rounded-[3px] bg-muted\",\n trigger: \"rounded-[3px] px-2.5 py-[5px] text-control\",\n },\n // Plain pills: no track, the active tab sits on a soft pill. For in-card view switchers.\n plain: {\n list: \"gap-0.5\",\n indicator: \"bg-muted\",\n trigger: \"px-2.5 py-1.5 text-sm\",\n },\n },\n },\n\n defaultVariants: {\n variant: \"segmented\",\n },\n})\n\ntype TabsVariant = NonNullable<VariantProps<typeof tabsListVariants>[\"variant\"]>\n\nconst TabsVariantContext = createContext<TabsVariant>(\"segmented\")\n\n/**\n * Sliding highlight that tracks the active tab via Base UI's --active-tab-*\n * CSS variables. Rendered automatically by TabsList, so every tab group shares\n * one pill. Duration/easing mirror the library's one motion curve — the\n * `--ease-out-expo` token, duplicated for JS in `~/lib/animation` — so the pill\n * glides in sync with the number spins and chart draws it sits beside.\n */\nfunction TabsIndicator({ className, ...props }: TabsPrimitive.Indicator.Props) {\n const variant = useContext(TabsVariantContext)\n\n return (\n <TabsPrimitive.Indicator\n className={cn(tabsListVariants({ variant }).indicator(), className)}\n {...props}\n />\n )\n}\n\ntype TabsListProps = TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>\n\nfunction TabsList({ className, children, variant = \"segmented\", ...props }: TabsListProps) {\n return (\n <TabsVariantContext value={variant}>\n <TabsPrimitive.List\n className={cn(tabsListVariants({ variant }).list(), className)}\n {...props}\n >\n <TabsIndicator />\n {children}\n </TabsPrimitive.List>\n </TabsVariantContext>\n )\n}\n\nfunction TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {\n const variant = useContext(TabsVariantContext)\n\n return (\n <TabsPrimitive.Tab\n className={cn(tabsListVariants({ variant }).trigger(), className)}\n {...props}\n />\n )\n}\n\nexport { Tabs, TabsList, TabsTrigger }\n"],"mappings":";;;;;;;AAOA,MAAM,OAAOA,OAAc;AAE3B,MAAM,mBAAmB,SAAS;CAChC,OAAO;EACL,MAAM;EACN,WACE;EACF,SAAS,GACP,oBAAoB,EAAE,OAAO,KAAK,CAAC,GACnC,mMACF;CACF;CAEA,UAAU,EACR,SAAS;EAIP,WAAW;GACT,MAAM;GACN,WAAW;GACX,SAAS;EACX;EAEA,OAAO;GACL,MAAM;GACN,WAAW;GACX,SAAS;EACX;CACF,EACF;CAEA,iBAAiB,EACf,SAAS,YACX;AACF,CAAC;AAID,MAAM,qBAAqB,cAA2B,WAAW;;;;;;;;AASjE,SAAS,cAAc,EAAE,WAAW,GAAG,SAAwC;CAC7E,MAAM,UAAU,WAAW,kBAAkB;CAE7C,OACE,oBAACA,OAAc,WAAf;EACE,WAAW,GAAG,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,GAAG,SAAS;EAClE,GAAI;CACL,CAAA;AAEL;AAIA,SAAS,SAAS,EAAE,WAAW,UAAU,UAAU,aAAa,GAAG,SAAwB;CACzF,OACE,oBAAC,oBAAD;EAAoB,OAAO;EACzB,UAAA,qBAACA,OAAc,MAAf;GACE,WAAW,GAAG,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,SAAS;GAC7D,GAAI;GAFN,UAAA,CAIE,oBAAC,eAAD,CAAgB,CAAA,GACf,QACiB;;CACF,CAAA;AAExB;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAkC;CACrE,MAAM,UAAU,WAAW,kBAAkB;CAE7C,OACE,oBAACA,OAAc,KAAf;EACE,WAAW,GAAG,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,GAAG,SAAS;EAChE,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"tabs.js","names":["TabsPrimitive"],"sources":["../../src/components/tabs.tsx"],"sourcesContent":["\"use client\"\n\nimport { Tabs as TabsPrimitive } from \"@base-ui/react/tabs\"\nimport { createContext, useContext } from \"react\"\nimport { controlTextClasses } from \"~/lib/classes\"\nimport { interactiveVariants } from \"~/lib/interactive\"\nimport { cn, variants, type VariantProps } from \"~/lib/variants\"\n\nconst Tabs = TabsPrimitive.Root\n\nconst tabsListVariants = variants({\n slots: {\n list: \"relative inline-flex items-center text-muted-foreground\",\n indicator:\n \"absolute top-1/2 left-0 z-0 h-[var(--active-tab-height)] w-[var(--active-tab-width)] -translate-y-1/2 translate-x-[var(--active-tab-left)] rounded-md transition-[translate,width] duration-500 ease-out-expo\",\n trigger: cn(\n interactiveVariants({ focus: true }),\n \"relative z-10 inline-flex items-center justify-center whitespace-nowrap rounded-md font-medium disabled:pointer-events-none disabled:opacity-50 hover:text-foreground data-active:text-foreground\",\n ),\n },\n\n variants: {\n variant: {\n // Segmented control, sized like an `md` Button so it sits flush beside one in a header:\n // the same 13px text, the same `--spacing-control` height, and a 6px outer radius over a\n // 3px inset (so the inner pill radius is 3px).\n segmented: {\n list: \"h-control justify-center rounded-md border bg-card p-[3px]\",\n indicator: \"rounded-[3px] bg-muted\",\n trigger: `rounded-[3px] px-2.5 py-[5px] ${controlTextClasses}`,\n },\n // Plain pills: no track, the active tab sits on a soft pill. For in-card view switchers.\n plain: {\n list: \"gap-0.5\",\n indicator: \"bg-muted\",\n trigger: \"px-2.5 py-1.5 text-sm\",\n },\n },\n },\n\n defaultVariants: {\n variant: \"segmented\",\n },\n})\n\ntype TabsVariant = NonNullable<VariantProps<typeof tabsListVariants>[\"variant\"]>\n\nconst TabsVariantContext = createContext<TabsVariant>(\"segmented\")\n\n/**\n * Sliding highlight that tracks the active tab via Base UI's --active-tab-*\n * CSS variables. Rendered automatically by TabsList, so every tab group shares\n * one pill. Duration/easing mirror the library's one motion curve — the\n * `--ease-out-expo` token, duplicated for JS in `~/lib/animation` — so the pill\n * glides in sync with the number spins and chart draws it sits beside.\n */\nfunction TabsIndicator({ className, ...props }: TabsPrimitive.Indicator.Props) {\n const variant = useContext(TabsVariantContext)\n\n return (\n <TabsPrimitive.Indicator\n className={cn(tabsListVariants({ variant }).indicator(), className)}\n {...props}\n />\n )\n}\n\ntype TabsListProps = TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>\n\nfunction TabsList({ className, children, variant = \"segmented\", ...props }: TabsListProps) {\n return (\n <TabsVariantContext value={variant}>\n <TabsPrimitive.List\n className={cn(tabsListVariants({ variant }).list(), className)}\n {...props}\n >\n <TabsIndicator />\n {children}\n </TabsPrimitive.List>\n </TabsVariantContext>\n )\n}\n\nfunction TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {\n const variant = useContext(TabsVariantContext)\n\n return (\n <TabsPrimitive.Tab\n className={cn(tabsListVariants({ variant }).trigger(), className)}\n {...props}\n />\n )\n}\n\nexport { Tabs, TabsList, TabsTrigger }\n"],"mappings":";;;;;;;;AAQA,MAAM,OAAOA,OAAc;AAE3B,MAAM,mBAAmB,SAAS;CAChC,OAAO;EACL,MAAM;EACN,WACE;EACF,SAAS,GACP,oBAAoB,EAAE,OAAO,KAAK,CAAC,GACnC,mMACF;CACF;CAEA,UAAU,EACR,SAAS;EAIP,WAAW;GACT,MAAM;GACN,WAAW;GACX,SAAS,iCAAiC;EAC5C;EAEA,OAAO;GACL,MAAM;GACN,WAAW;GACX,SAAS;EACX;CACF,EACF;CAEA,iBAAiB,EACf,SAAS,YACX;AACF,CAAC;AAID,MAAM,qBAAqB,cAA2B,WAAW;;;;;;;;AASjE,SAAS,cAAc,EAAE,WAAW,GAAG,SAAwC;CAC7E,MAAM,UAAU,WAAW,kBAAkB;CAE7C,OACE,oBAACA,OAAc,WAAf;EACE,WAAW,GAAG,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,GAAG,SAAS;EAClE,GAAI;CACL,CAAA;AAEL;AAIA,SAAS,SAAS,EAAE,WAAW,UAAU,UAAU,aAAa,GAAG,SAAwB;CACzF,OACE,oBAAC,oBAAD;EAAoB,OAAO;EACzB,UAAA,qBAACA,OAAc,MAAf;GACE,WAAW,GAAG,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,GAAG,SAAS;GAC7D,GAAI;GAFN,UAAA,CAIE,oBAAC,eAAD,CAAgB,CAAA,GACf,QACiB;;CACF,CAAA;AAExB;AAEA,SAAS,YAAY,EAAE,WAAW,GAAG,SAAkC;CACrE,MAAM,UAAU,WAAW,kBAAkB;CAE7C,OACE,oBAACA,OAAc,KAAf;EACE,WAAW,GAAG,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,GAAG,SAAS;EAChE,GAAI;CACL,CAAA;AAEL"}
@@ -1 +1 @@
1
- {"version":3,"file":"toaster.d.ts","names":[],"sources":["../../src/components/toaster.tsx"],"mappings":";;;wBAQgB,UAAU,cAAc,SAAS,sBAAsB,6BAAO,IAAA"}
1
+ {"version":3,"file":"toaster.d.ts","names":[],"sources":["../../src/components/toaster.tsx"],"mappings":";;;wBASgB,UAAU,cAAc,SAAS,sBAAsB,6BAAO,IAAA"}
@@ -1,4 +1,5 @@
1
1
  import { cn } from "../lib/variants.js";
2
+ import { controlTextClasses } from "../lib/classes.js";
2
3
  import { CircleCheckIcon, CircleHelpIcon, CircleXIcon, LoaderIcon } from "../lib/icons.js";
3
4
  import { jsx } from "react/jsx-runtime";
4
5
  import { Toaster as Toaster$1 } from "sonner";
@@ -9,10 +10,15 @@ function Toaster({ className, ...props }) {
9
10
  return /* @__PURE__ */ jsx(Toaster$1, {
10
11
  className: "pointer-events-auto",
11
12
  offset: 16,
13
+ mobileOffset: {
14
+ bottom: "calc(16px + env(safe-area-inset-bottom))",
15
+ left: 16,
16
+ right: 16
17
+ },
12
18
  toastOptions: {
13
19
  unstyled: true,
14
20
  classNames: {
15
- toast: cn("flex items-start gap-2 p-4 text-control font-medium rounded-lg shadow-sm", className),
21
+ toast: cn(`flex items-start gap-2 p-4 ${controlTextClasses} font-medium rounded-lg shadow-sm`, className),
16
22
  default: "bg-background border border-border text-foreground",
17
23
  info: cn("bg-foreground text-background", toastRingClasses),
18
24
  success: cn("bg-success text-white", toastRingClasses),
@@ -1 +1 @@
1
- {"version":3,"file":"toaster.js","names":["Sonner"],"sources":["../../src/components/toaster.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\"\nimport { Toaster as Sonner } from \"sonner\"\nimport { CircleCheckIcon, CircleHelpIcon, CircleXIcon, LoaderIcon } from \"~/lib/icons\"\nimport { cn } from \"~/lib/variants\"\n\n/** The halo that lifts a solid-colored toast off whatever it floats over. */\nconst toastRingClasses = \"ring ring-background/50\"\n\nexport function Toaster({ className, ...props }: ComponentProps<typeof Sonner>) {\n return (\n <Sonner\n className=\"pointer-events-auto\"\n offset={16}\n toastOptions={{\n unstyled: true,\n classNames: {\n /*\n * Sonner joins `toast` with exactly one type key per toast (`default` for untyped\n * ones) as a plain string, so tailwind-merge never sees the pair. Anything that\n * differs per type — background, text, halo — therefore lives on the type keys\n * only, and never gets cancelled here.\n */\n toast: cn(\n \"flex items-start gap-2 p-4 text-control font-medium rounded-lg shadow-sm\",\n className,\n ),\n default: \"bg-background border border-border text-foreground\",\n info: cn(\"bg-foreground text-background\", toastRingClasses),\n success: cn(\"bg-success text-white\", toastRingClasses),\n error: cn(\"bg-danger text-white\", toastRingClasses),\n content: \"w-full\",\n description: \"font-normal opacity-80\",\n icon: \"mt-0.5\",\n },\n }}\n icons={{\n info: <CircleHelpIcon className=\"size-4\" />,\n success: <CircleCheckIcon className=\"size-4\" />,\n error: <CircleXIcon className=\"size-4\" />,\n loading: <LoaderIcon className=\"size-4 animate-spin\" />,\n }}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;AAMA,MAAM,mBAAmB;AAEzB,SAAgB,QAAQ,EAAE,WAAW,GAAG,SAAwC;CAC9E,OACE,oBAACA,WAAD;EACE,WAAU;EACV,QAAQ;EACR,cAAc;GACZ,UAAU;GACV,YAAY;IAOV,OAAO,GACL,4EACA,SACF;IACA,SAAS;IACT,MAAM,GAAG,iCAAiC,gBAAgB;IAC1D,SAAS,GAAG,yBAAyB,gBAAgB;IACrD,OAAO,GAAG,wBAAwB,gBAAgB;IAClD,SAAS;IACT,aAAa;IACb,MAAM;GACR;EACF;EACA,OAAO;GACL,MAAM,oBAAC,gBAAD,EAAgB,WAAU,SAAU,CAAA;GAC1C,SAAS,oBAAC,iBAAD,EAAiB,WAAU,SAAU,CAAA;GAC9C,OAAO,oBAAC,aAAD,EAAa,WAAU,SAAU,CAAA;GACxC,SAAS,oBAAC,YAAD,EAAY,WAAU,sBAAuB,CAAA;EACxD;EACA,GAAI;CACL,CAAA;AAEL"}
1
+ {"version":3,"file":"toaster.js","names":["Sonner"],"sources":["../../src/components/toaster.tsx"],"sourcesContent":["import type { ComponentProps } from \"react\"\nimport { Toaster as Sonner } from \"sonner\"\nimport { controlTextClasses } from \"~/lib/classes\"\nimport { CircleCheckIcon, CircleHelpIcon, CircleXIcon, LoaderIcon } from \"~/lib/icons\"\nimport { cn } from \"~/lib/variants\"\n\n/** The halo that lifts a solid-colored toast off whatever it floats over. */\nconst toastRingClasses = \"ring ring-background/50\"\n\nexport function Toaster({ className, ...props }: ComponentProps<typeof Sonner>) {\n return (\n <Sonner\n className=\"pointer-events-auto\"\n offset={16}\n mobileOffset={{ bottom: \"calc(16px + env(safe-area-inset-bottom))\", left: 16, right: 16 }}\n toastOptions={{\n unstyled: true,\n classNames: {\n /*\n * Sonner joins `toast` with exactly one type key per toast (`default` for untyped\n * ones) as a plain string, so tailwind-merge never sees the pair. Anything that\n * differs per type — background, text, halo — therefore lives on the type keys\n * only, and never gets cancelled here.\n */\n toast: cn(\n `flex items-start gap-2 p-4 ${controlTextClasses} font-medium rounded-lg shadow-sm`,\n className,\n ),\n default: \"bg-background border border-border text-foreground\",\n info: cn(\"bg-foreground text-background\", toastRingClasses),\n success: cn(\"bg-success text-white\", toastRingClasses),\n error: cn(\"bg-danger text-white\", toastRingClasses),\n content: \"w-full\",\n description: \"font-normal opacity-80\",\n icon: \"mt-0.5\",\n },\n }}\n icons={{\n info: <CircleHelpIcon className=\"size-4\" />,\n success: <CircleCheckIcon className=\"size-4\" />,\n error: <CircleXIcon className=\"size-4\" />,\n loading: <LoaderIcon className=\"size-4 animate-spin\" />,\n }}\n {...props}\n />\n )\n}\n"],"mappings":";;;;;;;AAOA,MAAM,mBAAmB;AAEzB,SAAgB,QAAQ,EAAE,WAAW,GAAG,SAAwC;CAC9E,OACE,oBAACA,WAAD;EACE,WAAU;EACV,QAAQ;EACR,cAAc;GAAE,QAAQ;GAA4C,MAAM;GAAI,OAAO;EAAG;EACxF,cAAc;GACZ,UAAU;GACV,YAAY;IAOV,OAAO,GACL,8BAA8B,mBAAmB,oCACjD,SACF;IACA,SAAS;IACT,MAAM,GAAG,iCAAiC,gBAAgB;IAC1D,SAAS,GAAG,yBAAyB,gBAAgB;IACrD,OAAO,GAAG,wBAAwB,gBAAgB;IAClD,SAAS;IACT,aAAa;IACb,MAAM;GACR;EACF;EACA,OAAO;GACL,MAAM,oBAAC,gBAAD,EAAgB,WAAU,SAAU,CAAA;GAC1C,SAAS,oBAAC,iBAAD,EAAiB,WAAU,SAAU,CAAA;GAC9C,OAAO,oBAAC,aAAD,EAAa,WAAU,SAAU,CAAA;GACxC,SAAS,oBAAC,YAAD,EAAY,WAAU,sBAAuB,CAAA;EACxD;EACA,GAAI;CACL,CAAA;AAEL"}
@@ -25,5 +25,15 @@ export declare const eyebrowClasses = "text-[0.6875rem]/tight font-medium text-m
25
25
  * size the settings rows already use, so a form reads the same in either layout.
26
26
  */
27
27
  export declare const descriptionClasses = "text-pretty text-muted-foreground text-sm";
28
+ /**
29
+ * The default control font size + line height (buttons, inputs, selects, menu items, tabs,
30
+ * toasts). Written as an arbitrary `length:` font-size plus a paired `leading-*` rather than
31
+ * a `text-control` theme utility on purpose: a *named* custom text size is invisible to the
32
+ * class-merge engines (`cn` and tailwind-variants' twMerge), which fall back to treating
33
+ * `text-control` as a text COLOR and drop it the moment a variant adds its own
34
+ * `text-secondary-foreground`/`text-background`/... , leaving the control to inherit the
35
+ * page's 16px. The `length:` hint keeps it classified as a font-size so it survives the merge.
36
+ */
37
+ export declare const controlTextClasses = "text-(length:--text-control) leading-(--text-control--line-height)";
28
38
  //#endregion
29
39
  //# sourceMappingURL=classes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"classes.d.ts","names":[],"sources":["../../src/lib/classes.ts"],"mappings":";;;;;;;;;;;;;;;;qBAea;;;;;qBAcA;;;;;qBAMA"}
1
+ {"version":3,"file":"classes.d.ts","names":[],"sources":["../../src/lib/classes.ts"],"mappings":";;;;;;;;;;;;;;;;qBAea;;;;;qBAcA;;;;;qBAMA;;;;;;;;;;qBAWA"}
@@ -33,7 +33,17 @@ const eyebrowClasses = "text-[0.6875rem]/tight font-medium text-muted-foreground
33
33
  * size the settings rows already use, so a form reads the same in either layout.
34
34
  */
35
35
  const descriptionClasses = "text-pretty text-muted-foreground text-sm";
36
+ /**
37
+ * The default control font size + line height (buttons, inputs, selects, menu items, tabs,
38
+ * toasts). Written as an arbitrary `length:` font-size plus a paired `leading-*` rather than
39
+ * a `text-control` theme utility on purpose: a *named* custom text size is invisible to the
40
+ * class-merge engines (`cn` and tailwind-variants' twMerge), which fall back to treating
41
+ * `text-control` as a text COLOR and drop it the moment a variant adds its own
42
+ * `text-secondary-foreground`/`text-background`/... , leaving the control to inherit the
43
+ * page's 16px. The `length:` hint keeps it classified as a font-size so it survives the merge.
44
+ */
45
+ const controlTextClasses = "text-(length:--text-control) leading-(--text-control--line-height)";
36
46
  //#endregion
37
- export { descriptionClasses, eyebrowClasses, popoverAnimationClasses };
47
+ export { controlTextClasses, descriptionClasses, eyebrowClasses, popoverAnimationClasses };
38
48
 
39
49
  //# sourceMappingURL=classes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"classes.js","names":[],"sources":["../../src/lib/classes.ts"],"sourcesContent":["/**\n * Enter/exit animation classes for Base UI popups (Menu, Select, Popover, Tooltip, …).\n * Keyed on Base UI's `data-open`/`data-closed` state attributes and the positioner's\n * `data-[side=*]`, with the zoom anchored to the `--transform-origin` Base UI exposes on\n * the popup. Animation utilities (and their `duration-*`/`ease-*` bindings) come from\n * `tailwindcss-animate`.\n *\n * The `data-closed` animation is essential: Base UI keeps the popup mounted until the\n * exit animation finishes, so without it there is no close animation at all.\n *\n * Feel: a snappy 100ms, a barely-there 98% zoom, and a 2px directional slide. Enter eases\n * out (natural deceleration as it appears); exit eases in (accelerates away — it shouldn't\n * fight for attention). `data-instant` collapses the duration to 0 so Base UI's instant\n * transitions (keyboard nav between items, grouped tooltips) don't stutter.\n */\nexport const popoverAnimationClasses = [\n \"origin-(--transform-origin) duration-100 data-instant:duration-0\",\n \"data-open:animate-in data-open:ease-out data-open:fade-in-0 data-open:zoom-in-98\",\n \"data-closed:animate-out data-closed:ease-in data-closed:fade-out-0 data-closed:zoom-out-98\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=bottom]:slide-out-to-top-2\",\n \"data-[side=left]:slide-in-from-right-2 data-[side=left]:slide-out-to-right-2\",\n \"data-[side=right]:slide-in-from-left-2 data-[side=right]:slide-out-to-left-2\",\n \"data-[side=top]:slide-in-from-bottom-2 data-[side=top]:slide-out-to-bottom-2\",\n]\n\n/**\n * Small muted label over a group of items: sidebar sections, menu groups. One place so every\n * eyebrow in the app shares its size and weight.\n */\nexport const eyebrowClasses = \"text-[0.6875rem]/tight font-medium text-muted-foreground\"\n\n/**\n * Muted supporting copy under a heading, label, or control. Matches the description\n * size the settings rows already use, so a form reads the same in either layout.\n */\nexport const descriptionClasses = \"text-pretty text-muted-foreground text-sm\"\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,0BAA0B;CACrC;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;AAMA,MAAa,iBAAiB;;;;;AAM9B,MAAa,qBAAqB"}
1
+ {"version":3,"file":"classes.js","names":[],"sources":["../../src/lib/classes.ts"],"sourcesContent":["/**\n * Enter/exit animation classes for Base UI popups (Menu, Select, Popover, Tooltip, …).\n * Keyed on Base UI's `data-open`/`data-closed` state attributes and the positioner's\n * `data-[side=*]`, with the zoom anchored to the `--transform-origin` Base UI exposes on\n * the popup. Animation utilities (and their `duration-*`/`ease-*` bindings) come from\n * `tailwindcss-animate`.\n *\n * The `data-closed` animation is essential: Base UI keeps the popup mounted until the\n * exit animation finishes, so without it there is no close animation at all.\n *\n * Feel: a snappy 100ms, a barely-there 98% zoom, and a 2px directional slide. Enter eases\n * out (natural deceleration as it appears); exit eases in (accelerates away — it shouldn't\n * fight for attention). `data-instant` collapses the duration to 0 so Base UI's instant\n * transitions (keyboard nav between items, grouped tooltips) don't stutter.\n */\nexport const popoverAnimationClasses = [\n \"origin-(--transform-origin) duration-100 data-instant:duration-0\",\n \"data-open:animate-in data-open:ease-out data-open:fade-in-0 data-open:zoom-in-98\",\n \"data-closed:animate-out data-closed:ease-in data-closed:fade-out-0 data-closed:zoom-out-98\",\n \"data-[side=bottom]:slide-in-from-top-2 data-[side=bottom]:slide-out-to-top-2\",\n \"data-[side=left]:slide-in-from-right-2 data-[side=left]:slide-out-to-right-2\",\n \"data-[side=right]:slide-in-from-left-2 data-[side=right]:slide-out-to-left-2\",\n \"data-[side=top]:slide-in-from-bottom-2 data-[side=top]:slide-out-to-bottom-2\",\n]\n\n/**\n * Small muted label over a group of items: sidebar sections, menu groups. One place so every\n * eyebrow in the app shares its size and weight.\n */\nexport const eyebrowClasses = \"text-[0.6875rem]/tight font-medium text-muted-foreground\"\n\n/**\n * Muted supporting copy under a heading, label, or control. Matches the description\n * size the settings rows already use, so a form reads the same in either layout.\n */\nexport const descriptionClasses = \"text-pretty text-muted-foreground text-sm\"\n\n/**\n * The default control font size + line height (buttons, inputs, selects, menu items, tabs,\n * toasts). Written as an arbitrary `length:` font-size plus a paired `leading-*` rather than\n * a `text-control` theme utility on purpose: a *named* custom text size is invisible to the\n * class-merge engines (`cn` and tailwind-variants' twMerge), which fall back to treating\n * `text-control` as a text COLOR and drop it the moment a variant adds its own\n * `text-secondary-foreground`/`text-background`/... , leaving the control to inherit the\n * page's 16px. The `length:` hint keeps it classified as a font-size so it survives the merge.\n */\nexport const controlTextClasses =\n \"text-(length:--text-control) leading-(--text-control--line-height)\"\n"],"mappings":";;;;;;;;;;;;;;;;AAeA,MAAa,0BAA0B;CACrC;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;AAMA,MAAa,iBAAiB;;;;;AAM9B,MAAa,qBAAqB;;;;;;;;;;AAWlC,MAAa,qBACX"}
package/dist/styles.css CHANGED
@@ -110,6 +110,30 @@
110
110
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
111
111
 
112
112
  --animate-fill-bar: fill-bar 0.5s var(--ease-out-expo);
113
+ --animate-slide-up-and-fade: slide-up-and-fade 0.5s var(--ease-out-expo);
114
+ --animate-slide-down-and-fade: slide-down-and-fade 0.5s var(--ease-out-expo);
115
+
116
+ @keyframes slide-up-and-fade {
117
+ from {
118
+ opacity: 0;
119
+ transform: translateY(8px);
120
+ }
121
+ to {
122
+ opacity: 1;
123
+ transform: translateY(0);
124
+ }
125
+ }
126
+
127
+ @keyframes slide-down-and-fade {
128
+ from {
129
+ opacity: 0;
130
+ transform: translateY(-8px);
131
+ }
132
+ to {
133
+ opacity: 1;
134
+ transform: translateY(0);
135
+ }
136
+ }
113
137
 
114
138
  @keyframes fill-bar {
115
139
  from {
package/package.json CHANGED
@@ -108,5 +108,5 @@
108
108
  "engines": {
109
109
  "node": ">=18"
110
110
  },
111
- "version": "1.0.0"
111
+ "version": "1.1.0"
112
112
  }