@siyahi/ui 0.1.9-next.16 → 0.1.9-next.18

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 (93) hide show
  1. package/README.md +77 -207
  2. package/agents/examples/accordion.tsx +39 -0
  3. package/agents/examples/alert.tsx +25 -0
  4. package/agents/examples/app-sidebar.tsx +38 -0
  5. package/agents/examples/avatar.tsx +14 -0
  6. package/agents/examples/badge.tsx +18 -0
  7. package/agents/examples/bar-list-labels.tsx +22 -0
  8. package/agents/examples/bar-list-sides.tsx +30 -0
  9. package/agents/examples/bar-list.tsx +24 -0
  10. package/agents/examples/breadcrumb.tsx +28 -0
  11. package/agents/examples/button.tsx +21 -0
  12. package/agents/examples/calendar.tsx +15 -0
  13. package/agents/examples/card.tsx +34 -0
  14. package/agents/examples/chart-area.tsx +38 -0
  15. package/agents/examples/chart-bar-flows.tsx +31 -0
  16. package/agents/examples/chart-bar-hourly.tsx +28 -0
  17. package/agents/examples/chart-bar-losses.tsx +29 -0
  18. package/agents/examples/chart-bar-sectors.tsx +70 -0
  19. package/agents/examples/chart-bar-years.tsx +40 -0
  20. package/agents/examples/chart-bar.tsx +56 -0
  21. package/agents/examples/chart-category-ticks.tsx +50 -0
  22. package/agents/examples/chart-line-events.tsx +47 -0
  23. package/agents/examples/chart-line-timeline.tsx +41 -0
  24. package/agents/examples/chart-line.tsx +57 -0
  25. package/agents/examples/code-block.tsx +38 -0
  26. package/agents/examples/collapsible.tsx +16 -0
  27. package/agents/examples/command.tsx +27 -0
  28. package/agents/examples/context-menu.tsx +15 -0
  29. package/agents/examples/copy-button.tsx +8 -0
  30. package/agents/examples/data-bar.tsx +121 -0
  31. package/agents/examples/data-table-filters.tsx +103 -0
  32. package/agents/examples/data-table.tsx +98 -0
  33. package/agents/examples/delta.tsx +13 -0
  34. package/agents/examples/dialog.tsx +28 -0
  35. package/agents/examples/distribution-bar-budget.tsx +30 -0
  36. package/agents/examples/distribution-bar-tug.tsx +72 -0
  37. package/agents/examples/dropdown-menu.tsx +31 -0
  38. package/agents/examples/formatters.tsx +42 -0
  39. package/agents/examples/heatmap-calendar.tsx +50 -0
  40. package/agents/examples/heatmap-status.tsx +51 -0
  41. package/agents/examples/heatmap-weekday.tsx +53 -0
  42. package/agents/examples/input.tsx +17 -0
  43. package/agents/examples/local-time.tsx +14 -0
  44. package/agents/examples/metric-strip.tsx +40 -0
  45. package/agents/examples/page-section.tsx +52 -0
  46. package/agents/examples/popover.tsx +23 -0
  47. package/agents/examples/price-chart.tsx +32 -0
  48. package/agents/examples/progress-tone.tsx +28 -0
  49. package/agents/examples/progress.tsx +10 -0
  50. package/agents/examples/scroll-area.tsx +20 -0
  51. package/agents/examples/section-cards-select.tsx +27 -0
  52. package/agents/examples/section-cards-trend.tsx +30 -0
  53. package/agents/examples/section-cards.tsx +48 -0
  54. package/agents/examples/select.tsx +27 -0
  55. package/agents/examples/separator.tsx +13 -0
  56. package/agents/examples/sheet.tsx +15 -0
  57. package/agents/examples/skeleton.tsx +11 -0
  58. package/agents/examples/slider.tsx +5 -0
  59. package/agents/examples/surfaces.tsx +115 -0
  60. package/agents/examples/table.tsx +50 -0
  61. package/agents/examples/tabs.tsx +16 -0
  62. package/agents/examples/toggle-group.tsx +12 -0
  63. package/agents/examples/toggle.tsx +11 -0
  64. package/agents/examples/tooltip.tsx +13 -0
  65. package/agents/examples/treemap.tsx +87 -0
  66. package/agents/manifest.json +931 -0
  67. package/agents/report-rules.json +7 -0
  68. package/dist/components/registry/charts/bar-chart-card.js +1 -0
  69. package/dist/components/registry/dashboardcn/bar-list.js +8 -7
  70. package/dist/components/registry/heatmap/calendar-heatmap.js +8 -1
  71. package/dist/components/registry/heatmap/status-heatmap.js +8 -1
  72. package/dist/components/registry/heatmap/weekday-heatmap.d.ts +6 -2
  73. package/dist/components/registry/heatmap/weekday-heatmap.js +56 -37
  74. package/dist/components/registry/niko-table/core/data-table-context.d.ts +2 -0
  75. package/dist/components/registry/niko-table/core/data-table-context.js +21 -0
  76. package/dist/components/registry/niko-table/core/data-table-grouped-row.js +3 -1
  77. package/dist/components/registry/niko-table/core/data-table-structure.js +15 -12
  78. package/dist/components/registry/niko-table/core/data-table.d.ts +2 -2
  79. package/dist/components/registry/niko-table/core/data-table.js +5 -1
  80. package/dist/components/registry/niko-table/filters/table-search-filter.js +1 -1
  81. package/dist/components/registry/niko-table/lib/flex-columns.d.ts +1 -1
  82. package/dist/components/registry/niko-table/lib/flex-columns.js +3 -3
  83. package/dist/components/registry/niko-table/lib/styles.d.ts +1 -1
  84. package/dist/components/registry/niko-table/lib/styles.js +2 -2
  85. package/dist/components/registry/sidebar-07/nav-main.js +7 -1
  86. package/dist/components/siyahi/treemap.js +46 -4
  87. package/dist/lib/chart-frame.js +180 -123
  88. package/dist/lib/chart-series.d.ts +3 -3
  89. package/dist/lib/format.js +32 -13
  90. package/dist/lib/heatmap-navigation.d.ts +8 -0
  91. package/dist/lib/heatmap-navigation.js +49 -0
  92. package/package.json +3 -1
  93. package/styles/siyahi.css +24 -0
