@suzumiyaaoba/mdxr 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (236) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -0
  3. package/dist/cli.d.mts +1 -0
  4. package/dist/cli.mjs +2902 -0
  5. package/dist/components.d.mts +791 -0
  6. package/dist/components.mjs +2 -0
  7. package/dist/config-SI9IyFiC.mjs +184 -0
  8. package/dist/doc-context-CEqzMYKv.d.mts +568 -0
  9. package/dist/index.d.mts +20 -0
  10. package/dist/index.mjs +4 -0
  11. package/dist/ui-GKFD0mx5.mjs +15986 -0
  12. package/package.json +131 -0
  13. package/skill/SKILL.md +49 -0
  14. package/skill/references/components/charts.md +172 -0
  15. package/skill/references/components/document.md +98 -0
  16. package/skill/references/components/forms.md +35 -0
  17. package/skill/references/components/investigation.md +198 -0
  18. package/skill/references/components/layout.md +68 -0
  19. package/skill/references/components/output.md +158 -0
  20. package/skill/references/components/planning.md +155 -0
  21. package/skill/references/components/reports.md +252 -0
  22. package/skill/references/components/shadcn.md +19 -0
  23. package/skill/references/components.md +186 -0
  24. package/skill/references/extending.md +48 -0
  25. package/src/ask-sheet.ts +40 -0
  26. package/src/assets/css.ts +392 -0
  27. package/src/assets/scripts.ts +78 -0
  28. package/src/catalog.ts +287 -0
  29. package/src/cli.ts +178 -0
  30. package/src/client/doc-events.ts +1108 -0
  31. package/src/client/entry.ts +27 -0
  32. package/src/client-js.ts +47 -0
  33. package/src/component-map.ts +47 -0
  34. package/src/components/ui/accordion.tsx +77 -0
  35. package/src/components/ui/alert-dialog.tsx +185 -0
  36. package/src/components/ui/alert.tsx +76 -0
  37. package/src/components/ui/aspect-ratio.tsx +22 -0
  38. package/src/components/ui/attachment.tsx +208 -0
  39. package/src/components/ui/avatar.tsx +106 -0
  40. package/src/components/ui/badge.tsx +52 -0
  41. package/src/components/ui/breadcrumb.tsx +121 -0
  42. package/src/components/ui/bubble.tsx +128 -0
  43. package/src/components/ui/button-group.tsx +88 -0
  44. package/src/components/ui/button.tsx +58 -0
  45. package/src/components/ui/calendar.tsx +226 -0
  46. package/src/components/ui/card.tsx +102 -0
  47. package/src/components/ui/carousel.tsx +246 -0
  48. package/src/components/ui/chart.tsx +379 -0
  49. package/src/components/ui/checkbox.tsx +27 -0
  50. package/src/components/ui/collapsible.tsx +19 -0
  51. package/src/components/ui/combobox.tsx +298 -0
  52. package/src/components/ui/command.tsx +193 -0
  53. package/src/components/ui/context-menu.tsx +271 -0
  54. package/src/components/ui/dialog.tsx +159 -0
  55. package/src/components/ui/direction.tsx +4 -0
  56. package/src/components/ui/drawer.tsx +227 -0
  57. package/src/components/ui/dropdown-menu.tsx +269 -0
  58. package/src/components/ui/empty.tsx +104 -0
  59. package/src/components/ui/field.tsx +237 -0
  60. package/src/components/ui/fieldset.tsx +32 -0
  61. package/src/components/ui/frame.tsx +87 -0
  62. package/src/components/ui/hover-card.tsx +50 -0
  63. package/src/components/ui/input-group.tsx +159 -0
  64. package/src/components/ui/input-otp.tsx +83 -0
  65. package/src/components/ui/input.tsx +19 -0
  66. package/src/components/ui/item.tsx +202 -0
  67. package/src/components/ui/kbd.tsx +26 -0
  68. package/src/components/ui/label.tsx +19 -0
  69. package/src/components/ui/marker.tsx +71 -0
  70. package/src/components/ui/menubar.tsx +284 -0
  71. package/src/components/ui/message-scroller.tsx +128 -0
  72. package/src/components/ui/message.tsx +91 -0
  73. package/src/components/ui/meter.tsx +80 -0
  74. package/src/components/ui/native-select.tsx +64 -0
  75. package/src/components/ui/navigation-menu.tsx +170 -0
  76. package/src/components/ui/pagination.tsx +133 -0
  77. package/src/components/ui/popover.tsx +87 -0
  78. package/src/components/ui/progress.tsx +82 -0
  79. package/src/components/ui/questionnaire.tsx +328 -0
  80. package/src/components/ui/radio-group.tsx +35 -0
  81. package/src/components/ui/resizable.tsx +49 -0
  82. package/src/components/ui/scroll-area.tsx +50 -0
  83. package/src/components/ui/select.tsx +201 -0
  84. package/src/components/ui/separator.tsx +22 -0
  85. package/src/components/ui/sheet.tsx +135 -0
  86. package/src/components/ui/sidebar.tsx +730 -0
  87. package/src/components/ui/skeleton.tsx +13 -0
  88. package/src/components/ui/slider.tsx +51 -0
  89. package/src/components/ui/spinner.tsx +16 -0
  90. package/src/components/ui/switch.tsx +31 -0
  91. package/src/components/ui/table.tsx +113 -0
  92. package/src/components/ui/tabs.tsx +82 -0
  93. package/src/components/ui/textarea.tsx +17 -0
  94. package/src/components/ui/toast.tsx +229 -0
  95. package/src/components/ui/toggle-group.tsx +87 -0
  96. package/src/components/ui/toggle.tsx +43 -0
  97. package/src/components/ui/tooltip.tsx +65 -0
  98. package/src/components.ts +78 -0
  99. package/src/config.ts +56 -0
  100. package/src/define.ts +122 -0
  101. package/src/doc-context.ts +20 -0
  102. package/src/editor.ts +94 -0
  103. package/src/format-error.ts +78 -0
  104. package/src/guards.ts +84 -0
  105. package/src/hooks/use-mobile.ts +21 -0
  106. package/src/html.ts +91 -0
  107. package/src/hydrate/export-index.ts +232 -0
  108. package/src/hydrate/import-scan.ts +169 -0
  109. package/src/hydrate/plugins.ts +118 -0
  110. package/src/hydrate/runtime-module.ts +145 -0
  111. package/src/hydrate-runtime.ts +67 -0
  112. package/src/hydrate.ts +147 -0
  113. package/src/index.ts +16 -0
  114. package/src/init.ts +57 -0
  115. package/src/langs.ts +148 -0
  116. package/src/lines.ts +53 -0
  117. package/src/load-user-module.ts +191 -0
  118. package/src/mdx.ts +248 -0
  119. package/src/paths.ts +36 -0
  120. package/src/rehype/shiki.ts +533 -0
  121. package/src/remark/alerts.ts +53 -0
  122. package/src/remark/ast.ts +96 -0
  123. package/src/remark/callouts.ts +25 -0
  124. package/src/remark/code-file.ts +85 -0
  125. package/src/remark/code-meta.ts +21 -0
  126. package/src/remark/directives.ts +170 -0
  127. package/src/remark/file-paths.ts +64 -0
  128. package/src/remark/headings.ts +131 -0
  129. package/src/remark/no-js.ts +40 -0
  130. package/src/render.ts +337 -0
  131. package/src/serve.ts +322 -0
  132. package/src/styles/globals.css +134 -0
  133. package/src/styles/shadcn.css +641 -0
  134. package/src/tailwind.ts +119 -0
  135. package/src/ui/approvals.tsx +76 -0
  136. package/src/ui/ask-question.tsx +386 -0
  137. package/src/ui/ask.tsx +206 -0
  138. package/src/ui/attrs.ts +51 -0
  139. package/src/ui/audit.tsx +139 -0
  140. package/src/ui/bar-chart.tsx +334 -0
  141. package/src/ui/benchmarks.tsx +143 -0
  142. package/src/ui/bits.tsx +537 -0
  143. package/src/ui/board.tsx +173 -0
  144. package/src/ui/bridge.tsx +207 -0
  145. package/src/ui/bumps.tsx +178 -0
  146. package/src/ui/callout.tsx +106 -0
  147. package/src/ui/changes.tsx +89 -0
  148. package/src/ui/chart-bits.tsx +52 -0
  149. package/src/ui/chart.ts +577 -0
  150. package/src/ui/checks.tsx +203 -0
  151. package/src/ui/child-index.tsx +44 -0
  152. package/src/ui/children.ts +43 -0
  153. package/src/ui/chips.tsx +49 -0
  154. package/src/ui/cmd.tsx +27 -0
  155. package/src/ui/columns.tsx +31 -0
  156. package/src/ui/comments.tsx +544 -0
  157. package/src/ui/compare.tsx +67 -0
  158. package/src/ui/decision.tsx +79 -0
  159. package/src/ui/deps.tsx +78 -0
  160. package/src/ui/details.tsx +43 -0
  161. package/src/ui/diff-parse.ts +307 -0
  162. package/src/ui/diff.tsx +458 -0
  163. package/src/ui/diffstat.tsx +58 -0
  164. package/src/ui/due.tsx +65 -0
  165. package/src/ui/effort.tsx +29 -0
  166. package/src/ui/endpoints.tsx +118 -0
  167. package/src/ui/envvars.tsx +96 -0
  168. package/src/ui/figure.tsx +37 -0
  169. package/src/ui/file-icon.ts +1020 -0
  170. package/src/ui/file-link.ts +32 -0
  171. package/src/ui/file-ref.tsx +39 -0
  172. package/src/ui/files.tsx +112 -0
  173. package/src/ui/findings.tsx +85 -0
  174. package/src/ui/flow.tsx +73 -0
  175. package/src/ui/funnel.tsx +121 -0
  176. package/src/ui/gantt.tsx +443 -0
  177. package/src/ui/gauges.tsx +135 -0
  178. package/src/ui/glossary.tsx +29 -0
  179. package/src/ui/graph-layout.ts +149 -0
  180. package/src/ui/graph-specs.tsx +102 -0
  181. package/src/ui/graph.tsx +278 -0
  182. package/src/ui/grid.tsx +119 -0
  183. package/src/ui/hypothesis.tsx +94 -0
  184. package/src/ui/icon.tsx +80 -0
  185. package/src/ui/incident.tsx +130 -0
  186. package/src/ui/index.ts +342 -0
  187. package/src/ui/ins-del.tsx +41 -0
  188. package/src/ui/json.tsx +190 -0
  189. package/src/ui/layout.ts +9 -0
  190. package/src/ui/line-chart.tsx +251 -0
  191. package/src/ui/matrix.tsx +208 -0
  192. package/src/ui/meta.tsx +73 -0
  193. package/src/ui/option.tsx +64 -0
  194. package/src/ui/owner.tsx +40 -0
  195. package/src/ui/packages.tsx +104 -0
  196. package/src/ui/pathway.tsx +96 -0
  197. package/src/ui/phase.tsx +41 -0
  198. package/src/ui/pie-chart.tsx +170 -0
  199. package/src/ui/plan.tsx +77 -0
  200. package/src/ui/pre.tsx +175 -0
  201. package/src/ui/priority.tsx +51 -0
  202. package/src/ui/props.tsx +77 -0
  203. package/src/ui/quadrant.tsx +172 -0
  204. package/src/ui/radar.tsx +200 -0
  205. package/src/ui/ref.tsx +160 -0
  206. package/src/ui/release.tsx +178 -0
  207. package/src/ui/req.tsx +42 -0
  208. package/src/ui/review.tsx +133 -0
  209. package/src/ui/risk.tsx +67 -0
  210. package/src/ui/sankey.tsx +287 -0
  211. package/src/ui/scatter.tsx +237 -0
  212. package/src/ui/schema.tsx +113 -0
  213. package/src/ui/score.tsx +105 -0
  214. package/src/ui/search.tsx +120 -0
  215. package/src/ui/series.tsx +38 -0
  216. package/src/ui/severity.tsx +69 -0
  217. package/src/ui/shadcn.tsx +216 -0
  218. package/src/ui/spark.tsx +86 -0
  219. package/src/ui/stack.tsx +57 -0
  220. package/src/ui/stats.tsx +63 -0
  221. package/src/ui/status-badge.tsx +66 -0
  222. package/src/ui/statuspage.tsx +238 -0
  223. package/src/ui/steps.tsx +74 -0
  224. package/src/ui/summary.tsx +41 -0
  225. package/src/ui/symbol-ref.tsx +73 -0
  226. package/src/ui/terminal.tsx +117 -0
  227. package/src/ui/tests.tsx +218 -0
  228. package/src/ui/timeline.tsx +63 -0
  229. package/src/ui/toc.tsx +56 -0
  230. package/src/ui/tones.ts +187 -0
  231. package/src/ui/trace.tsx +69 -0
  232. package/src/ui/tree.tsx +281 -0
  233. package/src/ui/treemap.tsx +128 -0
  234. package/src/ui/venn.tsx +258 -0
  235. package/src/ui/verdict.tsx +78 -0
  236. package/src/ui/waterfall.tsx +142 -0
