@siyahi/ui 0.1.9-next.1 → 0.1.9-next.12

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 (69) hide show
  1. package/README.md +52 -8
  2. package/THIRD_PARTY_NOTICES.md +11 -10
  3. package/dist/components/registry/charts/area-chart-card.d.ts +4 -3
  4. package/dist/components/registry/charts/area-chart-card.js +2 -2
  5. package/dist/components/registry/charts/bar-chart-card.d.ts +7 -1
  6. package/dist/components/registry/charts/bar-chart-card.js +35 -14
  7. package/dist/components/registry/charts/line-chart-card.d.ts +5 -2
  8. package/dist/components/registry/charts/line-chart-card.js +2 -2
  9. package/dist/components/registry/dashboard-01/section-cards.d.ts +4 -0
  10. package/dist/components/registry/dashboard-01/section-cards.js +42 -34
  11. package/dist/components/registry/dashboardcn/bar-list.d.ts +3 -1
  12. package/dist/components/registry/dashboardcn/bar-list.js +3 -3
  13. package/dist/components/registry/dashboardcn/distribution-bar.d.ts +38 -0
  14. package/dist/components/registry/dashboardcn/distribution-bar.js +118 -0
  15. package/dist/components/registry/dashboardcn/kpi-row-card.d.ts +29 -0
  16. package/dist/components/registry/dashboardcn/kpi-row-card.js +81 -0
  17. package/dist/components/registry/dashboardcn/sparkline.d.ts +18 -0
  18. package/dist/components/registry/dashboardcn/sparkline.js +95 -0
  19. package/dist/components/registry/minidev/copy-button.d.ts +11 -0
  20. package/dist/components/registry/minidev/copy-button.js +34 -0
  21. package/dist/components/registry/niko-table/ui/table.js +2 -2
  22. package/dist/components/registry/sidebar-07/nav-main.d.ts +1 -1
  23. package/dist/components/siyahi/data-bar.d.ts +19 -0
  24. package/dist/components/siyahi/data-bar.js +29 -0
  25. package/dist/components/siyahi/page-section.d.ts +4 -1
  26. package/dist/components/siyahi/page-section.js +6 -3
  27. package/dist/components/siyahi/panel-grid.d.ts +22 -0
  28. package/dist/components/siyahi/panel-grid.js +34 -0
  29. package/dist/components/siyahi/siyahi-provider.d.ts +13 -2
  30. package/dist/components/siyahi/siyahi-provider.js +17 -4
  31. package/dist/components/ui/accordion.js +5 -5
  32. package/dist/components/ui/alert.js +2 -2
  33. package/dist/components/ui/badge.js +1 -1
  34. package/dist/components/ui/breadcrumb.js +2 -2
  35. package/dist/components/ui/button.js +10 -10
  36. package/dist/components/ui/calendar.js +1 -1
  37. package/dist/components/ui/card.js +4 -4
  38. package/dist/components/ui/chart.js +1 -1
  39. package/dist/components/ui/code-block.js +13 -12
  40. package/dist/components/ui/command.js +7 -6
  41. package/dist/components/ui/context-menu.js +7 -7
  42. package/dist/components/ui/dialog.js +5 -5
  43. package/dist/components/ui/dropdown-menu.js +8 -8
  44. package/dist/components/ui/input-group.js +11 -11
  45. package/dist/components/ui/input.js +1 -1
  46. package/dist/components/ui/popover.js +3 -3
  47. package/dist/components/ui/progress.js +1 -1
  48. package/dist/components/ui/select.js +6 -6
  49. package/dist/components/ui/sheet.js +5 -5
  50. package/dist/components/ui/sidebar.js +17 -18
  51. package/dist/components/ui/skeleton.js +1 -1
  52. package/dist/components/ui/slider.js +2 -2
  53. package/dist/components/ui/table.js +2 -2
  54. package/dist/components/ui/tabs.js +2 -2
  55. package/dist/components/ui/textarea.js +1 -1
  56. package/dist/components/ui/toggle-group.js +2 -2
  57. package/dist/components/ui/toggle.js +4 -4
  58. package/dist/components/ui/tooltip.js +2 -2
  59. package/dist/index.d.ts +12 -7
  60. package/dist/index.js +9 -4
  61. package/dist/lib/chart-frame.d.ts +18 -4
  62. package/dist/lib/chart-frame.js +183 -56
  63. package/dist/lib/chart-series.d.ts +58 -3
  64. package/package.json +1 -1
  65. package/registry.lock.json +32 -0
  66. package/report.css +11 -11
  67. package/styles/siyahi.css +53 -11
  68. package/dist/lib/recharts.d.ts +0 -2
  69. package/dist/lib/recharts.js +0 -1
