@lindaui/blocks 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 (255) hide show
  1. package/README.md +56 -0
  2. package/dist/ai-cost-card-f403ypsg.js +99 -0
  3. package/dist/ai-performance-card-cggm09nc.js +191 -0
  4. package/dist/analytics/ai-cost-card.d.ts +3 -0
  5. package/dist/analytics/ai-cost-card.d.ts.map +1 -0
  6. package/dist/analytics/ai-performance-card.d.ts +3 -0
  7. package/dist/analytics/ai-performance-card.d.ts.map +1 -0
  8. package/dist/analytics/analytics-card.d.ts +3 -0
  9. package/dist/analytics/analytics-card.d.ts.map +1 -0
  10. package/dist/analytics/analytics-skeleton.d.ts +5 -0
  11. package/dist/analytics/analytics-skeleton.d.ts.map +1 -0
  12. package/dist/analytics/entity-health-card.d.ts +3 -0
  13. package/dist/analytics/entity-health-card.d.ts.map +1 -0
  14. package/dist/analytics/status-distribution-chart.d.ts +3 -0
  15. package/dist/analytics/status-distribution-chart.d.ts.map +1 -0
  16. package/dist/analytics/time-range-picker.d.ts +3 -0
  17. package/dist/analytics/time-range-picker.d.ts.map +1 -0
  18. package/dist/analytics/top-entities-table.d.ts +3 -0
  19. package/dist/analytics/top-entities-table.d.ts.map +1 -0
  20. package/dist/analytics/types.d.ts +104 -0
  21. package/dist/analytics/types.d.ts.map +1 -0
  22. package/dist/analytics-card-bcmijpt6.js +38 -0
  23. package/dist/analytics-skeleton-imve37du.js +164 -0
  24. package/dist/analytics.d.ts +11 -0
  25. package/dist/analytics.d.ts.map +1 -0
  26. package/dist/analytics.js +8 -0
  27. package/dist/app-shell/drawer-focus.d.ts +8 -0
  28. package/dist/app-shell/drawer-focus.d.ts.map +1 -0
  29. package/dist/app-shell/footer.d.ts +39 -0
  30. package/dist/app-shell/footer.d.ts.map +1 -0
  31. package/dist/app-shell/logout-dialog.d.ts +6 -0
  32. package/dist/app-shell/logout-dialog.d.ts.map +1 -0
  33. package/dist/app-shell/navigation.d.ts +15 -0
  34. package/dist/app-shell/navigation.d.ts.map +1 -0
  35. package/dist/app-shell/types.d.ts +55 -0
  36. package/dist/app-shell/types.d.ts.map +1 -0
  37. package/dist/app-shell.d.ts +7 -0
  38. package/dist/app-shell.d.ts.map +1 -0
  39. package/dist/app-shell.js +254 -0
  40. package/dist/channel-settings.d.ts +24 -0
  41. package/dist/channel-settings.d.ts.map +1 -0
  42. package/dist/channel-settings.js +60 -0
  43. package/dist/chat-avatar-jdmeyf2o.js +30 -0
  44. package/dist/chat-layout-fwx3x26g.js +25 -0
  45. package/dist/chat.d.ts +22 -0
  46. package/dist/chat.d.ts.map +1 -0
  47. package/dist/chat.js +66 -0
  48. package/dist/command-palette.d.ts +22 -0
  49. package/dist/command-palette.d.ts.map +1 -0
  50. package/dist/command-palette.js +141 -0
  51. package/dist/compat-chat/chat-avatar.d.ts +16 -0
  52. package/dist/compat-chat/chat-avatar.d.ts.map +1 -0
  53. package/dist/compat-chat/chat-header.d.ts +9 -0
  54. package/dist/compat-chat/chat-header.d.ts.map +1 -0
  55. package/dist/compat-chat/chat-layout.d.ts +10 -0
  56. package/dist/compat-chat/chat-layout.d.ts.map +1 -0
  57. package/dist/compat-chat/conversation-list-item.d.ts +10 -0
  58. package/dist/compat-chat/conversation-list-item.d.ts.map +1 -0
  59. package/dist/compat-chat/conversation-list.d.ts +24 -0
  60. package/dist/compat-chat/conversation-list.d.ts.map +1 -0
  61. package/dist/compat-chat/conversation-thread.d.ts +18 -0
  62. package/dist/compat-chat/conversation-thread.d.ts.map +1 -0
  63. package/dist/compat-chat/date-divider.d.ts +5 -0
  64. package/dist/compat-chat/date-divider.d.ts.map +1 -0
  65. package/dist/compat-chat/empty-chat-view.d.ts +6 -0
  66. package/dist/compat-chat/empty-chat-view.d.ts.map +1 -0
  67. package/dist/compat-chat/image-lightbox.d.ts +7 -0
  68. package/dist/compat-chat/image-lightbox.d.ts.map +1 -0
  69. package/dist/compat-chat/message-bubble.d.ts +6 -0
  70. package/dist/compat-chat/message-bubble.d.ts.map +1 -0
  71. package/dist/compat-chat/message-composer.d.ts +11 -0
  72. package/dist/compat-chat/message-composer.d.ts.map +1 -0
  73. package/dist/compat-chat/time-divider.d.ts +5 -0
  74. package/dist/compat-chat/time-divider.d.ts.map +1 -0
  75. package/dist/compat-chat/time-grouping.d.ts +5 -0
  76. package/dist/compat-chat/time-grouping.d.ts.map +1 -0
  77. package/dist/compat-chat/types.d.ts +35 -0
  78. package/dist/compat-chat/types.d.ts.map +1 -0
  79. package/dist/compat-chat/whatsapp-audio-player.d.ts +7 -0
  80. package/dist/compat-chat/whatsapp-audio-player.d.ts.map +1 -0
  81. package/dist/compat.d.ts +9 -0
  82. package/dist/compat.d.ts.map +1 -0
  83. package/dist/compat.js +4 -0
  84. package/dist/connected-panel-lhwy25yk.js +132 -0
  85. package/dist/connection-panel/connected-panel.d.ts +26 -0
  86. package/dist/connection-panel/connected-panel.d.ts.map +1 -0
  87. package/dist/connection-panel/disconnected-panel.d.ts +12 -0
  88. package/dist/connection-panel/disconnected-panel.d.ts.map +1 -0
  89. package/dist/connection-panel/instructions.d.ts +5 -0
  90. package/dist/connection-panel/instructions.d.ts.map +1 -0
  91. package/dist/connection-panel/qr-panel.d.ts +14 -0
  92. package/dist/connection-panel/qr-panel.d.ts.map +1 -0
  93. package/dist/connection-panel/use-qr-refresh.d.ts +18 -0
  94. package/dist/connection-panel/use-qr-refresh.d.ts.map +1 -0
  95. package/dist/connection-panel.d.ts +39 -0
  96. package/dist/connection-panel.d.ts.map +1 -0
  97. package/dist/connection-panel.js +328 -0
  98. package/dist/conversation-list-ekq2dzca.js +133 -0
  99. package/dist/conversation-list-item-fy6t5af2.js +55 -0
  100. package/dist/conversation-thread-c60431oa.js +205 -0
  101. package/dist/entity-card.d.ts +17 -0
  102. package/dist/entity-card.d.ts.map +1 -0
  103. package/dist/entity-card.js +69 -0
  104. package/dist/entity-health-card-ggnmrtrq.js +192 -0
  105. package/dist/entity-switcher.d.ts +33 -0
  106. package/dist/entity-switcher.d.ts.map +1 -0
  107. package/dist/entity-switcher.js +137 -0
  108. package/dist/filter-bar.d.ts +41 -0
  109. package/dist/filter-bar.d.ts.map +1 -0
  110. package/dist/filter-bar.js +155 -0
  111. package/dist/footer-f7r5e42b.js +192 -0
  112. package/dist/image-lightbox-ci3arb6z.js +62 -0
  113. package/dist/kanban/drop-utils.d.ts +18 -0
  114. package/dist/kanban/drop-utils.d.ts.map +1 -0
  115. package/dist/kanban/navigation-buttons.d.ts +9 -0
  116. package/dist/kanban/navigation-buttons.d.ts.map +1 -0
  117. package/dist/kanban/scroll-indicators.d.ts +6 -0
  118. package/dist/kanban/scroll-indicators.d.ts.map +1 -0
  119. package/dist/kanban/use-keyboard-navigation.d.ts +4 -0
  120. package/dist/kanban/use-keyboard-navigation.d.ts.map +1 -0
  121. package/dist/kanban-board.d.ts +31 -0
  122. package/dist/kanban-board.d.ts.map +1 -0
  123. package/dist/kanban-board.js +128 -0
  124. package/dist/kanban-column.d.ts +13 -0
  125. package/dist/kanban-column.d.ts.map +1 -0
  126. package/dist/kanban-column.js +58 -0
  127. package/dist/legacy-kpi-card.d.ts +16 -0
  128. package/dist/legacy-kpi-card.d.ts.map +1 -0
  129. package/dist/legacy-kpi-card.js +4 -0
  130. package/dist/logout-dialog-bbv59tbi.js +93 -0
  131. package/dist/message-bubble-odjvhroq.js +110 -0
  132. package/dist/message-composer-m2n6soo7.js +59 -0
  133. package/dist/navigation-buttons-e77mshh0.js +65 -0
  134. package/dist/navigation-hotcrqoq.js +115 -0
  135. package/dist/save-bar.d.ts +15 -0
  136. package/dist/save-bar.d.ts.map +1 -0
  137. package/dist/save-bar.js +38 -0
  138. package/dist/scroll-indicators-gvxapogd.js +39 -0
  139. package/dist/settings-layout.d.ts +20 -0
  140. package/dist/settings-layout.d.ts.map +1 -0
  141. package/dist/settings-layout.js +56 -0
  142. package/dist/source-selector.d.ts +18 -0
  143. package/dist/source-selector.d.ts.map +1 -0
  144. package/dist/source-selector.js +59 -0
  145. package/dist/status-distribution-chart-oucedzv7.js +87 -0
  146. package/dist/status-filters.d.ts +12 -0
  147. package/dist/status-filters.d.ts.map +1 -0
  148. package/dist/status-filters.js +31 -0
  149. package/dist/stepper.d.ts +15 -0
  150. package/dist/stepper.d.ts.map +1 -0
  151. package/dist/stepper.js +42 -0
  152. package/dist/time-range-picker-mu38hul4.js +123 -0
  153. package/dist/top-entities-table-o7xzpq96.js +78 -0
  154. package/dist/use-keyboard-navigation-he1xmriz.js +52 -0
  155. package/dist/whatsapp-audio-player-nooty6jb.js +277 -0
  156. package/llms.txt +87 -4
  157. package/package.json +191 -46
  158. package/src/analytics/ai-cost-card.tsx +31 -0
  159. package/src/analytics/ai-performance-card.tsx +48 -0
  160. package/src/analytics/analytics-card.tsx +14 -0
  161. package/src/analytics/analytics-skeleton.tsx +15 -0
  162. package/src/analytics/entity-health-card.tsx +50 -0
  163. package/src/analytics/status-distribution-chart.tsx +20 -0
  164. package/src/analytics/time-range-picker.tsx +43 -0
  165. package/src/analytics/top-entities-table.tsx +24 -0
  166. package/src/analytics/types.ts +43 -0
  167. package/src/analytics.ts +10 -0
  168. package/src/app-shell/drawer-focus.ts +42 -0
  169. package/src/app-shell/footer.tsx +160 -0
  170. package/src/app-shell/logout-dialog.tsx +68 -0
  171. package/src/app-shell/navigation.tsx +147 -0
  172. package/src/app-shell/types.ts +57 -0
  173. package/src/app-shell.tsx +166 -0
  174. package/src/area-chart.tsx +85 -0
  175. package/src/audio-player.tsx +74 -0
  176. package/src/auth-layout.tsx +132 -0
  177. package/src/auth-provider.tsx +29 -0
  178. package/src/bar-chart.tsx +78 -0
  179. package/src/channel-settings.tsx +76 -0
  180. package/src/chart-card.tsx +45 -0
  181. package/src/chat-avatar.tsx +57 -0
  182. package/src/chat-date-divider.tsx +18 -0
  183. package/src/chat-header.tsx +24 -0
  184. package/src/chat-layout.tsx +41 -0
  185. package/src/chat-time-divider.tsx +20 -0
  186. package/src/chat-types.ts +32 -0
  187. package/src/chat.ts +21 -0
  188. package/src/command-palette.tsx +110 -0
  189. package/src/compat-chat/chat-avatar.tsx +23 -0
  190. package/src/compat-chat/chat-header.tsx +12 -0
  191. package/src/compat-chat/chat-layout.tsx +14 -0
  192. package/src/compat-chat/conversation-list-item.tsx +27 -0
  193. package/src/compat-chat/conversation-list.tsx +49 -0
  194. package/src/compat-chat/conversation-thread.tsx +92 -0
  195. package/src/compat-chat/date-divider.tsx +7 -0
  196. package/src/compat-chat/empty-chat-view.tsx +9 -0
  197. package/src/compat-chat/image-lightbox.tsx +22 -0
  198. package/src/compat-chat/message-bubble.tsx +28 -0
  199. package/src/compat-chat/message-composer.tsx +26 -0
  200. package/src/compat-chat/time-divider.tsx +5 -0
  201. package/src/compat-chat/time-grouping.ts +19 -0
  202. package/src/compat-chat/types.ts +31 -0
  203. package/src/compat-chat/whatsapp-audio-player.tsx +100 -0
  204. package/src/compat.ts +8 -0
  205. package/src/confirm-dialog.tsx +85 -0
  206. package/src/connection-panel/connected-panel.tsx +106 -0
  207. package/src/connection-panel/disconnected-panel.tsx +48 -0
  208. package/src/connection-panel/instructions.tsx +9 -0
  209. package/src/connection-panel/qr-panel.tsx +62 -0
  210. package/src/connection-panel/use-qr-refresh.ts +52 -0
  211. package/src/connection-panel.tsx +141 -0
  212. package/src/conversation-list-item.tsx +53 -0
  213. package/src/conversation-list.tsx +67 -0
  214. package/src/conversation-thread.tsx +64 -0
  215. package/src/detail-panel.tsx +123 -0
  216. package/src/document-panel.tsx +109 -0
  217. package/src/document-reader.tsx +29 -0
  218. package/src/empty-chat-view.tsx +25 -0
  219. package/src/entity-card.tsx +74 -0
  220. package/src/entity-health-card.tsx +53 -0
  221. package/src/entity-switcher.tsx +126 -0
  222. package/src/fetching-indicator.tsx +16 -0
  223. package/src/field-array-form.tsx +166 -0
  224. package/src/filter-bar.tsx +203 -0
  225. package/src/image-viewer.tsx +129 -0
  226. package/src/kanban/drop-utils.ts +31 -0
  227. package/src/kanban/navigation-buttons.tsx +80 -0
  228. package/src/kanban/scroll-indicators.tsx +47 -0
  229. package/src/kanban/use-keyboard-navigation.ts +43 -0
  230. package/src/kanban-board.tsx +160 -0
  231. package/src/kanban-column.tsx +62 -0
  232. package/src/legacy-kpi-card.tsx +38 -0
  233. package/src/line-chart.tsx +58 -0
  234. package/src/list-item.tsx +63 -0
  235. package/src/list-pane.tsx +143 -0
  236. package/src/login-form.tsx +128 -0
  237. package/src/message-bubble.tsx +70 -0
  238. package/src/message-composer.tsx +52 -0
  239. package/src/pie-chart.tsx +70 -0
  240. package/src/radar-chart.tsx +55 -0
  241. package/src/radial-chart.tsx +103 -0
  242. package/src/recording-overlay.tsx +159 -0
  243. package/src/save-bar.tsx +35 -0
  244. package/src/settings-layout.tsx +79 -0
  245. package/src/source-selector.tsx +71 -0
  246. package/src/split-workspace.tsx +74 -0
  247. package/src/stat-card.tsx +166 -0
  248. package/src/stats-grid.tsx +23 -0
  249. package/src/status-filters.tsx +28 -0
  250. package/src/stepper.tsx +47 -0
  251. package/src/table-pane.tsx +194 -0
  252. package/src/time-range-picker.tsx +89 -0
  253. package/src/workspace-back-button.tsx +32 -0
  254. package/dist/chat-types.test.d.ts +0 -2
  255. package/dist/chat-types.test.d.ts.map +0 -1
