@dirstack/ui 1.0.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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +67 -0
  3. package/dist/components/animated-number.d.ts +18 -0
  4. package/dist/components/animated-number.d.ts.map +1 -0
  5. package/dist/components/animated-number.js +29 -0
  6. package/dist/components/animated-number.js.map +1 -0
  7. package/dist/components/avatar.d.ts +8 -0
  8. package/dist/components/avatar.d.ts.map +1 -0
  9. package/dist/components/avatar.js +27 -0
  10. package/dist/components/avatar.js.map +1 -0
  11. package/dist/components/badge.d.ts +58 -0
  12. package/dist/components/badge.d.ts.map +1 -0
  13. package/dist/components/badge.js +51 -0
  14. package/dist/components/badge.js.map +1 -0
  15. package/dist/components/button.d.ts +63 -0
  16. package/dist/components/button.d.ts.map +1 -0
  17. package/dist/components/button.js +66 -0
  18. package/dist/components/button.js.map +1 -0
  19. package/dist/components/callout.d.ts +41 -0
  20. package/dist/components/callout.d.ts.map +1 -0
  21. package/dist/components/callout.js +49 -0
  22. package/dist/components/callout.js.map +1 -0
  23. package/dist/components/card.d.ts +61 -0
  24. package/dist/components/card.d.ts.map +1 -0
  25. package/dist/components/card.js +67 -0
  26. package/dist/components/card.js.map +1 -0
  27. package/dist/components/chart.d.ts +32 -0
  28. package/dist/components/chart.d.ts.map +1 -0
  29. package/dist/components/chart.js +121 -0
  30. package/dist/components/chart.js.map +1 -0
  31. package/dist/components/copy-button.d.ts +22 -0
  32. package/dist/components/copy-button.d.ts.map +1 -0
  33. package/dist/components/copy-button.js +50 -0
  34. package/dist/components/copy-button.js.map +1 -0
  35. package/dist/components/copy-input.d.ts +13 -0
  36. package/dist/components/copy-input.d.ts.map +1 -0
  37. package/dist/components/copy-input.js +28 -0
  38. package/dist/components/copy-input.js.map +1 -0
  39. package/dist/components/detail-row.d.ts +93 -0
  40. package/dist/components/detail-row.d.ts.map +1 -0
  41. package/dist/components/detail-row.js +69 -0
  42. package/dist/components/detail-row.js.map +1 -0
  43. package/dist/components/dialog.d.ts +173 -0
  44. package/dist/components/dialog.d.ts.map +1 -0
  45. package/dist/components/dialog.js +139 -0
  46. package/dist/components/dialog.js.map +1 -0
  47. package/dist/components/empty-state.d.ts +96 -0
  48. package/dist/components/empty-state.d.ts.map +1 -0
  49. package/dist/components/empty-state.js +69 -0
  50. package/dist/components/empty-state.js.map +1 -0
  51. package/dist/components/entity-avatar.d.ts +77 -0
  52. package/dist/components/entity-avatar.d.ts.map +1 -0
  53. package/dist/components/entity-avatar.js +48 -0
  54. package/dist/components/entity-avatar.js.map +1 -0
  55. package/dist/components/form-row.d.ts +35 -0
  56. package/dist/components/form-row.d.ts.map +1 -0
  57. package/dist/components/form-row.js +46 -0
  58. package/dist/components/form-row.js.map +1 -0
  59. package/dist/components/form-section.d.ts +24 -0
  60. package/dist/components/form-section.d.ts.map +1 -0
  61. package/dist/components/form-section.js +39 -0
  62. package/dist/components/form-section.js.map +1 -0
  63. package/dist/components/form.d.ts +28 -0
  64. package/dist/components/form.d.ts.map +1 -0
  65. package/dist/components/form.js +88 -0
  66. package/dist/components/form.js.map +1 -0
  67. package/dist/components/heading.d.ts +44 -0
  68. package/dist/components/heading.d.ts.map +1 -0
  69. package/dist/components/heading.js +45 -0
  70. package/dist/components/heading.js.map +1 -0
  71. package/dist/components/input.d.ts +55 -0
  72. package/dist/components/input.d.ts.map +1 -0
  73. package/dist/components/input.js +33 -0
  74. package/dist/components/input.js.map +1 -0
  75. package/dist/components/kbd.d.ts +28 -0
  76. package/dist/components/kbd.d.ts.map +1 -0
  77. package/dist/components/kbd.js +31 -0
  78. package/dist/components/kbd.js.map +1 -0
  79. package/dist/components/label.d.ts +21 -0
  80. package/dist/components/label.d.ts.map +1 -0
  81. package/dist/components/label.js +21 -0
  82. package/dist/components/label.js.map +1 -0
  83. package/dist/components/menu.d.ts +22 -0
  84. package/dist/components/menu.d.ts.map +1 -0
  85. package/dist/components/menu.js +73 -0
  86. package/dist/components/menu.js.map +1 -0
  87. package/dist/components/nav-button.d.ts +34 -0
  88. package/dist/components/nav-button.d.ts.map +1 -0
  89. package/dist/components/nav-button.js +70 -0
  90. package/dist/components/nav-button.js.map +1 -0
  91. package/dist/components/nav.d.ts +44 -0
  92. package/dist/components/nav.d.ts.map +1 -0
  93. package/dist/components/nav.js +53 -0
  94. package/dist/components/nav.js.map +1 -0
  95. package/dist/components/number-input.d.ts +18 -0
  96. package/dist/components/number-input.d.ts.map +1 -0
  97. package/dist/components/number-input.js +25 -0
  98. package/dist/components/number-input.js.map +1 -0
  99. package/dist/components/page.d.ts +24 -0
  100. package/dist/components/page.d.ts.map +1 -0
  101. package/dist/components/page.js +24 -0
  102. package/dist/components/page.js.map +1 -0
  103. package/dist/components/pagination.d.ts +17 -0
  104. package/dist/components/pagination.d.ts.map +1 -0
  105. package/dist/components/pagination.js +63 -0
  106. package/dist/components/pagination.js.map +1 -0
  107. package/dist/components/popover.d.ts +8 -0
  108. package/dist/components/popover.d.ts.map +1 -0
  109. package/dist/components/popover.js +24 -0
  110. package/dist/components/popover.js.map +1 -0
  111. package/dist/components/search-input.d.ts +14 -0
  112. package/dist/components/search-input.d.ts.map +1 -0
  113. package/dist/components/search-input.js +36 -0
  114. package/dist/components/search-input.js.map +1 -0
  115. package/dist/components/section-header.d.ts +107 -0
  116. package/dist/components/section-header.d.ts.map +1 -0
  117. package/dist/components/section-header.js +147 -0
  118. package/dist/components/section-header.js.map +1 -0
  119. package/dist/components/select.d.ts +17 -0
  120. package/dist/components/select.d.ts.map +1 -0
  121. package/dist/components/select.js +94 -0
  122. package/dist/components/select.js.map +1 -0
  123. package/dist/components/skeleton.d.ts +5 -0
  124. package/dist/components/skeleton.d.ts.map +1 -0
  125. package/dist/components/skeleton.js +13 -0
  126. package/dist/components/skeleton.js.map +1 -0
  127. package/dist/components/stack.d.ts +54 -0
  128. package/dist/components/stack.d.ts.map +1 -0
  129. package/dist/components/stack.js +46 -0
  130. package/dist/components/stack.js.map +1 -0
  131. package/dist/components/stat-strip.d.ts +38 -0
  132. package/dist/components/stat-strip.d.ts.map +1 -0
  133. package/dist/components/stat-strip.js +57 -0
  134. package/dist/components/stat-strip.js.map +1 -0
  135. package/dist/components/steps.d.ts +19 -0
  136. package/dist/components/steps.d.ts.map +1 -0
  137. package/dist/components/steps.js +29 -0
  138. package/dist/components/steps.js.map +1 -0
  139. package/dist/components/switch.d.ts +6 -0
  140. package/dist/components/switch.d.ts.map +1 -0
  141. package/dist/components/switch.js +17 -0
  142. package/dist/components/switch.js.map +1 -0
  143. package/dist/components/tabs.d.ts +62 -0
  144. package/dist/components/tabs.d.ts.map +1 -0
  145. package/dist/components/tabs.js +64 -0
  146. package/dist/components/tabs.js.map +1 -0
  147. package/dist/components/textarea.d.ts +9 -0
  148. package/dist/components/textarea.d.ts.map +1 -0
  149. package/dist/components/textarea.js +18 -0
  150. package/dist/components/textarea.js.map +1 -0
  151. package/dist/components/toaster.d.ts +6 -0
  152. package/dist/components/toaster.d.ts.map +1 -0
  153. package/dist/components/toaster.js +37 -0
  154. package/dist/components/toaster.js.map +1 -0
  155. package/dist/components/tooltip.d.ts +15 -0
  156. package/dist/components/tooltip.d.ts.map +1 -0
  157. package/dist/components/tooltip.js +41 -0
  158. package/dist/components/tooltip.js.map +1 -0
  159. package/dist/lib/animation.d.ts +12 -0
  160. package/dist/lib/animation.d.ts.map +1 -0
  161. package/dist/lib/animation.js +14 -0
  162. package/dist/lib/animation.js.map +1 -0
  163. package/dist/lib/classes.d.ts +29 -0
  164. package/dist/lib/classes.d.ts.map +1 -0
  165. package/dist/lib/classes.js +39 -0
  166. package/dist/lib/classes.js.map +1 -0
  167. package/dist/lib/icons.d.ts +21 -0
  168. package/dist/lib/icons.d.ts.map +1 -0
  169. package/dist/lib/icons.js +43 -0
  170. package/dist/lib/icons.js.map +1 -0
  171. package/dist/lib/interactive.d.ts +41 -0
  172. package/dist/lib/interactive.d.ts.map +1 -0
  173. package/dist/lib/interactive.js +30 -0
  174. package/dist/lib/interactive.js.map +1 -0
  175. package/dist/lib/slot.d.ts +12 -0
  176. package/dist/lib/slot.d.ts.map +1 -0
  177. package/dist/lib/slot.js +19 -0
  178. package/dist/lib/slot.js.map +1 -0
  179. package/dist/lib/variants.d.ts +3 -0
  180. package/dist/lib/variants.js +3 -0
  181. package/dist/styles.css +169 -0
  182. package/package.json +112 -0
