@inshorts/glint-ui 0.5.4 → 0.6.1

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 (340) hide show
  1. package/README.md +3 -1
  2. package/dist/alert.cjs +96 -0
  3. package/dist/alert.cjs.map +1 -0
  4. package/dist/alert.d.cts +29 -0
  5. package/dist/alert.d.ts +29 -0
  6. package/dist/alert.js +10 -0
  7. package/dist/alert.js.map +1 -0
  8. package/dist/autocomplete.cjs +578 -0
  9. package/dist/autocomplete.cjs.map +1 -0
  10. package/dist/autocomplete.d.cts +56 -0
  11. package/dist/autocomplete.d.ts +56 -0
  12. package/dist/autocomplete.js +11 -0
  13. package/dist/autocomplete.js.map +1 -0
  14. package/dist/badge.cjs +89 -0
  15. package/dist/badge.cjs.map +1 -0
  16. package/dist/badge.d.cts +25 -0
  17. package/dist/badge.d.ts +25 -0
  18. package/dist/badge.js +10 -0
  19. package/dist/badge.js.map +1 -0
  20. package/dist/breadcrumb.cjs +88 -0
  21. package/dist/breadcrumb.cjs.map +1 -0
  22. package/dist/breadcrumb.d.cts +14 -0
  23. package/dist/breadcrumb.d.ts +14 -0
  24. package/dist/breadcrumb.js +8 -0
  25. package/dist/breadcrumb.js.map +1 -0
  26. package/dist/button.cjs +143 -0
  27. package/dist/button.cjs.map +1 -0
  28. package/dist/button.d.cts +34 -0
  29. package/dist/button.d.ts +34 -0
  30. package/dist/button.js +9 -0
  31. package/dist/button.js.map +1 -0
  32. package/dist/card.cjs +111 -0
  33. package/dist/card.cjs.map +1 -0
  34. package/dist/card.d.cts +15 -0
  35. package/dist/card.d.ts +15 -0
  36. package/dist/card.js +18 -0
  37. package/dist/card.js.map +1 -0
  38. package/dist/checkbox.cjs +66 -0
  39. package/dist/checkbox.cjs.map +1 -0
  40. package/{src/checkbox.tsx → dist/checkbox.d.cts} +5 -22
  41. package/dist/checkbox.d.ts +25 -0
  42. package/dist/checkbox.js +10 -0
  43. package/dist/checkbox.js.map +1 -0
  44. package/dist/chunk-5MEOZHJA.js +513 -0
  45. package/dist/chunk-5MEOZHJA.js.map +1 -0
  46. package/dist/chunk-67ACNS42.js +29 -0
  47. package/dist/chunk-67ACNS42.js.map +1 -0
  48. package/dist/chunk-A6GRLKOO.js +85 -0
  49. package/dist/chunk-A6GRLKOO.js.map +1 -0
  50. package/dist/chunk-DS3QYIKL.js +90 -0
  51. package/dist/chunk-DS3QYIKL.js.map +1 -0
  52. package/dist/chunk-EWSBFU54.js +53 -0
  53. package/dist/chunk-EWSBFU54.js.map +1 -0
  54. package/dist/chunk-G4ZQUSAJ.js +38 -0
  55. package/dist/chunk-G4ZQUSAJ.js.map +1 -0
  56. package/dist/chunk-GMCUXEFI.js +67 -0
  57. package/dist/chunk-GMCUXEFI.js.map +1 -0
  58. package/dist/chunk-HBBOR43A.js +85 -0
  59. package/dist/chunk-HBBOR43A.js.map +1 -0
  60. package/dist/chunk-HCA5ODCD.js +11 -0
  61. package/dist/chunk-HCA5ODCD.js.map +1 -0
  62. package/dist/chunk-HYRJYUPI.js +26 -0
  63. package/dist/chunk-HYRJYUPI.js.map +1 -0
  64. package/dist/chunk-IRCTGJQB.js +26 -0
  65. package/dist/chunk-IRCTGJQB.js.map +1 -0
  66. package/dist/chunk-ISPICB4W.js +70 -0
  67. package/dist/chunk-ISPICB4W.js.map +1 -0
  68. package/dist/chunk-JDE5XYPT.js +30 -0
  69. package/dist/chunk-JDE5XYPT.js.map +1 -0
  70. package/dist/chunk-JSJEEKR3.js +59 -0
  71. package/dist/chunk-JSJEEKR3.js.map +1 -0
  72. package/dist/chunk-KR3BCFP7.js +85 -0
  73. package/dist/chunk-KR3BCFP7.js.map +1 -0
  74. package/dist/chunk-MLRSOTFI.js +81 -0
  75. package/dist/chunk-MLRSOTFI.js.map +1 -0
  76. package/dist/chunk-MQT5RAQV.js +202 -0
  77. package/dist/chunk-MQT5RAQV.js.map +1 -0
  78. package/dist/chunk-MUPW2TFJ.js +102 -0
  79. package/dist/chunk-MUPW2TFJ.js.map +1 -0
  80. package/dist/chunk-OUYT6SPU.js +76 -0
  81. package/dist/chunk-OUYT6SPU.js.map +1 -0
  82. package/dist/chunk-PM2VE7DJ.js +100 -0
  83. package/dist/chunk-PM2VE7DJ.js.map +1 -0
  84. package/dist/chunk-PPYR3O3L.js +44 -0
  85. package/dist/chunk-PPYR3O3L.js.map +1 -0
  86. package/dist/chunk-PUTC52SI.js +98 -0
  87. package/dist/chunk-PUTC52SI.js.map +1 -0
  88. package/dist/chunk-PWAKTEXF.js +18 -0
  89. package/dist/chunk-PWAKTEXF.js.map +1 -0
  90. package/dist/chunk-QTFWORA7.js +26 -0
  91. package/dist/chunk-QTFWORA7.js.map +1 -0
  92. package/dist/chunk-RUPL2H6V.js +49 -0
  93. package/dist/chunk-RUPL2H6V.js.map +1 -0
  94. package/dist/chunk-S7PVZAPL.js +28 -0
  95. package/dist/chunk-S7PVZAPL.js.map +1 -0
  96. package/dist/chunk-SQDV2AKJ.js +49 -0
  97. package/dist/chunk-SQDV2AKJ.js.map +1 -0
  98. package/dist/chunk-T2KXVH3O.js +297 -0
  99. package/dist/chunk-T2KXVH3O.js.map +1 -0
  100. package/dist/chunk-T4WCCHJQ.js +29 -0
  101. package/dist/chunk-T4WCCHJQ.js.map +1 -0
  102. package/dist/chunk-UC3ZIQPE.js +93 -0
  103. package/dist/chunk-UC3ZIQPE.js.map +1 -0
  104. package/dist/chunk-UE7JY7VR.js +28 -0
  105. package/dist/chunk-UE7JY7VR.js.map +1 -0
  106. package/dist/chunk-Y5WCT6XN.js +93 -0
  107. package/dist/chunk-Y5WCT6XN.js.map +1 -0
  108. package/dist/chunk-YDICVETX.js +151 -0
  109. package/dist/chunk-YDICVETX.js.map +1 -0
  110. package/dist/chunk-ZFSQVMLJ.js +126 -0
  111. package/dist/chunk-ZFSQVMLJ.js.map +1 -0
  112. package/dist/chunk-ZHATD73Y.js +46 -0
  113. package/dist/chunk-ZHATD73Y.js.map +1 -0
  114. package/dist/chunk-ZLAA4DGG.js +111 -0
  115. package/dist/chunk-ZLAA4DGG.js.map +1 -0
  116. package/dist/chunk-ZP252OJZ.js +56 -0
  117. package/dist/chunk-ZP252OJZ.js.map +1 -0
  118. package/dist/clipboard.cjs +125 -0
  119. package/dist/clipboard.cjs.map +1 -0
  120. package/dist/clipboard.d.cts +52 -0
  121. package/dist/clipboard.d.ts +52 -0
  122. package/dist/clipboard.js +23 -0
  123. package/dist/clipboard.js.map +1 -0
  124. package/dist/collapsible.cjs +94 -0
  125. package/dist/collapsible.cjs.map +1 -0
  126. package/dist/collapsible.d.cts +21 -0
  127. package/dist/collapsible.d.ts +21 -0
  128. package/dist/collapsible.js +9 -0
  129. package/dist/collapsible.js.map +1 -0
  130. package/dist/confirm-dialog.cjs +369 -0
  131. package/dist/confirm-dialog.cjs.map +1 -0
  132. package/dist/confirm-dialog.d.cts +16 -0
  133. package/dist/confirm-dialog.d.ts +16 -0
  134. package/dist/confirm-dialog.js +13 -0
  135. package/dist/confirm-dialog.js.map +1 -0
  136. package/dist/copy-button.cjs +102 -0
  137. package/dist/copy-button.cjs.map +1 -0
  138. package/dist/copy-button.d.cts +18 -0
  139. package/dist/copy-button.d.ts +18 -0
  140. package/dist/copy-button.js +10 -0
  141. package/dist/copy-button.js.map +1 -0
  142. package/dist/data-table.cjs +140 -0
  143. package/dist/data-table.cjs.map +1 -0
  144. package/dist/data-table.d.cts +81 -0
  145. package/dist/data-table.d.ts +81 -0
  146. package/dist/data-table.js +8 -0
  147. package/dist/data-table.js.map +1 -0
  148. package/dist/date-range-picker/dateRange.cjs +138 -0
  149. package/dist/date-range-picker/dateRange.cjs.map +1 -0
  150. package/dist/date-range-picker/dateRange.d.cts +57 -0
  151. package/dist/date-range-picker/dateRange.d.ts +57 -0
  152. package/dist/date-range-picker/dateRange.js +31 -0
  153. package/dist/date-range-picker/dateRange.js.map +1 -0
  154. package/dist/date-range-picker/index.cjs +375 -0
  155. package/dist/date-range-picker/index.cjs.map +1 -0
  156. package/dist/date-range-picker/index.d.cts +18 -0
  157. package/dist/date-range-picker/index.d.ts +18 -0
  158. package/dist/date-range-picker/index.js +10 -0
  159. package/dist/date-range-picker/index.js.map +1 -0
  160. package/dist/dialogLayer.cjs +121 -0
  161. package/dist/dialogLayer.cjs.map +1 -0
  162. package/dist/dialogLayer.d.cts +11 -0
  163. package/dist/dialogLayer.d.ts +11 -0
  164. package/dist/dialogLayer.js +8 -0
  165. package/dist/dialogLayer.js.map +1 -0
  166. package/dist/feature-access-gate.cjs +160 -0
  167. package/dist/feature-access-gate.cjs.map +1 -0
  168. package/dist/feature-access-gate.d.cts +14 -0
  169. package/dist/feature-access-gate.d.ts +14 -0
  170. package/dist/feature-access-gate.js +11 -0
  171. package/dist/feature-access-gate.js.map +1 -0
  172. package/dist/field.cjs +58 -0
  173. package/dist/field.cjs.map +1 -0
  174. package/dist/field.d.cts +23 -0
  175. package/dist/field.d.ts +23 -0
  176. package/dist/field.js +8 -0
  177. package/dist/field.js.map +1 -0
  178. package/dist/image-uploader.cjs +293 -0
  179. package/dist/image-uploader.cjs.map +1 -0
  180. package/dist/image-uploader.d.cts +34 -0
  181. package/dist/image-uploader.d.ts +34 -0
  182. package/dist/image-uploader.js +12 -0
  183. package/dist/image-uploader.js.map +1 -0
  184. package/dist/index.cjs +3008 -0
  185. package/dist/index.cjs.map +1 -0
  186. package/dist/index.d.cts +41 -0
  187. package/dist/index.d.ts +41 -0
  188. package/dist/index.js +232 -0
  189. package/dist/index.js.map +1 -0
  190. package/dist/input.cjs +58 -0
  191. package/dist/input.cjs.map +1 -0
  192. package/dist/input.d.cts +7 -0
  193. package/dist/input.d.ts +7 -0
  194. package/dist/input.js +10 -0
  195. package/dist/input.js.map +1 -0
  196. package/dist/label.cjs +67 -0
  197. package/dist/label.cjs.map +1 -0
  198. package/dist/label.d.cts +7 -0
  199. package/dist/label.d.ts +7 -0
  200. package/dist/label.js +9 -0
  201. package/dist/label.js.map +1 -0
  202. package/dist/modal.cjs +212 -0
  203. package/dist/modal.cjs.map +1 -0
  204. package/dist/modal.d.cts +39 -0
  205. package/dist/modal.d.ts +39 -0
  206. package/dist/modal.js +12 -0
  207. package/dist/modal.js.map +1 -0
  208. package/dist/page-header.cjs +78 -0
  209. package/dist/page-header.cjs.map +1 -0
  210. package/dist/page-header.d.cts +35 -0
  211. package/dist/page-header.d.ts +35 -0
  212. package/dist/page-header.js +8 -0
  213. package/dist/page-header.js.map +1 -0
  214. package/dist/pagination.cjs +237 -0
  215. package/dist/pagination.cjs.map +1 -0
  216. package/dist/pagination.d.cts +15 -0
  217. package/dist/pagination.d.ts +15 -0
  218. package/dist/pagination.js +11 -0
  219. package/dist/pagination.js.map +1 -0
  220. package/dist/panel-brand-mark.cjs +59 -0
  221. package/dist/panel-brand-mark.cjs.map +1 -0
  222. package/dist/panel-brand-mark.d.cts +13 -0
  223. package/dist/panel-brand-mark.d.ts +13 -0
  224. package/dist/panel-brand-mark.js +8 -0
  225. package/dist/panel-brand-mark.js.map +1 -0
  226. package/dist/panel-sign-in.cjs +256 -0
  227. package/dist/panel-sign-in.cjs.map +1 -0
  228. package/dist/panel-sign-in.d.cts +31 -0
  229. package/dist/panel-sign-in.d.ts +31 -0
  230. package/dist/panel-sign-in.js +14 -0
  231. package/dist/panel-sign-in.js.map +1 -0
  232. package/dist/segmented-control.cjs +122 -0
  233. package/dist/segmented-control.cjs.map +1 -0
  234. package/dist/segmented-control.d.cts +58 -0
  235. package/dist/segmented-control.d.ts +58 -0
  236. package/dist/segmented-control.js +9 -0
  237. package/dist/segmented-control.js.map +1 -0
  238. package/dist/select.cjs +648 -0
  239. package/dist/select.cjs.map +1 -0
  240. package/dist/select.d.cts +30 -0
  241. package/dist/select.d.ts +30 -0
  242. package/dist/select.js +12 -0
  243. package/dist/select.js.map +1 -0
  244. package/dist/separator.cjs +70 -0
  245. package/dist/separator.cjs.map +1 -0
  246. package/dist/separator.d.cts +13 -0
  247. package/dist/separator.d.ts +13 -0
  248. package/dist/separator.js +9 -0
  249. package/dist/separator.js.map +1 -0
  250. package/dist/side-drawer.cjs +321 -0
  251. package/dist/side-drawer.cjs.map +1 -0
  252. package/dist/side-drawer.d.cts +21 -0
  253. package/dist/side-drawer.d.ts +21 -0
  254. package/dist/side-drawer.js +13 -0
  255. package/dist/side-drawer.js.map +1 -0
  256. package/dist/spinner.cjs +57 -0
  257. package/dist/spinner.cjs.map +1 -0
  258. package/{src/spinner.tsx → dist/spinner.d.cts} +11 -22
  259. package/dist/spinner.d.ts +27 -0
  260. package/dist/spinner.js +8 -0
  261. package/dist/spinner.js.map +1 -0
  262. package/dist/spreadsheet-grid.cjs +238 -0
  263. package/dist/spreadsheet-grid.cjs.map +1 -0
  264. package/dist/spreadsheet-grid.d.cts +48 -0
  265. package/dist/spreadsheet-grid.d.ts +48 -0
  266. package/dist/spreadsheet-grid.js +8 -0
  267. package/dist/spreadsheet-grid.js.map +1 -0
  268. package/dist/state-panel.cjs +86 -0
  269. package/dist/state-panel.cjs.map +1 -0
  270. package/dist/state-panel.d.cts +23 -0
  271. package/dist/state-panel.d.ts +23 -0
  272. package/dist/state-panel.js +9 -0
  273. package/dist/state-panel.js.map +1 -0
  274. package/dist/switch.cjs +87 -0
  275. package/dist/switch.cjs.map +1 -0
  276. package/dist/switch.d.cts +13 -0
  277. package/dist/switch.d.ts +13 -0
  278. package/dist/switch.js +9 -0
  279. package/dist/switch.js.map +1 -0
  280. package/dist/table.cjs +139 -0
  281. package/dist/table.cjs.map +1 -0
  282. package/dist/table.d.cts +16 -0
  283. package/dist/table.d.ts +16 -0
  284. package/dist/table.js +22 -0
  285. package/dist/table.js.map +1 -0
  286. package/dist/tabs.cjs +168 -0
  287. package/dist/tabs.cjs.map +1 -0
  288. package/dist/tabs.d.cts +59 -0
  289. package/dist/tabs.d.ts +59 -0
  290. package/dist/tabs.js +11 -0
  291. package/dist/tabs.js.map +1 -0
  292. package/dist/textarea.cjs +66 -0
  293. package/dist/textarea.cjs.map +1 -0
  294. package/dist/textarea.d.cts +18 -0
  295. package/dist/textarea.d.ts +18 -0
  296. package/dist/textarea.js +10 -0
  297. package/dist/textarea.js.map +1 -0
  298. package/dist/utils.cjs +35 -0
  299. package/dist/utils.cjs.map +1 -0
  300. package/dist/utils.d.cts +5 -0
  301. package/dist/utils.d.ts +5 -0
  302. package/dist/utils.js +7 -0
  303. package/dist/utils.js.map +1 -0
  304. package/package.json +391 -14
  305. package/src/alert.tsx +0 -74
  306. package/src/autocomplete.tsx +0 -666
  307. package/src/badge.tsx +0 -60
  308. package/src/breadcrumb.tsx +0 -71
  309. package/src/button.tsx +0 -113
  310. package/src/card.tsx +0 -79
  311. package/src/clipboard.ts +0 -144
  312. package/src/collapsible.tsx +0 -63
  313. package/src/confirm-dialog.tsx +0 -84
  314. package/src/copy-button.tsx +0 -58
  315. package/src/data-table.tsx +0 -190
  316. package/src/date-range-picker/dateRange.ts +0 -142
  317. package/src/date-range-picker/index.tsx +0 -366
  318. package/src/dialogLayer.ts +0 -142
  319. package/src/feature-access-gate.tsx +0 -38
  320. package/src/field.tsx +0 -56
  321. package/src/image-uploader.tsx +0 -181
  322. package/src/index.ts +0 -37
  323. package/src/input.tsx +0 -16
  324. package/src/label.tsx +0 -23
  325. package/src/modal.tsx +0 -117
  326. package/src/page-header.tsx +0 -75
  327. package/src/pagination.tsx +0 -116
  328. package/src/panel-brand-mark.tsx +0 -32
  329. package/src/panel-sign-in.tsx +0 -134
  330. package/src/segmented-control.tsx +0 -155
  331. package/src/select.tsx +0 -105
  332. package/src/separator.tsx +0 -32
  333. package/src/side-drawer.tsx +0 -87
  334. package/src/spreadsheet-grid.tsx +0 -264
  335. package/src/state-panel.tsx +0 -46
  336. package/src/switch.tsx +0 -47
  337. package/src/table.tsx +0 -110
  338. package/src/tabs.tsx +0 -201
  339. package/src/textarea.tsx +0 -32
  340. package/src/utils.ts +0 -6