@@ -0,0 +1,27 @@
1
+ import { handleDocEvent, syncBoards } from "./doc-events.js";
2
+
3
+ /**
4
+ * Document entry point — bundled to an IIFE by `client-js.ts` and inlined
5
+ * into every rendered page. Registers the delegated handler, then seeds
6
+ * each Ask output pane (default-checked fields count as answers) by
7
+ * bubbling a synthetic `input` event off the block — the handler's own
8
+ * input branch does the render, so no serialization code is duplicated.
9
+ */
10
+ for (const type of [
11
+ "click",
12
+ "input",
13
+ "change",
14
+ "keydown",
15
+ "dragstart",
16
+ "dragover",
17
+ "drop",
18
+ "dragend",
19
+ ]) {
20
+ document.addEventListener(type, handleDocEvent);
21
+ }
22
+ for (const b of document.querySelectorAll("[data-ask]")) {
23
+ b.dispatchEvent(new Event("input", { bubbles: true }));
24
+ }
25
+ // Move-button `disabled` state depends on each card's lane position —
26
+ // client-side knowledge. Seed it once (and again after every move).
27
+ syncBoards(document);
@@ -0,0 +1,47 @@
1
+ import path from "node:path";
2
+
3
+ import { build } from "esbuild";
4
+
5
+ import { pkgRoot } from "./paths.js";
6
+
7
+ let cache: Promise<string> | undefined;
8
+
9
+ const buildClientJs = async (): Promise<string> => {
10
+ const result = await build({
11
+ absWorkingDir: pkgRoot,
12
+ bundle: true,
13
+ format: "iife",
14
+ logLevel: "silent",
15
+ minify: true,
16
+ platform: "browser",
17
+ stdin: {
18
+ contents: 'import "./client/entry.js";',
19
+ loader: "js",
20
+ resolveDir: path.join(pkgRoot, "src"),
21
+ sourcefile: "mdxr-client.js",
22
+ },
23
+ target: "es2022",
24
+ write: false,
25
+ });
26
+ return result.outputFiles[0]?.text ?? "";
27
+ };
28
+
29
+ /**
30
+ * Vanilla JS inlined into every document (copy/answer/save buttons, the
31
+ * live Markdown answer sheet, the theme toggle). Bundled from
32
+ * `src/client/entry.ts` at render time — real source, so the script is
33
+ * type-checked and unit-testable, and bundler changes can't silently
34
+ * break it the way `fn.toString()` serialization could. Memoized: the
35
+ * bundle is identical for every render in a process.
36
+ */
37
+ export const clientJs = async (): Promise<string> => {
38
+ cache ??= buildClientJs();
39
+ try {
40
+ return await cache;
41
+ } catch (error) {
42
+ // A rejected bundle promise would otherwise poison every later render
43
+ // in this process (mdxr serve keeps failing on one transient error).
44
+ cache = undefined;
45
+ throw error;
46
+ }
47
+ };
@@ -0,0 +1,47 @@
1
+ import type { ComponentMap, MdxrComponent } from "./define.js";
2
+ import { isComponent, isRecord } from "./guards.js";
3
+
4
+ /**
5
+ * `into[k] = v` with `k === "__proto__"` would silently replace the map's
6
+ * prototype instead of registering the component — define it as data.
7
+ */
8
+ const put = (into: ComponentMap, k: string, v: MdxrComponent): void => {
9
+ Object.defineProperty(into, k, {
10
+ configurable: true,
11
+ enumerable: true,
12
+ value: v,
13
+ writable: true,
14
+ });
15
+ };
16
+
17
+ /** A default-exported object is treated as a `{ Name: Component }` map. */
18
+ const mergeDefaultMap = (val: unknown, into: ComponentMap): void => {
19
+ if (!isRecord(val)) {
20
+ return;
21
+ }
22
+ for (const [k, v] of Object.entries(val)) {
23
+ if (isComponent(v)) {
24
+ put(into, k, v);
25
+ }
26
+ }
27
+ };
28
+
29
+ /**
30
+ * Merge a user module's exports into a ComponentMap. A default-exported
31
+ * object is treated as a `{ Name: Component }` map; PascalCase named exports
32
+ * that are functions count directly. Shared by the SSR loader (render.ts)
33
+ * and the hydration bundle (hydrate-runtime.ts) — node-free on purpose.
34
+ */
35
+ export const mergeUserComponents = (
36
+ mod: Record<string, unknown>,
37
+ into: ComponentMap = {}
38
+ ): ComponentMap => {
39
+ for (const [key, val] of Object.entries(mod)) {
40
+ if (key === "default") {
41
+ mergeDefaultMap(val, into);
42
+ } else if (isComponent(val) && /^[A-Z]/u.test(key)) {
43
+ put(into, key, val);
44
+ }
45
+ }
46
+ return into;
47
+ };
@@ -0,0 +1,77 @@
1
+ import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
2
+ import { cn } from "cn";
3
+ import { ChevronDownIcon, ChevronUpIcon } from "lucide-react";
4
+
5
+ function Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {
6
+ return (
7
+ <AccordionPrimitive.Root
8
+ data-slot="accordion"
9
+ className={cn("flex w-full flex-col", className)}
10
+ {...props}
11
+ />
12
+ );
13
+ }
14
+
15
+ function AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {
16
+ return (
17
+ <AccordionPrimitive.Item
18
+ data-slot="accordion-item"
19
+ className={cn("not-last:border-b", className)}
20
+ {...props}
21
+ />
22
+ );
23
+ }
24
+
25
+ function AccordionTrigger({
26
+ className,
27
+ children,
28
+ ...props
29
+ }: AccordionPrimitive.Trigger.Props) {
30
+ return (
31
+ <AccordionPrimitive.Header className="flex">
32
+ <AccordionPrimitive.Trigger
33
+ data-slot="accordion-trigger"
34
+ className={cn(
35
+ "group/accordion-trigger focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:after:border-ring **:data-[slot=accordion-trigger-icon]:text-muted-foreground relative flex flex-1 items-start justify-between rounded-lg border border-transparent py-2.5 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-3 aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4",
36
+ className
37
+ )}
38
+ {...props}
39
+ >
40
+ {children}
41
+ <ChevronDownIcon
42
+ data-slot="accordion-trigger-icon"
43
+ className="pointer-events-none shrink-0 group-aria-expanded/accordion-trigger:hidden"
44
+ />
45
+ <ChevronUpIcon
46
+ data-slot="accordion-trigger-icon"
47
+ className="pointer-events-none hidden shrink-0 group-aria-expanded/accordion-trigger:inline"
48
+ />
49
+ </AccordionPrimitive.Trigger>
50
+ </AccordionPrimitive.Header>
51
+ );
52
+ }
53
+
54
+ function AccordionContent({
55
+ className,
56
+ children,
57
+ ...props
58
+ }: AccordionPrimitive.Panel.Props) {
59
+ return (
60
+ <AccordionPrimitive.Panel
61
+ data-slot="accordion-content"
62
+ className="data-open:animate-accordion-down data-closed:animate-accordion-up overflow-hidden text-sm"
63
+ {...props}
64
+ >
65
+ <div
66
+ className={cn(
67
+ "[&_a]:hover:text-foreground h-(--accordion-panel-height) pt-0 pb-2.5 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4",
68
+ className
69
+ )}
70
+ >
71
+ {children}
72
+ </div>
73
+ </AccordionPrimitive.Panel>
74
+ );
75
+ }
76
+
77
+ export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
@@ -0,0 +1,185 @@
1
+ import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog";
2
+ import { cn } from "cn";
3
+ import * as React from "react";
4
+
5
+ import { Button } from "./button.js";
6
+
7
+ function AlertDialog({ ...props }: AlertDialogPrimitive.Root.Props) {
8
+ return <AlertDialogPrimitive.Root data-slot="alert-dialog" {...props} />;
9
+ }
10
+
11
+ function AlertDialogTrigger({ ...props }: AlertDialogPrimitive.Trigger.Props) {
12
+ return (
13
+ <AlertDialogPrimitive.Trigger data-slot="alert-dialog-trigger" {...props} />
14
+ );
15
+ }
16
+
17
+ function AlertDialogPortal({ ...props }: AlertDialogPrimitive.Portal.Props) {
18
+ return (
19
+ <AlertDialogPrimitive.Portal data-slot="alert-dialog-portal" {...props} />
20
+ );
21
+ }
22
+
23
+ function AlertDialogOverlay({
24
+ className,
25
+ ...props
26
+ }: AlertDialogPrimitive.Backdrop.Props) {
27
+ return (
28
+ <AlertDialogPrimitive.Backdrop
29
+ data-slot="alert-dialog-overlay"
30
+ className={cn(
31
+ "data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs",
32
+ className
33
+ )}
34
+ {...props}
35
+ />
36
+ );
37
+ }
38
+
39
+ function AlertDialogContent({
40
+ className,
41
+ size = "default",
42
+ ...props
43
+ }: AlertDialogPrimitive.Popup.Props & {
44
+ size?: "default" | "sm";
45
+ }) {
46
+ return (
47
+ <AlertDialogPortal>
48
+ <AlertDialogOverlay />
49
+ <AlertDialogPrimitive.Popup
50
+ data-slot="alert-dialog-content"
51
+ data-size={size}
52
+ className={cn(
53
+ "group/alert-dialog-content bg-popover text-popover-foreground ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl p-4 ring-1 duration-100 outline-none data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-sm",
54
+ className
55
+ )}
56
+ {...props}
57
+ />
58
+ </AlertDialogPortal>
59
+ );
60
+ }
61
+
62
+ function AlertDialogHeader({
63
+ className,
64
+ ...props
65
+ }: React.ComponentProps<"div">) {
66
+ return (
67
+ <div
68
+ data-slot="alert-dialog-header"
69
+ className={cn(
70
+ "grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-4 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]",
71
+ className
72
+ )}
73
+ {...props}
74
+ />
75
+ );
76
+ }
77
+
78
+ function AlertDialogFooter({
79
+ className,
80
+ ...props
81
+ }: React.ComponentProps<"div">) {
82
+ return (
83
+ <div
84
+ data-slot="alert-dialog-footer"
85
+ className={cn(
86
+ "bg-muted/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t p-4 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end",
87
+ className
88
+ )}
89
+ {...props}
90
+ />
91
+ );
92
+ }
93
+
94
+ function AlertDialogMedia({
95
+ className,
96
+ ...props
97
+ }: React.ComponentProps<"div">) {
98
+ return (
99
+ <div
100
+ data-slot="alert-dialog-media"
101
+ className={cn(
102
+ "bg-muted mb-2 inline-flex size-10 items-center justify-center rounded-md sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-6",
103
+ className
104
+ )}
105
+ {...props}
106
+ />
107
+ );
108
+ }
109
+
110
+ function AlertDialogTitle({
111
+ className,
112
+ ...props
113
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Title>) {
114
+ return (
115
+ <AlertDialogPrimitive.Title
116
+ data-slot="alert-dialog-title"
117
+ className={cn(
118
+ "font-heading text-base font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2",
119
+ className
120
+ )}
121
+ {...props}
122
+ />
123
+ );
124
+ }
125
+
126
+ function AlertDialogDescription({
127
+ className,
128
+ ...props
129
+ }: React.ComponentProps<typeof AlertDialogPrimitive.Description>) {
130
+ return (
131
+ <AlertDialogPrimitive.Description
132
+ data-slot="alert-dialog-description"
133
+ className={cn(
134
+ "text-muted-foreground *:[a]:hover:text-foreground text-sm text-balance md:text-pretty *:[a]:underline *:[a]:underline-offset-3",
135
+ className
136
+ )}
137
+ {...props}
138
+ />
139
+ );
140
+ }
141
+
142
+ function AlertDialogAction({
143
+ className,
144
+ ...props
145
+ }: React.ComponentProps<typeof Button>) {
146
+ return (
147
+ <Button
148
+ data-slot="alert-dialog-action"
149
+ className={cn(className)}
150
+ {...props}
151
+ />
152
+ );
153
+ }
154
+
155
+ function AlertDialogCancel({
156
+ className,
157
+ variant = "outline",
158
+ size = "default",
159
+ ...props
160
+ }: AlertDialogPrimitive.Close.Props &
161
+ Pick<React.ComponentProps<typeof Button>, "variant" | "size">) {
162
+ return (
163
+ <AlertDialogPrimitive.Close
164
+ data-slot="alert-dialog-cancel"
165
+ className={cn(className)}
166
+ render={<Button variant={variant} size={size} />}
167
+ {...props}
168
+ />
169
+ );
170
+ }
171
+
172
+ export {
173
+ AlertDialog,
174
+ AlertDialogAction,
175
+ AlertDialogCancel,
176
+ AlertDialogContent,
177
+ AlertDialogDescription,
178
+ AlertDialogFooter,
179
+ AlertDialogHeader,
180
+ AlertDialogMedia,
181
+ AlertDialogOverlay,
182
+ AlertDialogPortal,
183
+ AlertDialogTitle,
184
+ AlertDialogTrigger,
185
+ };
@@ -0,0 +1,76 @@
1
+ import { cva } from "class-variance-authority";
2
+ import type { VariantProps } from "class-variance-authority";
3
+ import { cn } from "cn";
4
+ import * as React from "react";
5
+
6
+ const alertVariants = cva(
7
+ "group/alert relative grid w-full gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4",
8
+ {
9
+ defaultVariants: {
10
+ variant: "default",
11
+ },
12
+ variants: {
13
+ variant: {
14
+ default: "bg-card text-card-foreground",
15
+ destructive:
16
+ "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current",
17
+ },
18
+ },
19
+ }
20
+ );
21
+
22
+ function Alert({
23
+ className,
24
+ variant,
25
+ ...props
26
+ }: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
27
+ return (
28
+ <div
29
+ data-slot="alert"
30
+ role="alert"
31
+ className={cn(alertVariants({ variant }), className)}
32
+ {...props}
33
+ />
34
+ );
35
+ }
36
+
37
+ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
38
+ return (
39
+ <div
40
+ data-slot="alert-title"
41
+ className={cn(
42
+ "[&_a]:hover:text-foreground font-medium group-has-[>svg]/alert:col-start-2 [&_a]:underline [&_a]:underline-offset-3",
43
+ className
44
+ )}
45
+ {...props}
46
+ />
47
+ );
48
+ }
49
+
50
+ function AlertDescription({
51
+ className,
52
+ ...props
53
+ }: React.ComponentProps<"div">) {
54
+ return (
55
+ <div
56
+ data-slot="alert-description"
57
+ className={cn(
58
+ "text-muted-foreground [&_a]:hover:text-foreground text-sm text-balance md:text-pretty [&_a]:underline [&_a]:underline-offset-3 [&_p:not(:last-child)]:mb-4",
59
+ className
60
+ )}
61
+ {...props}
62
+ />
63
+ );
64
+ }
65
+
66
+ function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
67
+ return (
68
+ <div
69
+ data-slot="alert-action"
70
+ className={cn("absolute top-2 right-2", className)}
71
+ {...props}
72
+ />
73
+ );
74
+ }
75
+
76
+ export { Alert, AlertTitle, AlertDescription, AlertAction };
@@ -0,0 +1,22 @@
1
+ import { cn } from "cn";
2
+
3
+ function AspectRatio({
4
+ ratio,
5
+ className,
6
+ ...props
7
+ }: React.ComponentProps<"div"> & { ratio: number }) {
8
+ return (
9
+ <div
10
+ data-slot="aspect-ratio"
11
+ style={
12
+ {
13
+ "--ratio": ratio,
14
+ } as React.CSSProperties
15
+ }
16
+ className={cn("relative aspect-(--ratio)", className)}
17
+ {...props}
18
+ />
19
+ );
20
+ }
21
+
22
+ export { AspectRatio };
@@ -0,0 +1,208 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cva } from "class-variance-authority";
4
+ import type { VariantProps } from "class-variance-authority";
5
+ import { cn } from "cn";
6
+ import * as React from "react";
7
+
8
+ import { Button } from "./button.js";
9
+
10
+ const attachmentVariants = cva(
11
+ "group/attachment bg-card text-card-foreground focus-within:ring-ring/50 has-[>a,>button]:hover:bg-muted/50 data-[state=error]:border-destructive/30 relative flex w-fit max-w-full min-w-0 shrink-0 flex-wrap rounded-xl border transition-colors focus-within:ring-1 data-[state=idle]:border-dashed",
12
+ {
13
+ variants: {
14
+ orientation: {
15
+ horizontal: "min-w-40 items-center",
16
+ vertical: "w-24 flex-col has-data-[slot=attachment-content]:w-30",
17
+ },
18
+ size: {
19
+ default:
20
+ "gap-2 text-sm has-data-[slot=attachment-content]:px-2.5 has-data-[slot=attachment-content]:py-2 has-data-[slot=attachment-media]:p-2",
21
+ sm: "gap-2.5 text-xs has-data-[slot=attachment-content]:px-2 has-data-[slot=attachment-content]:py-1.5 has-data-[slot=attachment-media]:p-1.5",
22
+ xs: "gap-1.5 rounded-lg text-xs has-data-[slot=attachment-content]:px-1.5 has-data-[slot=attachment-content]:py-1 has-data-[slot=attachment-media]:p-1",
23
+ },
24
+ },
25
+ }
26
+ );
27
+
28
+ function Attachment({
29
+ className,
30
+ state = "done",
31
+ size = "default",
32
+ orientation = "horizontal",
33
+ ...props
34
+ }: React.ComponentProps<"div"> &
35
+ VariantProps<typeof attachmentVariants> & {
36
+ state?: "idle" | "uploading" | "processing" | "error" | "done";
37
+ }) {
38
+ return (
39
+ <div
40
+ data-slot="attachment"
41
+ data-state={state}
42
+ data-size={size}
43
+ data-orientation={orientation}
44
+ className={cn(attachmentVariants({ orientation, size }), className)}
45
+ {...props}
46
+ />
47
+ );
48
+ }
49
+
50
+ const attachmentMediaVariants = cva(
51
+ "bg-muted text-foreground group-data-[state=error]/attachment:bg-destructive/10 group-data-[state=error]/attachment:text-destructive relative flex aspect-square w-10 shrink-0 items-center justify-center overflow-hidden rounded-lg group-data-[orientation=vertical]/attachment:w-full group-data-[size=sm]/attachment:w-8 group-data-[size=xs]/attachment:w-7 group-data-[size=xs]/attachment:rounded-md group-data-[orientation=vertical]/attachment:*:data-[slot=spinner]:size-6! [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 group-data-[orientation=vertical]/attachment:[&_svg:not([class*='size-'])]:size-6 group-data-[size=xs]/attachment:[&_svg:not([class*='size-'])]:size-3.5",
52
+ {
53
+ defaultVariants: {
54
+ variant: "icon",
55
+ },
56
+ variants: {
57
+ variant: {
58
+ icon: "",
59
+ image:
60
+ "opacity-60 group-data-[state=done]/attachment:opacity-100 group-data-[state=idle]/attachment:opacity-100 *:[img]:aspect-square *:[img]:w-full *:[img]:object-cover",
61
+ },
62
+ },
63
+ }
64
+ );
65
+
66
+ function AttachmentMedia({
67
+ className,
68
+ variant = "icon",
69
+ ...props
70
+ }: React.ComponentProps<"div"> & VariantProps<typeof attachmentMediaVariants>) {
71
+ return (
72
+ <div
73
+ data-slot="attachment-media"
74
+ data-variant={variant}
75
+ className={cn(attachmentMediaVariants({ variant }), className)}
76
+ {...props}
77
+ />
78
+ );
79
+ }
80
+
81
+ function AttachmentContent({
82
+ className,
83
+ ...props
84
+ }: React.ComponentProps<"div">) {
85
+ return (
86
+ <div
87
+ data-slot="attachment-content"
88
+ className={cn(
89
+ "max-w-full min-w-0 flex-1 leading-tight group-data-[orientation=vertical]/attachment:px-1",
90
+ className
91
+ )}
92
+ {...props}
93
+ />
94
+ );
95
+ }
96
+
97
+ function AttachmentTitle({
98
+ className,
99
+ ...props
100
+ }: React.ComponentProps<"span">) {
101
+ return (
102
+ <span
103
+ data-slot="attachment-title"
104
+ className={cn(
105
+ "group-data-[state=processing]/attachment:shimmer group-data-[state=uploading]/attachment:shimmer block max-w-full min-w-0 truncate font-medium",
106
+ className
107
+ )}
108
+ {...props}
109
+ />
110
+ );
111
+ }
112
+
113
+ function AttachmentDescription({
114
+ className,
115
+ ...props
116
+ }: React.ComponentProps<"span">) {
117
+ return (
118
+ <span
119
+ data-slot="attachment-description"
120
+ className={cn(
121
+ "text-muted-foreground group-data-[state=error]/attachment:text-destructive/80 mt-0.5 block min-w-0 truncate text-xs",
122
+ "max-w-full",
123
+ className
124
+ )}
125
+ {...props}
126
+ />
127
+ );
128
+ }
129
+
130
+ function AttachmentActions({
131
+ className,
132
+ ...props
133
+ }: React.ComponentProps<"div">) {
134
+ return (
135
+ <div
136
+ data-slot="attachment-actions"
137
+ className={cn(
138
+ "relative z-20 flex shrink-0 items-center group-data-[orientation=vertical]/attachment:absolute group-data-[orientation=vertical]/attachment:top-3 group-data-[orientation=vertical]/attachment:right-3 group-data-[orientation=vertical]/attachment:gap-1",
139
+ className
140
+ )}
141
+ {...props}
142
+ />
143
+ );
144
+ }
145
+
146
+ function AttachmentAction({
147
+ className,
148
+ variant,
149
+ size = "icon-xs",
150
+ ...props
151
+ }: React.ComponentProps<typeof Button>) {
152
+ return (
153
+ <Button
154
+ data-slot="attachment-action"
155
+ variant={variant ?? "ghost"}
156
+ size={size}
157
+ className={cn(className)}
158
+ {...props}
159
+ />
160
+ );
161
+ }
162
+
163
+ function AttachmentTrigger({
164
+ className,
165
+ render,
166
+ type,
167
+ ...props
168
+ }: useRender.ComponentProps<"button">) {
169
+ return useRender({
170
+ defaultTagName: "button",
171
+ props: mergeProps<"button">(
172
+ {
173
+ className: cn("absolute inset-0 z-10 outline-none", className),
174
+ type: render ? type : (type ?? "button"),
175
+ },
176
+ props
177
+ ),
178
+ render,
179
+ state: {
180
+ slot: "attachment-trigger",
181
+ },
182
+ });
183
+ }
184
+
185
+ function AttachmentGroup({ className, ...props }: React.ComponentProps<"div">) {
186
+ return (
187
+ <div
188
+ data-slot="attachment-group"
189
+ className={cn(
190
+ "scroll-fade-x no-scrollbar flex min-w-0 snap-x snap-mandatory scroll-px-1 gap-3 overflow-x-auto overscroll-x-contain py-1 *:data-[slot=attachment]:flex-none *:data-[slot=attachment]:snap-start",
191
+ className
192
+ )}
193
+ {...props}
194
+ />
195
+ );
196
+ }
197
+
198
+ export {
199
+ Attachment,
200
+ AttachmentGroup,
201
+ AttachmentMedia,
202
+ AttachmentContent,
203
+ AttachmentTitle,
204
+ AttachmentDescription,
205
+ AttachmentActions,
206
+ AttachmentAction,
207
+ AttachmentTrigger,
208
+ };