@@ -0,0 +1,29 @@
1
+ import { Card } from "../../ui/card.js";
2
+ import * as React$1 from "react";
3
+ //#region src/components/registry/dashboardcn/kpi-row-card.d.ts
4
+ export interface MetricStripItem {
5
+ /** Muted label above the figure. */
6
+ label: string;
7
+ /** The figure, formatted by the page: money(4512300). */
8
+ value: React$1.ReactNode;
9
+ /** The signed change, drawn as a Delta under the figure; its sign colours the trend. For "pct", a fraction. */
10
+ change?: number;
11
+ changeFormat?: "pct" | "money";
12
+ /** Muted words after the change, such as "vs last month". */
13
+ note?: React$1.ReactNode;
14
+ /** Recent values, oldest first, drawn as a sparkline beside the figure. */
15
+ trend?: number[];
16
+ }
17
+ export interface MetricStripProps extends Omit<React$1.ComponentProps<typeof Card>, "title"> {
18
+ title?: React$1.ReactNode;
19
+ description?: React$1.ReactNode;
20
+ /** A range toggle, top right, that changes every figure. */
21
+ action?: React$1.ReactNode;
22
+ items: MetricStripItem[];
23
+ /** Lines under the strip, such as what the figures cover. */
24
+ footer?: React$1.ReactNode;
25
+ }
26
+ /** A card holding a row of small figures, each with its change and a sparkline: more numbers in less room than stat tiles. */
27
+ declare function MetricStrip({ title, description, action, items, footer, className, ...props }: MetricStripProps): React$1.JSX.Element;
28
+ //#endregion
29
+ export { MetricStrip };
@@ -0,0 +1,81 @@
1
+ import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "../../ui/card.js";
2
+ import { cn } from "../../../lib/utils.js";
3
+ import { Delta } from "../../siyahi/delta.js";
4
+ import { Sparkline } from "./sparkline.js";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import "react";
7
+ //#region src/components/registry/dashboardcn/kpi-row-card.tsx
8
+ const COLUMNS = {
9
+ 1: "basis-full",
10
+ 2: "basis-full @2xs/strip:basis-1/2",
11
+ 3: "basis-full @lg/strip:basis-1/3",
12
+ 4: "basis-full @2xs/strip:basis-1/2 @3xl/strip:basis-1/4",
13
+ 5: "basis-full @2xs/strip:basis-1/2 @3xl/strip:basis-1/5",
14
+ 6: "basis-full @2xs/strip:basis-1/2 @xl/strip:basis-1/3 @5xl/strip:basis-1/6",
15
+ 8: "basis-full @2xs/strip:basis-1/2 @3xl/strip:basis-1/4 @7xl/strip:basis-1/8"
16
+ };
17
+ function trendColor(change) {
18
+ if (change === void 0) return "var(--chart-1)";
19
+ if (change > 0) return "var(--positive)";
20
+ if (change < 0) return "var(--negative)";
21
+ return "var(--muted-foreground)";
22
+ }
23
+ /** A card holding a row of small figures, each with its change and a sparkline: more numbers in less room than stat tiles. */
24
+ function MetricStrip({ title, description, action, items, footer, className, ...props }) {
25
+ const columns = COLUMNS[Math.min(items.length, 8)] ?? COLUMNS[8];
26
+ return /* @__PURE__ */ jsxs(Card, {
27
+ className: cn("gap-4", className),
28
+ ...props,
29
+ children: [
30
+ (title || description || action) && /* @__PURE__ */ jsxs(CardHeader, { children: [
31
+ title && /* @__PURE__ */ jsx(CardTitle, { children: title }),
32
+ description && /* @__PURE__ */ jsx(CardDescription, { children: description }),
33
+ action && /* @__PURE__ */ jsx(CardAction, { children: action })
34
+ ] }),
35
+ /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx("div", {
36
+ "data-slot": "metric-strip",
37
+ className: "@container/strip -mx-4 -my-3 overflow-hidden",
38
+ children: /* @__PURE__ */ jsx("div", {
39
+ className: "-mt-px -ml-px flex flex-wrap",
40
+ children: items.map((item) => /* @__PURE__ */ jsxs("div", {
41
+ "data-slot": "metric-strip-item",
42
+ className: cn("flex min-w-0 flex-col gap-1 border-t border-l px-4 py-3", columns),
43
+ children: [/* @__PURE__ */ jsx("div", {
44
+ className: "truncate text-xs text-muted-foreground",
45
+ children: item.label
46
+ }), /* @__PURE__ */ jsxs("div", {
47
+ className: "flex flex-wrap items-end justify-between gap-x-3 gap-y-1",
48
+ children: [/* @__PURE__ */ jsxs("div", {
49
+ className: "flex min-w-0 flex-col gap-0.5",
50
+ children: [/* @__PURE__ */ jsx("div", {
51
+ className: "text-xl font-semibold tracking-tight tabular-nums",
52
+ children: item.value
53
+ }), (item.change !== void 0 || item.note) && /* @__PURE__ */ jsxs("div", {
54
+ className: "flex flex-wrap items-center gap-x-1.5 text-xs",
55
+ children: [item.change !== void 0 && /* @__PURE__ */ jsx(Delta, {
56
+ value: item.change,
57
+ format: item.changeFormat
58
+ }), item.note && /* @__PURE__ */ jsx("span", {
59
+ className: "text-muted-foreground",
60
+ children: item.note
61
+ })]
62
+ })]
63
+ }), item.trend && item.trend.length > 1 && /* @__PURE__ */ jsx(Sparkline, {
64
+ data: item.trend,
65
+ variant: "line",
66
+ color: trendColor(item.change),
67
+ className: "h-8 w-16 shrink-0"
68
+ })]
69
+ })]
70
+ }, item.label))
71
+ })
72
+ }) }),
73
+ footer && /* @__PURE__ */ jsx(CardFooter, {
74
+ className: "flex-col items-start gap-2 text-sm",
75
+ children: footer
76
+ })
77
+ ]
78
+ });
79
+ }
80
+ //#endregion
81
+ export { MetricStrip };
@@ -0,0 +1,18 @@
1
+ import { ChartColor } from "../../../lib/chart-series.js";
2
+ import * as React$1 from "react";
3
+ //#region src/components/registry/dashboardcn/sparkline.d.ts
4
+ export interface SparklineProps extends React$1.ComponentProps<"div"> {
5
+ /** Series to plot, oldest first. */
6
+ data: number[];
7
+ variant?: "area" | "line";
8
+ /** A chart slot, or var(--positive) or var(--negative) for a gain or a loss. Defaults to var(--chart-1). */
9
+ color?: ChartColor;
10
+ curve?: "monotone" | "linear" | "step";
11
+ strokeWidth?: number;
12
+ /** Animate after hydration and when data changes. Respects reduced motion. */
13
+ animate?: boolean;
14
+ animationDuration?: number;
15
+ }
16
+ declare function Sparkline({ data, variant, color, curve, strokeWidth, animate, animationDuration, className, ...props }: SparklineProps): React$1.JSX.Element;
17
+ //#endregion
18
+ export { Sparkline };
@@ -0,0 +1,95 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import * as React$1 from "react";
4
+ import { Area, AreaChart, Line, LineChart, ResponsiveContainer, YAxis } from "recharts";
5
+ //#region src/components/registry/dashboardcn/sparkline.tsx
6
+ const reducedMotionQuery = "(prefers-reduced-motion: reduce)";
7
+ function subscribeToReducedMotion(onChange) {
8
+ const query = window.matchMedia(reducedMotionQuery);
9
+ query.addEventListener("change", onChange);
10
+ return () => query.removeEventListener("change", onChange);
11
+ }
12
+ function getReducedMotionSnapshot() {
13
+ return window.matchMedia(reducedMotionQuery).matches;
14
+ }
15
+ function getReducedMotionServerSnapshot() {
16
+ return true;
17
+ }
18
+ function Sparkline({ data, variant = "area", color = "var(--chart-1)", curve = "monotone", strokeWidth = 1.5, animate = true, animationDuration = 500, className, ...props }) {
19
+ const id = React$1.useId();
20
+ const reducedMotion = React$1.useSyncExternalStore(subscribeToReducedMotion, getReducedMotionSnapshot, getReducedMotionServerSnapshot);
21
+ const animationActive = animate && !reducedMotion;
22
+ const points = React$1.useMemo(() => data.map((y, i) => ({
23
+ i,
24
+ y
25
+ })), [data]);
26
+ const margin = {
27
+ top: 2,
28
+ right: 0,
29
+ bottom: 2,
30
+ left: 0
31
+ };
32
+ const axis = /* @__PURE__ */ jsx(YAxis, {
33
+ hide: true,
34
+ domain: ["dataMin", "dataMax"]
35
+ });
36
+ return /* @__PURE__ */ jsx("div", {
37
+ "data-slot": "sparkline",
38
+ "aria-hidden": "true",
39
+ className: cn("h-10 w-full", className),
40
+ ...props,
41
+ children: /* @__PURE__ */ jsx(ResponsiveContainer, {
42
+ width: "100%",
43
+ height: "100%",
44
+ children: variant === "line" ? /* @__PURE__ */ jsxs(LineChart, {
45
+ data: points,
46
+ margin,
47
+ children: [axis, /* @__PURE__ */ jsx(Line, {
48
+ type: curve,
49
+ dataKey: "y",
50
+ stroke: color,
51
+ strokeWidth,
52
+ dot: false,
53
+ isAnimationActive: animationActive,
54
+ animationDuration,
55
+ animationEasing: "ease-out"
56
+ })]
57
+ }) : /* @__PURE__ */ jsxs(AreaChart, {
58
+ data: points,
59
+ margin,
60
+ children: [
61
+ axis,
62
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs("linearGradient", {
63
+ id,
64
+ x1: "0",
65
+ y1: "0",
66
+ x2: "0",
67
+ y2: "1",
68
+ children: [/* @__PURE__ */ jsx("stop", {
69
+ offset: "0%",
70
+ stopColor: color,
71
+ stopOpacity: .3
72
+ }), /* @__PURE__ */ jsx("stop", {
73
+ offset: "100%",
74
+ stopColor: color,
75
+ stopOpacity: 0
76
+ })]
77
+ }) }),
78
+ /* @__PURE__ */ jsx(Area, {
79
+ type: curve,
80
+ dataKey: "y",
81
+ stroke: color,
82
+ strokeWidth,
83
+ fill: `url(#${id})`,
84
+ dot: false,
85
+ isAnimationActive: animationActive,
86
+ animationDuration,
87
+ animationEasing: "ease-out"
88
+ })
89
+ ]
90
+ })
91
+ })
92
+ });
93
+ }
94
+ //#endregion
95
+ export { Sparkline };
@@ -0,0 +1,11 @@
1
+ import { buttonVariants } from "../../ui/button.js";
2
+ import * as React$1 from "react";
3
+ import { VariantProps } from "class-variance-authority";
4
+ //#region src/components/registry/minidev/copy-button.d.ts
5
+ declare function CopyButton({ value, className, variant, size, label, copiedLabel, ...props }: {
6
+ value: string;
7
+ label?: string;
8
+ copiedLabel?: string;
9
+ } & React$1.ComponentProps<"button"> & VariantProps<typeof buttonVariants>): React$1.JSX.Element;
10
+ //#endregion
11
+ export { CopyButton };
@@ -0,0 +1,34 @@
1
+ "use client";
2
+ import { Button } from "../../ui/button.js";
3
+ import { cn } from "../../../lib/utils.js";
4
+ import { CheckIcon, CopyIcon } from "lucide-react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import * as React$1 from "react";
7
+ import "class-variance-authority";
8
+ //#region src/components/registry/minidev/copy-button.tsx
9
+ function CopyButton({ value, className, variant = "outline", size = "sm", label = "Copy", copiedLabel = "Copied", ...props }) {
10
+ const [copied, setCopied] = React$1.useState(false);
11
+ React$1.useEffect(() => {
12
+ if (!copied) return;
13
+ const timeout = setTimeout(() => setCopied(false), 2e3);
14
+ return () => clearTimeout(timeout);
15
+ }, [copied]);
16
+ return /* @__PURE__ */ jsxs(Button, {
17
+ type: "button",
18
+ variant,
19
+ size,
20
+ "data-slot": "copy-button",
21
+ className: cn(className),
22
+ "aria-label": copied ? copiedLabel : label,
23
+ onClick: async () => {
24
+ try {
25
+ await navigator.clipboard.writeText(value);
26
+ setCopied(true);
27
+ } catch {}
28
+ },
29
+ ...props,
30
+ children: [copied ? /* @__PURE__ */ jsx(CheckIcon, { "data-icon": "inline-start" }) : /* @__PURE__ */ jsx(CopyIcon, { "data-icon": "inline-start" }), copied ? copiedLabel : label]
31
+ });
32
+ }
33
+ //#endregion
34
+ export { CopyButton };
@@ -52,14 +52,14 @@ function TableRow({ className, ...props }) {
52
52
  function TableHead({ className, ...props }) {
53
53
  return /* @__PURE__ */ jsx("th", {
54
54
  "data-slot": "table-head",
55
- className: cn("h-12 px-3 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-[2px]", className),
55
+ className: cn("h-10 px-2 text-left align-middle font-medium whitespace-nowrap text-foreground [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-[2px]", className),
56
56
  ...props
57
57
  });
58
58
  }
59
59
  function TableCell({ className, ...props }) {
60
60
  return /* @__PURE__ */ jsx("td", {
61
61
  "data-slot": "table-cell",
62
- className: cn("p-3 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-[2px]", className),
62
+ className: cn("p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 *:[[role=checkbox]]:translate-y-[2px]", className),
63
63
  ...props
64
64
  });
65
65
  }
@@ -4,7 +4,7 @@ export declare function NavMain({ items, label }: {
4
4
  items: {
5
5
  title: string;
6
6
  url: string;
7
- icon?: React.ReactNode;
7
+ icon: React.ReactNode;
8
8
  isActive?: boolean;
9
9
  linkProps?: Omit<React.ComponentProps<"a">, "href">;
10
10
  items?: {
@@ -0,0 +1,19 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/components/siyahi/data-bar.d.ts
3
+ export interface DataBarProps {
4
+ value: number;
5
+ /** The value a full bar stands for, usually the column's largest: Math.max(...rows.map((row) => row.value)). */
6
+ max: number;
7
+ /** "sign" draws a gain in --positive and a loss in --negative; by default every bar is --chart-1. */
8
+ tone?: "chart" | "sign";
9
+ /** The figure, as the page formats it. */
10
+ children: ReactNode;
11
+ className?: string;
12
+ }
13
+ /**
14
+ * A table cell's figure behind a short bar whose length is the figure's share of max, so a column reads as a chart.
15
+ * The bar has a fixed width, so every row draws to the same scale, and sits on the figure's line, so the row
16
+ * keeps its height.
17
+ */
18
+ export declare function DataBar({ value, max, tone, children, className }: DataBarProps): import("react").JSX.Element;
19
+ //#endregion
@@ -0,0 +1,29 @@
1
+ import { cn } from "cn";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ //#region src/components/siyahi/data-bar.tsx
4
+ /**
5
+ * A table cell's figure behind a short bar whose length is the figure's share of max, so a column reads as a chart.
6
+ * The bar has a fixed width, so every row draws to the same scale, and sits on the figure's line, so the row
7
+ * keeps its height.
8
+ */
9
+ function DataBar({ value, max, tone = "chart", children, className }) {
10
+ const share = max > 0 ? Math.min(1, Math.abs(value) / max) : 0;
11
+ const fill = tone === "chart" ? "bg-chart-1" : value < 0 ? "bg-negative" : "bg-positive";
12
+ return /* @__PURE__ */ jsxs("div", {
13
+ "data-slot": "data-bar",
14
+ className: cn("flex items-center gap-2", className),
15
+ children: [/* @__PURE__ */ jsx("div", {
16
+ "aria-hidden": "true",
17
+ className: "h-1.5 w-16 shrink-0 overflow-hidden rounded-full bg-muted",
18
+ children: /* @__PURE__ */ jsx("div", {
19
+ className: cn("h-full rounded-full", fill),
20
+ style: { width: `${share * 100}%` }
21
+ })
22
+ }), /* @__PURE__ */ jsx("span", {
23
+ className: "tabular-nums",
24
+ children
25
+ })]
26
+ });
27
+ }
28
+ //#endregion
29
+ export { DataBar };
@@ -12,7 +12,10 @@ export interface PageSectionProps {
12
12
  action?: ReactNode;
13
13
  children?: ReactNode;
14
14
  }
15
- /** One part of a long page: a rule above, then the heading and lead on the canvas, then its content. */
15
+ /**
16
+ * One part of a long page: a rule above, then the heading and lead on the canvas, then its content. Spaced for
17
+ * density, 24px under the rule and 16px to the content, so sections stacked 24px apart sit 24px either side of it.
18
+ */
16
19
  export declare function PageSection({ id, eyebrow, title, lead, action, children }: PageSectionProps): import("react").JSX.Element;
17
20
  /** A heading inside a PageSection, one level under its title. */
18
21
  export declare function PageSubheading({ children }: {
@@ -1,11 +1,14 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  //#region src/components/siyahi/page-section.tsx
3
- /** One part of a long page: a rule above, then the heading and lead on the canvas, then its content. */
3
+ /**
4
+ * One part of a long page: a rule above, then the heading and lead on the canvas, then its content. Spaced for
5
+ * density, 24px under the rule and 16px to the content, so sections stacked 24px apart sit 24px either side of it.
6
+ */
4
7
  function PageSection({ id, eyebrow, title, lead, action, children }) {
5
8
  return /* @__PURE__ */ jsxs("section", {
6
9
  id,
7
10
  "data-slot": "page-section",
8
- className: "flex scroll-mt-6 flex-col gap-6 border-t pt-10",
11
+ className: "flex scroll-mt-6 flex-col gap-4 border-t pt-6",
9
12
  children: [/* @__PURE__ */ jsxs("div", {
10
13
  className: "flex flex-wrap items-end justify-between gap-4",
11
14
  children: [/* @__PURE__ */ jsxs("div", {
@@ -16,7 +19,7 @@ function PageSection({ id, eyebrow, title, lead, action, children }) {
16
19
  children: eyebrow
17
20
  }),
18
21
  /* @__PURE__ */ jsx("h2", {
19
- className: "text-2xl font-semibold tracking-tight",
22
+ className: "text-xl font-semibold tracking-tight",
20
23
  children: title
21
24
  }),
22
25
  lead && /* @__PURE__ */ jsx("div", {
@@ -0,0 +1,22 @@
1
+ import { ReactNode } from "react";
2
+ //#region src/components/siyahi/panel-grid.d.ts
3
+ declare const COLUMNS: {
4
+ readonly 1: "";
5
+ readonly 2: "@2xl/panels:grid-cols-2";
6
+ readonly 3: "@2xl/panels:grid-cols-2 @5xl/panels:grid-cols-3";
7
+ readonly 4: "@2xl/panels:grid-cols-2 @5xl/panels:grid-cols-4";
8
+ };
9
+ export interface PanelGridProps {
10
+ /** Blocks across on a wide page; two on a medium one, and one on a phone. */
11
+ columns?: keyof typeof COLUMNS;
12
+ children: ReactNode;
13
+ className?: string;
14
+ }
15
+ /**
16
+ * Data blocks side by side: chart cards, tables, a MetricStrip. On a ruled surface a hairline parts them across and
17
+ * down, with a rule above and below the grid; open leaves whitespace between them, and card a gap between boxes.
18
+ * Each block's left and top edges carry its rules, and the grid clips the ones on its own edges.
19
+ */
20
+ export declare function PanelGrid({ columns, children, className }: PanelGridProps): import("react").JSX.Element;
21
+ //#endregion
22
+ export {};
@@ -0,0 +1,34 @@
1
+ import { useSurface } from "./siyahi-provider.js";
2
+ import { cn } from "cn";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { Children } from "react";
5
+ //#region src/components/siyahi/panel-grid.tsx
6
+ const COLUMNS = {
7
+ 1: "",
8
+ 2: "@2xl/panels:grid-cols-2",
9
+ 3: "@2xl/panels:grid-cols-2 @5xl/panels:grid-cols-3",
10
+ 4: "@2xl/panels:grid-cols-2 @5xl/panels:grid-cols-4"
11
+ };
12
+ /**
13
+ * Data blocks side by side: chart cards, tables, a MetricStrip. On a ruled surface a hairline parts them across and
14
+ * down, with a rule above and below the grid; open leaves whitespace between them, and card a gap between boxes.
15
+ * Each block's left and top edges carry its rules, and the grid clips the ones on its own edges.
16
+ */
17
+ function PanelGrid({ columns = 2, children, className }) {
18
+ const surface = useSurface();
19
+ const ruled = surface === "ruled";
20
+ return /* @__PURE__ */ jsx("div", {
21
+ "data-slot": "panel-grid",
22
+ className: cn("@container/panels", ruled && "overflow-hidden border-y", className),
23
+ children: /* @__PURE__ */ jsx("div", {
24
+ className: cn("grid grid-cols-1", COLUMNS[columns], ruled ? "-mt-px -ml-px" : surface === "open" ? "gap-x-8 gap-y-6" : "gap-4"),
25
+ children: Children.map(children, (child) => /* @__PURE__ */ jsx("div", {
26
+ "data-slot": "panel",
27
+ className: cn("min-w-0", ruled && "border-t border-l"),
28
+ children: child
29
+ }))
30
+ })
31
+ });
32
+ }
33
+ //#endregion
34
+ export { PanelGrid };
@@ -1,12 +1,23 @@
1
1
  import { SiyahiLocale } from "../../lib/locale.js";
2
2
  import { ReactNode } from "react";
3
3
  //#region src/components/siyahi/siyahi-provider.d.ts
4
+ /**
5
+ * How a data block sits on the page. "ruled": no box, hairlines between blocks in a PanelGrid. "open": no box and no
6
+ * lines, the block's content level with the page's text. "card": shadcn's own card, a filled box with a 1px ring.
7
+ */
8
+ export type Surface = "ruled" | "open" | "card";
4
9
  export interface SiyahiProviderProps {
5
10
  /** Any setting left out keeps its default: en-IN, INR, Asia/Kolkata. */
6
11
  locale?: Partial<SiyahiLocale>;
12
+ /**
13
+ * Set it on a nested provider for one part of a page. Left out, a provider keeps the surface around it, so a
14
+ * provider that only changes the locale changes nothing else; the outermost default is "ruled".
15
+ */
16
+ surface?: Surface;
7
17
  children: ReactNode;
8
18
  }
9
- /** Wrap the app once. Carries the locale and the tooltip provider shadcn asks for. */
10
- export declare function SiyahiProvider({ locale, children }: SiyahiProviderProps): import("react").JSX.Element;
19
+ /** Wrap the app once. Carries the locale, the surface and the tooltip provider shadcn asks for. */
20
+ export declare function SiyahiProvider({ locale, surface, children }: SiyahiProviderProps): import("react").JSX.Element;
11
21
  export declare function useLocale(): SiyahiLocale;
22
+ export declare function useSurface(): Surface;
12
23
  //#endregion
@@ -4,8 +4,9 @@ import { jsx } from "react/jsx-runtime";
4
4
  import { createContext, use, useMemo } from "react";
5
5
  //#region src/components/siyahi/siyahi-provider.tsx
6
6
  const LocaleContext = createContext(defaultLocale);
7
- /** Wrap the app once. Carries the locale and the tooltip provider shadcn asks for. */
8
- function SiyahiProvider({ locale, children }) {
7
+ const SurfaceContext = createContext("ruled");
8
+ /** Wrap the app once. Carries the locale, the surface and the tooltip provider shadcn asks for. */
9
+ function SiyahiProvider({ locale, surface, children }) {
9
10
  const { numberLocale, currency, timeZone } = {
10
11
  ...defaultLocale,
11
12
  ...locale
@@ -19,13 +20,25 @@ function SiyahiProvider({ locale, children }) {
19
20
  currency,
20
21
  timeZone
21
22
  ]);
23
+ const around = use(SurfaceContext);
22
24
  return /* @__PURE__ */ jsx(LocaleContext, {
23
25
  value,
24
- children: /* @__PURE__ */ jsx(TooltipProvider, { children })
26
+ children: /* @__PURE__ */ jsx(SurfaceContext, {
27
+ value: surface ?? around,
28
+ children: /* @__PURE__ */ jsx(TooltipProvider, { children: surface ? /* @__PURE__ */ jsx("div", {
29
+ "data-slot": "siyahi-provider",
30
+ "data-surface": surface,
31
+ className: "contents",
32
+ children
33
+ }) : children })
34
+ })
25
35
  });
26
36
  }
27
37
  function useLocale() {
28
38
  return use(LocaleContext);
29
39
  }
40
+ function useSurface() {
41
+ return use(SurfaceContext);
42
+ }
30
43
  //#endregion
31
- export { SiyahiProvider, useLocale };
44
+ export { SiyahiProvider, useLocale, useSurface };
@@ -6,14 +6,14 @@ import { jsx, jsxs } from "react/jsx-runtime";
6
6
  function Accordion({ className, ...props }) {
7
7
  return /* @__PURE__ */ jsx(Accordion$1.Root, {
8
8
  "data-slot": "accordion",
9
- className: cn("flex w-full flex-col overflow-hidden rounded-2xl border", className),
9
+ className: cn("flex w-full flex-col", className),
10
10
  ...props
11
11
  });
12
12
  }
13
13
  function AccordionItem({ className, ...props }) {
14
14
  return /* @__PURE__ */ jsx(Accordion$1.Item, {
15
15
  "data-slot": "accordion-item",
16
- className: cn("not-last:border-b data-open:bg-muted/50", className),
16
+ className: cn("not-last:border-b", className),
17
17
  ...props
18
18
  });
19
19
  }
@@ -22,7 +22,7 @@ function AccordionTrigger({ className, children, ...props }) {
22
22
  className: "flex",
23
23
  children: /* @__PURE__ */ jsxs(Accordion$1.Trigger, {
24
24
  "data-slot": "accordion-trigger",
25
- className: cn("group/accordion-trigger relative flex flex-1 items-start justify-between gap-6 border border-transparent p-4 text-left text-sm font-medium transition-all outline-none hover:underline aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground", className),
25
+ className: cn("group/accordion-trigger 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:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:after:border-ring aria-disabled:pointer-events-none aria-disabled:opacity-50 **:data-[slot=accordion-trigger-icon]:ml-auto **:data-[slot=accordion-trigger-icon]:size-4 **:data-[slot=accordion-trigger-icon]:text-muted-foreground", className),
26
26
  ...props,
27
27
  children: [
28
28
  children,
@@ -41,10 +41,10 @@ function AccordionTrigger({ className, children, ...props }) {
41
41
  function AccordionContent({ className, children, ...props }) {
42
42
  return /* @__PURE__ */ jsx(Accordion$1.Panel, {
43
43
  "data-slot": "accordion-content",
44
- className: "overflow-hidden px-4 text-sm data-open:animate-accordion-down data-closed:animate-accordion-up",
44
+ className: "overflow-hidden text-sm data-open:animate-accordion-down data-closed:animate-accordion-up",
45
45
  ...props,
46
46
  children: /* @__PURE__ */ jsx("div", {
47
- className: cn("h-(--accordion-panel-height) pt-0 pb-4 data-ending-style:h-0 data-starting-style:h-0 [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4", className),
47
+ className: cn("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 [&_a]:hover:text-foreground [&_p:not(:last-child)]:mb-4", className),
48
48
  children
49
49
  })
50
50
  });
@@ -3,7 +3,7 @@ import { jsx } from "react/jsx-runtime";
3
3
  import "react";
4
4
  import { cva } from "class-variance-authority";
5
5
  //#region src/components/ui/alert.tsx
6
- const alertVariants = cva("group/alert relative grid w-full gap-0.5 rounded-2xl border px-4 py-3 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.5 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4", {
6
+ const alertVariants = cva("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", {
7
7
  variants: { variant: {
8
8
  default: "bg-card text-card-foreground",
9
9
  destructive: "bg-card text-destructive *:data-[slot=alert-description]:text-destructive/90 *:[svg]:text-current"
@@ -35,7 +35,7 @@ function AlertDescription({ className, ...props }) {
35
35
  function AlertAction({ className, ...props }) {
36
36
  return /* @__PURE__ */ jsx("div", {
37
37
  "data-slot": "alert-action",
38
- className: cn("absolute top-2.5 right-3", className),
38
+ className: cn("absolute top-2 right-2", className),
39
39
  ...props
40
40
  });
41
41
  }
@@ -3,7 +3,7 @@ import { cva } from "class-variance-authority";
3
3
  import { mergeProps } from "@base-ui/react/merge-props";
4
4
  import { useRender } from "@base-ui/react/use-render";
5
5
  //#region src/components/ui/badge.tsx
6
- const badgeVariants = cva("group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-3xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", {
6
+ const badgeVariants = cva("group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", {
7
7
  variants: { variant: {
8
8
  default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
9
9
  secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
@@ -16,14 +16,14 @@ function Breadcrumb({ className, ...props }) {
16
16
  function BreadcrumbList({ className, ...props }) {
17
17
  return /* @__PURE__ */ jsx("ol", {
18
18
  "data-slot": "breadcrumb-list",
19
- className: cn("flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground sm:gap-2.5", className),
19
+ className: cn("flex flex-wrap items-center gap-1.5 text-sm wrap-break-word text-muted-foreground", className),
20
20
  ...props
21
21
  });
22
22
  }
23
23
  function BreadcrumbItem({ className, ...props }) {
24
24
  return /* @__PURE__ */ jsx("li", {
25
25
  "data-slot": "breadcrumb-item",
26
- className: cn("inline-flex items-center gap-1.5", className),
26
+ className: cn("inline-flex items-center gap-1", className),
27
27
  ...props
28
28
  });
29
29
  }