package/src/badge.tsx DELETED
@@ -1,60 +0,0 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
-
4
- import { cn } from "./utils";
5
-
6
- /**
7
- * The status pill every list panel was spelling out by hand.
8
- *
9
- * Variants are semantic rather than named after a colour, because the same
10
- * status means the same thing on every panel and should not have to be
11
- * re-decided per table — Deleted was `bg-rose-100 text-rose-800` in one place
12
- * and `text-rose-900` two files away.
13
- *
14
- * These stay light-on-dark-text in both themes on purpose. A pill is a small
15
- * block of colour whose whole job is to be picked out of a row of text, and
16
- * inverting it per theme made the same status read as two different states.
17
- */
18
- const badgeVariants = cva(
19
- "inline-flex items-center gap-1 rounded font-medium whitespace-nowrap",
20
- {
21
- variants: {
22
- variant: {
23
- neutral: "bg-muted text-muted-foreground",
24
- success: "bg-success/15 text-success",
25
- warning: "bg-warning/15 text-warning",
26
- danger: "bg-destructive/15 text-destructive",
27
- info: "bg-info/15 text-info",
28
- },
29
- size: {
30
- /** Inline chips — a category, a tenant, a permission. */
31
- sm: "px-1.5 py-0.5 text-xs",
32
- /** A row's status. */
33
- md: "px-2 py-0.5 text-xs",
34
- },
35
- },
36
- defaultVariants: {
37
- variant: "neutral",
38
- size: "md",
39
- },
40
- },
41
- );
42
-
43
- export interface BadgeProps
44
- extends
45
- React.HTMLAttributes<HTMLSpanElement>,
46
- VariantProps<typeof badgeVariants> {}
47
-
48
- export const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(
49
- ({ className, variant, size, ...props }, ref) => (
50
- <span
51
- ref={ref}
52
- className={cn(badgeVariants({ variant, size }), className)}
53
- {...props}
54
- />
55
- ),
56
- );
57
-
58
- Badge.displayName = "Badge";
59
-
60
- export { badgeVariants };
@@ -1,71 +0,0 @@
1
- import { ChevronRight } from "lucide-react";
2
- import * as React from "react";
3
-
4
- import { cn } from "./utils";
5
-
6
- export type BreadcrumbItem = {
7
- label: string;
8
- href?: string;
9
- onClick?: () => void;
10
- };
11
-
12
- interface BreadcrumbProps {
13
- items: BreadcrumbItem[];
14
- className?: string;
15
- }
16
-
17
- export function Breadcrumb({ items, className }: BreadcrumbProps) {
18
- return (
19
- <nav aria-label="Breadcrumb" className={cn("text-sm", className)}>
20
- <ol className="flex flex-wrap items-center gap-1.5">
21
- {items.map((item, index) => {
22
- const isLast = index === items.length - 1;
23
- const isInteractive = !isLast && (item.href || item.onClick);
24
-
25
- return (
26
- <li
27
- key={`${item.label}-${index}`}
28
- className="flex items-center gap-1.5"
29
- >
30
- {index > 0 && (
31
- <ChevronRight
32
- className="text-muted-foreground/70 size-3.5 shrink-0"
33
- aria-hidden
34
- />
35
- )}
36
- {isInteractive ? (
37
- item.href ? (
38
- <a
39
- href={item.href}
40
- className="text-muted-foreground hover:text-foreground transition"
41
- >
42
- {item.label}
43
- </a>
44
- ) : (
45
- <button
46
- type="button"
47
- onClick={item.onClick}
48
- className="text-muted-foreground hover:text-foreground transition"
49
- >
50
- {item.label}
51
- </button>
52
- )
53
- ) : (
54
- <span
55
- className={cn(
56
- isLast
57
- ? "text-foreground font-medium"
58
- : "text-muted-foreground",
59
- )}
60
- aria-current={isLast ? "page" : undefined}
61
- >
62
- {item.label}
63
- </span>
64
- )}
65
- </li>
66
- );
67
- })}
68
- </ol>
69
- </nav>
70
- );
71
- }
package/src/button.tsx DELETED
@@ -1,113 +0,0 @@
1
- import * as React from "react";
2
- import { cva, type VariantProps } from "class-variance-authority";
3
- import { Slot } from "@radix-ui/react-slot";
4
-
5
- import { Spinner } from "./spinner";
6
- import { cn } from "./utils";
7
-
8
- const buttonVariants = cva(
9
- "inline-flex h-9 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md px-3 text-sm font-medium transition duration-200 active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
10
- {
11
- variants: {
12
- variant: {
13
- default: "bg-primary text-primary-foreground hover:bg-primary/90",
14
- secondary: "bg-muted text-foreground hover:bg-muted/80",
15
- ghost: "hover:bg-muted",
16
- destructive:
17
- "bg-destructive text-destructive-foreground hover:bg-destructive/90",
18
- outline: "border border-border bg-background hover:bg-muted",
19
- },
20
- size: {
21
- sm: "h-8 px-2.5",
22
- md: "h-9 px-3",
23
- lg: "h-10 px-4",
24
- icon: "h-9 w-9 px-0",
25
- // Square, matching `sm`'s height — for an icon-only control sitting in
26
- // a table row or beside `sm` buttons, where `icon` is a row taller.
27
- "icon-sm": "h-8 w-8 px-0",
28
- },
29
- },
30
- defaultVariants: {
31
- variant: "default",
32
- size: "md",
33
- },
34
- },
35
- );
36
-
37
- export interface ButtonProps
38
- extends
39
- React.ButtonHTMLAttributes<HTMLButtonElement>,
40
- VariantProps<typeof buttonVariants> {
41
- asChild?: boolean;
42
- /**
43
- * Work is in flight: shows a spinner, disables the button, and sets
44
- * `aria-busy`.
45
- *
46
- * This exists because the panel had 272 disabled buttons and only 22 that
47
- * said anything about why — the rest went dead on click with no spinner and
48
- * no label change, which reads as a broken button rather than a busy one.
49
- * Making the feedback part of `disabled` rather than something each caller
50
- * remembers separately is the only way that ratio stays fixed.
51
- *
52
- * The label is kept rather than swapped. "Saving…" loses which button you
53
- * pressed, and the spinner already says it is working. An icon-only button
54
- * is the exception — there is no room beside the glyph, so the spinner takes
55
- * its place; the `aria-label` is what names the button either way.
56
- *
57
- * "Icon-only" means an icon `size`. A square button that grew a spinner
58
- * beside its glyph would not just look wrong, it would resize mid-request
59
- * and shove whatever sits next to it sideways.
60
- */
61
- loading?: boolean;
62
- }
63
-
64
- /** Sizes with no room for a spinner beside the glyph. */
65
- const ICON_SIZES = new Set<string>(["icon", "icon-sm"]);
66
-
67
- export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
68
- (
69
- {
70
- className,
71
- variant,
72
- size,
73
- asChild = false,
74
- loading,
75
- disabled,
76
- children,
77
- ...props
78
- },
79
- ref,
80
- ) => {
81
- const Comp = asChild ? Slot : "button";
82
-
83
- // `asChild` renders someone else's element, which may not take a spinner or
84
- // a disabled attribute — so the busy treatment is only applied to a real
85
- // button, and passing both is a mistake worth not papering over.
86
- if (asChild) {
87
- return (
88
- <Comp
89
- ref={ref}
90
- className={cn(buttonVariants({ variant, size }), className)}
91
- {...props}
92
- >
93
- {children}
94
- </Comp>
95
- );
96
- }
97
-
98
- return (
99
- <button
100
- ref={ref}
101
- disabled={disabled || loading}
102
- aria-busy={loading || undefined}
103
- className={cn(buttonVariants({ variant, size }), className)}
104
- {...props}
105
- >
106
- {loading ? <Spinner size="sm" /> : null}
107
- {loading && size != null && ICON_SIZES.has(size) ? null : children}
108
- </button>
109
- );
110
- },
111
- );
112
-
113
- Button.displayName = "Button";
package/src/card.tsx DELETED
@@ -1,79 +0,0 @@
1
- import * as React from "react";
2
-
3
- import { cn } from "./utils";
4
-
5
- /**
6
- * Surface container for grouped content. Prefer a bare section when there is
7
- * no need for border / padding chrome — cards are for interactive or
8
- * self-contained blocks, not every stack of text.
9
- */
10
- export const Card = React.forwardRef<
11
- HTMLDivElement,
12
- React.HTMLAttributes<HTMLDivElement>
13
- >(({ className, ...props }, ref) => (
14
- <div
15
- ref={ref}
16
- className={cn(
17
- "bg-card text-card-foreground rounded-xl border shadow",
18
- className,
19
- )}
20
- {...props}
21
- />
22
- ));
23
- Card.displayName = "Card";
24
-
25
- export const CardHeader = React.forwardRef<
26
- HTMLDivElement,
27
- React.HTMLAttributes<HTMLDivElement>
28
- >(({ className, ...props }, ref) => (
29
- <div
30
- ref={ref}
31
- className={cn("flex flex-col space-y-1.5 p-6", className)}
32
- {...props}
33
- />
34
- ));
35
- CardHeader.displayName = "CardHeader";
36
-
37
- export const CardTitle = React.forwardRef<
38
- HTMLDivElement,
39
- React.HTMLAttributes<HTMLDivElement>
40
- >(({ className, ...props }, ref) => (
41
- <div
42
- ref={ref}
43
- className={cn("leading-none font-semibold tracking-tight", className)}
44
- {...props}
45
- />
46
- ));
47
- CardTitle.displayName = "CardTitle";
48
-
49
- export const CardDescription = React.forwardRef<
50
- HTMLDivElement,
51
- React.HTMLAttributes<HTMLDivElement>
52
- >(({ className, ...props }, ref) => (
53
- <div
54
- ref={ref}
55
- className={cn("text-muted-foreground text-sm", className)}
56
- {...props}
57
- />
58
- ));
59
- CardDescription.displayName = "CardDescription";
60
-
61
- export const CardContent = React.forwardRef<
62
- HTMLDivElement,
63
- React.HTMLAttributes<HTMLDivElement>
64
- >(({ className, ...props }, ref) => (
65
- <div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
66
- ));
67
- CardContent.displayName = "CardContent";
68
-
69
- export const CardFooter = React.forwardRef<
70
- HTMLDivElement,
71
- React.HTMLAttributes<HTMLDivElement>
72
- >(({ className, ...props }, ref) => (
73
- <div
74
- ref={ref}
75
- className={cn("flex items-center p-6 pt-0", className)}
76
- {...props}
77
- />
78
- ));
79
- CardFooter.displayName = "CardFooter";
package/src/clipboard.ts DELETED
@@ -1,144 +0,0 @@
1
- /**
2
- * Range maths and clipboard text for the card table's spreadsheet selection.
3
- *
4
- * Ported from video-shorts-panel `app/src/common/components/ExcelTable.jsx`.
5
- * Kept free of React and the DOM (except `writeToClipboard`) so the escaping
6
- * and range rules are unit-testable.
7
- */
8
-
9
- export type CellRef = { r: number; c: number };
10
-
11
- export type CellRange = { r1: number; r2: number; c1: number; c2: number };
12
-
13
- /** Tab for the clipboard (Excel/Sheets split on it), comma for a .csv file. */
14
- export const TSV_DELIMITER = "\t";
15
- export const CSV_DELIMITER = ",";
16
-
17
- /**
18
- * Anchor and focus can be dragged in any direction, so the range is whichever
19
- * corners they happen to be — normalize to top-left / bottom-right.
20
- */
21
- export function normalizeRange(
22
- anchor: CellRef | null | undefined,
23
- focus: CellRef | null | undefined,
24
- ): CellRange | null {
25
- if (!anchor || !focus) return null;
26
- return {
27
- r1: Math.min(anchor.r, focus.r),
28
- r2: Math.max(anchor.r, focus.r),
29
- c1: Math.min(anchor.c, focus.c),
30
- c2: Math.max(anchor.c, focus.c),
31
- };
32
- }
33
-
34
- /**
35
- * A cell needs quoting once it carries the delimiters themselves — the same
36
- * rule Excel uses when it parses the clipboard. Without it, a title containing
37
- * a tab or a newline silently becomes extra columns or rows on paste.
38
- */
39
- export function escapeCell(raw: unknown, delimiter: string): string {
40
- const value = raw == null ? "" : String(raw);
41
- if (
42
- value.includes(delimiter) ||
43
- value.includes("\n") ||
44
- value.includes("\r") ||
45
- value.includes('"')
46
- ) {
47
- return `"${value.replace(/"/g, '""')}"`;
48
- }
49
- return value;
50
- }
51
-
52
- export type TextColumn<Row> = {
53
- title: string;
54
- value: (row: Row) => string;
55
- };
56
-
57
- /** Renders a range as delimited text, optionally with a header line. */
58
- export function buildRangeText<Row>(
59
- range: CellRange | null,
60
- columns: TextColumn<Row>[],
61
- rows: Row[],
62
- delimiter: string,
63
- includeHeaders: boolean,
64
- ): string {
65
- if (!range) return "";
66
- const lines: string[] = [];
67
-
68
- if (includeHeaders) {
69
- const header: string[] = [];
70
- for (let c = range.c1; c <= range.c2; c++) {
71
- header.push(escapeCell(columns[c]?.title, delimiter));
72
- }
73
- lines.push(header.join(delimiter));
74
- }
75
-
76
- for (let r = range.r1; r <= range.r2; r++) {
77
- const line: string[] = [];
78
- const row = rows[r];
79
- for (let c = range.c1; c <= range.c2; c++) {
80
- const column = columns[c];
81
- line.push(
82
- escapeCell(
83
- column && row !== undefined ? column.value(row) : "",
84
- delimiter,
85
- ),
86
- );
87
- }
88
- lines.push(line.join(delimiter));
89
- }
90
-
91
- return lines.join("\n");
92
- }
93
-
94
- /** The whole grid, or null when there is nothing to select. */
95
- export function fullRange<Row>(
96
- columns: TextColumn<Row>[],
97
- rows: Row[],
98
- ): CellRange | null {
99
- if (!rows.length || !columns.length) return null;
100
- return { r1: 0, r2: rows.length - 1, c1: 0, c2: columns.length - 1 };
101
- }
102
-
103
- /** "3 × 2 selected" — what the toolbar reports back to the user. */
104
- export function describeRange(range: CellRange | null): string {
105
- if (!range) return "No selection";
106
- const rowCount = range.r2 - range.r1 + 1;
107
- const colCount = range.c2 - range.c1 + 1;
108
- if (rowCount === 1 && colCount === 1) return "1 cell selected";
109
- return `${rowCount} × ${colCount} selected`;
110
- }
111
-
112
- export function countCells(range: CellRange): {
113
- rows: number;
114
- columns: number;
115
- } {
116
- return {
117
- rows: range.r2 - range.r1 + 1,
118
- columns: range.c2 - range.c1 + 1,
119
- };
120
- }
121
-
122
- /**
123
- * `navigator.clipboard` is unavailable on http origins and older browsers, so
124
- * fall back to a hidden textarea + execCommand rather than failing the copy.
125
- */
126
- export async function writeToClipboard(text: string): Promise<void> {
127
- if (navigator.clipboard?.writeText) {
128
- return navigator.clipboard.writeText(text);
129
- }
130
-
131
- const textarea = document.createElement("textarea");
132
- textarea.value = text;
133
- textarea.style.position = "fixed";
134
- textarea.style.top = "-1000px";
135
- document.body.appendChild(textarea);
136
- textarea.select();
137
- try {
138
- if (!document.execCommand("copy")) {
139
- throw new Error("Could not write to the clipboard");
140
- }
141
- } finally {
142
- document.body.removeChild(textarea);
143
- }
144
- }
@@ -1,63 +0,0 @@
1
- "use client";
2
-
3
- import { ChevronDown } from "lucide-react";
4
- import * as React from "react";
5
-
6
- import { cn } from "./utils";
7
-
8
- /**
9
- * A titled section that folds away.
10
- *
11
- * For sidebar panels that are long but not always in use — the body stays
12
- * mounted so its state (a loaded list, a half-filled filter) survives being
13
- * collapsed, rather than being thrown away and refetched on the way back.
14
- */
15
- export function CollapsibleSection({
16
- title,
17
- icon,
18
- defaultOpen = true,
19
- right,
20
- className,
21
- children,
22
- }: {
23
- title: string;
24
- /** Optional leading glyph, shown between the chevron and the title. */
25
- icon?: React.ReactNode;
26
- defaultOpen?: boolean;
27
- /** Optional trailing content in the header, e.g. a count. */
28
- right?: React.ReactNode;
29
- className?: string;
30
- children: React.ReactNode;
31
- }) {
32
- const [open, setOpen] = React.useState(defaultOpen);
33
- const bodyId = React.useId();
34
-
35
- return (
36
- <div className={cn("border-border rounded-lg border", className)}>
37
- <button
38
- type="button"
39
- aria-expanded={open}
40
- aria-controls={bodyId}
41
- onClick={() => setOpen((current) => !current)}
42
- className="hover:bg-muted/50 flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm font-semibold transition"
43
- >
44
- <ChevronDown
45
- size={14}
46
- aria-hidden
47
- className={cn(
48
- "shrink-0 transition-transform",
49
- open ? "" : "-rotate-90",
50
- )}
51
- />
52
- {icon}
53
- <span className="flex-1">{title}</span>
54
- {right}
55
- </button>
56
- {/* Hidden rather than unmounted, so collapsing does not discard the
57
- panel's state or refetch what it had already loaded. */}
58
- <div id={bodyId} hidden={!open} className="space-y-3 px-3 pt-1 pb-3">
59
- {children}
60
- </div>
61
- </div>
62
- );
63
- }
@@ -1,84 +0,0 @@
1
- "use client";
2
-
3
- import * as React from "react";
4
-
5
- import { Button } from "./button";
6
- import { Modal } from "./modal";
7
-
8
- interface ConfirmDialogProps {
9
- isOpen: boolean;
10
- title: string;
11
- description?: React.ReactNode;
12
- confirmLabel?: string;
13
- cancelLabel?: string;
14
- isConfirming?: boolean;
15
- error?: string | null;
16
- onConfirm: () => void;
17
- onClose: () => void;
18
- }
19
-
20
- export function ConfirmDialog({
21
- isOpen,
22
- title,
23
- description,
24
- confirmLabel = "Delete",
25
- cancelLabel = "Cancel",
26
- isConfirming,
27
- error,
28
- onConfirm,
29
- onClose,
30
- }: ConfirmDialogProps) {
31
- const titleId = React.useId();
32
- const descriptionId = React.useId();
33
- const errorId = React.useId();
34
-
35
- const describedBy = [
36
- description ? descriptionId : null,
37
- error ? errorId : null,
38
- ]
39
- .filter(Boolean)
40
- .join(" ");
41
-
42
- return (
43
- <Modal
44
- isOpen={isOpen}
45
- role="alertdialog"
46
- labelledBy={titleId}
47
- describedBy={describedBy || undefined}
48
- closeLabel="Close dialog"
49
- onClose={onClose}
50
- >
51
- <h3 id={titleId} className="text-lg font-semibold">
52
- {title}
53
- </h3>
54
- {description ? (
55
- <div id={descriptionId} className="text-muted-foreground mt-2 text-sm">
56
- {description}
57
- </div>
58
- ) : null}
59
-
60
- {error ? (
61
- <div
62
- id={errorId}
63
- role="alert"
64
- className="border-destructive/30 bg-destructive/5 text-destructive mt-4 rounded-lg border px-3 py-2 text-sm"
65
- >
66
- {error}
67
- </div>
68
- ) : null}
69
-
70
- <div className="mt-6 flex justify-end gap-2">
71
- <Button variant="outline" onClick={onClose} disabled={isConfirming}>
72
- {cancelLabel}
73
- </Button>
74
- <Button
75
- variant="destructive"
76
- onClick={onConfirm}
77
- loading={isConfirming}
78
- >
79
- {confirmLabel}
80
- </Button>
81
- </div>
82
- </Modal>
83
- );
84
- }
@@ -1,58 +0,0 @@
1
- "use client";
2
-
3
- import { Check, Copy } from "lucide-react";
4
- import * as React from "react";
5
-
6
- import { writeToClipboard } from "./clipboard";
7
- import { cn } from "./utils";
8
-
9
- /**
10
- * Copies one short string — an id, a title, a URL — and says so for a moment.
11
- *
12
- * The panel had this three times over, each with its own timeout and its own
13
- * silent-failure story. `writeToClipboard` is used rather than
14
- * `navigator.clipboard` directly because the latter is undefined on http
15
- * origins, which is exactly where this panel runs in local dev.
16
- */
17
- export function CopyButton({
18
- value,
19
- label,
20
- className,
21
- }: {
22
- value: string;
23
- /** What is being copied, for the accessible name: "card id", "title". */
24
- label: string;
25
- className?: string;
26
- }) {
27
- const [copied, setCopied] = React.useState(false);
28
-
29
- React.useEffect(() => {
30
- if (!copied) return;
31
- const timer = window.setTimeout(() => setCopied(false), 1500);
32
- return () => window.clearTimeout(timer);
33
- }, [copied]);
34
-
35
- return (
36
- <button
37
- type="button"
38
- aria-label={copied ? `${label} copied` : `Copy ${label}`}
39
- title={copied ? "Copied" : `Copy ${label}`}
40
- className={cn(
41
- "text-muted-foreground hover:text-foreground hover:bg-muted focus-visible:ring-ring shrink-0 cursor-pointer rounded p-1 transition focus-visible:ring-2 focus-visible:outline-none",
42
- className,
43
- )}
44
- onClick={() => {
45
- // A denied clipboard permission should not throw into the row.
46
- void writeToClipboard(value)
47
- .then(() => setCopied(true))
48
- .catch(() => undefined);
49
- }}
50
- >
51
- {copied ? (
52
- <Check className="size-3.5 text-success" aria-hidden />
53
- ) : (
54
- <Copy className="size-3.5" aria-hidden />
55
- )}
56
- </button>
57
- );
58
- }