@@ -0,0 +1,173 @@
1
+ import { VariantProps } from "../lib/variants.js";
2
+ import { Button } from "./button.js";
3
+ import { SectionHeader } from "./section-header.js";
4
+ import { ComponentProps, ReactNode } from "react";
5
+ import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
6
+ //#region src/components/dialog.d.ts
7
+ declare const Dialog: typeof Dialog$1.Root;
8
+ declare const DialogTrigger: Dialog$1.Trigger;
9
+ declare const DialogTitle: import("react").ForwardRefExoticComponent<Omit<import("@base-ui/react").AlertDialogTitleProps, "ref"> & import("react").RefAttributes<HTMLHeadingElement>>;
10
+ declare const DialogDescription: import("react").ForwardRefExoticComponent<Omit<import("@base-ui/react").AlertDialogDescriptionProps, "ref"> & import("react").RefAttributes<HTMLParagraphElement>>;
11
+ declare const dialogContentVariants: import("tailwind-variants").TVReturnType<{
12
+ size: {
13
+ xs: "max-w-xs";
14
+ sm: "max-w-sm";
15
+ md: "max-w-md";
16
+ lg: "max-w-lg";
17
+ xl: "max-w-xl";
18
+ "2xl": "max-w-2xl";
19
+ "3xl": "max-w-3xl";
20
+ "4xl": "max-w-4xl";
21
+ "5xl": "max-w-5xl";
22
+ };
23
+ /**
24
+ * Pin the dialog near the top of the viewport instead of centering it, so its height can
25
+ * change without the whole thing jumping. A dialog stacked on top of another one
26
+ * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.
27
+ */
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)]";
31
+ };
32
+ /**
33
+ * Drop the dialog's own padding and gap so sections can run edge to edge and draw their
34
+ * own borders, e.g. a bordered header over a scrolling body over a bordered footer.
35
+ */
36
+ flush: {
37
+ true: "gap-0 p-0";
38
+ false: "gap-6 p-6";
39
+ };
40
+ }, undefined, string[], {
41
+ size: {
42
+ xs: "max-w-xs";
43
+ sm: "max-w-sm";
44
+ md: "max-w-md";
45
+ lg: "max-w-lg";
46
+ xl: "max-w-xl";
47
+ "2xl": "max-w-2xl";
48
+ "3xl": "max-w-3xl";
49
+ "4xl": "max-w-4xl";
50
+ "5xl": "max-w-5xl";
51
+ };
52
+ /**
53
+ * Pin the dialog near the top of the viewport instead of centering it, so its height can
54
+ * change without the whole thing jumping. A dialog stacked on top of another one
55
+ * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.
56
+ */
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)]";
60
+ };
61
+ /**
62
+ * Drop the dialog's own padding and gap so sections can run edge to edge and draw their
63
+ * own borders, e.g. a bordered header over a scrolling body over a bordered footer.
64
+ */
65
+ flush: {
66
+ true: "gap-0 p-0";
67
+ false: "gap-6 p-6";
68
+ };
69
+ }, undefined, import("tailwind-variants").TVReturnTypeLike<{
70
+ size: {
71
+ xs: "max-w-xs";
72
+ sm: "max-w-sm";
73
+ md: "max-w-md";
74
+ lg: "max-w-lg";
75
+ xl: "max-w-xl";
76
+ "2xl": "max-w-2xl";
77
+ "3xl": "max-w-3xl";
78
+ "4xl": "max-w-4xl";
79
+ "5xl": "max-w-5xl";
80
+ };
81
+ /**
82
+ * Pin the dialog near the top of the viewport instead of centering it, so its height can
83
+ * change without the whole thing jumping. A dialog stacked on top of another one
84
+ * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.
85
+ */
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)]";
89
+ };
90
+ /**
91
+ * Drop the dialog's own padding and gap so sections can run edge to edge and draw their
92
+ * own borders, e.g. a bordered header over a scrolling body over a bordered footer.
93
+ */
94
+ flush: {
95
+ true: "gap-0 p-0";
96
+ false: "gap-6 p-6";
97
+ };
98
+ }, undefined>>;
99
+ type DialogContentProps = Omit<Dialog$1.Popup.Props, "className"> & VariantProps<typeof dialogContentVariants> & {
100
+ className?: string;
101
+ /**
102
+ * Hide the close button in the top right corner, for a dialog that must be dismissed
103
+ * through one of its own actions.
104
+ */
105
+ hideClose?: boolean;
106
+ };
107
+ declare function DialogContent({ className, children, size, fixed, flush, hideClose, ...props }: DialogContentProps): import("react").JSX.Element;
108
+ declare const dialogHeaderVariants: import("tailwind-variants").TVReturnType<{
109
+ /**
110
+ * Give the header its own hairline and padding, for a `flush` dialog whose body scrolls
111
+ * under it. The extra right padding clears the dialog's close button.
112
+ */
113
+ bordered: {
114
+ true: "border-b px-6 py-5 pr-14";
115
+ };
116
+ }, undefined, undefined, {
117
+ /**
118
+ * Give the header its own hairline and padding, for a `flush` dialog whose body scrolls
119
+ * under it. The extra right padding clears the dialog's close button.
120
+ */
121
+ bordered: {
122
+ true: "border-b px-6 py-5 pr-14";
123
+ };
124
+ }, undefined, import("tailwind-variants").TVReturnTypeLike<{
125
+ /**
126
+ * Give the header its own hairline and padding, for a `flush` dialog whose body scrolls
127
+ * under it. The extra right padding clears the dialog's close button.
128
+ */
129
+ bordered: {
130
+ true: "border-b px-6 py-5 pr-14";
131
+ };
132
+ }, undefined>>;
133
+ type DialogHeaderProps = Omit<ComponentProps<typeof SectionHeader>, "title" | "description"> & VariantProps<typeof dialogHeaderVariants> & {
134
+ title: ReactNode;
135
+ description?: ReactNode;
136
+ };
137
+ /**
138
+ * The standard dialog heading: a card-scale `SectionHeader` whose title and description are wired to
139
+ * Base UI's `DialogTitle` / `DialogDescription` for accessibility. Extra children render after
140
+ * them.
141
+ */
142
+ declare function DialogHeader({ title, description, bordered, className, children, ...props }: DialogHeaderProps): import("react").JSX.Element;
143
+ declare const dialogFooterVariants: import("tailwind-variants").TVReturnType<{
144
+ /**
145
+ * Give the footer its own hairline and padding, for a `flush` dialog where the body
146
+ * scrolls behind it.
147
+ */
148
+ bordered: {
149
+ true: "border-t px-6 py-4";
150
+ };
151
+ }, undefined, "flex flex-col-reverse flex-wrap gap-x-2 gap-y-4 sm:flex-row sm:justify-end", {
152
+ /**
153
+ * Give the footer its own hairline and padding, for a `flush` dialog where the body
154
+ * scrolls behind it.
155
+ */
156
+ bordered: {
157
+ true: "border-t px-6 py-4";
158
+ };
159
+ }, undefined, import("tailwind-variants").TVReturnTypeLike<{
160
+ /**
161
+ * Give the footer its own hairline and padding, for a `flush` dialog where the body
162
+ * scrolls behind it.
163
+ */
164
+ bordered: {
165
+ true: "border-t px-6 py-4";
166
+ };
167
+ }, undefined>>;
168
+ type DialogFooterProps = ComponentProps<"div"> & VariantProps<typeof dialogFooterVariants>;
169
+ declare function DialogFooter({ className, bordered, ...props }: DialogFooterProps): import("react").JSX.Element;
170
+ declare function DialogClose({ ...props }: ComponentProps<typeof Button>): import("react").JSX.Element;
171
+ //#endregion
172
+ export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger };
173
+ //# sourceMappingURL=dialog.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,139 @@
1
+ "use client";
2
+ import { cn, variants } from "../lib/variants.js";
3
+ import { XIcon } from "../lib/icons.js";
4
+ import { Button } from "./button.js";
5
+ import { SectionHeader, SectionHeaderBody, SectionHeaderDescription, SectionHeaderTitle } from "./section-header.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
8
+ //#region src/components/dialog.tsx
9
+ const Dialog = Dialog$1.Root;
10
+ const DialogTrigger = Dialog$1.Trigger;
11
+ const DialogTitle = Dialog$1.Title;
12
+ const DialogDescription = Dialog$1.Description;
13
+ /** The dashed, blurred backdrop behind the dialog. Rendered by `DialogContent`. */
14
+ function DialogOverlay({ className, ...props }) {
15
+ return /* @__PURE__ */ jsx(Dialog$1.Backdrop, {
16
+ className: cn("fixed inset-0 z-50 bg-dashed backdrop-blur-xs", "data-open:animate-in data-closed:animate-out", "data-open:fade-in-0 data-closed:fade-out-0", className),
17
+ ...props
18
+ });
19
+ }
20
+ const dialogContentVariants = variants({
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",
24
+ "data-open:animate-in data-closed:animate-out",
25
+ "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
+ ],
28
+ variants: {
29
+ size: {
30
+ xs: "max-w-xs",
31
+ sm: "max-w-sm",
32
+ md: "max-w-md",
33
+ lg: "max-w-lg",
34
+ xl: "max-w-xl",
35
+ "2xl": "max-w-2xl",
36
+ "3xl": "max-w-3xl",
37
+ "4xl": "max-w-4xl",
38
+ "5xl": "max-w-5xl"
39
+ },
40
+ /**
41
+ * Pin the dialog near the top of the viewport instead of centering it, so its height can
42
+ * change without the whole thing jumping. A dialog stacked on top of another one
43
+ * (`[[role=dialog]~&]`) sits a little lower still, so both remain visible.
44
+ */
45
+ 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
+ },
49
+ /**
50
+ * Drop the dialog's own padding and gap so sections can run edge to edge and draw their
51
+ * own borders, e.g. a bordered header over a scrolling body over a bordered footer.
52
+ */
53
+ flush: {
54
+ true: "gap-0 p-0",
55
+ false: "gap-6 p-6"
56
+ }
57
+ },
58
+ defaultVariants: {
59
+ size: "md",
60
+ fixed: true,
61
+ flush: false
62
+ }
63
+ });
64
+ function DialogContent({ className, children, size, fixed, flush, hideClose, ...props }) {
65
+ return /* @__PURE__ */ jsxs(Dialog$1.Portal, { children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(Dialog$1.Popup, {
66
+ className: dialogContentVariants({
67
+ size,
68
+ fixed,
69
+ flush,
70
+ className
71
+ }),
72
+ ...props,
73
+ children: [children, !hideClose && /* @__PURE__ */ jsx(Dialog$1.Close, {
74
+ render: /* @__PURE__ */ jsx(Button, {
75
+ variant: "ghost",
76
+ size: "sm",
77
+ "aria-label": "Close",
78
+ prefix: /* @__PURE__ */ jsx(XIcon, {})
79
+ }),
80
+ className: "absolute top-3 right-3"
81
+ })]
82
+ })] });
83
+ }
84
+ const dialogHeaderVariants = variants({ variants: {
85
+ /**
86
+ * Give the header its own hairline and padding, for a `flush` dialog whose body scrolls
87
+ * under it. The extra right padding clears the dialog's close button.
88
+ */
89
+ bordered: { true: "border-b px-6 py-5 pr-14" } } });
90
+ /**
91
+ * The standard dialog heading: a card-scale `SectionHeader` whose title and description are wired to
92
+ * Base UI's `DialogTitle` / `DialogDescription` for accessibility. Extra children render after
93
+ * them.
94
+ */
95
+ function DialogHeader({ title, description, bordered, className, children, ...props }) {
96
+ return /* @__PURE__ */ jsxs(SectionHeader, {
97
+ size: "card",
98
+ className: dialogHeaderVariants({
99
+ bordered,
100
+ className
101
+ }),
102
+ ...props,
103
+ children: [/* @__PURE__ */ jsxs(SectionHeaderBody, { children: [/* @__PURE__ */ jsx(DialogTitle, {
104
+ render: /* @__PURE__ */ jsx(SectionHeaderTitle, {}),
105
+ children: title
106
+ }), description && /* @__PURE__ */ jsx(DialogDescription, {
107
+ render: /* @__PURE__ */ jsx(SectionHeaderDescription, {}),
108
+ children: description
109
+ })] }), children]
110
+ });
111
+ }
112
+ const dialogFooterVariants = variants({
113
+ base: "flex flex-col-reverse flex-wrap gap-x-2 gap-y-4 sm:flex-row sm:justify-end",
114
+ variants: {
115
+ /**
116
+ * Give the footer its own hairline and padding, for a `flush` dialog where the body
117
+ * scrolls behind it.
118
+ */
119
+ bordered: { true: "border-t px-6 py-4" } }
120
+ });
121
+ function DialogFooter({ className, bordered, ...props }) {
122
+ return /* @__PURE__ */ jsx("div", {
123
+ className: dialogFooterVariants({
124
+ bordered,
125
+ className
126
+ }),
127
+ ...props
128
+ });
129
+ }
130
+ function DialogClose({ ...props }) {
131
+ return /* @__PURE__ */ jsx(Dialog$1.Close, { render: /* @__PURE__ */ jsx(Button, {
132
+ variant: "secondary",
133
+ ...props
134
+ }) });
135
+ }
136
+ //#endregion
137
+ export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger };
138
+
139
+ //# sourceMappingURL=dialog.js.map
@@ -0,0 +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"}
@@ -0,0 +1,96 @@
1
+ import { VariantProps } from "../lib/variants.js";
2
+ import { ComponentProps, ReactNode } from "react";
3
+ //#region src/components/empty-state.d.ts
4
+ declare const emptyStateVariants: import("tailwind-variants").TVReturnType<{
5
+ variant: {
6
+ block: {
7
+ root: string;
8
+ title: string;
9
+ description: string;
10
+ action: string;
11
+ };
12
+ inline: {
13
+ root: string;
14
+ title: string;
15
+ action: string;
16
+ };
17
+ dashed: {
18
+ root: string;
19
+ title: string;
20
+ action: string;
21
+ };
22
+ };
23
+ }, {
24
+ root: string;
25
+ icon: string;
26
+ content: string;
27
+ title: string;
28
+ description: string;
29
+ action: string;
30
+ }, undefined, {
31
+ variant: {
32
+ block: {
33
+ root: string;
34
+ title: string;
35
+ description: string;
36
+ action: string;
37
+ };
38
+ inline: {
39
+ root: string;
40
+ title: string;
41
+ action: string;
42
+ };
43
+ dashed: {
44
+ root: string;
45
+ title: string;
46
+ action: string;
47
+ };
48
+ };
49
+ }, {
50
+ root: string;
51
+ icon: string;
52
+ content: string;
53
+ title: string;
54
+ description: string;
55
+ action: string;
56
+ }, import("tailwind-variants").TVReturnTypeLike<{
57
+ variant: {
58
+ block: {
59
+ root: string;
60
+ title: string;
61
+ description: string;
62
+ action: string;
63
+ };
64
+ inline: {
65
+ root: string;
66
+ title: string;
67
+ action: string;
68
+ };
69
+ dashed: {
70
+ root: string;
71
+ title: string;
72
+ action: string;
73
+ };
74
+ };
75
+ }, {
76
+ root: string;
77
+ icon: string;
78
+ content: string;
79
+ title: string;
80
+ description: string;
81
+ action: string;
82
+ }>>;
83
+ type EmptyStateProps = Omit<ComponentProps<"div">, "title"> & VariantProps<typeof emptyStateVariants> & {
84
+ icon?: ReactNode;
85
+ title: ReactNode;
86
+ description?: ReactNode;
87
+ action?: ReactNode;
88
+ };
89
+ /**
90
+ * The one empty state. `block` fills a card or list with a centered icon, title and
91
+ * description; `inline` is a single muted line inside a form section; `dashed` is a
92
+ * short dashed panel that stands in for a missing chart.
93
+ */
94
+ export declare function EmptyState({ icon, title, description, action, variant, className, ...props }: EmptyStateProps): import("react").JSX.Element;
95
+ //#endregion
96
+ //# sourceMappingURL=empty-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.d.ts","names":[],"sources":["../../src/components/empty-state.tsx"],"mappings":";;;cAIM,gDAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAoCnB,kBAAkB,KAAK,kCAC1B,oBAAoB;EAClB,OAAO;EACP,OAAO;EACP,cAAc;EACd,SAAS;;;;;;;wBAQG,aACd,MACA,OACA,aACA,QACA,SACA,cACG,SACF,kCAAe,IAAA"}
@@ -0,0 +1,69 @@
1
+ import { cn, variants } from "../lib/variants.js";
2
+ import { descriptionClasses } from "../lib/classes.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/components/empty-state.tsx
5
+ const emptyStateVariants = variants({
6
+ slots: {
7
+ root: "",
8
+ icon: "flex size-11 items-center justify-center rounded-full bg-muted text-muted-foreground [&_svg]:size-5",
9
+ content: "space-y-1",
10
+ title: "",
11
+ description: descriptionClasses,
12
+ action: ""
13
+ },
14
+ variants: { variant: {
15
+ block: {
16
+ root: "flex flex-col items-center gap-3 px-6 py-12 text-center",
17
+ title: "font-medium text-sm",
18
+ description: "mx-auto max-w-sm",
19
+ action: "mt-1"
20
+ },
21
+ inline: {
22
+ root: "py-5",
23
+ title: "text-muted-foreground text-sm",
24
+ action: "mt-2"
25
+ },
26
+ dashed: {
27
+ root: "bg-dashed flex h-32 items-center justify-center rounded-lg border",
28
+ title: "rounded-md bg-background px-3 py-1.5 text-muted-foreground text-sm",
29
+ action: "mt-2"
30
+ }
31
+ } },
32
+ defaultVariants: { variant: "block" }
33
+ });
34
+ /**
35
+ * The one empty state. `block` fills a card or list with a centered icon, title and
36
+ * description; `inline` is a single muted line inside a form section; `dashed` is a
37
+ * short dashed panel that stands in for a missing chart.
38
+ */
39
+ function EmptyState({ icon, title, description, action, variant, className, ...props }) {
40
+ const styles = emptyStateVariants({ variant });
41
+ return /* @__PURE__ */ jsxs("div", {
42
+ className: cn(styles.root(), className),
43
+ ...props,
44
+ children: [
45
+ icon && /* @__PURE__ */ jsx("div", {
46
+ className: styles.icon(),
47
+ children: icon
48
+ }),
49
+ /* @__PURE__ */ jsxs("div", {
50
+ className: styles.content(),
51
+ children: [/* @__PURE__ */ jsx("p", {
52
+ className: styles.title(),
53
+ children: title
54
+ }), description && /* @__PURE__ */ jsx("p", {
55
+ className: styles.description(),
56
+ children: description
57
+ })]
58
+ }),
59
+ action && /* @__PURE__ */ jsx("div", {
60
+ className: styles.action(),
61
+ children: action
62
+ })
63
+ ]
64
+ });
65
+ }
66
+ //#endregion
67
+ export { EmptyState };
68
+
69
+ //# sourceMappingURL=empty-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"empty-state.js","names":[],"sources":["../../src/components/empty-state.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\"\nimport { descriptionClasses } from \"~/lib/classes\"\nimport { cn, variants, type VariantProps } from \"~/lib/variants\"\n\nconst emptyStateVariants = variants({\n slots: {\n root: \"\",\n icon: \"flex size-11 items-center justify-center rounded-full bg-muted text-muted-foreground [&_svg]:size-5\",\n content: \"space-y-1\",\n title: \"\",\n description: descriptionClasses,\n action: \"\",\n },\n\n variants: {\n variant: {\n block: {\n root: \"flex flex-col items-center gap-3 px-6 py-12 text-center\",\n title: \"font-medium text-sm\",\n description: \"mx-auto max-w-sm\",\n action: \"mt-1\",\n },\n inline: {\n root: \"py-5\",\n title: \"text-muted-foreground text-sm\",\n action: \"mt-2\",\n },\n dashed: {\n root: \"bg-dashed flex h-32 items-center justify-center rounded-lg border\",\n title: \"rounded-md bg-background px-3 py-1.5 text-muted-foreground text-sm\",\n action: \"mt-2\",\n },\n },\n },\n\n defaultVariants: {\n variant: \"block\",\n },\n})\n\ntype EmptyStateProps = Omit<ComponentProps<\"div\">, \"title\"> &\n VariantProps<typeof emptyStateVariants> & {\n icon?: ReactNode\n title: ReactNode\n description?: ReactNode\n action?: ReactNode\n }\n\n/**\n * The one empty state. `block` fills a card or list with a centered icon, title and\n * description; `inline` is a single muted line inside a form section; `dashed` is a\n * short dashed panel that stands in for a missing chart.\n */\nexport function EmptyState({\n icon,\n title,\n description,\n action,\n variant,\n className,\n ...props\n}: EmptyStateProps) {\n const styles = emptyStateVariants({ variant })\n\n return (\n <div className={cn(styles.root(), className)} {...props}>\n {icon && <div className={styles.icon()}>{icon}</div>}\n\n <div className={styles.content()}>\n <p className={styles.title()}>{title}</p>\n {description && <p className={styles.description()}>{description}</p>}\n </div>\n\n {action && <div className={styles.action()}>{action}</div>}\n </div>\n )\n}\n"],"mappings":";;;;AAIA,MAAM,qBAAqB,SAAS;CAClC,OAAO;EACL,MAAM;EACN,MAAM;EACN,SAAS;EACT,OAAO;EACP,aAAa;EACb,QAAQ;CACV;CAEA,UAAU,EACR,SAAS;EACP,OAAO;GACL,MAAM;GACN,OAAO;GACP,aAAa;GACb,QAAQ;EACV;EACA,QAAQ;GACN,MAAM;GACN,OAAO;GACP,QAAQ;EACV;EACA,QAAQ;GACN,MAAM;GACN,OAAO;GACP,QAAQ;EACV;CACF,EACF;CAEA,iBAAiB,EACf,SAAS,QACX;AACF,CAAC;;;;;;AAeD,SAAgB,WAAW,EACzB,MACA,OACA,aACA,QACA,SACA,WACA,GAAG,SACe;CAClB,MAAM,SAAS,mBAAmB,EAAE,QAAQ,CAAC;CAE7C,OACE,qBAAC,OAAD;EAAK,WAAW,GAAG,OAAO,KAAK,GAAG,SAAS;EAAG,GAAI;EAAlD,UAAA;GACG,QAAQ,oBAAC,OAAD;IAAK,WAAW,OAAO,KAAK;IAAI,UAAA;GAAU,CAAA;GAEnD,qBAAC,OAAD;IAAK,WAAW,OAAO,QAAQ;IAA/B,UAAA,CACE,oBAAC,KAAD;KAAG,WAAW,OAAO,MAAM;KAAI,UAAA;IAAS,CAAA,GACvC,eAAe,oBAAC,KAAD;KAAG,WAAW,OAAO,YAAY;KAAI,UAAA;IAAe,CAAA,CACjE;;GAEJ,UAAU,oBAAC,OAAD;IAAK,WAAW,OAAO,OAAO;IAAI,UAAA;GAAY,CAAA;EACtD;;AAET"}
@@ -0,0 +1,77 @@
1
+ import { Avatar } from "./avatar.js";
2
+ import { VariantProps } from "../lib/variants.js";
3
+ import { ComponentProps, ReactNode } from "react";
4
+ //#region src/components/entity-avatar.d.ts
5
+ declare const entityAvatar: import("tailwind-variants").TVReturnType<{
6
+ size: {
7
+ sm: {
8
+ root: string;
9
+ image: string;
10
+ fallback: string;
11
+ };
12
+ md: {
13
+ root: string;
14
+ };
15
+ lg: {
16
+ root: string;
17
+ };
18
+ };
19
+ }, {
20
+ root: string;
21
+ image: string;
22
+ fallback: string;
23
+ }, undefined, {
24
+ size: {
25
+ sm: {
26
+ root: string;
27
+ image: string;
28
+ fallback: string;
29
+ };
30
+ md: {
31
+ root: string;
32
+ };
33
+ lg: {
34
+ root: string;
35
+ };
36
+ };
37
+ }, {
38
+ root: string;
39
+ image: string;
40
+ fallback: string;
41
+ }, import("tailwind-variants").TVReturnTypeLike<{
42
+ size: {
43
+ sm: {
44
+ root: string;
45
+ image: string;
46
+ fallback: string;
47
+ };
48
+ md: {
49
+ root: string;
50
+ };
51
+ lg: {
52
+ root: string;
53
+ };
54
+ };
55
+ }, {
56
+ root: string;
57
+ image: string;
58
+ fallback: string;
59
+ }>>;
60
+ type EntityAvatarProps = Omit<ComponentProps<typeof Avatar>, "className"> & VariantProps<typeof entityAvatar> & {
61
+ className?: string;
62
+ /**
63
+ * The image source (e.g. a favicon URL). When absent, only the fallback renders.
64
+ */
65
+ src?: string | null;
66
+ /**
67
+ * The entity's display name; its initials are the default fallback.
68
+ */
69
+ name: string;
70
+ /**
71
+ * Overrides the initials derived from `name`.
72
+ */
73
+ fallback?: ReactNode;
74
+ };
75
+ export declare function EntityAvatar({ src, name, fallback, size, className, ...props }: EntityAvatarProps): import("react").JSX.Element;
76
+ //#endregion
77
+ //# sourceMappingURL=entity-avatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-avatar.d.ts","names":[],"sources":["../../src/components/entity-avatar.tsx"],"mappings":";;;;cAyBM,0CAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAuBb,oBAAoB,KAAK,sBAAsB,wBAClD,oBAAoB;EAClB;;;;EAKA;;;;EAKA;;;;EAKA,WAAW;;wBAGC,eACd,KACA,MACA,UACA,MACA,cACG,SACF,oCAAiB,IAAA"}
@@ -0,0 +1,48 @@
1
+ import { variants } from "../lib/variants.js";
2
+ import { Avatar, AvatarFallback, AvatarImage } from "./avatar.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/components/entity-avatar.tsx
5
+ /**
6
+ * The initials standing in for a missing image: a name of two characters or less as it is,
7
+ * otherwise the first letter of each word, capped at `max` (uncapped when `max` is 0).
8
+ */
9
+ function getInitials(name, max = 0) {
10
+ const value = name.trim();
11
+ if (value.length <= 2) return value.toUpperCase();
12
+ const initials = value.split(" ").filter(Boolean).map((word) => word.charAt(0).toUpperCase()).join("");
13
+ return max > 0 ? initials.slice(0, max) : initials;
14
+ }
15
+ const entityAvatar = variants({
16
+ slots: {
17
+ root: "rounded-md border",
18
+ image: "p-[7.5%]",
19
+ fallback: ""
20
+ },
21
+ variants: { size: {
22
+ sm: {
23
+ root: "size-5 rounded-sm border-0",
24
+ image: "p-0",
25
+ fallback: "text-[0.625rem]"
26
+ },
27
+ md: { root: "size-9" },
28
+ lg: { root: "size-14" }
29
+ } }
30
+ });
31
+ function EntityAvatar({ src, name, fallback, size, className, ...props }) {
32
+ const styles = entityAvatar({ size });
33
+ return /* @__PURE__ */ jsxs(Avatar, {
34
+ className: styles.root({ className }),
35
+ ...props,
36
+ children: [src && /* @__PURE__ */ jsx(AvatarImage, {
37
+ src,
38
+ className: styles.image()
39
+ }), /* @__PURE__ */ jsx(AvatarFallback, {
40
+ className: styles.fallback(),
41
+ children: fallback ?? getInitials(name, size === "sm" ? 2 : 3)
42
+ })]
43
+ });
44
+ }
45
+ //#endregion
46
+ export { EntityAvatar };
47
+
48
+ //# sourceMappingURL=entity-avatar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entity-avatar.js","names":[],"sources":["../../src/components/entity-avatar.tsx"],"sourcesContent":["import type { ComponentProps, ReactNode } from \"react\"\nimport { Avatar, AvatarFallback, AvatarImage } from \"~/components/avatar\"\nimport { variants, type VariantProps } from \"~/lib/variants\"\n\n/**\n * The initials standing in for a missing image: a name of two characters or less as it is,\n * otherwise the first letter of each word, capped at `max` (uncapped when `max` is 0).\n */\nfunction getInitials(name: string, max = 0) {\n const value = name.trim()\n\n if (value.length <= 2) {\n return value.toUpperCase()\n }\n\n const initials = value\n .split(\" \")\n .filter(Boolean)\n .map(word => word.charAt(0).toUpperCase())\n .join(\"\")\n\n return max > 0 ? initials.slice(0, max) : initials\n}\n\n// Radius lives on the root, which clips its children.\nconst entityAvatar = variants({\n slots: {\n root: \"rounded-md border\",\n image: \"p-[7.5%]\",\n fallback: \"\",\n },\n\n variants: {\n size: {\n // 20px: the identity mark of a nav row or menu item — borderless, flush, two initials.\n sm: {\n root: \"size-5 rounded-sm border-0\",\n image: \"p-0\",\n fallback: \"text-[0.625rem]\",\n },\n // 36px: list rows and cards.\n md: { root: \"size-9\" },\n // 56px: the logo field.\n lg: { root: \"size-14\" },\n },\n },\n})\n\ntype EntityAvatarProps = Omit<ComponentProps<typeof Avatar>, \"className\"> &\n VariantProps<typeof entityAvatar> & {\n className?: string\n\n /**\n * The image source (e.g. a favicon URL). When absent, only the fallback renders.\n */\n src?: string | null\n\n /**\n * The entity's display name; its initials are the default fallback.\n */\n name: string\n\n /**\n * Overrides the initials derived from `name`.\n */\n fallback?: ReactNode\n }\n\nexport function EntityAvatar({\n src,\n name,\n fallback,\n size,\n className,\n ...props\n}: EntityAvatarProps) {\n const styles = entityAvatar({ size })\n\n return (\n <Avatar className={styles.root({ className })} {...props}>\n {src && <AvatarImage src={src} className={styles.image()} />}\n\n <AvatarFallback className={styles.fallback()}>\n {fallback ?? getInitials(name, size === \"sm\" ? 2 : 3)}\n </AvatarFallback>\n </Avatar>\n )\n}\n"],"mappings":";;;;;;;;AAQA,SAAS,YAAY,MAAc,MAAM,GAAG;CAC1C,MAAM,QAAQ,KAAK,KAAK;CAExB,IAAI,MAAM,UAAU,GAClB,OAAO,MAAM,YAAY;CAG3B,MAAM,WAAW,MACd,MAAM,GAAG,CAAC,CACV,OAAO,OAAO,CAAC,CACf,KAAI,SAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CACzC,KAAK,EAAE;CAEV,OAAO,MAAM,IAAI,SAAS,MAAM,GAAG,GAAG,IAAI;AAC5C;AAGA,MAAM,eAAe,SAAS;CAC5B,OAAO;EACL,MAAM;EACN,OAAO;EACP,UAAU;CACZ;CAEA,UAAU,EACR,MAAM;EAEJ,IAAI;GACF,MAAM;GACN,OAAO;GACP,UAAU;EACZ;EAEA,IAAI,EAAE,MAAM,SAAS;EAErB,IAAI,EAAE,MAAM,UAAU;CACxB,EACF;AACF,CAAC;AAsBD,SAAgB,aAAa,EAC3B,KACA,MACA,UACA,MACA,WACA,GAAG,SACiB;CACpB,MAAM,SAAS,aAAa,EAAE,KAAK,CAAC;CAEpC,OACE,qBAAC,QAAD;EAAQ,WAAW,OAAO,KAAK,EAAE,UAAU,CAAC;EAAG,GAAI;EAAnD,UAAA,CACG,OAAO,oBAAC,aAAD;GAAkB;GAAK,WAAW,OAAO,MAAM;EAAI,CAAA,GAE3D,oBAAC,gBAAD;GAAgB,WAAW,OAAO,SAAS;GACxC,UAAA,YAAY,YAAY,MAAM,SAAS,OAAO,IAAI,CAAC;EACtC,CAAA,CACV;;AAEZ"}