@@ -0,0 +1,194 @@
1
+ "use client";
2
+ import type { ReactNode } from "react";
3
+ import { AlertCircle, FileText, RotateCcw } from "lucide-react";
4
+ import { Button } from "@lindaui/ui/button";
5
+ import { SearchField } from "@lindaui/ui/search-field";
6
+ import { Skeleton } from "@lindaui/ui/skeleton";
7
+ import { Table, type TableColumnDef } from "@lindaui/ui/table";
8
+
9
+ export interface TablePaneFilter {
10
+ key: string;
11
+ label: string;
12
+ count?: number;
13
+ }
14
+
15
+ /**
16
+ * Tabular sibling of `list-pane`: the same controlled chrome (filter tabs +
17
+ * search + loading/error/empty states) wrapped around `@lindaui/ui/table`,
18
+ * plus a `toolbarExtra` slot and an optional footer. Zero data-fetching — the
19
+ * app passes already-filtered `rows` (each cell is a `ReactNode`, so domain
20
+ * chips/avatars live in the consumer) and owns all state.
21
+ */
22
+ export interface TablePaneProps {
23
+ // Table data (delegated to @lindaui/ui/table).
24
+ columns: TableColumnDef[];
25
+ rows: Record<string, ReactNode>[];
26
+ ariaLabel?: string;
27
+
28
+ // Filter tabs (same model as list-pane).
29
+ filters?: TablePaneFilter[];
30
+ activeFilter?: string;
31
+ onFilterChange?: (key: string) => void;
32
+
33
+ // Search.
34
+ searchValue?: string;
35
+ onSearchChange?: (value: string) => void;
36
+ searchPlaceholder?: string;
37
+ searchLabel?: string;
38
+
39
+ // Extra toolbar controls to the right of the search (e.g. a <Select>).
40
+ toolbarExtra?: ReactNode;
41
+
42
+ // States.
43
+ loading?: boolean;
44
+ error?: string | null;
45
+ onRetry?: () => void;
46
+ errorTitle?: string;
47
+ retryLabel?: string;
48
+ isEmpty?: boolean;
49
+ emptyTitle?: string;
50
+ emptyDescription?: ReactNode;
51
+ emptyIcon?: ReactNode;
52
+
53
+ // Footer: `footer` is an escape hatch that wins over the `footerCount` helper.
54
+ footer?: ReactNode;
55
+ footerCount?: { shown: number; total: number; label?: string };
56
+ }
57
+
58
+ export function TablePane({
59
+ columns,
60
+ rows,
61
+ ariaLabel = "Tabla",
62
+ filters,
63
+ activeFilter,
64
+ onFilterChange,
65
+ searchValue = "",
66
+ onSearchChange,
67
+ searchPlaceholder = "Buscar",
68
+ searchLabel = "Buscar",
69
+ toolbarExtra,
70
+ loading = false,
71
+ error = null,
72
+ onRetry,
73
+ errorTitle = "No se pudo cargar",
74
+ retryLabel = "Reintentar",
75
+ isEmpty,
76
+ emptyTitle = "Sin resultados",
77
+ emptyDescription,
78
+ emptyIcon,
79
+ footer,
80
+ footerCount,
81
+ }: TablePaneProps) {
82
+ const showEmpty =
83
+ !loading && !error && (isEmpty !== undefined ? isEmpty : rows.length === 0);
84
+ const showFooter =
85
+ !loading && !error && (footer != null || footerCount != null);
86
+
87
+ return (
88
+ <div className="flex flex-col overflow-hidden rounded-xl border border-border bg-card">
89
+ {filters && filters.length > 0 && (
90
+ <div className="flex flex-wrap gap-2 overflow-x-auto border-b border-border p-3">
91
+ {filters.map((f) => (
92
+ <Button
93
+ key={f.key}
94
+ variant={activeFilter === f.key ? "primary" : "ghost"}
95
+ onPress={() => onFilterChange?.(f.key)}
96
+ size="sm"
97
+ >
98
+ {f.label}
99
+ {f.count != null && (
100
+ <span
101
+ aria-hidden
102
+ className="ml-1.5 inline-flex h-4 min-w-4 items-center justify-center rounded-full bg-muted-foreground/15 px-1 text-[11px] font-semibold tabular-nums text-muted-foreground"
103
+ >
104
+ {f.count}
105
+ </span>
106
+ )}
107
+ </Button>
108
+ ))}
109
+ </div>
110
+ )}
111
+
112
+ {(onSearchChange || toolbarExtra) && (
113
+ <div className="flex flex-wrap items-center gap-3 border-b border-border p-4">
114
+ {onSearchChange && (
115
+ <div className="min-w-[240px] flex-1">
116
+ <SearchField
117
+ value={searchValue}
118
+ onChange={onSearchChange}
119
+ placeholder={searchPlaceholder}
120
+ aria-label={searchLabel}
121
+ />
122
+ </div>
123
+ )}
124
+ {toolbarExtra}
125
+ </div>
126
+ )}
127
+
128
+ <div className="min-h-0 flex-1 overflow-x-auto">
129
+ {loading && (
130
+ <div role="status" aria-label="Cargando" className="space-y-2 p-3">
131
+ {Array.from({ length: 6 }).map((_, i) => (
132
+ <Skeleton key={i} className="h-12 w-full" />
133
+ ))}
134
+ </div>
135
+ )}
136
+
137
+ {!loading && error && (
138
+ <div className="m-3 rounded-xl border border-destructive/35 bg-destructive/5 p-6 text-center">
139
+ <AlertCircle className="mx-auto h-6 w-6 text-destructive" />
140
+ <p className="mt-2 text-sm font-semibold">{errorTitle}</p>
141
+ <p className="mt-1 text-xs text-muted-foreground">{error}</p>
142
+ {onRetry && (
143
+ <Button
144
+ variant="secondary"
145
+ size="sm"
146
+ onPress={onRetry}
147
+ className="mt-3"
148
+ >
149
+ <RotateCcw className="h-3.5 w-3.5" />
150
+ {retryLabel}
151
+ </Button>
152
+ )}
153
+ </div>
154
+ )}
155
+
156
+ {showEmpty && (
157
+ <div className="py-16 text-center">
158
+ <div className="mx-auto grid h-11 w-11 place-items-center rounded-xl bg-secondary">
159
+ {emptyIcon ?? (
160
+ <FileText className="h-5 w-5 text-muted-foreground" />
161
+ )}
162
+ </div>
163
+ <p className="mt-3 text-sm font-semibold">{emptyTitle}</p>
164
+ {emptyDescription && (
165
+ <div className="mt-1 text-xs text-muted-foreground">
166
+ {emptyDescription}
167
+ </div>
168
+ )}
169
+ </div>
170
+ )}
171
+
172
+ {!loading && !error && !showEmpty && (
173
+ <Table aria-label={ariaLabel} columns={columns} rows={rows} />
174
+ )}
175
+ </div>
176
+
177
+ {showFooter &&
178
+ (footer ?? (
179
+ <div className="flex items-center justify-between border-t border-border px-5 py-3 text-xs text-muted-foreground">
180
+ <span>
181
+ {footerCount!.label ?? "Mostrando"}{" "}
182
+ <span className="font-medium text-foreground">
183
+ {footerCount!.shown}
184
+ </span>{" "}
185
+ de{" "}
186
+ <span className="font-medium text-foreground">
187
+ {footerCount!.total}
188
+ </span>
189
+ </span>
190
+ </div>
191
+ ))}
192
+ </div>
193
+ );
194
+ }
@@ -0,0 +1,89 @@
1
+ "use client";
2
+ import { Button } from "@lindaui/ui/button";
3
+
4
+ export interface TimeRangePreset {
5
+ key: string;
6
+ label: string;
7
+ }
8
+
9
+ export interface TimeRangeValue {
10
+ start: string;
11
+ end: string;
12
+ }
13
+
14
+ export interface TimeRangePickerProps {
15
+ presets?: TimeRangePreset[];
16
+ activePreset: string;
17
+ onPresetChange: (key: string) => void;
18
+ /** Key del preset que revela los inputs de rango custom. Default `"custom"`. */
19
+ customKey?: string;
20
+ range?: TimeRangeValue;
21
+ onRangeChange?: (range: TimeRangeValue) => void;
22
+ startLabel?: string;
23
+ endLabel?: string;
24
+ }
25
+
26
+ const DEFAULT_PRESETS: TimeRangePreset[] = [
27
+ { key: "today", label: "Hoy" },
28
+ { key: "7d", label: "Últimos 7 días" },
29
+ { key: "30d", label: "Últimos 30 días" },
30
+ { key: "custom", label: "Personalizado" },
31
+ ];
32
+
33
+ const fieldInputClass =
34
+ "rounded-[var(--field-radius)] border border-[var(--field-border)] bg-[var(--field-background)] px-2 py-1 text-sm text-[var(--field-foreground)]";
35
+
36
+ /**
37
+ * Presets + rango custom, controlado. El custom usa `<input type="date">` nativo
38
+ * (no el `date-range-picker` de HeroUI): evita traer `@internationalized/date` a
39
+ * un caso de uso simple de fecha-a-fecha.
40
+ */
41
+ export function TimeRangePicker({
42
+ presets = DEFAULT_PRESETS,
43
+ activePreset,
44
+ onPresetChange,
45
+ customKey = "custom",
46
+ range,
47
+ onRangeChange,
48
+ startLabel = "Desde",
49
+ endLabel = "Hasta",
50
+ }: TimeRangePickerProps) {
51
+ return (
52
+ <div className="flex flex-wrap items-center gap-2">
53
+ <div className="flex flex-wrap gap-2">
54
+ {presets.map((p) => (
55
+ <Button
56
+ key={p.key}
57
+ variant={activePreset === p.key ? "primary" : "ghost"}
58
+ size="sm"
59
+ onPress={() => onPresetChange(p.key)}
60
+ >
61
+ {p.label}
62
+ </Button>
63
+ ))}
64
+ </div>
65
+ {activePreset === customKey && (
66
+ <div className="flex items-center gap-2">
67
+ <label className="flex items-center gap-1.5 text-sm">
68
+ <span className="text-muted-foreground">{startLabel}</span>
69
+ <input
70
+ type="date"
71
+ value={range?.start ?? ""}
72
+ onChange={(e) => onRangeChange?.({ start: e.target.value, end: range?.end ?? "" })}
73
+ className={fieldInputClass}
74
+ />
75
+ </label>
76
+ <label className="flex items-center gap-1.5 text-sm">
77
+ <span className="text-muted-foreground">{endLabel}</span>
78
+ <input
79
+ type="date"
80
+ value={range?.end ?? ""}
81
+ onChange={(e) => onRangeChange?.({ start: range?.start ?? "", end: e.target.value })}
82
+ className={fieldInputClass}
83
+ />
84
+ </label>
85
+ </div>
86
+ )}
87
+ </div>
88
+ );
89
+ }
@@ -0,0 +1,32 @@
1
+ "use client";
2
+ import type { ReactNode } from "react";
3
+ import { ChevronLeft } from "lucide-react";
4
+
5
+ /**
6
+ * Legible back pill for media overlays. `SplitWorkspace` renders it by default
7
+ * from `backHref`/`backLabel` so a consumer never has to hand-build a readable
8
+ * control over dark/bright media. Token-driven surface (`bg-secondary` +
9
+ * `border-border`) so it reads on any background.
10
+ */
11
+ export interface WorkspaceBackButtonProps {
12
+ href: string;
13
+ label: ReactNode;
14
+ /** Leading icon; defaults to a chevron. Rendered `aria-hidden` — the label names the link. */
15
+ icon?: ReactNode;
16
+ }
17
+
18
+ export function WorkspaceBackButton({
19
+ href,
20
+ label,
21
+ icon = <ChevronLeft size={18} aria-hidden />,
22
+ }: WorkspaceBackButtonProps) {
23
+ return (
24
+ <a
25
+ href={href}
26
+ className="inline-flex h-9 items-center gap-1 rounded-full border border-border bg-secondary pl-2 pr-3 text-sm font-medium text-secondary-foreground shadow-sm transition-colors hover:bg-border"
27
+ >
28
+ {icon}
29
+ {label}
30
+ </a>
31
+ );
32
+ }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=chat-types.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"chat-types.test.d.ts","sourceRoot":"","sources":["../src/chat-types.test.ts"],"names":[],"mappings":""}