@caqophony/ui 0.0.0-stage → 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Caqophony
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,67 @@
1
- # Temporary Holding Version
1
+ # @caqophony/ui
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Generic React UI components built on Gossamer semantic design tokens
4
+ (Tailwind). Maintained centrally by Caqophony and MIT licensed.
5
+
6
+ **This library is optional.** Apps generated by Caqophony may use it so that
7
+ common UI (buttons, cards, dialogs, tables, page layout) is not regenerated
8
+ from scratch for every app, which saves tokens. It is a courtesy, not an SDK:
9
+ nothing in a generated app requires it. If reuse is turned off for a project,
10
+ the app is built without this dependency and its components are written from
11
+ scratch. It contains only generic UI: no platform, product, auth or
12
+ data-access code.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ pnpm add @caqophony/ui # or npm i / yarn add
18
+ ```
19
+
20
+ Peer dependencies: `react` and `react-dom` (`^18 || ^19`). `@caqophony/ui/charts`
21
+ requires the optional peers `chart.js` and `react-chartjs-2`: install them
22
+ yourself if you import that subpath. No `next` dependency.
23
+
24
+ The package is ESM-only. Subpath types (`@caqophony/ui/charts`) resolve through
25
+ the `exports` map, so TypeScript needs `moduleResolution` of `bundler` (or
26
+ `node16`/`nodenext`).
27
+
28
+ `DiceBearAvatar` renders an image from `api.dicebear.com` at runtime, so it
29
+ makes a network request from the user's browser; do not use it where that is
30
+ unacceptable.
31
+
32
+ ## Styles (Tailwind v4)
33
+
34
+ Components use Gossamer token classes (`bg-primary`, `text-muted-foreground`,
35
+ `border-intent-error-border`, ...). Tailwind v4 does not scan `node_modules`
36
+ and has no mapping for these names, so import the stylesheet this package
37
+ ships, after Tailwind, in your global CSS:
38
+
39
+ ```css
40
+ @import 'tailwindcss';
41
+ @import '@caqophony/ui/styles.css';
42
+ ```
43
+
44
+ `styles.css` defines the token variables (light and `.dark`), maps them to
45
+ Tailwind v4 colour/radius/z-index/opacity/duration utilities and registers the
46
+ package's built files as a Tailwind `@source`. Override any `--token` after the
47
+ import to re-theme.
48
+
49
+ Tailwind v3 consumers: add `./node_modules/@caqophony/ui/dist/**/*.js` to
50
+ `content` and map the same variables in `theme.extend.colors`.
51
+
52
+ `animate-in` / `animate-out` (used by tooltips) come from `tailwindcss-animate`
53
+ (v3) or `tw-animate-css` (v4); without it those animations are simply absent.
54
+
55
+ ## Use
56
+
57
+ ```tsx
58
+ import { Button, Card, PageContent } from '@caqophony/ui';
59
+ import { BarChart } from '@caqophony/ui/charts';
60
+ import { MarkdownRenderer } from '@caqophony/ui/markdown';
61
+ ```
62
+
63
+ Every entry point carries a `'use client'` directive.
64
+
65
+ ## Licence
66
+
67
+ MIT, see `LICENSE`.
@@ -0,0 +1,117 @@
1
+ import * as react_jsx_runtime from 'react/jsx-runtime';
2
+ export { Chart as ChartJS } from 'chart.js';
3
+
4
+ /**
5
+ * Chart Types - Shared type definitions for chart components
6
+ *
7
+ * Authored by Caqophony
8
+ */
9
+ interface ChartDataPoint {
10
+ label: string;
11
+ value: number;
12
+ }
13
+ interface TimeSeriesDataPoint {
14
+ date: string | Date;
15
+ value: number;
16
+ secondaryValue?: number;
17
+ }
18
+ interface BaseChartProps {
19
+ /** Height of the chart container */
20
+ height?: number | string;
21
+ /** Whether to show the legend */
22
+ showLegend?: boolean;
23
+ /** Empty state message when no data */
24
+ emptyMessage?: string;
25
+ /** Additional CSS classes */
26
+ className?: string;
27
+ }
28
+ interface LineChartProps extends BaseChartProps {
29
+ data: TimeSeriesDataPoint[];
30
+ /** Label for the primary dataset */
31
+ label?: string;
32
+ /** Label for the secondary dataset (if secondaryValue provided) */
33
+ secondaryLabel?: string;
34
+ /** Primary line color */
35
+ color?: string;
36
+ /** Secondary line color */
37
+ secondaryColor?: string;
38
+ /** Fill area under line */
39
+ fill?: boolean;
40
+ /** Date format for labels */
41
+ dateFormat?: Intl.DateTimeFormatOptions;
42
+ }
43
+ interface BarChartProps extends BaseChartProps {
44
+ data: ChartDataPoint[];
45
+ /** Label for the dataset */
46
+ label?: string;
47
+ /** Bar color */
48
+ color?: string;
49
+ /** Horizontal bar chart */
50
+ horizontal?: boolean;
51
+ }
52
+ interface DoughnutChartProps extends BaseChartProps {
53
+ data: ChartDataPoint[];
54
+ /** Colors for each segment */
55
+ colors?: string[];
56
+ /** Show percentage labels */
57
+ showPercentage?: boolean;
58
+ }
59
+ type NumberFormatMode = 'compact' | 'full' | 'currency';
60
+
61
+ declare function LineChart({ data, label, secondaryLabel, color, secondaryColor, fill, showLegend, height, emptyMessage, dateFormat, className, }: LineChartProps): react_jsx_runtime.JSX.Element;
62
+
63
+ declare function BarChart({ data, label, color, horizontal, showLegend, height, emptyMessage, className, }: BarChartProps): react_jsx_runtime.JSX.Element;
64
+
65
+ declare function DoughnutChart({ data, colors, showPercentage, showLegend, height, emptyMessage, className, }: DoughnutChartProps): react_jsx_runtime.JSX.Element;
66
+
67
+ /**
68
+ * ChartSkeleton - Loading state for chart components
69
+ *
70
+ * @example
71
+ * ```tsx
72
+ * import { ChartSkeleton } from '@caqophony/ui/charts';
73
+ *
74
+ * {isLoading ? <ChartSkeleton /> : <LineChart data={data} />}
75
+ * ```
76
+ *
77
+ * Authored by Caqophony
78
+ */
79
+ interface ChartSkeletonProps {
80
+ height?: number | string;
81
+ className?: string;
82
+ }
83
+ declare function ChartSkeleton({ height, className }: ChartSkeletonProps): react_jsx_runtime.JSX.Element;
84
+
85
+ /**
86
+ * Chart Utilities - Shared formatting and helper functions
87
+ *
88
+ * Authored by Caqophony
89
+ */
90
+
91
+ /**
92
+ * Format a number for display in charts (compact: 1K, 1M, etc.)
93
+ */
94
+ declare function formatNumber(value: number, mode?: NumberFormatMode): string;
95
+ /**
96
+ * Format a date for chart labels
97
+ */
98
+ declare function formatDateLabel(date: string | Date, options?: Intl.DateTimeFormatOptions): string;
99
+ /**
100
+ * Generate colors for chart segments
101
+ */
102
+ declare function generateColors(count: number): string[];
103
+ /**
104
+ * Default chart colors
105
+ */
106
+ declare const CHART_COLORS: {
107
+ readonly primary: "rgb(59, 130, 246)";
108
+ readonly primaryFill: "rgba(59, 130, 246, 0.1)";
109
+ readonly secondary: "rgb(147, 51, 234)";
110
+ readonly secondaryFill: "rgba(147, 51, 234, 0.1)";
111
+ readonly success: "rgb(34, 197, 94)";
112
+ readonly warning: "rgb(234, 179, 8)";
113
+ readonly danger: "rgb(239, 68, 68)";
114
+ readonly gray: "rgb(107, 114, 128)";
115
+ };
116
+
117
+ export { BarChart, type BarChartProps, type BaseChartProps, CHART_COLORS, type ChartDataPoint, ChartSkeleton, DoughnutChart, type DoughnutChartProps, LineChart, type LineChartProps, type NumberFormatMode, type TimeSeriesDataPoint, formatDateLabel, formatNumber, generateColors };
package/dist/charts.js ADDED
@@ -0,0 +1,367 @@
1
+ 'use client';
2
+
3
+ // src/charts/line-chart.tsx
4
+ import { useMemo } from "react";
5
+ import { Line } from "react-chartjs-2";
6
+
7
+ // src/charts/utils.ts
8
+ function formatNumber(value, mode = "compact") {
9
+ if (mode === "currency") {
10
+ return new Intl.NumberFormat("en-US", {
11
+ style: "currency",
12
+ currency: "USD",
13
+ minimumFractionDigits: 0,
14
+ maximumFractionDigits: 0
15
+ }).format(value);
16
+ }
17
+ if (mode === "full") {
18
+ return value.toLocaleString();
19
+ }
20
+ if (value >= 1e6) {
21
+ return `${(value / 1e6).toFixed(1)}M`;
22
+ }
23
+ if (value >= 1e3) {
24
+ return `${Math.round(value / 1e3)}K`;
25
+ }
26
+ return value.toString();
27
+ }
28
+ function formatDateLabel(date, options = { month: "short", day: "numeric" }) {
29
+ const d = typeof date === "string" ? new Date(date) : date;
30
+ return d.toLocaleDateString("en-US", options);
31
+ }
32
+ function generateColors(count) {
33
+ return Array.from({ length: count }, (_, i) => {
34
+ const hue = i * 360 / count;
35
+ return `hsla(${hue}, 70%, 60%, 0.8)`;
36
+ });
37
+ }
38
+ var CHART_COLORS = {
39
+ primary: "rgb(59, 130, 246)",
40
+ // blue-500
41
+ primaryFill: "rgba(59, 130, 246, 0.1)",
42
+ secondary: "rgb(147, 51, 234)",
43
+ // purple-600
44
+ secondaryFill: "rgba(147, 51, 234, 0.1)",
45
+ success: "rgb(34, 197, 94)",
46
+ // green-500
47
+ warning: "rgb(234, 179, 8)",
48
+ // yellow-500
49
+ danger: "rgb(239, 68, 68)",
50
+ // red-500
51
+ gray: "rgb(107, 114, 128)"
52
+ // gray-500
53
+ };
54
+ var BASE_CHART_OPTIONS = {
55
+ responsive: true,
56
+ maintainAspectRatio: false,
57
+ interaction: {
58
+ intersect: false,
59
+ mode: "index"
60
+ }
61
+ };
62
+
63
+ // src/charts/chart-registry.ts
64
+ import {
65
+ Chart as ChartJS,
66
+ CategoryScale,
67
+ LinearScale,
68
+ PointElement,
69
+ LineElement,
70
+ BarElement,
71
+ ArcElement,
72
+ Title,
73
+ Tooltip,
74
+ Legend,
75
+ Filler
76
+ } from "chart.js";
77
+ ChartJS.register(
78
+ CategoryScale,
79
+ LinearScale,
80
+ PointElement,
81
+ LineElement,
82
+ BarElement,
83
+ ArcElement,
84
+ Title,
85
+ Tooltip,
86
+ Legend,
87
+ Filler
88
+ );
89
+
90
+ // src/charts/line-chart.tsx
91
+ import { jsx } from "react/jsx-runtime";
92
+ function LineChart({
93
+ data,
94
+ label = "Value",
95
+ secondaryLabel,
96
+ color = CHART_COLORS.primary,
97
+ secondaryColor = CHART_COLORS.secondary,
98
+ fill = false,
99
+ showLegend = false,
100
+ height = 256,
101
+ emptyMessage = "No data available",
102
+ dateFormat,
103
+ className
104
+ }) {
105
+ const chartData = useMemo(() => {
106
+ const labels = data.map((d) => formatDateLabel(d.date, dateFormat));
107
+ const datasets = [
108
+ {
109
+ label,
110
+ data: data.map((d) => d.value),
111
+ borderColor: color,
112
+ backgroundColor: fill ? color.replace("rgb", "rgba").replace(")", ", 0.1)") : "transparent",
113
+ fill,
114
+ tension: 0.3,
115
+ pointRadius: 3,
116
+ pointHoverRadius: 5
117
+ }
118
+ ];
119
+ if (data.some((d) => d.secondaryValue !== void 0) && secondaryLabel) {
120
+ datasets.push({
121
+ label: secondaryLabel,
122
+ data: data.map((d) => d.secondaryValue ?? 0),
123
+ borderColor: secondaryColor,
124
+ backgroundColor: "transparent",
125
+ fill: false,
126
+ tension: 0.3,
127
+ pointRadius: 2,
128
+ pointHoverRadius: 5
129
+ });
130
+ }
131
+ return { labels, datasets };
132
+ }, [data, label, secondaryLabel, color, secondaryColor, fill, dateFormat]);
133
+ const options = useMemo(
134
+ () => ({
135
+ ...BASE_CHART_OPTIONS,
136
+ plugins: {
137
+ legend: {
138
+ display: showLegend,
139
+ position: "top"
140
+ },
141
+ tooltip: {
142
+ callbacks: {
143
+ label: (context) => {
144
+ const val = context.parsed.y ?? 0;
145
+ return `${context.dataset.label}: ${formatNumber(val)}`;
146
+ }
147
+ }
148
+ }
149
+ },
150
+ scales: {
151
+ x: {
152
+ grid: {
153
+ display: false
154
+ }
155
+ },
156
+ y: {
157
+ beginAtZero: true,
158
+ ticks: {
159
+ callback: (tickValue) => {
160
+ if (tickValue === null) return "";
161
+ const value = typeof tickValue === "number" ? tickValue : parseFloat(String(tickValue));
162
+ return formatNumber(value);
163
+ }
164
+ }
165
+ }
166
+ }
167
+ }),
168
+ [showLegend]
169
+ );
170
+ if (data.length === 0) {
171
+ return /* @__PURE__ */ jsx(
172
+ "div",
173
+ {
174
+ className: `flex items-center justify-center text-gray-500 ${className ?? ""}`,
175
+ style: { height },
176
+ children: emptyMessage
177
+ }
178
+ );
179
+ }
180
+ return /* @__PURE__ */ jsx("div", { className, style: { height }, children: /* @__PURE__ */ jsx(Line, { data: chartData, options }) });
181
+ }
182
+
183
+ // src/charts/bar-chart.tsx
184
+ import { useMemo as useMemo2 } from "react";
185
+ import { Bar } from "react-chartjs-2";
186
+ import { jsx as jsx2 } from "react/jsx-runtime";
187
+ function BarChart({
188
+ data,
189
+ label = "Value",
190
+ color = CHART_COLORS.primary,
191
+ horizontal = false,
192
+ showLegend = false,
193
+ height = 256,
194
+ emptyMessage = "No data available",
195
+ className
196
+ }) {
197
+ const chartData = useMemo2(() => {
198
+ const labels = data.map((d) => d.label);
199
+ const colors = data.length > 1 ? generateColors(data.length) : [color];
200
+ return {
201
+ labels,
202
+ datasets: [
203
+ {
204
+ label,
205
+ data: data.map((d) => d.value),
206
+ backgroundColor: colors,
207
+ borderColor: colors.map((c) => c.replace("0.8", "1")),
208
+ borderWidth: 1
209
+ }
210
+ ]
211
+ };
212
+ }, [data, label, color]);
213
+ const options = useMemo2(
214
+ () => ({
215
+ ...BASE_CHART_OPTIONS,
216
+ indexAxis: horizontal ? "y" : "x",
217
+ plugins: {
218
+ legend: {
219
+ display: showLegend
220
+ },
221
+ tooltip: {
222
+ callbacks: {
223
+ label: (context) => {
224
+ const val = horizontal ? context.parsed.x ?? 0 : context.parsed.y ?? 0;
225
+ return `${context.dataset.label}: ${formatNumber(val)}`;
226
+ }
227
+ }
228
+ }
229
+ },
230
+ scales: {
231
+ x: {
232
+ beginAtZero: true,
233
+ ticks: horizontal ? {
234
+ callback: (tickValue) => {
235
+ if (tickValue === null) return "";
236
+ const value = typeof tickValue === "number" ? tickValue : parseFloat(String(tickValue));
237
+ return formatNumber(value);
238
+ }
239
+ } : void 0
240
+ },
241
+ y: {
242
+ beginAtZero: true,
243
+ ticks: !horizontal ? {
244
+ callback: (tickValue) => {
245
+ if (tickValue === null) return "";
246
+ const value = typeof tickValue === "number" ? tickValue : parseFloat(String(tickValue));
247
+ return formatNumber(value);
248
+ }
249
+ } : void 0
250
+ }
251
+ }
252
+ }),
253
+ [horizontal, showLegend]
254
+ );
255
+ if (data.length === 0) {
256
+ return /* @__PURE__ */ jsx2(
257
+ "div",
258
+ {
259
+ className: `flex items-center justify-center text-gray-500 ${className ?? ""}`,
260
+ style: { height },
261
+ children: emptyMessage
262
+ }
263
+ );
264
+ }
265
+ return /* @__PURE__ */ jsx2("div", { className, style: { height }, children: /* @__PURE__ */ jsx2(Bar, { data: chartData, options }) });
266
+ }
267
+
268
+ // src/charts/doughnut-chart.tsx
269
+ import { useMemo as useMemo3 } from "react";
270
+ import { Doughnut } from "react-chartjs-2";
271
+ import { jsx as jsx3 } from "react/jsx-runtime";
272
+ function DoughnutChart({
273
+ data,
274
+ colors,
275
+ showPercentage = false,
276
+ showLegend = true,
277
+ height = 256,
278
+ emptyMessage = "No data available",
279
+ className
280
+ }) {
281
+ const total = useMemo3(
282
+ () => data.reduce((sum, d) => sum + d.value, 0),
283
+ [data]
284
+ );
285
+ const chartData = useMemo3(() => {
286
+ const labels = data.map((d) => d.label);
287
+ const chartColors = colors ?? generateColors(data.length);
288
+ return {
289
+ labels,
290
+ datasets: [
291
+ {
292
+ data: data.map((d) => d.value),
293
+ backgroundColor: chartColors,
294
+ borderColor: chartColors.map((c) => c.replace("0.8", "1")),
295
+ borderWidth: 1
296
+ }
297
+ ]
298
+ };
299
+ }, [data, colors]);
300
+ const options = useMemo3(
301
+ () => ({
302
+ ...BASE_CHART_OPTIONS,
303
+ plugins: {
304
+ legend: {
305
+ display: showLegend,
306
+ position: "right"
307
+ },
308
+ tooltip: {
309
+ callbacks: {
310
+ label: (context) => {
311
+ const val = context.parsed;
312
+ const percentage = total > 0 ? Math.round(val / total * 100) : 0;
313
+ if (showPercentage) {
314
+ return `${context.label}: ${formatNumber(val)} (${percentage}%)`;
315
+ }
316
+ return `${context.label}: ${formatNumber(val)}`;
317
+ }
318
+ }
319
+ }
320
+ }
321
+ }),
322
+ [showLegend, showPercentage, total]
323
+ );
324
+ if (data.length === 0) {
325
+ return /* @__PURE__ */ jsx3(
326
+ "div",
327
+ {
328
+ className: `flex items-center justify-center text-gray-500 ${className ?? ""}`,
329
+ style: { height },
330
+ children: emptyMessage
331
+ }
332
+ );
333
+ }
334
+ return /* @__PURE__ */ jsx3("div", { className, style: { height }, children: /* @__PURE__ */ jsx3(Doughnut, { data: chartData, options }) });
335
+ }
336
+
337
+ // src/charts/chart-skeleton.tsx
338
+ import { jsx as jsx4, jsxs } from "react/jsx-runtime";
339
+ function ChartSkeleton({ height = 256, className }) {
340
+ return /* @__PURE__ */ jsx4(
341
+ "div",
342
+ {
343
+ className: `animate-pulse rounded-lg bg-gray-100 ${className ?? ""}`,
344
+ style: { height },
345
+ children: /* @__PURE__ */ jsxs("div", { className: "flex h-full items-end justify-around gap-2 p-4", children: [
346
+ /* @__PURE__ */ jsx4("div", { className: "h-1/3 w-8 rounded-t bg-gray-200" }),
347
+ /* @__PURE__ */ jsx4("div", { className: "h-1/2 w-8 rounded-t bg-gray-200" }),
348
+ /* @__PURE__ */ jsx4("div", { className: "h-2/3 w-8 rounded-t bg-gray-200" }),
349
+ /* @__PURE__ */ jsx4("div", { className: "h-1/2 w-8 rounded-t bg-gray-200" }),
350
+ /* @__PURE__ */ jsx4("div", { className: "h-3/4 w-8 rounded-t bg-gray-200" }),
351
+ /* @__PURE__ */ jsx4("div", { className: "h-1/3 w-8 rounded-t bg-gray-200" }),
352
+ /* @__PURE__ */ jsx4("div", { className: "h-1/2 w-8 rounded-t bg-gray-200" })
353
+ ] })
354
+ }
355
+ );
356
+ }
357
+ export {
358
+ BarChart,
359
+ CHART_COLORS,
360
+ ChartJS,
361
+ ChartSkeleton,
362
+ DoughnutChart,
363
+ LineChart,
364
+ formatDateLabel,
365
+ formatNumber,
366
+ generateColors
367
+ };
@@ -0,0 +1,72 @@
1
+ 'use client';
2
+
3
+ // src/markdown-renderer.tsx
4
+ import { memo } from "react";
5
+ import ReactMarkdown from "react-markdown";
6
+ import remarkGfm from "remark-gfm";
7
+
8
+ // src/utils.ts
9
+ import { clsx } from "clsx";
10
+ import { twMerge } from "tailwind-merge";
11
+ function cn(...inputs) {
12
+ return twMerge(clsx(inputs));
13
+ }
14
+
15
+ // src/markdown-renderer.tsx
16
+ import { Fragment, jsx } from "react/jsx-runtime";
17
+ var components = {
18
+ // Links open in new tab
19
+ a: ({ children, href, ...props }) => /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", ...props, children }),
20
+ // Pre blocks pass through children (code block handles its own styling)
21
+ pre: ({ children }) => /* @__PURE__ */ jsx(Fragment, { children })
22
+ };
23
+ var remarkPlugins = [remarkGfm];
24
+ function getProseClasses(size, className) {
25
+ return cn(
26
+ // Base prose sizing
27
+ size === "sm" ? "prose prose-sm" : "prose",
28
+ // Let parent container control width
29
+ "max-w-none",
30
+ // Headings
31
+ "prose-headings:text-foreground dark:prose-headings:text-foreground prose-headings:font-semibold",
32
+ // Body text
33
+ "prose-p:text-foreground dark:prose-p:text-foreground",
34
+ // Strong/bold
35
+ "prose-strong:text-foreground dark:prose-strong:text-foreground",
36
+ // Emphasis/italic
37
+ "prose-em:text-foreground dark:prose-em:text-foreground",
38
+ // Links
39
+ "prose-a:text-primary dark:prose-a:text-primary prose-a:no-underline hover:prose-a:underline",
40
+ // Lists
41
+ "prose-li:text-foreground dark:prose-li:text-foreground",
42
+ // Inline code
43
+ "prose-code:text-foreground dark:prose-code:text-foreground prose-code:bg-muted dark:prose-code:bg-muted prose-code:rounded prose-code:px-1.5 prose-code:py-0.5 prose-code:text-[0.85em] prose-code:font-normal prose-code:before:content-none prose-code:after:content-none",
44
+ // Code blocks
45
+ "prose-pre:bg-muted dark:prose-pre:bg-muted prose-pre:text-foreground dark:prose-pre:text-foreground prose-pre:rounded-md",
46
+ // Blockquotes
47
+ "prose-blockquote:text-muted-foreground dark:prose-blockquote:text-muted-foreground prose-blockquote:border-border dark:prose-blockquote:border-border",
48
+ // Horizontal rules
49
+ "prose-hr:border-border dark:prose-hr:border-border",
50
+ // Tables
51
+ "prose-th:text-foreground dark:prose-th:text-foreground prose-th:border-border dark:prose-th:border-border",
52
+ "prose-td:text-foreground dark:prose-td:text-foreground prose-td:border-border dark:prose-td:border-border",
53
+ className
54
+ );
55
+ }
56
+ function NonMemoizedMarkdownRenderer({
57
+ children,
58
+ className,
59
+ size = "sm"
60
+ }) {
61
+ return /* @__PURE__ */ jsx("div", { className: getProseClasses(size, className), children: /* @__PURE__ */ jsx(ReactMarkdown, { remarkPlugins, components, children }) });
62
+ }
63
+ var MarkdownRenderer = memo(
64
+ NonMemoizedMarkdownRenderer,
65
+ (prev, next) => prev.children === next.children && prev.className === next.className && prev.size === next.size
66
+ );
67
+ MarkdownRenderer.displayName = "MarkdownRenderer";
68
+
69
+ export {
70
+ cn,
71
+ MarkdownRenderer
72
+ };