@@ -0,0 +1,121 @@
1
+ import {
2
+ Card,
3
+ CardContent,
4
+ CardDescription,
5
+ CardHeader,
6
+ CardTitle,
7
+ DataBar,
8
+ DataTable,
9
+ DataTableBody,
10
+ DataTableHeader,
11
+ DataTableRoot,
12
+ DataTableSortHeader,
13
+ Sparkline,
14
+ useFormat,
15
+ type DataTableColumnDef,
16
+ } from "@siyahi/ui";
17
+
18
+ interface Holding {
19
+ symbol: string;
20
+ value: number;
21
+ gain: number;
22
+ /** Closing prices over the last ten sessions, oldest first. */
23
+ closes: number[];
24
+ }
25
+
26
+ const holdings: Holding[] = [
27
+ { symbol: "ITC", value: 276000, gain: -18400, closes: [478, 474, 470, 471, 466, 463, 465, 461, 459, 460] },
28
+ {
29
+ symbol: "HDFCBANK",
30
+ value: 262500,
31
+ gain: 21300,
32
+ closes: [1712, 1718, 1726, 1720, 1731, 1744, 1739, 1748, 1752, 1750],
33
+ },
34
+ {
35
+ symbol: "ICICIBANK",
36
+ value: 258000,
37
+ gain: 44100,
38
+ closes: [1250, 1262, 1258, 1271, 1266, 1280, 1284, 1279, 1288, 1290],
39
+ },
40
+ { symbol: "NIFTYBEES", value: 255600, gain: 12800, closes: [281, 282, 280, 283, 284, 283, 285, 284, 286, 284] },
41
+ { symbol: "INFY", value: 224400, gain: 30900, closes: [1820, 1834, 1829, 1841, 1852, 1848, 1860, 1855, 1866, 1870] },
42
+ { symbol: "TCS", value: 166000, gain: -2600, closes: [4180, 4172, 4165, 4170, 4158, 4150, 4161, 4155, 4148, 4150] },
43
+ ];
44
+
45
+ // Each bar is a share of its column's largest figure, so the rows draw to one scale.
46
+ const largestValue = Math.max(...holdings.map((h) => h.value));
47
+ const largestGain = Math.max(...holdings.map((h) => Math.abs(h.gain)));
48
+
49
+ function Money({ amount }: { amount: number }) {
50
+ return useFormat().money(amount);
51
+ }
52
+
53
+ const header = () => <DataTableSortHeader />;
54
+
55
+ const columns: DataTableColumnDef<Holding>[] = [
56
+ { accessorKey: "symbol", header, size: 120, meta: { label: "Symbol" } },
57
+ {
58
+ accessorKey: "value",
59
+ header,
60
+ size: 170,
61
+ meta: { label: "Value", variant: "number" },
62
+ cell: ({ row }) => (
63
+ <DataBar value={row.original.value} max={largestValue}>
64
+ <Money amount={row.original.value} />
65
+ </DataBar>
66
+ ),
67
+ },
68
+ {
69
+ accessorKey: "gain",
70
+ header,
71
+ size: 170,
72
+ meta: { label: "Gain", variant: "number" },
73
+ cell: ({ row }) => (
74
+ <DataBar value={row.original.gain} max={largestGain} tone="sign">
75
+ <Money amount={row.original.gain} />
76
+ </DataBar>
77
+ ),
78
+ },
79
+ {
80
+ id: "closes",
81
+ header: "10 days",
82
+ size: 110,
83
+ enableSorting: false,
84
+ cell: ({ row }) => {
85
+ const { closes } = row.original;
86
+ const rising = (closes.at(-1) ?? 0) >= (closes[0] ?? 0);
87
+ return (
88
+ <Sparkline
89
+ data={closes}
90
+ variant="line"
91
+ color={rising ? "var(--positive)" : "var(--negative)"}
92
+ animate={false}
93
+ className="h-5 w-20"
94
+ />
95
+ );
96
+ },
97
+ },
98
+ ];
99
+
100
+ export default function DataBarExample() {
101
+ return (
102
+ <Card>
103
+ <CardHeader>
104
+ <CardTitle>Holdings</CardTitle>
105
+ <CardDescription>Bars give each figure's size against the column's largest</CardDescription>
106
+ </CardHeader>
107
+ <CardContent>
108
+ <DataTableRoot
109
+ data={holdings}
110
+ columns={columns}
111
+ initialState={{ columnPinning: { start: ["symbol"], end: [] } }}
112
+ >
113
+ <DataTable>
114
+ <DataTableHeader />
115
+ <DataTableBody />
116
+ </DataTable>
117
+ </DataTableRoot>
118
+ </CardContent>
119
+ </Card>
120
+ );
121
+ }
@@ -0,0 +1,103 @@
1
+ import {
2
+ Button,
3
+ Card,
4
+ CardContent,
5
+ CardDescription,
6
+ CardHeader,
7
+ CardTitle,
8
+ DataTable,
9
+ DataTableBody,
10
+ DataTableFacetedFilter,
11
+ DataTableHeader,
12
+ DataTableRoot,
13
+ DataTableRowCount,
14
+ DataTableSearchFilter,
15
+ DataTableSortHeader,
16
+ DataTableToolbarSection,
17
+ Sheet,
18
+ SheetClose,
19
+ SheetContent,
20
+ SheetDescription,
21
+ SheetFooter,
22
+ SheetHeader,
23
+ SheetTitle,
24
+ SheetTrigger,
25
+ useDataTable,
26
+ type DataTableColumnDef,
27
+ } from "@siyahi/ui";
28
+
29
+ interface Holding {
30
+ symbol: string;
31
+ sector: string;
32
+ broker: string;
33
+ }
34
+ const data: Holding[] = [
35
+ { symbol: "INFY", sector: "Information technology", broker: "Kite" },
36
+ { symbol: "HDFCBANK", sector: "Banks", broker: "Dhan" },
37
+ { symbol: "TCS", sector: "Information technology", broker: "Dhan" },
38
+ ];
39
+ const header = () => <DataTableSortHeader />;
40
+ const columns: DataTableColumnDef<Holding>[] = [
41
+ { accessorKey: "symbol", header, size: 140, meta: { label: "Instrument" } },
42
+ { accessorKey: "sector", header, meta: { label: "Sector" } },
43
+ { accessorKey: "broker", header, meta: { label: "Broker" } },
44
+ ];
45
+
46
+ function Filters() {
47
+ const { table, isCompact } = useDataTable<Holding>();
48
+ const active = table.state.columnFilters.length;
49
+ const controls = (
50
+ <div className="flex flex-wrap gap-2">
51
+ <DataTableFacetedFilter accessorKey="sector" title="Sector" />
52
+ <DataTableFacetedFilter accessorKey="broker" title="Broker" />
53
+ </div>
54
+ );
55
+ if (!isCompact) return controls;
56
+ return (
57
+ <Sheet>
58
+ <SheetTrigger render={<Button variant="outline" size="sm" />}>Filters{active ? ` (${active})` : ""}</SheetTrigger>
59
+ <SheetContent>
60
+ <SheetHeader>
61
+ <SheetTitle>Holding filters</SheetTitle>
62
+ <SheetDescription>Selections stay applied when this panel closes.</SheetDescription>
63
+ </SheetHeader>
64
+ <div className="overflow-y-auto px-4">{controls}</div>
65
+ <SheetFooter>
66
+ <Button variant="outline" disabled={!active} onClick={() => table.resetColumnFilters()}>
67
+ Clear filters
68
+ </Button>
69
+ <SheetClose render={<Button />}>Done</SheetClose>
70
+ </SheetFooter>
71
+ </SheetContent>
72
+ </Sheet>
73
+ );
74
+ }
75
+
76
+ export default function DataTableFiltersExample() {
77
+ return (
78
+ <Card>
79
+ <CardHeader>
80
+ <CardTitle>Holdings with compact filters</CardTitle>
81
+ <CardDescription>Search stays visible; secondary filters move into a panel in narrow space.</CardDescription>
82
+ </CardHeader>
83
+ <CardContent>
84
+ {/* The closed filter panel is absent at first render, so configure its features explicitly. */}
85
+ <DataTableRoot data={data} columns={columns} config={{ enableFilters: true, enableSorting: true }}>
86
+ <DataTableToolbarSection>
87
+ <DataTableSearchFilter
88
+ label="Search compact example"
89
+ placeholder="Search holdings…"
90
+ className="w-full sm:w-64"
91
+ />
92
+ <Filters />
93
+ <DataTableRowCount unit="holdings" />
94
+ </DataTableToolbarSection>
95
+ <DataTable aria-label="Holdings with compact filters">
96
+ <DataTableHeader />
97
+ <DataTableBody />
98
+ </DataTable>
99
+ </DataTableRoot>
100
+ </CardContent>
101
+ </Card>
102
+ );
103
+ }
@@ -0,0 +1,98 @@
1
+ import {
2
+ Card,
3
+ CardContent,
4
+ CardDescription,
5
+ CardHeader,
6
+ CardTitle,
7
+ DataTable,
8
+ DataTableBody,
9
+ DataTableFacetedFilter,
10
+ DataTableHeader,
11
+ DataTableRoot,
12
+ DataTableRowCount,
13
+ DataTableSearchFilter,
14
+ DataTableSortHeader,
15
+ DataTableToolbarSection,
16
+ Delta,
17
+ useFormat,
18
+ type DataTableColumnDef,
19
+ } from "@siyahi/ui";
20
+
21
+ interface Holding {
22
+ symbol: string;
23
+ sector: string;
24
+ quantity: number;
25
+ value: number;
26
+ change: number;
27
+ }
28
+
29
+ const holdings: Holding[] = [
30
+ { symbol: "INFY", sector: "IT", quantity: 120, value: 224400, change: 0.018 },
31
+ { symbol: "HDFCBANK", sector: "Banks", quantity: 150, value: 262500, change: -0.006 },
32
+ { symbol: "TCS", sector: "IT", quantity: 40, value: 166000, change: 0.004 },
33
+ { symbol: "ITC", sector: "Fast Moving Consumer Goods", quantity: 600, value: 276000, change: -0.012 },
34
+ { symbol: "ICICIBANK", sector: "Banks", quantity: 200, value: 258000, change: 0.022 },
35
+ { symbol: "NIFTYBEES", sector: "ETF", quantity: 900, value: 255600, change: 0.009 },
36
+ ];
37
+
38
+ // One click sorts largest (or Z) first; the title comes from meta.label.
39
+ const header = () => <DataTableSortHeader />;
40
+
41
+ function Money({ amount }: { amount: number }) {
42
+ return useFormat().money(amount);
43
+ }
44
+
45
+ const columns: DataTableColumnDef<Holding>[] = [
46
+ { accessorKey: "symbol", header, size: 140, meta: { label: "Symbol" } },
47
+ { accessorKey: "sector", header, size: 120, meta: { label: "Sector" } },
48
+ { accessorKey: "quantity", header, size: 100, meta: { label: "Qty", variant: "number" } },
49
+ {
50
+ accessorKey: "value",
51
+ header,
52
+ size: 140,
53
+ meta: { label: "Value", variant: "number" },
54
+ cell: ({ row }) => <Money amount={row.original.value} />,
55
+ },
56
+ {
57
+ accessorKey: "change",
58
+ header,
59
+ size: 110,
60
+ meta: { label: "Day", variant: "number" },
61
+ cell: ({ row }) => <Delta value={row.original.change} />,
62
+ },
63
+ ];
64
+
65
+ export default function DataTableExample() {
66
+ return (
67
+ <Card>
68
+ <CardHeader>
69
+ <CardTitle>Holdings</CardTitle>
70
+ <CardDescription>
71
+ Search every column, filter by sector, sort any column in one click; the symbol stays put when the table
72
+ scrolls in wide panels. In narrow panels every column scrolls, leaving room for the values
73
+ </CardDescription>
74
+ </CardHeader>
75
+ <CardContent>
76
+ <DataTableRoot
77
+ data={holdings}
78
+ columns={columns}
79
+ initialState={{ columnPinning: { start: ["symbol"], end: [] } }}
80
+ >
81
+ <DataTableToolbarSection>
82
+ <DataTableSearchFilter
83
+ placeholder="Search holdings…"
84
+ label="Filter holdings"
85
+ className="flex-none sm:w-64"
86
+ />
87
+ <DataTableFacetedFilter accessorKey="sector" title="Sector" />
88
+ <DataTableRowCount unit="holdings" />
89
+ </DataTableToolbarSection>
90
+ <DataTable aria-label="Holdings">
91
+ <DataTableHeader />
92
+ <DataTableBody />
93
+ </DataTable>
94
+ </DataTableRoot>
95
+ </CardContent>
96
+ </Card>
97
+ );
98
+ }
@@ -0,0 +1,13 @@
1
+ import { Delta } from "@siyahi/ui";
2
+
3
+ export default function DeltaExample() {
4
+ return (
5
+ <div className="flex flex-wrap items-center gap-6">
6
+ <Delta value={0.0234} />
7
+ <Delta value={-0.0108} />
8
+ <Delta value={0} />
9
+ <Delta value={18250} format="money" />
10
+ <Delta value={-4300} format="money" />
11
+ </div>
12
+ );
13
+ }
@@ -0,0 +1,28 @@
1
+ import {
2
+ Button,
3
+ Dialog,
4
+ DialogClose,
5
+ DialogContent,
6
+ DialogDescription,
7
+ DialogFooter,
8
+ DialogHeader,
9
+ DialogTitle,
10
+ DialogTrigger,
11
+ } from "@siyahi/ui";
12
+
13
+ export default function DialogExample() {
14
+ return (
15
+ <Dialog>
16
+ <DialogTrigger render={<Button variant="outline" className="w-fit" />}>Show fills</DialogTrigger>
17
+ <DialogContent>
18
+ <DialogHeader>
19
+ <DialogTitle>Fills for this sell</DialogTitle>
20
+ <DialogDescription>Each lot this sale was matched against, oldest first.</DialogDescription>
21
+ </DialogHeader>
22
+ <DialogFooter>
23
+ <DialogClose render={<Button variant="outline" />}>Close</DialogClose>
24
+ </DialogFooter>
25
+ </DialogContent>
26
+ </Dialog>
27
+ );
28
+ }
@@ -0,0 +1,30 @@
1
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle, DistributionBar } from "@siyahi/ui";
2
+
3
+ // Where a memory budget sits, on a fixed 0 to 12 GiB scale; made-up figures.
4
+ const gib = (value: number) => `${value.toFixed(1)} GiB`;
5
+
6
+ export default function DistributionBarBudgetExample() {
7
+ return (
8
+ <Card>
9
+ <CardHeader>
10
+ <CardTitle>The agents group's budget</CardTitle>
11
+ <CardDescription>0 to 12 GiB; the lines mark its limits</CardDescription>
12
+ </CardHeader>
13
+ <CardContent>
14
+ <DistributionBar
15
+ max={12}
16
+ valueFormatter={gib}
17
+ markers={[
18
+ { at: 6, label: "High" },
19
+ { at: 8.7, label: "Max" },
20
+ ]}
21
+ segments={[
22
+ { name: "In RAM, under High", value: 6, color: "var(--chart-1)" },
23
+ { name: "In RAM, over High", value: 1.4, color: "var(--chart-2)" },
24
+ { name: "Pushed to zram", value: 2.6, color: "var(--chart-3)" },
25
+ ]}
26
+ />
27
+ </CardContent>
28
+ </Card>
29
+ );
30
+ }
@@ -0,0 +1,72 @@
1
+ import { useState } from "react";
2
+ import {
3
+ Card,
4
+ CardContent,
5
+ CardDescription,
6
+ CardFooter,
7
+ CardHeader,
8
+ CardTitle,
9
+ Delta,
10
+ DistributionBar,
11
+ type DistributionSegment,
12
+ } from "@siyahi/ui";
13
+
14
+ // Each closed position's net realized, ₹; made-up figures.
15
+ const positions = [
16
+ { name: "INFY", value: 61000 },
17
+ { name: "TCS", value: 38000 },
18
+ { name: "HDFCBANK", value: 17000 },
19
+ { name: "ITC", value: -26000 },
20
+ { name: "WIPRO", value: -14000 },
21
+ { name: "SBIN", value: -6000 },
22
+ ];
23
+ const won = positions.filter((p) => p.value > 0).reduce((sum, p) => sum + p.value, 0);
24
+ const lost = positions.filter((p) => p.value < 0).reduce((sum, p) => sum + p.value, 0);
25
+ // One scale both ways, so whichever side reaches farther is the net.
26
+ const reach = Math.max(won, -lost);
27
+
28
+ export default function DistributionBarTugExample() {
29
+ const [focus, setFocus] = useState<DistributionSegment | null>(null);
30
+ return (
31
+ <Card>
32
+ <CardHeader>
33
+ <CardTitle>The tug-of-war</CardTitle>
34
+ <CardDescription>Each closed position, losses left of break-even and gains right</CardDescription>
35
+ </CardHeader>
36
+ <CardContent className="flex flex-col gap-2">
37
+ <DistributionBar
38
+ min={-reach}
39
+ max={reach}
40
+ showLegend={false}
41
+ markers={[{ at: 0 }]}
42
+ highlighted={focus?.name ?? null}
43
+ onHover={setFocus}
44
+ segments={positions.map(({ name, value }) => ({
45
+ name,
46
+ value,
47
+ color: value > 0 ? "var(--positive)" : "var(--negative)",
48
+ }))}
49
+ />
50
+ <div className="grid grid-cols-3 text-xs text-muted-foreground tabular-nums">
51
+ <span>
52
+ losers <Delta value={lost} format="money" />
53
+ </span>
54
+ <span className="text-center">break-even</span>
55
+ <span className="text-right">
56
+ winners <Delta value={won} format="money" />
57
+ </span>
58
+ </div>
59
+ </CardContent>
60
+ <CardFooter className="min-h-12" aria-live="polite">
61
+ {focus ? (
62
+ <p className="flex items-center gap-2">
63
+ <span className="font-medium">{focus.name}</span>
64
+ <Delta value={focus.value} format="money" />
65
+ </p>
66
+ ) : (
67
+ <p className="text-muted-foreground">Hover a band to see its position.</p>
68
+ )}
69
+ </CardFooter>
70
+ </Card>
71
+ );
72
+ }
@@ -0,0 +1,31 @@
1
+ import {
2
+ Button,
3
+ DropdownMenu,
4
+ DropdownMenuContent,
5
+ DropdownMenuGroup,
6
+ DropdownMenuItem,
7
+ DropdownMenuLabel,
8
+ DropdownMenuSeparator,
9
+ DropdownMenuTrigger,
10
+ } from "@siyahi/ui";
11
+ import { EllipsisIcon } from "lucide-react";
12
+
13
+ export default function DropdownMenuExample() {
14
+ return (
15
+ <DropdownMenu>
16
+ <DropdownMenuTrigger render={<Button variant="outline" className="w-fit" />}>
17
+ <EllipsisIcon />
18
+ Actions
19
+ </DropdownMenuTrigger>
20
+ <DropdownMenuContent>
21
+ <DropdownMenuGroup>
22
+ <DropdownMenuLabel>Holding</DropdownMenuLabel>
23
+ <DropdownMenuItem>View lots</DropdownMenuItem>
24
+ <DropdownMenuItem>Export CSV</DropdownMenuItem>
25
+ </DropdownMenuGroup>
26
+ <DropdownMenuSeparator />
27
+ <DropdownMenuItem variant="destructive">Hide</DropdownMenuItem>
28
+ </DropdownMenuContent>
29
+ </DropdownMenu>
30
+ );
31
+ }
@@ -0,0 +1,42 @@
1
+ import { SiyahiProvider, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, useFormat } from "@siyahi/ui";
2
+
3
+ function Row({ label }: { label: string }) {
4
+ const { count, money, moneyCompact, pct, time } = useFormat();
5
+ return (
6
+ <TableRow>
7
+ <TableCell>{label}</TableCell>
8
+ <TableCell className="text-right">{count(153110)}</TableCell>
9
+ <TableCell className="text-right">{money(153110)}</TableCell>
10
+ <TableCell className="text-right">{moneyCompact(99999)}</TableCell>
11
+ <TableCell className="text-right">{moneyCompact(240000)}</TableCell>
12
+ <TableCell className="text-right">{moneyCompact(400000000)}</TableCell>
13
+ <TableCell className="text-right">{pct(0.1234)}</TableCell>
14
+ <TableCell className="text-right">{time("2026-10-20T09:00:00Z")}</TableCell>
15
+ </TableRow>
16
+ );
17
+ }
18
+
19
+ export default function FormattersExample() {
20
+ return (
21
+ <Table>
22
+ <TableHeader>
23
+ <TableRow>
24
+ <TableHead>Locale</TableHead>
25
+ <TableHead className="text-right">count</TableHead>
26
+ <TableHead className="text-right">money</TableHead>
27
+ <TableHead className="text-right">moneyCompact</TableHead>
28
+ <TableHead className="text-right">moneyCompact</TableHead>
29
+ <TableHead className="text-right">moneyCompact</TableHead>
30
+ <TableHead className="text-right">pct</TableHead>
31
+ <TableHead className="text-right">time</TableHead>
32
+ </TableRow>
33
+ </TableHeader>
34
+ <TableBody>
35
+ <Row label="Default (en-IN, INR, Kolkata)" />
36
+ <SiyahiProvider locale={{ numberLocale: "en-US", currency: "USD", timeZone: "America/New_York" }}>
37
+ <Row label="en-US, USD, New York" />
38
+ </SiyahiProvider>
39
+ </TableBody>
40
+ </Table>
41
+ );
42
+ }
@@ -0,0 +1,50 @@
1
+ import { useState } from "react";
2
+ import {
3
+ CalendarHeatmap,
4
+ CalendarHeatmapBlock,
5
+ CalendarHeatmapBody,
6
+ useFormat,
7
+ Card,
8
+ CardContent,
9
+ CardDescription,
10
+ CardHeader,
11
+ CardTitle,
12
+ } from "@siyahi/ui";
13
+
14
+ // A year of trading days with a count of trades on each.
15
+ const data = Array.from({ length: 365 }, (_, i) => {
16
+ const day = new Date(Date.UTC(2025, 9, 20 + i));
17
+ const weekday = day.getUTCDay();
18
+ const value = weekday === 0 || weekday === 6 ? 0 : (i * 7 + weekday * 3) % 6;
19
+ return { date: day.toISOString().slice(0, 10), value };
20
+ });
21
+
22
+ export default function HeatmapCalendarExample() {
23
+ const [selected, setSelected] = useState<string | null>(null);
24
+ const { count } = useFormat();
25
+ return (
26
+ <Card>
27
+ <CardHeader>
28
+ <CardTitle>Trades per day</CardTitle>
29
+ <CardDescription>Counts use a single-hue fade of --chart-1</CardDescription>
30
+ </CardHeader>
31
+ <CardContent>
32
+ <CalendarHeatmap data={data}>
33
+ <CalendarHeatmapBody>
34
+ {({ activity, dayIndex, weekIndex }) => (
35
+ <CalendarHeatmapBlock
36
+ activity={activity}
37
+ dayIndex={dayIndex}
38
+ weekIndex={weekIndex}
39
+ onCellClick={(cell) => setSelected(`${cell.date}: ${count(cell.value)} trades`)}
40
+ />
41
+ )}
42
+ </CalendarHeatmapBody>
43
+ </CalendarHeatmap>
44
+ <p aria-live="polite" className="mt-3 text-sm">
45
+ {selected ?? "Select a day for its trade count. Use arrow keys to move between days."}
46
+ </p>
47
+ </CardContent>
48
+ </Card>
49
+ );
50
+ }
@@ -0,0 +1,51 @@
1
+ import { useState } from "react";
2
+ import {
3
+ Card,
4
+ CardContent,
5
+ CardDescription,
6
+ CardHeader,
7
+ CardTitle,
8
+ StatusHeatmap,
9
+ StatusHeatmapBlock,
10
+ StatusHeatmapBody,
11
+ } from "@siyahi/ui";
12
+
13
+ // One cell per day for the last 60 days, as a status the heatmap colours:
14
+ // 3 healthy (--positive), 2 degraded (--warning), 1 critical (--negative).
15
+ const data = Array.from({ length: 60 }, (_, i) => {
16
+ const day = new Date(Date.UTC(2026, 7, 22 + i));
17
+ return { date: day.toISOString().slice(0, 10), value: i % 17 === 5 ? 1 : i % 11 === 3 ? 2 : 3 };
18
+ });
19
+
20
+ export default function HeatmapStatusExample() {
21
+ const [selected, setSelected] = useState<string | null>(null);
22
+
23
+ return (
24
+ <Card>
25
+ <CardHeader>
26
+ <CardTitle>Price feed</CardTitle>
27
+ <CardDescription>Daily health: healthy, degraded or critical</CardDescription>
28
+ </CardHeader>
29
+ <CardContent>
30
+ <StatusHeatmap data={data}>
31
+ <StatusHeatmapBody>
32
+ {({ activity, dayIndex }) => (
33
+ <StatusHeatmapBlock
34
+ activity={activity}
35
+ dayIndex={dayIndex}
36
+ onCellClick={(cell) =>
37
+ setSelected(
38
+ `${cell.date}: ${["unknown", "critical", "degraded", "healthy"][cell.value] ?? "unknown"}`,
39
+ )
40
+ }
41
+ />
42
+ )}
43
+ </StatusHeatmapBody>
44
+ </StatusHeatmap>
45
+ <p aria-live="polite" className="mt-3 text-sm">
46
+ {selected ?? "Select a day for its health. Use arrow keys to move between days."}
47
+ </p>
48
+ </CardContent>
49
+ </Card>
50
+ );
51
+ }