@classytic/fluid 0.4.2 → 0.5.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 (51) hide show
  1. package/README.md +21 -1
  2. package/dist/client/calendar.d.mts +1 -2
  3. package/dist/client/calendar.mjs +4 -4
  4. package/dist/client/color-picker.d.mts +41 -25
  5. package/dist/client/color-picker.mjs +121 -73
  6. package/dist/client/core.d.mts +243 -557
  7. package/dist/client/core.mjs +351 -1462
  8. package/dist/client/error.d.mts +41 -41
  9. package/dist/client/error.mjs +35 -35
  10. package/dist/client/gallery.d.mts +33 -33
  11. package/dist/client/gallery.mjs +128 -127
  12. package/dist/client/hooks.d.mts +57 -39
  13. package/dist/client/hooks.mjs +29 -7
  14. package/dist/client/spreadsheet.d.mts +28 -28
  15. package/dist/client/spreadsheet.mjs +77 -77
  16. package/dist/client/table.d.mts +66 -33
  17. package/dist/client/table.mjs +87 -54
  18. package/dist/client/theme.mjs +1 -1
  19. package/dist/command.d.mts +6 -4
  20. package/dist/command.mjs +3 -3
  21. package/dist/compact.d.mts +97 -95
  22. package/dist/compact.mjs +336 -322
  23. package/dist/dashboard.d.mts +614 -422
  24. package/dist/dashboard.mjs +1051 -762
  25. package/dist/{dropdown-wrapper-B86u9Fri.mjs → dropdown-wrapper-B9nRDUlz.mjs} +25 -35
  26. package/dist/forms.d.mts +1037 -972
  27. package/dist/forms.mjs +2849 -2721
  28. package/dist/index.d.mts +218 -152
  29. package/dist/index.mjs +357 -264
  30. package/dist/layouts.d.mts +94 -94
  31. package/dist/layouts.mjs +115 -110
  32. package/dist/phone-input-B9_XPNvv.mjs +429 -0
  33. package/dist/phone-input-CLH_UjQZ.d.mts +31 -0
  34. package/dist/{search-context-DR7DBs7S.mjs → search-context-1g3ZmOvx.mjs} +1 -1
  35. package/dist/search.d.mts +168 -164
  36. package/dist/search.mjs +305 -301
  37. package/dist/{sheet-wrapper-C13Y-Q6w.mjs → sheet-wrapper-B2uxookb.mjs} +1 -1
  38. package/dist/timeline-Bgu1mIe9.d.mts +373 -0
  39. package/dist/timeline-HJtWf4Op.mjs +804 -0
  40. package/dist/{use-base-search-BGgWnWaF.d.mts → use-base-search-DFC4QKYU.d.mts} +1 -1
  41. package/dist/{use-media-query-BnVNIKT4.mjs → use-media-query-ChLfFChU.mjs} +6 -7
  42. package/package.json +2 -2
  43. /package/dist/{api-pagination-CJ0vR_w6.d.mts → api-pagination-C30ser2L.d.mts} +0 -0
  44. /package/dist/{filter-utils-DqMmy_v-.mjs → filter-utils-BGIvtq1R.mjs} +0 -0
  45. /package/dist/{filter-utils-IZ0GtuPo.d.mts → filter-utils-DOFTBWm1.d.mts} +0 -0
  46. /package/dist/{use-debounce-xmZucz5e.mjs → use-debounce-BNoNiEon.mjs} +0 -0
  47. /package/dist/{use-keyboard-shortcut-Bl6YM5Q7.mjs → use-keyboard-shortcut-C_Vk-36P.mjs} +0 -0
  48. /package/dist/{use-keyboard-shortcut-_mRCh3QO.d.mts → use-keyboard-shortcut-Q4CSPzSI.d.mts} +0 -0
  49. /package/dist/{use-mobile-BX3SQVo2.mjs → use-mobile-CnEmFiQx.mjs} +0 -0
  50. /package/dist/{use-scroll-detection-CsgsQYvy.mjs → use-scroll-detection-BKfqkmEC.mjs} +0 -0
  51. /package/dist/{utils-CDue7cEt.d.mts → utils-rqvYP1by.d.mts} +0 -0
package/dist/index.mjs CHANGED
@@ -1,54 +1,25 @@
1
1
  import { t as cn } from "./utils-DQ5SCVoW.mjs";
