@siyahi/ui 0.1.9-next.33 → 0.1.9-next.35
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 +21 -7
- package/README.md +5 -5
- package/agents/examples/app-sidebar.tsx +0 -2
- package/agents/examples/chart-panels-three.tsx +51 -0
- package/agents/examples/context-menu.tsx +14 -4
- package/agents/examples/overview-dashboard.tsx +2 -2
- package/agents/examples/{page-hero.tsx → page-header.tsx} +4 -4
- package/agents/examples/select.tsx +2 -1
- package/agents/manifest.json +16 -5
- package/dist/components/registry/charts/area-chart-card.js +1 -0
- package/dist/components/registry/charts/bar-chart-card.js +0 -2
- package/dist/components/registry/heatmap/calendar-heatmap.js +1 -1
- package/dist/components/registry/heatmap/status-heatmap.js +1 -1
- package/dist/components/registry/heatmap/weekday-heatmap.js +1 -1
- package/dist/components/registry/niko-table/core/data-table-error-boundary.js +1 -1
- package/dist/components/registry/niko-table/core/data-table-structure.js +6 -0
- package/dist/components/registry/niko-table/core/data-table.js +1 -1
- package/dist/components/registry/niko-table/filters/table-column-sort.js +2 -2
- package/dist/components/registry/niko-table/filters/table-faceted-filter.js +3 -3
- package/dist/components/registry/niko-table/lib/column-resize-handle.js +1 -1
- package/dist/components/registry/sidebar-07/nav-user.js +16 -19
- package/dist/components/siyahi/{page-hero.d.ts → page-header.d.ts} +3 -3
- package/dist/components/siyahi/{page-hero.js → page-header.js} +4 -4
- package/dist/components/siyahi/panel-grid.d.ts +5 -2
- package/dist/components/siyahi/panel-grid.js +1 -1
- package/dist/components/siyahi/range-position.js +1 -1
- package/dist/components/siyahi/scatter-chart.js +15 -2
- package/dist/components/siyahi/status-badge.js +1 -0
- package/dist/components/siyahi/target-rows.js +2 -2
- package/dist/components/siyahi/treemap.js +0 -3
- package/dist/components/ui/alert-dialog.d.ts +20 -0
- package/dist/components/ui/alert-dialog.js +94 -0
- package/dist/components/ui/aspect-ratio.d.ts +6 -0
- package/dist/components/ui/aspect-ratio.js +13 -0
- package/dist/components/ui/attachment.d.ts +25 -0
- package/dist/components/ui/attachment.js +104 -0
- package/dist/components/ui/bubble.d.ts +18 -0
- package/dist/components/ui/bubble.js +73 -0
- package/dist/components/ui/button-group.d.ts +12 -0
- package/dist/components/ui/button-group.js +41 -0
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/carousel.d.ts +30 -0
- package/dist/components/ui/carousel.js +131 -0
- package/dist/components/ui/checkbox.d.ts +5 -0
- package/dist/components/ui/checkbox.js +20 -0
- package/dist/components/ui/combobox.d.ts +26 -0
- package/dist/components/ui/combobox.js +162 -0
- package/dist/components/ui/command.js +1 -1
- package/dist/components/ui/direction.d.ts +2 -0
- package/dist/components/ui/direction.js +1 -0
- package/dist/components/ui/drawer.d.ts +18 -0
- package/dist/components/ui/drawer.js +123 -0
- package/dist/components/ui/empty.d.ts +13 -0
- package/dist/components/ui/empty.js +59 -0
- package/dist/components/ui/field.js +1 -1
- package/dist/components/ui/hover-card.d.ts +7 -0
- package/dist/components/ui/hover-card.js +36 -0
- package/dist/components/ui/input-otp.d.ts +13 -0
- package/dist/components/ui/input-otp.js +46 -0
- package/dist/components/ui/item.d.ts +24 -0
- package/dist/components/ui/item.js +121 -0
- package/dist/components/ui/kbd.d.ts +5 -0
- package/dist/components/ui/kbd.js +19 -0
- package/dist/components/ui/marker.d.ts +12 -0
- package/dist/components/ui/marker.js +43 -0
- package/dist/components/ui/menubar.d.ts +31 -0
- package/dist/components/ui/menubar.js +136 -0
- package/dist/components/ui/message-scroller.d.ts +12 -0
- package/dist/components/ui/message-scroller.js +60 -0
- package/dist/components/ui/message.d.ts +12 -0
- package/dist/components/ui/message.js +49 -0
- package/dist/components/ui/native-select.d.ts +10 -0
- package/dist/components/ui/native-select.js +38 -0
- package/dist/components/ui/navigation-menu.d.ts +13 -0
- package/dist/components/ui/navigation-menu.js +82 -0
- package/dist/components/ui/pagination.d.ts +19 -0
- package/dist/components/ui/pagination.js +80 -0
- package/dist/components/ui/questionnaire.d.ts +21 -0
- package/dist/components/ui/questionnaire.js +170 -0
- package/dist/components/ui/radio-group.d.ts +7 -0
- package/dist/components/ui/radio-group.js +26 -0
- package/dist/components/ui/resizable.d.ts +9 -0
- package/dist/components/ui/resizable.js +28 -0
- package/dist/components/ui/sidebar.js +1 -1
- package/dist/components/ui/spinner.d.ts +4 -0
- package/dist/components/ui/spinner.js +15 -0
- package/dist/components/ui/switch.d.ts +7 -0
- package/dist/components/ui/switch.js +19 -0
- package/dist/components/ui/toast.d.ts +18 -0
- package/dist/components/ui/toast.js +123 -0
- package/dist/components/ui/trace.d.ts +20 -0
- package/dist/components/ui/trace.js +75 -0
- package/dist/index.d.ts +32 -2
- package/dist/index.js +35 -5
- package/dist/lib/chart-frame.d.ts +37 -9
- package/dist/lib/chart-frame.js +60 -30
- package/dist/lib/chart-series.d.ts +3 -2
- package/dist/lib/ticks.d.ts +9 -0
- package/dist/lib/ticks.js +25 -3
- package/dist/lib/use-render-when-fonts-load.d.ts +11 -0
- package/dist/lib/use-render-when-fonts-load.js +49 -0
- package/package.json +5 -3
- package/styles/siyahi.css +224 -26
- package/agents/report-rules.json +0 -7
- package/report.css +0 -145
package/dist/lib/chart-frame.js
CHANGED
|
@@ -5,34 +5,23 @@ import { useAxisScale } from "../components/siyahi/scale-toggle.js";
|
|
|
5
5
|
import { StaleNote } from "../components/siyahi/stale-note.js";
|
|
6
6
|
import { useLocale } from "../components/siyahi/siyahi-provider.js";
|
|
7
7
|
import { EndLabels, QUIET, TimeMarks, endLabelRoom, endLabelsFit, linesEndAtEdge } from "./chart-marks.js";
|
|
8
|
-
import { fitsLog, logAxis } from "./ticks.js";
|
|
8
|
+
import { fitsLog, linearAxis, logAxis } from "./ticks.js";
|
|
9
9
|
import { useElementWidth } from "./use-element-width.js";
|
|
10
|
+
import { useRenderWhenFontsLoad } from "./use-render-when-fonts-load.js";
|
|
10
11
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
|
-
import {
|
|
12
|
-
import { CartesianGrid, Line, ReferenceLine, Text, XAxis, YAxis, useChartWidth, useXAxisTicks, useYAxisTicks } from "recharts";
|
|
12
|
+
import { useId, useMemo, useState } from "react";
|
|
13
|
+
import { BarChart, CartesianGrid, Line, ReferenceLine, Text, XAxis, YAxis, useChartWidth, useXAxisTicks, useYAxisTicks } from "recharts";
|
|
13
14
|
//#region src/lib/chart-frame.tsx
|
|
14
15
|
const AXIS_TITLE = "fill-muted-foreground text-xs";
|
|
15
16
|
const TICK = { className: "fill-muted-foreground font-mono" };
|
|
16
17
|
const NO_LINES = [];
|
|
17
18
|
const SERIES_LEGEND = /* @__PURE__ */ jsx(ChartLegendContent, { className: "flex-wrap gap-y-1" });
|
|
18
19
|
/**
|
|
19
|
-
* A bar's fill:
|
|
20
|
-
* the bars it leaves out to a fainter tint; their edges stay, so they keep 3:1 against the card.
|
|
20
|
+
* A bar's fill: the theme's --bar-tint of its colour, inside a 1px edge of the full colour the bar is drawn with. A
|
|
21
|
+
* selection dims the bars it leaves out to a fainter tint; their edges stay, so they keep 3:1 against the card.
|
|
21
22
|
*/
|
|
22
23
|
function barFill(color, dim = false) {
|
|
23
|
-
return `color-mix(in oklab, ${color} ${dim ? 10 :
|
|
24
|
-
}
|
|
25
|
-
/** Renders the component again once the page's fonts load, so text measured on a canvas is measured in Geist. */
|
|
26
|
-
function useRenderWhenFontsLoad() {
|
|
27
|
-
const [loaded, setLoaded] = useState(() => typeof document === "undefined" || document.fonts?.status === "loaded");
|
|
28
|
-
useEffect(() => {
|
|
29
|
-
if (loaded || !document.fonts) return;
|
|
30
|
-
let live = true;
|
|
31
|
-
document.fonts.ready.then(() => live && setLoaded(true));
|
|
32
|
-
return () => {
|
|
33
|
-
live = false;
|
|
34
|
-
};
|
|
35
|
-
}, [loaded]);
|
|
24
|
+
return `color-mix(in oklab, ${color} ${dim ? "10%" : "var(--bar-tint)"}, var(--card))`;
|
|
36
25
|
}
|
|
37
26
|
/**
|
|
38
27
|
* The legend when some series are quiet: every series by name. The grey ones share a colour, so a legend square
|
|
@@ -83,6 +72,43 @@ function haloLine({ x1, y1, x2, y2, stroke, strokeDasharray }) {
|
|
|
83
72
|
strokeWidth: 1
|
|
84
73
|
})] });
|
|
85
74
|
}
|
|
75
|
+
const sum = (values) => values.reduce((total, value) => total + value, 0);
|
|
76
|
+
/**
|
|
77
|
+
* The values a value axis must reach: each one drawn, or a stack's running totals, where its segments end. A "sign"
|
|
78
|
+
* stack runs a row's losses down from zero and its gains up, so the row reaches its two sums.
|
|
79
|
+
*/
|
|
80
|
+
function axisValues(data, series, stackOffset) {
|
|
81
|
+
return data.flatMap((row) => {
|
|
82
|
+
const values = series.map(({ key }) => row[key]).filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
83
|
+
if (stackOffset === "none") {
|
|
84
|
+
let total = 0;
|
|
85
|
+
return [0, ...values.map((value) => total += value)];
|
|
86
|
+
}
|
|
87
|
+
if (stackOffset === "sign") return [sum(values.filter((value) => value < 0)), sum(values.filter((value) => value > 0))];
|
|
88
|
+
return values;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
/** The value levels a page marks with reference lines. */
|
|
92
|
+
const levelsOf = (lines) => lines.flatMap(({ y }) => y === void 0 ? [] : [y]);
|
|
93
|
+
/**
|
|
94
|
+
* A log value axis over the values and the page's levels above zero: a level at or under zero has no place on it, and
|
|
95
|
+
* must not turn Log off.
|
|
96
|
+
*/
|
|
97
|
+
function logValueAxis(values, referenceLines, range) {
|
|
98
|
+
return logAxis([...values, ...levelsOf(referenceLines).filter((level) => level > 0)], range);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A linear value axis that just covers what is drawn: the values (a stack's totals), the page's levels and ticks, and
|
|
102
|
+
* zero under bars, so no bar hangs from its smallest loss and no level falls off the plot.
|
|
103
|
+
*/
|
|
104
|
+
function linearValueAxis(data, series, { stackOffset, referenceLines = NO_LINES, yTicks = [], bars = false }) {
|
|
105
|
+
return linearAxis([
|
|
106
|
+
...axisValues(data, series, stackOffset),
|
|
107
|
+
...levelsOf(referenceLines),
|
|
108
|
+
...yTicks,
|
|
109
|
+
...bars ? [0] : []
|
|
110
|
+
]);
|
|
111
|
+
}
|
|
86
112
|
/**
|
|
87
113
|
* The colour a series' Bar takes, which its legend chip shows: the negative colour when every value drawn is below
|
|
88
114
|
* zero, since each bar's own Cell follows its sign but the chip follows the Bar.
|
|
@@ -246,10 +272,10 @@ function ChartFrame({ chart: Chart, children, horizontal = false, stackOffset, o
|
|
|
246
272
|
const { numberLocale } = useLocale();
|
|
247
273
|
const clipId = useId();
|
|
248
274
|
const [contentRef, contentWidth] = useElementWidth();
|
|
249
|
-
useRenderWhenFontsLoad();
|
|
250
275
|
const [raisedKey, setRaisedKey] = useState();
|
|
251
276
|
const names = endLabels ? series.map(({ label }) => label) : [];
|
|
252
277
|
const labelRoom = endLabels ? endLabelRoom(names) : 0;
|
|
278
|
+
useRenderWhenFontsLoad(() => endLabels ? endLabelRoom(names) : 0);
|
|
253
279
|
const plotHeight = height - 12 - (xTickDetail ? 40 : 30) - (xLabel ? 18 : 0);
|
|
254
280
|
const ends = endLabels && linesEndAtEdge(data, xKey, series, xDomain) && endLabelsFit(names, contentWidth, plotHeight);
|
|
255
281
|
const quiet = series.some(({ color }) => color === QUIET);
|
|
@@ -260,16 +286,20 @@ function ChartFrame({ chart: Chart, children, horizontal = false, stackOffset, o
|
|
|
260
286
|
color
|
|
261
287
|
}]));
|
|
262
288
|
const crossesZero = data.some((row) => series.some(({ key }) => Number(row[key]) < 0));
|
|
263
|
-
const
|
|
264
|
-
const range = typeof low === "number" && typeof high === "number" ? [low, high] : void 0;
|
|
265
|
-
const values = [...data.flatMap((row) => series.map(({ key }) => row[key])), ...range ?? []].filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
289
|
+
const values = [...data.flatMap((row) => series.map(({ key }) => row[key])), ...yDomain ?? []].filter((value) => typeof value === "number" && Number.isFinite(value));
|
|
266
290
|
const valueAxis = useAxisScale({
|
|
267
291
|
initial: yScale,
|
|
268
292
|
toggle: yScaleToggle,
|
|
269
293
|
label: yLabel ? `${yLabel} scale` : "Value axis scale",
|
|
270
294
|
logBlocked: logBlocked ?? (fitsLog(values) ? void 0 : "Log needs every value above zero")
|
|
271
295
|
});
|
|
272
|
-
const log = valueAxis.scale === "log" ?
|
|
296
|
+
const log = valueAxis.scale === "log" ? logValueAxis(values, referenceLines, yDomain) : void 0;
|
|
297
|
+
const linear = log || yDomain !== void 0 ? void 0 : linearValueAxis(data, series, {
|
|
298
|
+
stackOffset,
|
|
299
|
+
referenceLines,
|
|
300
|
+
yTicks,
|
|
301
|
+
bars: Chart === BarChart
|
|
302
|
+
});
|
|
273
303
|
const detailedRows = horizontal && xTickDetail !== void 0;
|
|
274
304
|
const rowCount = (xTicks ?? data).length;
|
|
275
305
|
const plotClass = detailedRows ? "min-h-(--wrapped-chart-height) @min-[24rem]/chart:min-h-0" : void 0;
|
|
@@ -336,10 +366,10 @@ function ChartFrame({ chart: Chart, children, horizontal = false, stackOffset, o
|
|
|
336
366
|
}),
|
|
337
367
|
horizontal ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(XAxis, {
|
|
338
368
|
type: "number",
|
|
339
|
-
niceTicks: "snap125",
|
|
369
|
+
niceTicks: linear ? void 0 : "snap125",
|
|
340
370
|
hide: !yTickFormatter,
|
|
341
|
-
domain: yDomain,
|
|
342
|
-
ticks: yTicks,
|
|
371
|
+
domain: linear?.domain ?? yDomain,
|
|
372
|
+
ticks: yTicks ?? linear?.ticks,
|
|
343
373
|
tickLine: false,
|
|
344
374
|
axisLine: false,
|
|
345
375
|
tickMargin: 8,
|
|
@@ -373,12 +403,12 @@ function ChartFrame({ chart: Chart, children, horizontal = false, stackOffset, o
|
|
|
373
403
|
interval: xTickDetail || xTicks ? 0 : void 0
|
|
374
404
|
}), /* @__PURE__ */ jsx(YAxis, {
|
|
375
405
|
scale: valueAxis.scale,
|
|
376
|
-
niceTicks: log ? void 0 : "snap125",
|
|
406
|
+
niceTicks: log || linear ? void 0 : "snap125",
|
|
377
407
|
tickLine: false,
|
|
378
408
|
axisLine: false,
|
|
379
409
|
width: "auto",
|
|
380
|
-
domain: log?.domain ?? yDomain,
|
|
381
|
-
ticks: log?.ticks ?? yTicks,
|
|
410
|
+
domain: log?.domain ?? linear?.domain ?? yDomain,
|
|
411
|
+
ticks: log?.ticks ?? yTicks ?? linear?.ticks,
|
|
382
412
|
label: yLabel ? {
|
|
383
413
|
value: yLabel,
|
|
384
414
|
angle: -90,
|
|
@@ -477,4 +507,4 @@ function ChartFrame({ chart: Chart, children, horizontal = false, stackOffset, o
|
|
|
477
507
|
});
|
|
478
508
|
}
|
|
479
509
|
//#endregion
|
|
480
|
-
export { ChartFrame, QuietLegend, barFill, endDot, seriesFill, seriesRow };
|
|
510
|
+
export { ChartFrame, QuietLegend, axisValues, barFill, endDot, linearValueAxis, logValueAxis, seriesFill, seriesRow };
|
|
@@ -64,8 +64,9 @@ export interface SeriesChartProps<T extends object, K extends keyof T> {
|
|
|
64
64
|
*/
|
|
65
65
|
yTickFormatter?: ((value: number, scale: number) => string) | undefined;
|
|
66
66
|
/**
|
|
67
|
-
* A fixed range for the value axis, such as [0, 100] for a percentage. By default
|
|
68
|
-
*
|
|
67
|
+
* A fixed range for the value axis, such as [0, 100] for a percentage. By default the axis ends on the round
|
|
68
|
+
* ticks that just cover the data (a 46,800 peak ends at 50,000), a stack's totals for a stack, and a bar chart's
|
|
69
|
+
* always reaches zero.
|
|
69
70
|
*/
|
|
70
71
|
yDomain?: [number, number] | undefined;
|
|
71
72
|
/** Where the value axis puts its ticks, such as [0, 25, 50, 75, 100]. */
|
package/dist/lib/ticks.d.ts
CHANGED
|
@@ -10,6 +10,15 @@ export declare function logTicks(min: number, max: number): number[];
|
|
|
10
10
|
* noise, such as 0.3 and 0.30000000000000004, count as one value and get that value as their only tick.
|
|
11
11
|
*/
|
|
12
12
|
export declare function linearTicks(min: number, max: number, count?: number): number[];
|
|
13
|
+
/**
|
|
14
|
+
* A value axis' ends and ticks: the round ticks that just cover the values, and their outer two as the ends. About
|
|
15
|
+
* six, not five, so a 46,800 peak ends at 50,000 by 10,000s rather than at 60,000 by 20,000s. None when the values
|
|
16
|
+
* span no range (no values, or one), which leaves the axis to the chart.
|
|
17
|
+
*/
|
|
18
|
+
export declare function linearAxis(values: readonly number[]): {
|
|
19
|
+
domain: [number, number];
|
|
20
|
+
ticks: number[];
|
|
21
|
+
} | undefined;
|
|
13
22
|
/** How an axis spaces its values: evenly, or by powers of ten for values that run from tiny to large. */
|
|
14
23
|
export type AxisScale = "linear" | "log";
|
|
15
24
|
/** An axis' ticks for its scale: round steps either way, so a linear axis starting at 0.4% reads 0%, 5%, 10%. */
|
package/dist/lib/ticks.js
CHANGED
|
@@ -39,6 +39,29 @@ function linearTicks(min, max, count = 5) {
|
|
|
39
39
|
const last = Math.ceil(max / step - 1e-9);
|
|
40
40
|
return Array.from({ length: last - first + 1 }, (_, i) => clean((first + i) * step));
|
|
41
41
|
}
|
|
42
|
+
/** The smallest and largest value, by a loop: Math.min(...values) overflows the call stack past about 100,000. */
|
|
43
|
+
function extent(values) {
|
|
44
|
+
let low = Number.POSITIVE_INFINITY;
|
|
45
|
+
let high = Number.NEGATIVE_INFINITY;
|
|
46
|
+
for (const value of values) {
|
|
47
|
+
low = Math.min(low, value);
|
|
48
|
+
high = Math.max(high, value);
|
|
49
|
+
}
|
|
50
|
+
return [low, high];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A value axis' ends and ticks: the round ticks that just cover the values, and their outer two as the ends. About
|
|
54
|
+
* six, not five, so a 46,800 peak ends at 50,000 by 10,000s rather than at 60,000 by 20,000s. None when the values
|
|
55
|
+
* span no range (no values, or one), which leaves the axis to the chart.
|
|
56
|
+
*/
|
|
57
|
+
function linearAxis(values) {
|
|
58
|
+
const ticks = linearTicks(...extent(values), 6);
|
|
59
|
+
const [low, high] = [ticks[0], ticks.at(-1)];
|
|
60
|
+
return low !== void 0 && high !== void 0 && low < high ? {
|
|
61
|
+
domain: [low, high],
|
|
62
|
+
ticks
|
|
63
|
+
} : void 0;
|
|
64
|
+
}
|
|
42
65
|
/** An axis' ticks for its scale: round steps either way, so a linear axis starting at 0.4% reads 0%, 5%, 10%. */
|
|
43
66
|
const ticksFor = (scale, min, max) => scale === "log" ? logTicks(min, max) : linearTicks(min, max);
|
|
44
67
|
/** 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. */
|
|
@@ -55,8 +78,7 @@ function logAxis(values, range) {
|
|
|
55
78
|
ticks: logTicks(low, high).filter((tick) => tick >= low && tick <= high)
|
|
56
79
|
};
|
|
57
80
|
}
|
|
58
|
-
const low =
|
|
59
|
-
const high = Math.max(...values);
|
|
81
|
+
const [low, high] = extent(values);
|
|
60
82
|
const ticks = logTicks(low, high);
|
|
61
83
|
return {
|
|
62
84
|
domain: [ticks[0] ?? low, ticks.at(-1) ?? high],
|
|
@@ -64,4 +86,4 @@ function logAxis(values, range) {
|
|
|
64
86
|
};
|
|
65
87
|
}
|
|
66
88
|
//#endregion
|
|
67
|
-
export { fitsLog, linearTicks, logAxis, logTicks, ticksFor };
|
|
89
|
+
export { fitsLog, linearAxis, linearTicks, logAxis, logTicks, ticksFor };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
//#region src/lib/use-render-when-fonts-load.d.ts
|
|
2
|
+
/** How many font loads the page has finished: a width a canvas measured before the last one may be the fallback's. */
|
|
3
|
+
export declare function fontLoads(): number;
|
|
4
|
+
/**
|
|
5
|
+
* Renders the component again when a font load changes what `measure` returns: the width of the component's own
|
|
6
|
+
* text, measured on a canvas. Any face may change it, whenever it loads: Geist after the fallback, a subset for other
|
|
7
|
+
* characters, another family. A load that changes nothing the component measures leaves it alone, as Recharts redraws
|
|
8
|
+
* a chart's marks on every render and their fade-in would play again.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useRenderWhenFontsLoad(measure: () => number | string): void;
|
|
11
|
+
//#endregion
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useLayoutEffect, useReducer, useRef } from "react";
|
|
2
|
+
//#region src/lib/use-render-when-fonts-load.ts
|
|
3
|
+
let loads = 0;
|
|
4
|
+
const counted = /* @__PURE__ */ new WeakSet();
|
|
5
|
+
/** How many font loads the page has finished: a width a canvas measured before the last one may be the fallback's. */
|
|
6
|
+
function fontLoads() {
|
|
7
|
+
if (typeof document !== "undefined" && document.fonts && !counted.has(document.fonts)) {
|
|
8
|
+
counted.add(document.fonts);
|
|
9
|
+
document.fonts.addEventListener("loadingdone", () => loads++);
|
|
10
|
+
}
|
|
11
|
+
return loads;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Renders the component again when a font load changes what `measure` returns: the width of the component's own
|
|
15
|
+
* text, measured on a canvas. Any face may change it, whenever it loads: Geist after the fallback, a subset for other
|
|
16
|
+
* characters, another family. A load that changes nothing the component measures leaves it alone, as Recharts redraws
|
|
17
|
+
* a chart's marks on every render and their fade-in would play again.
|
|
18
|
+
*/
|
|
19
|
+
function useRenderWhenFontsLoad(measure) {
|
|
20
|
+
const drawn = measure();
|
|
21
|
+
const seen = fontLoads();
|
|
22
|
+
const committed = useRef({
|
|
23
|
+
measure,
|
|
24
|
+
drawn
|
|
25
|
+
});
|
|
26
|
+
const [, render] = useReducer((count) => count + 1, 0);
|
|
27
|
+
useLayoutEffect(() => {
|
|
28
|
+
committed.current = {
|
|
29
|
+
measure,
|
|
30
|
+
drawn
|
|
31
|
+
};
|
|
32
|
+
if (fontLoads() !== seen && measure() !== drawn) render();
|
|
33
|
+
}, [
|
|
34
|
+
measure,
|
|
35
|
+
drawn,
|
|
36
|
+
seen
|
|
37
|
+
]);
|
|
38
|
+
useLayoutEffect(() => {
|
|
39
|
+
const fonts = document.fonts;
|
|
40
|
+
if (!fonts) return;
|
|
41
|
+
const recheck = () => {
|
|
42
|
+
if (committed.current.measure() !== committed.current.drawn) render();
|
|
43
|
+
};
|
|
44
|
+
fonts.addEventListener("loadingdone", recheck);
|
|
45
|
+
return () => fonts.removeEventListener("loadingdone", recheck);
|
|
46
|
+
}, []);
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { fontLoads, useRenderWhenFontsLoad };
|
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.35",
|
|
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",
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"agents",
|
|
23
23
|
"dist",
|
|
24
24
|
"styles",
|
|
25
|
-
"report.css",
|
|
26
25
|
"registry.lock.json",
|
|
27
26
|
"README.md",
|
|
28
27
|
"DESIGN.md",
|
|
@@ -40,7 +39,6 @@
|
|
|
40
39
|
"default": "./dist/index.js"
|
|
41
40
|
},
|
|
42
41
|
"./styles.css": "./styles/siyahi.css",
|
|
43
|
-
"./report.css": "./report.css",
|
|
44
42
|
"./registry.lock.json": "./registry.lock.json",
|
|
45
43
|
"./package.json": "./package.json"
|
|
46
44
|
},
|
|
@@ -48,15 +46,19 @@
|
|
|
48
46
|
"@base-ui/react": "^1.9.0",
|
|
49
47
|
"@fontsource-variable/geist": "^5.3.0",
|
|
50
48
|
"@fontsource-variable/geist-mono": "^5.3.0",
|
|
49
|
+
"@shadcn/react": "^0.3.1",
|
|
51
50
|
"@tanstack/react-table": "^9.3.1",
|
|
52
51
|
"class-variance-authority": "^0.7.1",
|
|
53
52
|
"cmdk": "^1.1.1",
|
|
54
53
|
"cn": "^0.5.0",
|
|
55
54
|
"d3-hierarchy": "^3.1.2",
|
|
56
55
|
"date-fns": "^4.4.0",
|
|
56
|
+
"embla-carousel-react": "^8.6.0",
|
|
57
|
+
"input-otp": "^1.5.0",
|
|
57
58
|
"lightweight-charts": "^5.2.1",
|
|
58
59
|
"lucide-react": "^1.59.0",
|
|
59
60
|
"react-day-picker": "^10.0.2",
|
|
61
|
+
"react-resizable-panels": "^4.21.0",
|
|
60
62
|
"recharts": "3.8.0",
|
|
61
63
|
"tw-animate-css": "^1.4.0"
|
|
62
64
|
},
|