@siyahi/ui 0.1.9-next.3 → 0.1.9-next.30
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/DESIGN.md +170 -0
- package/README.md +94 -177
- package/THIRD_PARTY_NOTICES.md +11 -11
- package/agents/examples/accordion.tsx +39 -0
- package/agents/examples/alert.tsx +24 -0
- package/agents/examples/app-sidebar.tsx +40 -0
- package/agents/examples/avatar.tsx +24 -0
- package/agents/examples/badge.tsx +26 -0
- package/agents/examples/bar-list-labels.tsx +22 -0
- package/agents/examples/bar-list-sides.tsx +40 -0
- package/agents/examples/bar-list.tsx +24 -0
- package/agents/examples/breadcrumb.tsx +28 -0
- package/agents/examples/button-states.tsx +23 -0
- package/agents/examples/button.tsx +21 -0
- package/agents/examples/calendar.tsx +11 -0
- package/agents/examples/callout.tsx +33 -0
- package/agents/examples/card.tsx +36 -0
- package/agents/examples/change-bar.tsx +104 -0
- package/agents/examples/change-grid-money.tsx +36 -0
- package/agents/examples/change-grid.tsx +42 -0
- package/agents/examples/chart-area-log.tsx +45 -0
- package/agents/examples/chart-area.tsx +39 -0
- package/agents/examples/chart-bar-flows.tsx +32 -0
- package/agents/examples/chart-bar-hourly.tsx +28 -0
- package/agents/examples/chart-bar-losses.tsx +29 -0
- package/agents/examples/chart-bar-teams.tsx +72 -0
- package/agents/examples/chart-bar-years.tsx +40 -0
- package/agents/examples/chart-bar.tsx +56 -0
- package/agents/examples/chart-category-ticks.tsx +50 -0
- package/agents/examples/chart-line-events.tsx +47 -0
- package/agents/examples/chart-line-forecast.tsx +36 -0
- package/agents/examples/chart-line-log.tsx +39 -0
- package/agents/examples/chart-line-quiet.tsx +114 -0
- package/agents/examples/chart-line-timeline.tsx +41 -0
- package/agents/examples/chart-line.tsx +57 -0
- package/agents/examples/chart-panels.tsx +94 -0
- package/agents/examples/code-block.tsx +40 -0
- package/agents/examples/collapsible.tsx +18 -0
- package/agents/examples/command.tsx +29 -0
- package/agents/examples/context-menu.tsx +17 -0
- package/agents/examples/copy-button.tsx +8 -0
- package/agents/examples/data-bar.tsx +108 -0
- package/agents/examples/data-table-compact.tsx +96 -0
- package/agents/examples/data-table-filters.tsx +103 -0
- package/agents/examples/data-table.tsx +99 -0
- package/agents/examples/delta.tsx +18 -0
- package/agents/examples/dialog.tsx +28 -0
- package/agents/examples/distribution-bar-budget.tsx +30 -0
- package/agents/examples/distribution-bar-tug.tsx +74 -0
- package/agents/examples/drawdown-chart.tsx +35 -0
- package/agents/examples/dropdown-menu.tsx +31 -0
- package/agents/examples/field.tsx +108 -0
- package/agents/examples/formatters.tsx +42 -0
- package/agents/examples/heatmap-calendar-signed.tsx +67 -0
- package/agents/examples/heatmap-calendar.tsx +62 -0
- package/agents/examples/heatmap-status.tsx +61 -0
- package/agents/examples/heatmap-weekday.tsx +72 -0
- package/agents/examples/histogram-chart.tsx +28 -0
- package/agents/examples/input-states.tsx +23 -0
- package/agents/examples/input.tsx +17 -0
- package/agents/examples/local-time.tsx +14 -0
- package/agents/examples/metric-strip.tsx +46 -0
- package/agents/examples/overview-dashboard.tsx +180 -0
- package/agents/examples/page-hero.tsx +38 -0
- package/agents/examples/page-section.tsx +52 -0
- package/agents/examples/popover.tsx +23 -0
- package/agents/examples/price-chart.tsx +32 -0
- package/agents/examples/progress-tone.tsx +29 -0
- package/agents/examples/progress.tsx +10 -0
- package/agents/examples/range-position-table.tsx +101 -0
- package/agents/examples/range-position.tsx +55 -0
- package/agents/examples/scatter-chart-quadrants.tsx +63 -0
- package/agents/examples/scatter-chart-scales.tsx +46 -0
- package/agents/examples/scatter-chart.tsx +78 -0
- package/agents/examples/scroll-area.tsx +22 -0
- package/agents/examples/section-cards-select.tsx +28 -0
- package/agents/examples/section-cards-trend.tsx +32 -0
- package/agents/examples/section-cards.tsx +48 -0
- package/agents/examples/select.tsx +27 -0
- package/agents/examples/separator.tsx +13 -0
- package/agents/examples/sheet.tsx +15 -0
- package/agents/examples/skeleton.tsx +11 -0
- package/agents/examples/slider.tsx +5 -0
- package/agents/examples/slope-chart-market.tsx +33 -0
- package/agents/examples/slope-chart.tsx +26 -0
- package/agents/examples/stale-blocks.tsx +56 -0
- package/agents/examples/surfaces.tsx +116 -0
- package/agents/examples/table.tsx +60 -0
- package/agents/examples/tabs.tsx +16 -0
- package/agents/examples/target-rows.tsx +74 -0
- package/agents/examples/toggle-group.tsx +12 -0
- package/agents/examples/toggle.tsx +11 -0
- package/agents/examples/tooltip.tsx +13 -0
- package/agents/examples/treemap.tsx +93 -0
- package/agents/examples/waterfall-chart-stores.tsx +27 -0
- package/agents/examples/waterfall-chart.tsx +37 -0
- package/agents/manifest.json +1391 -0
- package/agents/report-rules.json +7 -0
- package/dist/components/registry/charts/area-chart-card.d.ts +7 -3
- package/dist/components/registry/charts/area-chart-card.js +56 -10
- package/dist/components/registry/charts/bar-chart-card.d.ts +1 -1
- package/dist/components/registry/charts/bar-chart-card.js +20 -22
- package/dist/components/registry/charts/line-chart-card.d.ts +3 -3
- package/dist/components/registry/charts/line-chart-card.js +44 -9
- package/dist/components/registry/dashboard-01/section-cards.d.ts +6 -0
- package/dist/components/registry/dashboard-01/section-cards.js +51 -35
- package/dist/components/registry/dashboardcn/bar-list.js +17 -10
- package/dist/components/registry/dashboardcn/distribution-bar.js +6 -4
- package/dist/components/registry/dashboardcn/kpi-row-card.d.ts +29 -0
- package/dist/components/registry/dashboardcn/kpi-row-card.js +81 -0
- package/dist/components/registry/dashboardcn/sparkline.d.ts +22 -0
- package/dist/components/registry/dashboardcn/sparkline.js +117 -0
- package/dist/components/registry/heatmap/calendar-heatmap.d.ts +11 -3
- package/dist/components/registry/heatmap/calendar-heatmap.js +164 -45
- package/dist/components/registry/heatmap/status-heatmap.d.ts +5 -3
- package/dist/components/registry/heatmap/status-heatmap.js +115 -54
- package/dist/components/registry/heatmap/weekday-heatmap.d.ts +9 -3
- package/dist/components/registry/heatmap/weekday-heatmap.js +83 -53
- package/dist/components/registry/niko-table/core/data-table-context.d.ts +18 -1
- package/dist/components/registry/niko-table/core/data-table-context.js +7 -1
- package/dist/components/registry/niko-table/core/data-table-grouped-row.js +3 -1
- package/dist/components/registry/niko-table/core/data-table-root.js +39 -4
- package/dist/components/registry/niko-table/core/data-table-structure.js +17 -12
- package/dist/components/registry/niko-table/core/data-table.d.ts +2 -2
- package/dist/components/registry/niko-table/core/data-table.js +5 -1
- package/dist/components/registry/niko-table/filters/table-faceted-filter.js +5 -5
- package/dist/components/registry/niko-table/filters/table-search-filter.js +1 -1
- package/dist/components/registry/niko-table/lib/flex-columns.d.ts +1 -1
- package/dist/components/registry/niko-table/lib/flex-columns.js +3 -3
- package/dist/components/registry/niko-table/lib/styles.d.ts +1 -1
- package/dist/components/registry/niko-table/lib/styles.js +3 -3
- package/dist/components/registry/niko-table/types/index.d.ts +9 -0
- package/dist/components/registry/niko-table/ui/table.js +2 -2
- package/dist/components/registry/sidebar-07/app-sidebar.d.ts +1 -1
- package/dist/components/registry/sidebar-07/app-sidebar.js +3 -1
- package/dist/components/registry/sidebar-07/nav-main.d.ts +2 -1
- package/dist/components/registry/sidebar-07/nav-main.js +16 -3
- package/dist/components/siyahi/callout.d.ts +17 -0
- package/dist/components/siyahi/callout.js +34 -0
- package/dist/components/siyahi/change-bar.d.ts +21 -0
- package/dist/components/siyahi/change-bar.js +35 -0
- package/dist/components/siyahi/change-grid.d.ts +31 -0
- package/dist/components/siyahi/change-grid.js +74 -0
- package/dist/components/siyahi/data-bar.d.ts +19 -0
- package/dist/components/siyahi/data-bar.js +29 -0
- package/dist/components/siyahi/data-table-compact-columns-toggle.d.ts +4 -0
- package/dist/components/siyahi/data-table-compact-columns-toggle.js +19 -0
- package/dist/components/siyahi/data-table-footnote.d.ts +12 -0
- package/dist/components/siyahi/data-table-footnote.js +35 -0
- package/dist/components/siyahi/default-sidebar-open.d.ts +8 -0
- package/dist/components/siyahi/default-sidebar-open.js +13 -0
- package/dist/components/siyahi/delta.d.ts +5 -1
- package/dist/components/siyahi/delta.js +14 -9
- package/dist/components/siyahi/drawdown-chart.d.ts +34 -0
- package/dist/components/siyahi/drawdown-chart.js +102 -0
- package/dist/components/siyahi/histogram-chart.d.ts +57 -0
- package/dist/components/siyahi/histogram-chart.js +134 -0
- package/dist/components/siyahi/page-hero.d.ts +23 -0
- package/dist/components/siyahi/page-hero.js +43 -0
- package/dist/components/siyahi/page-section.d.ts +4 -1
- package/dist/components/siyahi/page-section.js +6 -3
- package/dist/components/siyahi/page-toc.d.ts +20 -0
- package/dist/components/siyahi/page-toc.js +76 -0
- package/dist/components/siyahi/panel-grid.d.ts +24 -0
- package/dist/components/siyahi/panel-grid.js +37 -0
- package/dist/components/siyahi/quote.d.ts +12 -0
- package/dist/components/siyahi/quote.js +23 -0
- package/dist/components/siyahi/range-position.d.ts +24 -0
- package/dist/components/siyahi/range-position.js +105 -0
- package/dist/components/siyahi/scale-toggle.d.ts +32 -0
- package/dist/components/siyahi/scale-toggle.js +61 -0
- package/dist/components/siyahi/scatter-chart.d.ts +69 -0
- package/dist/components/siyahi/scatter-chart.js +395 -0
- package/dist/components/siyahi/siyahi-provider.d.ts +15 -2
- package/dist/components/siyahi/siyahi-provider.js +17 -4
- package/dist/components/siyahi/slope-chart.d.ts +35 -0
- package/dist/components/siyahi/slope-chart.js +159 -0
- package/dist/components/siyahi/stale-note.d.ts +9 -0
- package/dist/components/siyahi/stale-note.js +12 -0
- package/dist/components/siyahi/status-alert.d.ts +15 -0
- package/dist/components/siyahi/status-alert.js +29 -0
- package/dist/components/siyahi/status-badge.d.ts +15 -0
- package/dist/components/siyahi/status-badge.js +24 -0
- package/dist/components/siyahi/target-rows.d.ts +34 -0
- package/dist/components/siyahi/target-rows.js +97 -0
- package/dist/components/siyahi/tone-progress.d.ts +1 -1
- package/dist/components/siyahi/tone-progress.js +1 -1
- package/dist/components/siyahi/treemap.d.ts +8 -5
- package/dist/components/siyahi/treemap.js +80 -34
- package/dist/components/siyahi/waterfall-chart.d.ts +51 -0
- package/dist/components/siyahi/waterfall-chart.js +147 -0
- package/dist/components/ui/accordion.js +5 -5
- package/dist/components/ui/alert.js +2 -2
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/breadcrumb.js +2 -2
- package/dist/components/ui/button.js +10 -10
- package/dist/components/ui/calendar.js +1 -1
- package/dist/components/ui/card.js +4 -4
- package/dist/components/ui/chart.js +1 -1
- package/dist/components/ui/code-block.js +13 -12
- package/dist/components/ui/command.js +7 -6
- package/dist/components/ui/context-menu.js +7 -7
- package/dist/components/ui/dialog.js +5 -5
- package/dist/components/ui/dropdown-menu.js +8 -8
- package/dist/components/ui/field.d.ts +26 -0
- package/dist/components/ui/field.js +109 -0
- package/dist/components/ui/input-group.js +11 -11
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/label.d.ts +5 -0
- package/dist/components/ui/label.js +13 -0
- package/dist/components/ui/popover.js +3 -3
- package/dist/components/ui/progress.js +1 -1
- package/dist/components/ui/select.js +6 -6
- package/dist/components/ui/sheet.js +5 -5
- package/dist/components/ui/sidebar.js +17 -18
- package/dist/components/ui/skeleton.js +1 -1
- package/dist/components/ui/slider.js +2 -2
- package/dist/components/ui/table.js +2 -2
- package/dist/components/ui/tabs.js +2 -2
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/toggle-group.js +2 -2
- package/dist/components/ui/toggle.js +4 -4
- package/dist/components/ui/tooltip.js +2 -2
- package/dist/index.d.ts +35 -8
- package/dist/index.js +30 -4
- package/dist/lib/chart-frame.d.ts +51 -7
- package/dist/lib/chart-frame.js +390 -133
- package/dist/lib/chart-marks.d.ts +83 -0
- package/dist/lib/chart-marks.js +216 -0
- package/dist/lib/chart-series.d.ts +42 -10
- package/dist/lib/compact-columns.d.ts +19 -0
- package/dist/lib/compact-columns.js +55 -0
- package/dist/lib/fit-text.d.ts +6 -0
- package/dist/lib/fit-text.js +11 -0
- package/dist/lib/format.d.ts +8 -3
- package/dist/lib/format.js +55 -17
- package/dist/lib/heat.d.ts +7 -0
- package/dist/lib/heat.js +14 -0
- package/dist/lib/heatmap-navigation.d.ts +8 -0
- package/dist/lib/heatmap-navigation.js +49 -0
- package/dist/lib/scatter.d.ts +88 -0
- package/dist/lib/scatter.js +179 -0
- package/dist/lib/ticks.d.ts +27 -0
- package/dist/lib/ticks.js +67 -0
- package/dist/lib/tone.d.ts +36 -0
- package/dist/lib/tone.js +35 -0
- package/dist/lib/treemap.d.ts +0 -5
- package/dist/lib/treemap.js +1 -11
- package/dist/lib/use-element-width.d.ts +5 -0
- package/dist/lib/use-element-width.js +15 -0
- package/package.json +5 -1
- package/registry.lock.json +16 -0
- package/report.css +63 -47
- package/styles/siyahi.css +708 -55
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { KeyboardEventHandler, RefObject } from "react";
|
|
2
|
+
//#region src/lib/heatmap-navigation.d.ts
|
|
3
|
+
/** One tab stop per heatmap; arrows move between its actual drawn cells. */
|
|
4
|
+
export declare function useHeatmapNavigation(): {
|
|
5
|
+
ref: RefObject<HTMLDivElement | null>;
|
|
6
|
+
onKeyDown: KeyboardEventHandler<HTMLDivElement>;
|
|
7
|
+
};
|
|
8
|
+
//#endregion
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef } from "react";
|
|
2
|
+
//#region src/lib/heatmap-navigation.ts
|
|
3
|
+
/** One tab stop per heatmap; arrows move between its actual drawn cells. */
|
|
4
|
+
function useHeatmapNavigation() {
|
|
5
|
+
const ref = useRef(null);
|
|
6
|
+
const cells = () => [...ref.current?.querySelectorAll("rect[role=\"button\"]") ?? []];
|
|
7
|
+
useLayoutEffect(() => {
|
|
8
|
+
const buttons = cells();
|
|
9
|
+
const active = buttons.find((cell) => cell === document.activeElement) ?? buttons[0];
|
|
10
|
+
for (const cell of buttons) cell.tabIndex = cell === active ? 0 : -1;
|
|
11
|
+
});
|
|
12
|
+
const onKeyDown = (event) => {
|
|
13
|
+
if (!(event.target instanceof SVGElement) || event.target.getAttribute("role") !== "button") return;
|
|
14
|
+
const buttons = cells();
|
|
15
|
+
let next;
|
|
16
|
+
if (event.key === "Home") next = buttons[0];
|
|
17
|
+
else if (event.key === "End") next = buttons.at(-1);
|
|
18
|
+
else if ([
|
|
19
|
+
"ArrowLeft",
|
|
20
|
+
"ArrowRight",
|
|
21
|
+
"ArrowUp",
|
|
22
|
+
"ArrowDown"
|
|
23
|
+
].includes(event.key)) {
|
|
24
|
+
const origin = event.target.getBoundingClientRect();
|
|
25
|
+
const horizontal = event.key === "ArrowLeft" || event.key === "ArrowRight";
|
|
26
|
+
const direction = event.key === "ArrowLeft" || event.key === "ArrowUp" ? -1 : 1;
|
|
27
|
+
let nearest = Infinity;
|
|
28
|
+
for (const cell of buttons) {
|
|
29
|
+
const box = cell.getBoundingClientRect();
|
|
30
|
+
const primary = (horizontal ? box.x - origin.x : box.y - origin.y) * direction;
|
|
31
|
+
const distance = primary + Math.abs(horizontal ? box.y - origin.y : box.x - origin.x) * 4;
|
|
32
|
+
if (primary > 1 && distance < nearest) {
|
|
33
|
+
nearest = distance;
|
|
34
|
+
next = cell;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} else return;
|
|
38
|
+
event.preventDefault();
|
|
39
|
+
if (!next) return;
|
|
40
|
+
for (const cell of buttons) cell.tabIndex = cell === next ? 0 : -1;
|
|
41
|
+
next.focus();
|
|
42
|
+
};
|
|
43
|
+
return {
|
|
44
|
+
ref,
|
|
45
|
+
onKeyDown
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { useHeatmapNavigation };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { AxisScale } from "./ticks.js";
|
|
2
|
+
//#region src/lib/scatter.d.ts
|
|
3
|
+
export interface Box {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
}
|
|
9
|
+
export interface LabelCandidate {
|
|
10
|
+
key: string;
|
|
11
|
+
text: string;
|
|
12
|
+
/** The dot's centre, in pixels. */
|
|
13
|
+
cx: number;
|
|
14
|
+
cy: number;
|
|
15
|
+
/** The dot's radius, its edge included: a sized dot keeps names off all of itself. */
|
|
16
|
+
r: number;
|
|
17
|
+
}
|
|
18
|
+
export interface PlacedLabel {
|
|
19
|
+
key: string;
|
|
20
|
+
text: string;
|
|
21
|
+
/** Where the text starts and its baseline, with textAnchor="start". */
|
|
22
|
+
x: number;
|
|
23
|
+
y: number;
|
|
24
|
+
}
|
|
25
|
+
/** How labels are set: their type size in pixels and a name's width in that type. */
|
|
26
|
+
export interface LabelType {
|
|
27
|
+
size: number;
|
|
28
|
+
measure: (text: string) => number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Names beside dots, in the candidates' order, up to `limit`: each tries the right of its dot, then the left, above,
|
|
32
|
+
* below and the four corners, and takes the first spot inside the plot that covers no other label, no other dot and
|
|
33
|
+
* nothing `reserved` (such as a quadrant's name). A name that finds no spot is left to the tooltip, so labels never sit
|
|
34
|
+
* on top of each other.
|
|
35
|
+
*/
|
|
36
|
+
export declare function placeLabels(candidates: readonly LabelCandidate[], plot: Box, limit: number, { size, measure }: LabelType, reserved?: readonly Box[]): PlacedLabel[];
|
|
37
|
+
/**
|
|
38
|
+
* Splits the plot into four at a value on each axis, such as zero, with an optional name in each corner. On a log
|
|
39
|
+
* axis that value must be above zero, or no split is drawn. A name that does not fit its quadrant in two lines is left out.
|
|
40
|
+
*/
|
|
41
|
+
export interface ScatterQuadrants {
|
|
42
|
+
x: number;
|
|
43
|
+
y: number;
|
|
44
|
+
labels?: {
|
|
45
|
+
topLeft?: string;
|
|
46
|
+
topRight?: string;
|
|
47
|
+
bottomLeft?: string;
|
|
48
|
+
bottomRight?: string;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export type QuadrantLabels = ScatterQuadrants["labels"];
|
|
52
|
+
/** A split a log axis cannot place, at or below zero, or one that is not a number, is no split at all. */
|
|
53
|
+
export declare function quadrantSplit(quadrants: ScatterQuadrants | undefined, xScale: AxisScale, yScale: AxisScale): ScatterQuadrants | undefined;
|
|
54
|
+
/** The largest sized dot; the smallest stays big enough to see and to tap. */
|
|
55
|
+
export declare const MAX_RADIUS = 20;
|
|
56
|
+
/**
|
|
57
|
+
* Each dot's radius. Area, not radius, follows size, so a holding twice as large has twice the ink. A size that weighs
|
|
58
|
+
* nothing draws the smallest dot, so it cannot shrink or hide the others. Points without sizes all take `plain`.
|
|
59
|
+
*/
|
|
60
|
+
export declare function dotSizes(points: readonly {
|
|
61
|
+
size?: number;
|
|
62
|
+
}[], plain: number): {
|
|
63
|
+
radiusOf: (p: {
|
|
64
|
+
size?: number;
|
|
65
|
+
}) => number;
|
|
66
|
+
sized: boolean;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Each corner's name in the plot's corner, in the band the y axis keeps clear above or below the data, wrapped to its
|
|
70
|
+
* own quadrant's width so two names on one edge never meet: where its lines are drawn, and the box they take.
|
|
71
|
+
*/
|
|
72
|
+
export declare function corners(plot: Box, names: QuadrantLabels, split: {
|
|
73
|
+
x: number;
|
|
74
|
+
y: number;
|
|
75
|
+
} | null, type: LabelType): {
|
|
76
|
+
key: string;
|
|
77
|
+
lines: string[];
|
|
78
|
+
x: number;
|
|
79
|
+
y: number;
|
|
80
|
+
line: number;
|
|
81
|
+
box: {
|
|
82
|
+
x: number;
|
|
83
|
+
y: number;
|
|
84
|
+
width: number;
|
|
85
|
+
height: number;
|
|
86
|
+
};
|
|
87
|
+
}[];
|
|
88
|
+
//#endregion
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
//#region src/lib/scatter.ts
|
|
2
|
+
const HALO = 2;
|
|
3
|
+
const GAP = 4;
|
|
4
|
+
const overlaps = (a, b) => a.x < b.x + b.width && b.x < a.x + a.width && a.y < b.y + b.height && b.y < a.y + a.height;
|
|
5
|
+
/**
|
|
6
|
+
* Names beside dots, in the candidates' order, up to `limit`: each tries the right of its dot, then the left, above,
|
|
7
|
+
* below and the four corners, and takes the first spot inside the plot that covers no other label, no other dot and
|
|
8
|
+
* nothing `reserved` (such as a quadrant's name). A name that finds no spot is left to the tooltip, so labels never sit
|
|
9
|
+
* on top of each other.
|
|
10
|
+
*/
|
|
11
|
+
function placeLabels(candidates, plot, limit, { size, measure }, reserved = []) {
|
|
12
|
+
const line = size * 4 / 3;
|
|
13
|
+
const dots = candidates.map(({ key, cx, cy, r }) => ({
|
|
14
|
+
key,
|
|
15
|
+
box: {
|
|
16
|
+
x: cx - r,
|
|
17
|
+
y: cy - r,
|
|
18
|
+
width: r * 2,
|
|
19
|
+
height: r * 2
|
|
20
|
+
}
|
|
21
|
+
}));
|
|
22
|
+
const taken = [...reserved];
|
|
23
|
+
const placed = [];
|
|
24
|
+
for (const { key, text, cx, cy, r: radius } of candidates) {
|
|
25
|
+
if (placed.length >= limit) break;
|
|
26
|
+
const width = measure(text) + 4;
|
|
27
|
+
const spot = [
|
|
28
|
+
{
|
|
29
|
+
x: cx + radius + GAP,
|
|
30
|
+
y: cy - line / 2,
|
|
31
|
+
width,
|
|
32
|
+
height: line
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
x: cx - radius - GAP - width,
|
|
36
|
+
y: cy - line / 2,
|
|
37
|
+
width,
|
|
38
|
+
height: line
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
x: cx - width / 2,
|
|
42
|
+
y: cy - radius - GAP - line,
|
|
43
|
+
width,
|
|
44
|
+
height: line
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
x: cx - width / 2,
|
|
48
|
+
y: cy + radius + GAP,
|
|
49
|
+
width,
|
|
50
|
+
height: line
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
x: cx + radius,
|
|
54
|
+
y: cy - radius - line,
|
|
55
|
+
width,
|
|
56
|
+
height: line
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
x: cx - radius - width,
|
|
60
|
+
y: cy - radius - line,
|
|
61
|
+
width,
|
|
62
|
+
height: line
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
x: cx + radius,
|
|
66
|
+
y: cy + radius,
|
|
67
|
+
width,
|
|
68
|
+
height: line
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
x: cx - radius - width,
|
|
72
|
+
y: cy + radius,
|
|
73
|
+
width,
|
|
74
|
+
height: line
|
|
75
|
+
}
|
|
76
|
+
].find((box) => box.x >= plot.x && box.y >= plot.y && box.x + box.width <= plot.x + plot.width && box.y + box.height <= plot.y + plot.height && !taken.some((other) => overlaps(box, other)) && !dots.some((dot) => dot.key !== key && overlaps(box, dot.box)));
|
|
77
|
+
if (!spot) continue;
|
|
78
|
+
taken.push(spot);
|
|
79
|
+
placed.push({
|
|
80
|
+
key,
|
|
81
|
+
text,
|
|
82
|
+
x: spot.x + HALO,
|
|
83
|
+
y: spot.y + size
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return placed;
|
|
87
|
+
}
|
|
88
|
+
const fits = (scale, at) => scale === "linear" || at > 0;
|
|
89
|
+
/** A split a log axis cannot place, at or below zero, or one that is not a number, is no split at all. */
|
|
90
|
+
function quadrantSplit(quadrants, xScale, yScale) {
|
|
91
|
+
if (!quadrants || !Number.isFinite(quadrants.x) || !Number.isFinite(quadrants.y)) return void 0;
|
|
92
|
+
return fits(xScale, quadrants.x) && fits(yScale, quadrants.y) ? quadrants : void 0;
|
|
93
|
+
}
|
|
94
|
+
/** The largest sized dot; the smallest stays big enough to see and to tap. */
|
|
95
|
+
const MAX_RADIUS = 20;
|
|
96
|
+
const MIN_RADIUS = 3;
|
|
97
|
+
/** A size that is not a positive number (NaN, Infinity, a negative) weighs nothing. */
|
|
98
|
+
const weight = (p) => p.size !== void 0 && Number.isFinite(p.size) && p.size > 0 ? p.size : 0;
|
|
99
|
+
/**
|
|
100
|
+
* Each dot's radius. Area, not radius, follows size, so a holding twice as large has twice the ink. A size that weighs
|
|
101
|
+
* nothing draws the smallest dot, so it cannot shrink or hide the others. Points without sizes all take `plain`.
|
|
102
|
+
*/
|
|
103
|
+
function dotSizes(points, plain) {
|
|
104
|
+
const largest = points.reduce((most, p) => Math.max(most, weight(p)), 0);
|
|
105
|
+
const sized = points.some((p) => p.size !== void 0);
|
|
106
|
+
const radiusOf = (p) => {
|
|
107
|
+
if (!sized || p.size === void 0) return plain;
|
|
108
|
+
return largest > 0 ? Math.max(MIN_RADIUS, 20 * Math.sqrt(weight(p) / largest)) : MIN_RADIUS;
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
radiusOf,
|
|
112
|
+
sized
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** Words broken into lines no wider than `width`; a word wider than that keeps a line of its own. */
|
|
116
|
+
function wrap(text, width, measure) {
|
|
117
|
+
const lines = [];
|
|
118
|
+
for (const word of text.split(" ")) {
|
|
119
|
+
const last = lines.at(-1);
|
|
120
|
+
if (last !== void 0 && measure(`${last} ${word}`) <= width) lines[lines.length - 1] = `${last} ${word}`;
|
|
121
|
+
else lines.push(word);
|
|
122
|
+
}
|
|
123
|
+
return lines;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Each corner's name in the plot's corner, in the band the y axis keeps clear above or below the data, wrapped to its
|
|
127
|
+
* own quadrant's width so two names on one edge never meet: where its lines are drawn, and the box they take.
|
|
128
|
+
*/
|
|
129
|
+
function corners(plot, names, split, type) {
|
|
130
|
+
if (!names || !split) return [];
|
|
131
|
+
const line = type.size * 4 / 3;
|
|
132
|
+
const inset = 6;
|
|
133
|
+
return [
|
|
134
|
+
[
|
|
135
|
+
names.topLeft,
|
|
136
|
+
"left",
|
|
137
|
+
"top"
|
|
138
|
+
],
|
|
139
|
+
[
|
|
140
|
+
names.topRight,
|
|
141
|
+
"right",
|
|
142
|
+
"top"
|
|
143
|
+
],
|
|
144
|
+
[
|
|
145
|
+
names.bottomLeft,
|
|
146
|
+
"left",
|
|
147
|
+
"bottom"
|
|
148
|
+
],
|
|
149
|
+
[
|
|
150
|
+
names.bottomRight,
|
|
151
|
+
"right",
|
|
152
|
+
"bottom"
|
|
153
|
+
]
|
|
154
|
+
].flatMap(([text, side, edge]) => {
|
|
155
|
+
if (!text) return [];
|
|
156
|
+
const room = (side === "left" ? split.x - plot.x : plot.x + plot.width - split.x) - 12;
|
|
157
|
+
const lines = wrap(text, Math.max(room, 0), type.measure);
|
|
158
|
+
const width = Math.max(...lines.map(type.measure));
|
|
159
|
+
if (lines.length > 2 || width > room) return [];
|
|
160
|
+
const height = lines.length * line;
|
|
161
|
+
const x = side === "left" ? plot.x + inset : plot.x + plot.width - inset - width;
|
|
162
|
+
const top = edge === "top" ? plot.y + inset : plot.y + plot.height - inset - height;
|
|
163
|
+
return [{
|
|
164
|
+
key: `${side}-${edge}`,
|
|
165
|
+
lines,
|
|
166
|
+
x,
|
|
167
|
+
y: top + type.size,
|
|
168
|
+
line,
|
|
169
|
+
box: {
|
|
170
|
+
x,
|
|
171
|
+
y: top,
|
|
172
|
+
width,
|
|
173
|
+
height
|
|
174
|
+
}
|
|
175
|
+
}];
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
export { MAX_RADIUS, corners, dotSizes, placeLabels, quadrantSplit };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/lib/ticks.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Ticks for a log axis at 1, 2 and 5 times a power of ten, from the largest at or under min to the smallest at or
|
|
4
|
+
* over max, so the axis ends on a tick and every label reads as a round number.
|
|
5
|
+
*/
|
|
6
|
+
export declare function logTicks(min: number, max: number): number[];
|
|
7
|
+
/**
|
|
8
|
+
* Ticks for a linear axis that just covers min to max, about `count` of them, a step of 1, 2, 2.5 or 5 times a power
|
|
9
|
+
* of ten: −50% to +75% by 25s, never −50% to +150% because the step had to be 50. Values that differ only by float
|
|
10
|
+
* noise, such as 0.3 and 0.30000000000000004, count as one value and get that value as their only tick.
|
|
11
|
+
*/
|
|
12
|
+
export declare function linearTicks(min: number, max: number, count?: number): number[];
|
|
13
|
+
/** How an axis spaces its values: evenly, or by powers of ten for values that run from tiny to large. */
|
|
14
|
+
export type AxisScale = "linear" | "log";
|
|
15
|
+
/** An axis' ticks for its scale: round steps either way, so a linear axis starting at 0.4% reads 0%, 5%, 10%. */
|
|
16
|
+
export declare const ticksFor: (scale: AxisScale, min: number, max: number) => number[];
|
|
17
|
+
/** A log axis has no place for zero or below, so it can draw a set of values only when every one is above zero. */
|
|
18
|
+
export declare const fitsLog: (values: readonly number[]) => boolean;
|
|
19
|
+
/**
|
|
20
|
+
* A log axis' ends and ticks: a page's fixed range when it gives one, with the 1, 2 and 5 ticks inside it, or else the
|
|
21
|
+
* ticks that just cover the values and their outer two as the ends.
|
|
22
|
+
*/
|
|
23
|
+
export declare function logAxis(values: readonly number[], range?: readonly [number, number]): {
|
|
24
|
+
domain: [number, number];
|
|
25
|
+
ticks: number[];
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
//#region src/lib/ticks.ts
|
|
2
|
+
/**
|
|
3
|
+
* Ticks for a log axis at 1, 2 and 5 times a power of ten, from the largest at or under min to the smallest at or
|
|
4
|
+
* over max, so the axis ends on a tick and every label reads as a round number.
|
|
5
|
+
*/
|
|
6
|
+
function logTicks(min, max) {
|
|
7
|
+
if (!(min > 0) || !Number.isFinite(max) || !(max >= min)) return [];
|
|
8
|
+
const ticks = [];
|
|
9
|
+
for (let decade = Math.floor(Math.log10(min));; decade++) for (const step of [
|
|
10
|
+
1,
|
|
11
|
+
2,
|
|
12
|
+
5
|
|
13
|
+
]) {
|
|
14
|
+
const tick = Number((step * 10 ** decade).toPrecision(12));
|
|
15
|
+
if (Number(((step === 5 ? 10 : step === 2 ? 5 : 2) * 10 ** decade).toPrecision(12)) <= min) continue;
|
|
16
|
+
ticks.push(tick);
|
|
17
|
+
if (tick >= max) return ticks;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const clean = (value) => Number(value.toPrecision(12)) || 0;
|
|
21
|
+
/**
|
|
22
|
+
* Ticks for a linear axis that just covers min to max, about `count` of them, a step of 1, 2, 2.5 or 5 times a power
|
|
23
|
+
* of ten: −50% to +75% by 25s, never −50% to +150% because the step had to be 50. Values that differ only by float
|
|
24
|
+
* noise, such as 0.3 and 0.30000000000000004, count as one value and get that value as their only tick.
|
|
25
|
+
*/
|
|
26
|
+
function linearTicks(min, max, count = 5) {
|
|
27
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max < min) return [];
|
|
28
|
+
if (max - min <= Math.max(Math.abs(min), Math.abs(max)) * 1e-9) return [clean(min)];
|
|
29
|
+
const rough = (max - min) / (count - 1);
|
|
30
|
+
const power = 10 ** Math.floor(Math.log10(rough));
|
|
31
|
+
const step = ([
|
|
32
|
+
1,
|
|
33
|
+
2,
|
|
34
|
+
2.5,
|
|
35
|
+
5,
|
|
36
|
+
10
|
|
37
|
+
].find((m) => m * power >= rough * (1 - 1e-9)) ?? 10) * power;
|
|
38
|
+
const first = Math.floor(min / step + 1e-9);
|
|
39
|
+
const last = Math.ceil(max / step - 1e-9);
|
|
40
|
+
return Array.from({ length: last - first + 1 }, (_, i) => clean((first + i) * step));
|
|
41
|
+
}
|
|
42
|
+
/** An axis' ticks for its scale: round steps either way, so a linear axis starting at 0.4% reads 0%, 5%, 10%. */
|
|
43
|
+
const ticksFor = (scale, min, max) => scale === "log" ? logTicks(min, max) : linearTicks(min, max);
|
|
44
|
+
/** A log axis has no place for zero or below, so it can draw a set of values only when every one is above zero. */
|
|
45
|
+
const fitsLog = (values) => values.length > 0 && values.every((value) => value > 0);
|
|
46
|
+
/**
|
|
47
|
+
* A log axis' ends and ticks: a page's fixed range when it gives one, with the 1, 2 and 5 ticks inside it, or else the
|
|
48
|
+
* ticks that just cover the values and their outer two as the ends.
|
|
49
|
+
*/
|
|
50
|
+
function logAxis(values, range) {
|
|
51
|
+
if (range) {
|
|
52
|
+
const [low, high] = range;
|
|
53
|
+
return {
|
|
54
|
+
domain: [low, high],
|
|
55
|
+
ticks: logTicks(low, high).filter((tick) => tick >= low && tick <= high)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const low = Math.min(...values);
|
|
59
|
+
const high = Math.max(...values);
|
|
60
|
+
const ticks = logTicks(low, high);
|
|
61
|
+
return {
|
|
62
|
+
domain: [ticks[0] ?? low, ticks.at(-1) ?? high],
|
|
63
|
+
ticks
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { fitsLog, linearTicks, logAxis, logTicks, ticksFor };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/lib/tone.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* The tones a box can take: a faint wash of the colour inside a full border of it, with the colour itself kept for
|
|
4
|
+
* an icon or a dot. Text inside stays in the text colours: small coloured text on its own wash falls under 4.5:1.
|
|
5
|
+
* Callout, StatusAlert and StatusBadge share these, so a warning looks the same wherever it appears.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TONES: {
|
|
8
|
+
readonly neutral: {
|
|
9
|
+
readonly box: "border-border bg-muted/50";
|
|
10
|
+
readonly ink: "text-muted-foreground!";
|
|
11
|
+
readonly dot: "bg-muted-foreground";
|
|
12
|
+
};
|
|
13
|
+
readonly accent: {
|
|
14
|
+
readonly box: "border-chart-1/35 bg-chart-1/8";
|
|
15
|
+
readonly ink: "text-link!";
|
|
16
|
+
readonly dot: "bg-link";
|
|
17
|
+
};
|
|
18
|
+
readonly warning: {
|
|
19
|
+
readonly box: "border-warning/45 bg-warning/10";
|
|
20
|
+
readonly ink: "text-warning!";
|
|
21
|
+
readonly dot: "bg-warning";
|
|
22
|
+
};
|
|
23
|
+
readonly positive: {
|
|
24
|
+
readonly box: "border-positive/40 bg-positive/8";
|
|
25
|
+
readonly ink: "text-positive!";
|
|
26
|
+
readonly dot: "bg-positive";
|
|
27
|
+
};
|
|
28
|
+
readonly negative: {
|
|
29
|
+
readonly box: "border-negative/40 bg-negative/8";
|
|
30
|
+
readonly ink: "text-negative!";
|
|
31
|
+
readonly dot: "bg-negative";
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
/** neutral for information, accent for a key point, warning for a caution, positive and negative for good and bad. */
|
|
35
|
+
export type Tone = keyof typeof TONES;
|
|
36
|
+
//#endregion
|
package/dist/lib/tone.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/lib/tone.ts
|
|
2
|
+
/**
|
|
3
|
+
* The tones a box can take: a faint wash of the colour inside a full border of it, with the colour itself kept for
|
|
4
|
+
* an icon or a dot. Text inside stays in the text colours: small coloured text on its own wash falls under 4.5:1.
|
|
5
|
+
* Callout, StatusAlert and StatusBadge share these, so a warning looks the same wherever it appears.
|
|
6
|
+
*/
|
|
7
|
+
const TONES = {
|
|
8
|
+
neutral: {
|
|
9
|
+
box: "border-border bg-muted/50",
|
|
10
|
+
ink: "text-muted-foreground!",
|
|
11
|
+
dot: "bg-muted-foreground"
|
|
12
|
+
},
|
|
13
|
+
accent: {
|
|
14
|
+
box: "border-chart-1/35 bg-chart-1/8",
|
|
15
|
+
ink: "text-link!",
|
|
16
|
+
dot: "bg-link"
|
|
17
|
+
},
|
|
18
|
+
warning: {
|
|
19
|
+
box: "border-warning/45 bg-warning/10",
|
|
20
|
+
ink: "text-warning!",
|
|
21
|
+
dot: "bg-warning"
|
|
22
|
+
},
|
|
23
|
+
positive: {
|
|
24
|
+
box: "border-positive/40 bg-positive/8",
|
|
25
|
+
ink: "text-positive!",
|
|
26
|
+
dot: "bg-positive"
|
|
27
|
+
},
|
|
28
|
+
negative: {
|
|
29
|
+
box: "border-negative/40 bg-negative/8",
|
|
30
|
+
ink: "text-negative!",
|
|
31
|
+
dot: "bg-negative"
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
//#endregion
|
|
35
|
+
export { TONES };
|
package/dist/lib/treemap.d.ts
CHANGED
|
@@ -18,10 +18,5 @@ export declare function layout<T extends {
|
|
|
18
18
|
weight: number;
|
|
19
19
|
group?: string;
|
|
20
20
|
}>(items: T[], width: number, height: number): Layout<T>;
|
|
21
|
-
export declare const HEAT_STEPS = 5;
|
|
22
|
-
/** The range the heat scale uses: one that is not a positive number falls back to ±5%. */
|
|
23
|
-
export declare const heatRange: (range?: number) => number;
|
|
24
|
-
export declare const heatFill: (side: "positive" | "negative", step: number) => string;
|
|
25
|
-
export declare function heat(change: number | null, range?: number): string;
|
|
26
21
|
//#endregion
|
|
27
22
|
export {};
|
package/dist/lib/treemap.js
CHANGED
|
@@ -31,15 +31,5 @@ function layout(items, width, height) {
|
|
|
31
31
|
}])
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
-
const DEFAULT_RANGE = .05;
|
|
35
|
-
const HEAT_STEPS = 5;
|
|
36
|
-
/** The range the heat scale uses: one that is not a positive number falls back to ±5%. */
|
|
37
|
-
const heatRange = (range = DEFAULT_RANGE) => Number.isFinite(range) && range > 0 ? range : DEFAULT_RANGE;
|
|
38
|
-
const heatFill = (side, step) => `color-mix(in oklab, var(--${side}) ${step * 12}%, var(--card))`;
|
|
39
|
-
function heat(change, range) {
|
|
40
|
-
if (!change) return "var(--muted)";
|
|
41
|
-
const step = Math.min(5, Math.ceil(Math.abs(change) / heatRange(range) * 5));
|
|
42
|
-
return heatFill(change > 0 ? "positive" : "negative", step);
|
|
43
|
-
}
|
|
44
34
|
//#endregion
|
|
45
|
-
export {
|
|
35
|
+
export { layout };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { RefObject } from "react";
|
|
2
|
+
//#region src/lib/use-element-width.d.ts
|
|
3
|
+
/** The element's content width, kept current as it resizes; 0 until it is first measured. */
|
|
4
|
+
export declare function useElementWidth<T extends Element>(): [RefObject<T | null>, number];
|
|
5
|
+
//#endregion
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
2
|
+
//#region src/lib/use-element-width.ts
|
|
3
|
+
/** The element's content width, kept current as it resizes; 0 until it is first measured. */
|
|
4
|
+
function useElementWidth() {
|
|
5
|
+
const ref = useRef(null);
|
|
6
|
+
const [width, setWidth] = useState(0);
|
|
7
|
+
useLayoutEffect(() => {
|
|
8
|
+
const observer = new ResizeObserver(([entry]) => setWidth(entry?.contentRect.width ?? 0));
|
|
9
|
+
if (ref.current) observer.observe(ref.current);
|
|
10
|
+
return () => observer.disconnect();
|
|
11
|
+
}, []);
|
|
12
|
+
return [ref, width];
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { useElementWidth };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@siyahi/ui",
|
|
3
|
-
"version": "0.1.9-next.
|
|
3
|
+
"version": "0.1.9-next.30",
|
|
4
4
|
"description": "Stock shadcn/ui on Base UI and Tailwind v4, a finance theme, a few compositions and formatters.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"base-ui",
|
|
@@ -19,11 +19,13 @@
|
|
|
19
19
|
"directory": "packages/ui"
|
|
20
20
|
},
|
|
21
21
|
"files": [
|
|
22
|
+
"agents",
|
|
22
23
|
"dist",
|
|
23
24
|
"styles",
|
|
24
25
|
"report.css",
|
|
25
26
|
"registry.lock.json",
|
|
26
27
|
"README.md",
|
|
28
|
+
"DESIGN.md",
|
|
27
29
|
"LICENSE",
|
|
28
30
|
"THIRD_PARTY_NOTICES.md"
|
|
29
31
|
],
|
|
@@ -32,6 +34,7 @@
|
|
|
32
34
|
"**/*.css"
|
|
33
35
|
],
|
|
34
36
|
"exports": {
|
|
37
|
+
"./agents/*": "./agents/*",
|
|
35
38
|
".": {
|
|
36
39
|
"types": "./dist/index.d.ts",
|
|
37
40
|
"default": "./dist/index.js"
|
|
@@ -63,6 +66,7 @@
|
|
|
63
66
|
"@types/node": "24.19.2",
|
|
64
67
|
"@types/react": "~19.3.0",
|
|
65
68
|
"@types/react-dom": "~19.3.0",
|
|
69
|
+
"happy-dom": "^21.0.3",
|
|
66
70
|
"react": "19.3.1",
|
|
67
71
|
"react-dom": "19.3.1",
|
|
68
72
|
"shadcn": "4.22.1",
|
package/registry.lock.json
CHANGED
|
@@ -49,6 +49,22 @@
|
|
|
49
49
|
"copied": "2026-10-22",
|
|
50
50
|
"sha256": "9028368f1363732cef765dabad2eca3ba98b608f1e237123b09df701c41c8b5a"
|
|
51
51
|
},
|
|
52
|
+
{
|
|
53
|
+
"file": "src/components/registry/dashboardcn/kpi-row-card.tsx",
|
|
54
|
+
"registry": "@dashboardcn/kpi-row-card",
|
|
55
|
+
"origin": "https://dashboardcn.com/r/kpi-row-card.json",
|
|
56
|
+
"licence": "MIT, Copyright (c) 2026 dashboardcn contributors, https://github.com/NoahGdev/dashboardcn/blob/main/LICENSE",
|
|
57
|
+
"copied": "2026-10-26",
|
|
58
|
+
"sha256": "b49fa95b3efa19086b3df2e3a18f6a0d5a95204951448c5d93fc41c2bdb6326f"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"file": "src/components/registry/dashboardcn/sparkline.tsx",
|
|
62
|
+
"registry": "@dashboardcn/sparkline",
|
|
63
|
+
"origin": "https://dashboardcn.com/r/sparkline.json",
|
|
64
|
+
"licence": "MIT, Copyright (c) 2026 dashboardcn contributors, https://github.com/NoahGdev/dashboardcn/blob/main/LICENSE",
|
|
65
|
+
"copied": "2026-10-26",
|
|
66
|
+
"sha256": "54b43e63d866bcdf8071744df08e87f29385ba60d480ab9ee8aa1fac3eb33d5c"
|
|
67
|
+
},
|
|
52
68
|
{
|
|
53
69
|
"file": "src/components/registry/heatmap/calendar-heatmap.tsx",
|
|
54
70
|
"registry": "@heatmap/calendar-heatmap",
|