2
- import { a as getApiParams, i as clearSearchAndFilterParams, n as buildListingStatusParams, r as buildSearchParams, t as buildFilterParams } from "./filter-utils-DqMmy_v-.mjs";
2
+ import { S as FaqAccordion, _ as DataCard, a as PillButton, c as PillIndicator, g as CardWrapper, h as DetailView, l as PillStatus, m as DetailItem, n as Pill, o as PillDelta, r as PillAvatar, t as Timeline, u as InfoRow, x as AccordionSection, y as LoadingCard } from "./timeline-HJtWf4Op.mjs";
3
+ import { a as getApiParams, i as clearSearchAndFilterParams, n as buildListingStatusParams, r as buildSearchParams, t as buildFilterParams } from "./filter-utils-BGIvtq1R.mjs";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
- import { Skeleton } from "@/components/ui/skeleton";
5
- import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
6
- import "react";
7
5
  import { FileX2, InboxIcon, Loader2, SearchX } from "lucide-react";
8
6
  import { Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle } from "@/components/ui/empty";
7
+ import { Skeleton } from "@/components/ui/skeleton";
8
+ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
9
9
 
10
- //#region src/layout/section.tsx
11
- const backgrounds = {
12
- default: "bg-background",
13
- muted: "bg-muted",
14
- primary: "bg-primary text-primary-foreground",
15
- transparent: "bg-transparent"
16
- };
17
- const paddings = {
18
- none: "",
19
- sm: "py-8 md:py-12",
20
- md: "py-12 md:py-16",
21
- lg: "py-16 md:py-24",
22
- xl: "py-24 md:py-32"
23
- };
24
- function Section({ id, children, className, background = "default", padding = "sm" }) {
25
- return /* @__PURE__ */ jsx("section", {
26
- id,
27
- className: cn(backgrounds[background], paddings[padding], className),
28
- children
29
- });
30
- }
31
-
32
- //#endregion
33
- //#region src/layout/container.tsx
34
- const maxWidthClasses = {
35
- sm: "max-w-screen-sm",
36
- md: "max-w-screen-md",
37
- lg: "max-w-screen-lg",
38
- xl: "max-w-screen-xl",
39
- "2xl": "max-w-screen-2xl",
40
- "3xl": "max-w-3xl",
41
- "4xl": "max-w-4xl",
42
- "5xl": "max-w-5xl",
43
- "6xl": "max-w-6xl",
44
- "7xl": "max-w-7xl",
45
- full: "max-w-full"
46
- };
47
- function Container({ children, className, maxWidth = "7xl" }) {
48
- const isFullWidth = maxWidth === "full";
49
- return /* @__PURE__ */ jsx("div", {
50
- className: cn(isFullWidth ? "w-full px-4 sm:px-6 lg:px-10" : "mx-auto px-4 sm:px-6 lg:px-8", !isFullWidth && maxWidthClasses[maxWidth], className),
51
- children
10
+ //#region src/components/detail-field.tsx
11
+ function DetailField({ label, value, placeholder = "-", className, labelClassName, valueClassName, children }) {
12
+ const content = children ?? value;
13
+ const isEmpty = content === void 0 || content === null || content === "";
14
+ return /* @__PURE__ */ jsxs("div", {
15
+ className: cn("space-y-1", className),
16
+ children: [/* @__PURE__ */ jsx("dt", {
17
+ className: cn("text-xs font-medium uppercase tracking-wide text-muted-foreground", labelClassName),
18
+ children: label
19
+ }), /* @__PURE__ */ jsx("dd", {
20
+ className: cn("text-sm font-semibold", isEmpty ? "text-muted-foreground/50" : "text-foreground", valueClassName),
21
+ children: isEmpty ? placeholder : content
22
+ })]
52
23
  });
53
24
  }
54
25
 
@@ -95,155 +66,109 @@ function DisplayHeading({ children, size = "xl", align = "center", className, hi
95
66
  }
96
67
 
97
68
  //#endregion
98
- //#region src/components/social-icons.tsx
99
- const FacebookIcon = () => /* @__PURE__ */ jsx("svg", {
100
- xmlns: "http://www.w3.org/2000/svg",
101
- width: "18",
102
- height: "18",
103
- viewBox: "0 0 24 24",
104
- fill: "none",
105
- stroke: "currentColor",
106
- strokeWidth: "2",
107
- strokeLinecap: "round",
108
- strokeLinejoin: "round",
109
- children: /* @__PURE__ */ jsx("path", { d: "M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z" })
110
- });
111
- const GoogleIcon = () => /* @__PURE__ */ jsxs("svg", {
112
- xmlns: "http://www.w3.org/2000/svg",
113
- width: "18",
114
- height: "18",
115
- viewBox: "0 0 24 24",
116
- fill: "currentColor",
117
- children: [
118
- /* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" }),
119
- /* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }),
120
- /* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" }),
121
- /* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })
122
- ]
123
- });
124
- const TwitterXIcon = () => /* @__PURE__ */ jsx("svg", {
125
- xmlns: "http://www.w3.org/2000/svg",
126
- viewBox: "0 0 1200 1227",
127
- width: "18",
128
- height: "18",
129
- fill: "currentColor",
130
- children: /* @__PURE__ */ jsx("path", { d: "M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z" })
131
- });
132
- const InstagramIcon = () => /* @__PURE__ */ jsxs("svg", {
133
- xmlns: "http://www.w3.org/2000/svg",
134
- width: "18",
135
- height: "18",
136
- viewBox: "0 0 24 24",
137
- fill: "none",
138
- stroke: "currentColor",
139
- strokeWidth: "2",
140
- strokeLinecap: "round",
141
- strokeLinejoin: "round",
142
- children: [
143
- /* @__PURE__ */ jsx("rect", {
144
- x: "2",
145
- y: "2",
146
- width: "20",
147
- height: "20",
148
- rx: "5",
149
- ry: "5"
150
- }),
151
- /* @__PURE__ */ jsx("path", { d: "M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" }),
152
- /* @__PURE__ */ jsx("line", {
153
- x1: "17.5",
154
- y1: "6.5",
155
- x2: "17.51",
156
- y2: "6.5"
157
- })
158
- ]
159
- });
160
- const WhatsAppIcon = () => /* @__PURE__ */ jsx("svg", {
161
- viewBox: "0 0 24 24",
162
- fill: "currentColor",
163
- width: "18",
164
- height: "18",
165
- children: /* @__PURE__ */ jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" })
166
- });
167
-
168
- //#endregion
169
- //#region src/components/skeleton-wrappers.tsx
69
+ //#region src/components/empty-state.tsx
70
+ const PRESETS = {
71
+ noResults: {
72
+ icon: /* @__PURE__ */ jsx(SearchX, { className: "h-6 w-6" }),
73
+ title: "No results found",
74
+ description: "Try adjusting your search or filter criteria."
75
+ },
76
+ noData: {
77
+ icon: /* @__PURE__ */ jsx(InboxIcon, { className: "h-6 w-6" }),
78
+ title: "No data yet",
79
+ description: "Get started by creating your first item."
80
+ },
81
+ notFound: {
82
+ icon: /* @__PURE__ */ jsx(FileX2, { className: "h-6 w-6" }),
83
+ title: "Not found",
84
+ description: "The item you're looking for doesn't exist or has been removed."
85
+ }
86
+ };
170
87
  /**
171
- * SkeletonTable - Loading skeleton for tables
172
- * Matches DataTable structure for consistent loading states
88
+ * EmptyState — Higher-level wrapper around the composable Empty primitives.
173
89
  *
174
- * @example
90
+ * Composes: Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent
91
+ *
92
+ * @example Default
175
93
  * ```tsx
176
- * <SkeletonTable rows={5} columns={4} />
177
- * <SkeletonTable headers={["Name", "Email", "Status"]} rows={10} />
94
+ * <EmptyState
95
+ * title="No projects yet"
96
+ * description="Create your first project to get started."
97
+ * icon={<FolderPlus className="h-6 w-6" />}
98
+ * action={<Button>Create Project</Button>}
99
+ * />
178
100
  * ```
179
- */
180
- function SkeletonTable({ rows = 5, columns = 6, headers, className }) {
181
- const columnCount = headers?.length || columns;
182
- return /* @__PURE__ */ jsx("div", {
183
- className: cn("rounded-md border", className),
184
- children: /* @__PURE__ */ jsxs(Table, { children: [/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: headers ? headers.map((header, i) => /* @__PURE__ */ jsx(TableHead, { children: header }, i)) : Array.from({ length: columnCount }).map((_, i) => /* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }) }, i)) }) }), /* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: rows }).map((_, rowIndex) => /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: columnCount }).map((_, colIndex) => /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }) }, colIndex)) }, rowIndex)) })] })
185
- });
186
- }
187
- /**
188
- * SkeletonList - Compact skeleton for lists with avatars
189
101
  *
190
- * @example
102
+ * @example Compact (inline)
191
103
  * ```tsx
192
- * <SkeletonList items={5} />
193
- * <SkeletonList items={3} showAvatar={false} />
104
+ * <EmptyState variant="compact" title="No items" />
194
105
  * ```
195
- */
196
- function SkeletonList({ items = 3, className, showAvatar = true, avatarShape = "circle" }) {
197
- return /* @__PURE__ */ jsx("div", {
198
- className: cn("space-y-3", className),
199
- children: Array.from({ length: items }).map((_, i) => /* @__PURE__ */ jsxs("div", {
200
- className: "flex items-center gap-3",
201
- children: [showAvatar && /* @__PURE__ */ jsx(Skeleton, { className: cn("h-10 w-10 flex-shrink-0", avatarShape === "circle" ? "rounded-full" : "rounded-md") }), /* @__PURE__ */ jsxs("div", {
202
- className: "flex-1 space-y-2",
203
- children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-3/4" })]
204
- })]
205
- }, i))
206
- });
207
- }
208
- /**
209
- * SkeletonCard - Card skeleton for grid layouts
210
106
  *
211
- * @example
107
+ * @example With preset
212
108
  * ```tsx
213
- * <SkeletonCard />
214
- * <SkeletonCard showActions={false} lines={2} />
109
+ * <EmptyStateNoResults action={<Button onClick={clearFilters}>Clear filters</Button>} />
215
110
  * ```
216
111
  */
217
- function SkeletonCard({ className, showActions = true, lines = 3 }) {
218
- return /* @__PURE__ */ jsxs("div", {
219
- className: cn("rounded-lg border p-4 space-y-3", className),
112
+ function EmptyState({ title = "Nothing here", description, icon = /* @__PURE__ */ jsx(InboxIcon, { className: "h-6 w-6" }), action, secondaryAction, variant = "default", className, children }) {
113
+ if (variant === "compact") return /* @__PURE__ */ jsxs("div", {
114
+ "data-slot": "empty-state",
115
+ className: cn("flex items-center gap-3 py-6 px-4 text-muted-foreground", className),
220
116
  children: [
221
- /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-3/4" }),
222
- Array.from({ length: lines - 1 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: cn("h-4", i === lines - 2 ? "w-5/6" : "w-full") }, i)),
223
- showActions && /* @__PURE__ */ jsxs("div", {
224
- className: "flex gap-2 pt-2",
225
- children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" })]
226
- })
117
+ icon && /* @__PURE__ */ jsx("div", {
118
+ className: "flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
119
+ children: icon
120
+ }),
121
+ /* @__PURE__ */ jsxs("div", {
122
+ className: "flex-1 min-w-0",
123
+ children: [/* @__PURE__ */ jsx("p", {
124
+ className: "text-sm font-medium",
125
+ children: title
126
+ }), description && /* @__PURE__ */ jsx("p", {
127
+ className: "text-xs text-muted-foreground/80 mt-0.5",
128
+ children: description
129
+ })]
130
+ }),
131
+ action
132
+ ]
133
+ });
134
+ return /* @__PURE__ */ jsxs(Empty, {
135
+ className: cn(variant === "card" && "border border-dashed", className),
136
+ children: [
137
+ /* @__PURE__ */ jsxs(EmptyHeader, { children: [
138
+ icon && /* @__PURE__ */ jsx(EmptyMedia, {
139
+ variant: "icon",
140
+ children: icon
141
+ }),
142
+ /* @__PURE__ */ jsx(EmptyTitle, { children: title }),
143
+ description && /* @__PURE__ */ jsx(EmptyDescription, { children: description })
144
+ ] }),
145
+ children && /* @__PURE__ */ jsx(EmptyContent, { children }),
146
+ (action || secondaryAction) && /* @__PURE__ */ jsx(EmptyContent, { children: /* @__PURE__ */ jsxs("div", {
147
+ className: "flex items-center gap-3",
148
+ children: [action, secondaryAction]
149
+ }) })
227
150
  ]
228
151
  });
229
152
  }
230
- /**
231
- * SkeletonGrid - Grid of skeleton cards
232
- *
233
- * @example
234
- * ```tsx
235
- * <SkeletonGrid cards={6} columns={3} />
236
- * ```
237
- */
238
- function SkeletonGrid({ cards = 6, columns = 3, className, cardProps }) {
239
- return /* @__PURE__ */ jsx("div", {
240
- className: cn("grid gap-4", {
241
- 1: "grid-cols-1",
242
- 2: "grid-cols-1 sm:grid-cols-2",
243
- 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
244
- 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
245
- }[columns], className),
246
- children: Array.from({ length: cards }).map((_, i) => /* @__PURE__ */ jsx(SkeletonCard, { ...cardProps }, i))
153
+ /** No search results — with search icon */
154
+ function EmptyStateNoResults(props) {
155
+ return /* @__PURE__ */ jsx(EmptyState, {
156
+ ...PRESETS.noResults,
157
+ ...props
158
+ });
159
+ }
160
+ /** No data — with inbox icon */
161
+ function EmptyStateNoData(props) {
162
+ return /* @__PURE__ */ jsx(EmptyState, {
163
+ ...PRESETS.noData,
164
+ ...props
165
+ });
166
+ }
167
+ /** Not found — with file-x icon */
168
+ function EmptyStateNotFound(props) {
169
+ return /* @__PURE__ */ jsx(EmptyState, {
170
+ ...PRESETS.notFound,
171
+ ...props
247
172
  });
248
173
  }
249
174
 
@@ -281,10 +206,14 @@ function LoadingState({ text, variant = "default", size = "md", className }) {
281
206
  const spinner = /* @__PURE__ */ jsx(Loader2, { className: cn(SIZES[size], "animate-spin text-muted-foreground") });
282
207
  if (variant === "minimal") return /* @__PURE__ */ jsx("div", {
283
208
  className: cn("flex items-center justify-center", className),
209
+ role: "status",
210
+ "aria-live": "polite",
284
211
  children: spinner
285
212
  });
286
213
  if (variant === "inline") return /* @__PURE__ */ jsxs("div", {
287
214
  className: cn("flex items-center gap-2 text-muted-foreground", className),
215
+ role: "status",
216
+ "aria-live": "polite",
288
217
  children: [spinner, text && /* @__PURE__ */ jsx("span", {
289
218
  className: TEXT_SIZES[size],
290
219
  children: text
@@ -292,6 +221,8 @@ function LoadingState({ text, variant = "default", size = "md", className }) {
292
221
  });
293
222
  return /* @__PURE__ */ jsxs("div", {
294
223
  className: cn("flex flex-col items-center justify-center gap-3 py-12 px-6", className),
224
+ role: "status",
225
+ "aria-live": "polite",
295
226
  children: [spinner, text && /* @__PURE__ */ jsx("p", {
296
227
  className: cn("text-muted-foreground", TEXT_SIZES[size]),
297
228
  children: text
@@ -322,111 +253,273 @@ function LoadingOverlay({ text, visible = true, className, children }) {
322
253
  }
323
254
 
324
255
  //#endregion
325
- //#region src/components/empty-state.tsx
326
- const PRESETS = {
327
- noResults: {
328
- icon: /* @__PURE__ */ jsx(SearchX, { className: "h-6 w-6" }),
329
- title: "No results found",
330
- description: "Try adjusting your search or filter criteria."
331
- },
332
- noData: {
333
- icon: /* @__PURE__ */ jsx(InboxIcon, { className: "h-6 w-6" }),
334
- title: "No data yet",
335
- description: "Get started by creating your first item."
336
- },
337
- notFound: {
338
- icon: /* @__PURE__ */ jsx(FileX2, { className: "h-6 w-6" }),
339
- title: "Not found",
340
- description: "The item you're looking for doesn't exist or has been removed."
341
- }
342
- };
256
+ //#region src/components/skeleton-wrappers.tsx
343
257
  /**
344
- * EmptyState — Higher-level wrapper around the composable Empty primitives.
345
- *
346
- * Composes: Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent
258
+ * SkeletonTable - Loading skeleton for tables
259
+ * Matches DataTable structure for consistent loading states
347
260
  *
348
- * @example Default
261
+ * @example
349
262
  * ```tsx
350
- * <EmptyState
351
- * title="No projects yet"
352
- * description="Create your first project to get started."
353
- * icon={<FolderPlus className="h-6 w-6" />}
354
- * action={<Button>Create Project</Button>}
355
- * />
263
+ * <SkeletonTable rows={5} columns={4} />
264
+ * <SkeletonTable headers={["Name", "Email", "Status"]} rows={10} />
356
265
  * ```
266
+ */
267
+ function SkeletonTable({ rows = 5, columns = 6, headers, className }) {
268
+ const columnCount = headers?.length || columns;
269
+ return /* @__PURE__ */ jsx("div", {
270
+ className: cn("rounded-md border", className),
271
+ children: /* @__PURE__ */ jsxs(Table, { children: [/* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsx(TableRow, { children: headers ? headers.map((header, i) => /* @__PURE__ */ jsx(TableHead, { children: header }, i)) : Array.from({ length: columnCount }).map((_, i) => /* @__PURE__ */ jsx(TableHead, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }) }, i)) }) }), /* @__PURE__ */ jsx(TableBody, { children: Array.from({ length: rows }).map((_, rowIndex) => /* @__PURE__ */ jsx(TableRow, { children: Array.from({ length: columnCount }).map((_, colIndex) => /* @__PURE__ */ jsx(TableCell, { children: /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }) }, colIndex)) }, rowIndex)) })] })
272
+ });
273
+ }
274
+ /**
275
+ * SkeletonList - Compact skeleton for lists with avatars
357
276
  *
358
- * @example Compact (inline)
277
+ * @example
359
278
  * ```tsx
360
- * <EmptyState variant="compact" title="No items" />
279
+ * <SkeletonList items={5} />
280
+ * <SkeletonList items={3} showAvatar={false} />
361
281
  * ```
282
+ */
283
+ function SkeletonList({ items = 3, className, showAvatar = true, avatarShape = "circle" }) {
284
+ return /* @__PURE__ */ jsx("div", {
285
+ className: cn("space-y-3", className),
286
+ children: Array.from({ length: items }).map((_, i) => /* @__PURE__ */ jsxs("div", {
287
+ className: "flex items-center gap-3",
288
+ children: [showAvatar && /* @__PURE__ */ jsx(Skeleton, { className: cn("h-10 w-10 flex-shrink-0", avatarShape === "circle" ? "rounded-full" : "rounded-md") }), /* @__PURE__ */ jsxs("div", {
289
+ className: "flex-1 space-y-2",
290
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-3/4" })]
291
+ })]
292
+ }, i))
293
+ });
294
+ }
295
+ /**
296
+ * SkeletonCard - Card skeleton for grid layouts
362
297
  *
363
- * @example With preset
298
+ * @example
364
299
  * ```tsx
365
- * <EmptyStateNoResults action={<Button onClick={clearFilters}>Clear filters</Button>} />
300
+ * <SkeletonCard />
301
+ * <SkeletonCard showActions={false} lines={2} />
366
302
  * ```
367
303
  */
368
- function EmptyState({ title = "Nothing here", description, icon = /* @__PURE__ */ jsx(InboxIcon, { className: "h-6 w-6" }), action, secondaryAction, variant = "default", className, children }) {
369
- if (variant === "compact") return /* @__PURE__ */ jsxs("div", {
370
- "data-slot": "empty-state",
371
- className: cn("flex items-center gap-3 py-6 px-4 text-muted-foreground", className),
304
+ function SkeletonCard({ className, showActions = true, lines = 3 }) {
305
+ return /* @__PURE__ */ jsxs("div", {
306
+ className: cn("rounded-lg border p-4 space-y-3", className),
372
307
  children: [
373
- icon && /* @__PURE__ */ jsx("div", {
374
- className: "flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
375
- children: icon
376
- }),
377
- /* @__PURE__ */ jsxs("div", {
378
- className: "flex-1 min-w-0",
379
- children: [/* @__PURE__ */ jsx("p", {
380
- className: "text-sm font-medium",
381
- children: title
382
- }), description && /* @__PURE__ */ jsx("p", {
383
- className: "text-xs text-muted-foreground/80 mt-0.5",
384
- children: description
385
- })]
386
- }),
387
- action
308
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-3/4" }),
309
+ Array.from({ length: lines - 1 }).map((_, i) => /* @__PURE__ */ jsx(Skeleton, { className: cn("h-4", i === lines - 2 ? "w-5/6" : "w-full") }, i)),
310
+ showActions && /* @__PURE__ */ jsxs("div", {
311
+ className: "flex gap-2 pt-2",
312
+ children: [/* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" }), /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" })]
313
+ })
388
314
  ]
389
315
  });
390
- return /* @__PURE__ */ jsxs(Empty, {
391
- className: cn(variant === "card" && "border border-dashed", className),
392
- children: [
393
- /* @__PURE__ */ jsxs(EmptyHeader, { children: [
394
- icon && /* @__PURE__ */ jsx(EmptyMedia, {
395
- variant: "icon",
396
- children: icon
397
- }),
398
- /* @__PURE__ */ jsx(EmptyTitle, { children: title }),
399
- description && /* @__PURE__ */ jsx(EmptyDescription, { children: description })
400
- ] }),
401
- children && /* @__PURE__ */ jsx(EmptyContent, { children }),
402
- (action || secondaryAction) && /* @__PURE__ */ jsx(EmptyContent, { children: /* @__PURE__ */ jsxs("div", {
403
- className: "flex items-center gap-3",
404
- children: [action, secondaryAction]
405
- }) })
406
- ]
316
+ }
317
+ /**
318
+ * SkeletonGrid - Grid of skeleton cards
319
+ *
320
+ * @example
321
+ * ```tsx
322
+ * <SkeletonGrid cards={6} columns={3} />
323
+ * ```
324
+ */
325
+ function SkeletonGrid({ cards = 6, columns = 3, className, cardProps }) {
326
+ return /* @__PURE__ */ jsx("div", {
327
+ className: cn("grid gap-4", {
328
+ 1: "grid-cols-1",
329
+ 2: "grid-cols-1 sm:grid-cols-2",
330
+ 3: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3",
331
+ 4: "grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"
332
+ }[columns], className),
333
+ children: Array.from({ length: cards }).map((_, i) => /* @__PURE__ */ jsx(SkeletonCard, { ...cardProps }, i))
407
334
  });
408
335
  }
409
- /** No search results — with search icon */
410
- function EmptyStateNoResults(props) {
411
- return /* @__PURE__ */ jsx(EmptyState, {
412
- ...PRESETS.noResults,
413
- ...props
336
+
337
+ //#endregion
338
+ //#region src/components/social-icons.tsx
339
+ const FacebookIcon = () => /* @__PURE__ */ jsx("svg", {
340
+ xmlns: "http://www.w3.org/2000/svg",
341
+ width: "18",
342
+ height: "18",
343
+ viewBox: "0 0 24 24",
344
+ fill: "none",
345
+ stroke: "currentColor",
346
+ strokeWidth: "2",
347
+ strokeLinecap: "round",
348
+ strokeLinejoin: "round",
349
+ children: /* @__PURE__ */ jsx("path", { d: "M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z" })
350
+ });
351
+ const GoogleIcon = () => /* @__PURE__ */ jsxs("svg", {
352
+ xmlns: "http://www.w3.org/2000/svg",
353
+ width: "18",
354
+ height: "18",
355
+ viewBox: "0 0 24 24",
356
+ fill: "currentColor",
357
+ children: [
358
+ /* @__PURE__ */ jsx("path", { d: "M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z" }),
359
+ /* @__PURE__ */ jsx("path", { d: "M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" }),
360
+ /* @__PURE__ */ jsx("path", { d: "M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" }),
361
+ /* @__PURE__ */ jsx("path", { d: "M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" })
362
+ ]
363
+ });
364
+ const TwitterXIcon = () => /* @__PURE__ */ jsx("svg", {
365
+ xmlns: "http://www.w3.org/2000/svg",
366
+ viewBox: "0 0 1200 1227",
367
+ width: "18",
368
+ height: "18",
369
+ fill: "currentColor",
370
+ children: /* @__PURE__ */ jsx("path", { d: "M714.163 519.284L1160.89 0H1055.03L667.137 450.887L357.328 0H0L468.492 681.821L0 1226.37H105.866L515.491 750.218L842.672 1226.37H1200L714.137 519.284H714.163ZM569.165 687.828L521.697 619.934L144.011 79.6944H306.615L611.412 515.685L658.88 583.579L1055.08 1150.3H892.476L569.165 687.854V687.828Z" })
371
+ });
372
+ const InstagramIcon = () => /* @__PURE__ */ jsxs("svg", {
373
+ xmlns: "http://www.w3.org/2000/svg",
374
+ width: "18",
375
+ height: "18",
376
+ viewBox: "0 0 24 24",
377
+ fill: "none",
378
+ stroke: "currentColor",
379
+ strokeWidth: "2",
380
+ strokeLinecap: "round",
381
+ strokeLinejoin: "round",
382
+ children: [
383
+ /* @__PURE__ */ jsx("rect", {
384
+ x: "2",
385
+ y: "2",
386
+ width: "20",
387
+ height: "20",
388
+ rx: "5",
389
+ ry: "5"
390
+ }),
391
+ /* @__PURE__ */ jsx("path", { d: "M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" }),
392
+ /* @__PURE__ */ jsx("line", {
393
+ x1: "17.5",
394
+ y1: "6.5",
395
+ x2: "17.51",
396
+ y2: "6.5"
397
+ })
398
+ ]
399
+ });
400
+ const WhatsAppIcon = () => /* @__PURE__ */ jsx("svg", {
401
+ viewBox: "0 0 24 24",
402
+ fill: "currentColor",
403
+ width: "18",
404
+ height: "18",
405
+ children: /* @__PURE__ */ jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" })
406
+ });
407
+
408
+ //#endregion
409
+ //#region src/components/stats-grid.tsx
410
+ const COL_CLASSES = {
411
+ 1: "grid-cols-1",
412
+ 2: "grid-cols-2",
413
+ 3: "grid-cols-3",
414
+ 4: "grid-cols-4"
415
+ };
416
+ const SM_COL_CLASSES = {
417
+ 1: "sm:grid-cols-1",
418
+ 2: "sm:grid-cols-2",
419
+ 3: "sm:grid-cols-3",
420
+ 4: "sm:grid-cols-4"
421
+ };
422
+ const MD_COL_CLASSES = {
423
+ 1: "md:grid-cols-1",
424
+ 2: "md:grid-cols-2",
425
+ 3: "md:grid-cols-3",
426
+ 4: "md:grid-cols-4"
427
+ };
428
+ const LG_COL_CLASSES = {
429
+ 1: "lg:grid-cols-1",
430
+ 2: "lg:grid-cols-2",
431
+ 3: "lg:grid-cols-3",
432
+ 4: "lg:grid-cols-4"
433
+ };
434
+ const GAP_CLASSES = {
435
+ sm: "gap-3",
436
+ default: "gap-4",
437
+ lg: "gap-6"
438
+ };
439
+ function StatsGrid({ columns = {}, gap = "default", className, children }) {
440
+ const { default: defaultCols = 1, sm = 2, md, lg = 4 } = columns;
441
+ return /* @__PURE__ */ jsx("div", {
442
+ className: cn("grid", COL_CLASSES[defaultCols], SM_COL_CLASSES[sm], md && MD_COL_CLASSES[md], LG_COL_CLASSES[lg], GAP_CLASSES[gap], className),
443
+ children
414
444
  });
415
445
  }
416
- /** No data — with inbox icon */
417
- function EmptyStateNoData(props) {
418
- return /* @__PURE__ */ jsx(EmptyState, {
419
- ...PRESETS.noData,
420
- ...props
446
+
447
+ //#endregion
448
+ //#region src/components/status-badge.tsx
449
+ const VARIANT_CLASSES = {
450
+ info: "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300",
451
+ success: "bg-emerald-100 text-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-300",
452
+ warning: "bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300",
453
+ error: "bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300",
454
+ neutral: "bg-muted text-muted-foreground"
455
+ };
456
+ const DOT_CLASSES = {
457
+ info: "bg-blue-500",
458
+ success: "bg-emerald-500",
459
+ warning: "bg-amber-500",
460
+ error: "bg-red-500",
461
+ neutral: "bg-muted-foreground/50"
462
+ };
463
+ const SIZE_CLASSES = {
464
+ sm: "text-[11px] px-1.5 py-0 leading-5",
465
+ default: "text-xs px-2 py-0.5",
466
+ lg: "text-sm px-2.5 py-1"
467
+ };
468
+ function StatusBadge({ variant = "neutral", dot = false, size = "default", className, children }) {
469
+ return /* @__PURE__ */ jsxs("span", {
470
+ className: cn("inline-flex items-center gap-1.5 rounded-full font-medium whitespace-nowrap", VARIANT_CLASSES[variant], SIZE_CLASSES[size], className),
471
+ children: [dot && /* @__PURE__ */ jsx("span", {
472
+ className: cn("size-1.5 rounded-full shrink-0", DOT_CLASSES[variant]),
473
+ "aria-hidden": "true"
474
+ }), children]
421
475
  });
422
476
  }
423
- /** Not found — with file-x icon */
424
- function EmptyStateNotFound(props) {
425
- return /* @__PURE__ */ jsx(EmptyState, {
426
- ...PRESETS.notFound,
427
- ...props
477
+
478
+ //#endregion
479
+ //#region src/layout/container.tsx
480
+ const maxWidthClasses = {
481
+ sm: "max-w-screen-sm",
482
+ md: "max-w-screen-md",
483
+ lg: "max-w-screen-lg",
484
+ xl: "max-w-screen-xl",
485
+ "2xl": "max-w-screen-2xl",
486
+ "3xl": "max-w-3xl",
487
+ "4xl": "max-w-4xl",
488
+ "5xl": "max-w-5xl",
489
+ "6xl": "max-w-6xl",
490
+ "7xl": "max-w-7xl",
491
+ full: "max-w-full"
492
+ };
493
+ function Container({ children, className, maxWidth = "7xl" }) {
494
+ const isFullWidth = maxWidth === "full";
495
+ return /* @__PURE__ */ jsx("div", {
496
+ className: cn(isFullWidth ? "w-full px-4 sm:px-6 lg:px-10" : "mx-auto px-4 sm:px-6 lg:px-8", !isFullWidth && maxWidthClasses[maxWidth], className),
497
+ children
498
+ });
499
+ }
500
+
501
+ //#endregion
502
+ //#region src/layout/section.tsx
503
+ const backgrounds = {
504
+ default: "bg-background",
505
+ muted: "bg-muted",
506
+ primary: "bg-primary text-primary-foreground",
507
+ transparent: "bg-transparent"
508
+ };
509
+ const paddings = {
510
+ none: "",
511
+ sm: "py-8 md:py-12",
512
+ md: "py-12 md:py-16",
513
+ lg: "py-16 md:py-24",
514
+ xl: "py-24 md:py-32"
515
+ };
516
+ function Section({ id, children, className, background = "default", padding = "sm" }) {
517
+ return /* @__PURE__ */ jsx("section", {
518
+ id,
519
+ className: cn(backgrounds[background], paddings[padding], className),
520
+ children
428
521
  });
429
522
  }
430
523
 
431
524
  //#endregion
432
- export { Container, DisplayHeading, EmptyState, EmptyStateNoData, EmptyStateNoResults, EmptyStateNotFound, FacebookIcon, GoogleIcon, InstagramIcon, LoadingOverlay, LoadingState, Section, SkeletonCard, SkeletonGrid, SkeletonList, SkeletonTable, TwitterXIcon, WhatsAppIcon, buildFilterParams, buildListingStatusParams, buildSearchParams, clearSearchAndFilterParams, cn, getApiParams };
525
+ export { AccordionSection, CardWrapper, Container, DataCard, DetailField, DetailItem, DetailView, DisplayHeading, EmptyState, EmptyStateNoData, EmptyStateNoResults, EmptyStateNotFound, FacebookIcon, FaqAccordion, GoogleIcon, InfoRow, InstagramIcon, LoadingCard, LoadingOverlay, LoadingState, Pill, PillAvatar, PillButton, PillDelta, PillIndicator, PillStatus, Section, SkeletonCard, SkeletonGrid, SkeletonList, SkeletonTable, StatsGrid, StatusBadge, Timeline, TwitterXIcon, WhatsAppIcon, buildFilterParams, buildListingStatusParams, buildSearchParams, clearSearchAndFilterParams, cn, getApiParams };