@flanksource/clicky-ui 0.2.4 → 0.2.6
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/dist/components/Combobox.cjs +291 -0
- package/dist/components/Combobox.cjs.map +1 -0
- package/dist/components/Combobox.d.ts +59 -0
- package/dist/components/Combobox.d.ts.map +1 -0
- package/dist/components/Combobox.js +291 -0
- package/dist/components/Combobox.js.map +1 -0
- package/dist/components/FilterBar.cjs +153 -124
- package/dist/components/FilterBar.cjs.map +1 -1
- package/dist/components/FilterBar.d.ts +25 -1
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +153 -124
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/FormatOptionsDropdown.cjs +62 -0
- package/dist/components/FormatOptionsDropdown.cjs.map +1 -0
- package/dist/components/FormatOptionsDropdown.d.ts +37 -0
- package/dist/components/FormatOptionsDropdown.d.ts.map +1 -0
- package/dist/components/FormatOptionsDropdown.js +62 -0
- package/dist/components/FormatOptionsDropdown.js.map +1 -0
- package/dist/components/SplitButton.cjs +87 -0
- package/dist/components/SplitButton.cjs.map +1 -0
- package/dist/components/SplitButton.d.ts +32 -0
- package/dist/components/SplitButton.d.ts.map +1 -0
- package/dist/components/SplitButton.js +87 -0
- package/dist/components/SplitButton.js.map +1 -0
- package/dist/components/icon-menu-picker.cjs +1 -1
- package/dist/components/icon-menu-picker.cjs.map +1 -1
- package/dist/components/icon-menu-picker.js +1 -1
- package/dist/components/icon-menu-picker.js.map +1 -1
- package/dist/components.cjs +7 -0
- package/dist/components.cjs.map +1 -1
- package/dist/components.d.ts +3 -0
- package/dist/components.d.ts.map +1 -1
- package/dist/components.js +7 -0
- package/dist/components.js.map +1 -1
- package/dist/data/Badge.d.ts +1 -1
- package/dist/data/ProgressBar.cjs +4 -2
- package/dist/data/ProgressBar.cjs.map +1 -1
- package/dist/data/ProgressBar.d.ts +1 -1
- package/dist/data/ProgressBar.d.ts.map +1 -1
- package/dist/data/ProgressBar.js +4 -2
- package/dist/data/ProgressBar.js.map +1 -1
- package/dist/data/StatusBreakdown.cjs +80 -0
- package/dist/data/StatusBreakdown.cjs.map +1 -0
- package/dist/data/StatusBreakdown.d.ts +36 -0
- package/dist/data/StatusBreakdown.d.ts.map +1 -0
- package/dist/data/StatusBreakdown.js +80 -0
- package/dist/data/StatusBreakdown.js.map +1 -0
- package/dist/data/TaskManager.cjs +162 -0
- package/dist/data/TaskManager.cjs.map +1 -0
- package/dist/data/TaskManager.d.ts +21 -0
- package/dist/data/TaskManager.d.ts.map +1 -0
- package/dist/data/TaskManager.js +162 -0
- package/dist/data/TaskManager.js.map +1 -0
- package/dist/data/TaskProgress.cjs +125 -0
- package/dist/data/TaskProgress.cjs.map +1 -0
- package/dist/data/TaskProgress.d.ts +20 -0
- package/dist/data/TaskProgress.d.ts.map +1 -0
- package/dist/data/TaskProgress.js +125 -0
- package/dist/data/TaskProgress.js.map +1 -0
- package/dist/data/TaskSnapshot.cjs +23 -0
- package/dist/data/TaskSnapshot.cjs.map +1 -0
- package/dist/data/TaskSnapshot.d.ts +49 -0
- package/dist/data/TaskSnapshot.d.ts.map +1 -0
- package/dist/data/TaskSnapshot.js +23 -0
- package/dist/data/TaskSnapshot.js.map +1 -0
- package/dist/data/TimeseriesGauge.cjs +144 -0
- package/dist/data/TimeseriesGauge.cjs.map +1 -0
- package/dist/data/TimeseriesGauge.d.ts +56 -0
- package/dist/data/TimeseriesGauge.d.ts.map +1 -0
- package/dist/data/TimeseriesGauge.js +144 -0
- package/dist/data/TimeseriesGauge.js.map +1 -0
- package/dist/data/TimeseriesPanel.axes.cjs +39 -0
- package/dist/data/TimeseriesPanel.axes.cjs.map +1 -0
- package/dist/data/TimeseriesPanel.axes.d.ts +28 -0
- package/dist/data/TimeseriesPanel.axes.d.ts.map +1 -0
- package/dist/data/TimeseriesPanel.axes.js +39 -0
- package/dist/data/TimeseriesPanel.axes.js.map +1 -0
- package/dist/data/TimeseriesPanel.cjs +324 -0
- package/dist/data/TimeseriesPanel.cjs.map +1 -0
- package/dist/data/TimeseriesPanel.d.ts +141 -0
- package/dist/data/TimeseriesPanel.d.ts.map +1 -0
- package/dist/data/TimeseriesPanel.js +324 -0
- package/dist/data/TimeseriesPanel.js.map +1 -0
- package/dist/data/Tree.cjs.map +1 -1
- package/dist/data/Tree.d.ts.map +1 -1
- package/dist/data/Tree.js.map +1 -1
- package/dist/data/TreeNode.cjs +44 -7
- package/dist/data/TreeNode.cjs.map +1 -1
- package/dist/data/TreeNode.d.ts +19 -1
- package/dist/data/TreeNode.d.ts.map +1 -1
- package/dist/data/TreeNode.js +44 -7
- package/dist/data/TreeNode.js.map +1 -1
- package/dist/data/diagnostics/DiagnosticsDetailPanel.cjs +66 -44
- package/dist/data/diagnostics/DiagnosticsDetailPanel.cjs.map +1 -1
- package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts +21 -1
- package/dist/data/diagnostics/DiagnosticsDetailPanel.d.ts.map +1 -1
- package/dist/data/diagnostics/DiagnosticsDetailPanel.js +65 -43
- package/dist/data/diagnostics/DiagnosticsDetailPanel.js.map +1 -1
- package/dist/data/diagnostics/DiagnosticsTree.cjs +2 -1
- package/dist/data/diagnostics/DiagnosticsTree.cjs.map +1 -1
- package/dist/data/diagnostics/DiagnosticsTree.js +2 -1
- package/dist/data/diagnostics/DiagnosticsTree.js.map +1 -1
- package/dist/data/diagnostics/FrameSourceWindow.cjs +37 -0
- package/dist/data/diagnostics/FrameSourceWindow.cjs.map +1 -0
- package/dist/data/diagnostics/FrameSourceWindow.d.ts +15 -0
- package/dist/data/diagnostics/FrameSourceWindow.d.ts.map +1 -0
- package/dist/data/diagnostics/FrameSourceWindow.js +37 -0
- package/dist/data/diagnostics/FrameSourceWindow.js.map +1 -0
- package/dist/data/diagnostics/JvmStackTrace.cjs +25 -12
- package/dist/data/diagnostics/JvmStackTrace.cjs.map +1 -1
- package/dist/data/diagnostics/JvmStackTrace.d.ts +8 -1
- package/dist/data/diagnostics/JvmStackTrace.d.ts.map +1 -1
- package/dist/data/diagnostics/JvmStackTrace.js +26 -13
- package/dist/data/diagnostics/JvmStackTrace.js.map +1 -1
- package/dist/data/diagnostics/ThreadCard.cjs +9 -2
- package/dist/data/diagnostics/ThreadCard.cjs.map +1 -1
- package/dist/data/diagnostics/ThreadCard.d.ts +3 -1
- package/dist/data/diagnostics/ThreadCard.d.ts.map +1 -1
- package/dist/data/diagnostics/ThreadCard.js +9 -2
- package/dist/data/diagnostics/ThreadCard.js.map +1 -1
- package/dist/data/diagnostics/jvm-stacktrace.cjs +10 -1
- package/dist/data/diagnostics/jvm-stacktrace.cjs.map +1 -1
- package/dist/data/diagnostics/jvm-stacktrace.d.ts.map +1 -1
- package/dist/data/diagnostics/jvm-stacktrace.js +10 -1
- package/dist/data/diagnostics/jvm-stacktrace.js.map +1 -1
- package/dist/data/diagnostics/utils.cjs +0 -12
- package/dist/data/diagnostics/utils.cjs.map +1 -1
- package/dist/data/diagnostics/utils.d.ts +1 -1
- package/dist/data/diagnostics/utils.d.ts.map +1 -1
- package/dist/data/diagnostics/utils.js +0 -12
- package/dist/data/diagnostics/utils.js.map +1 -1
- package/dist/data/task-status.cjs +108 -0
- package/dist/data/task-status.cjs.map +1 -0
- package/dist/data/task-status.d.ts +21 -0
- package/dist/data/task-status.d.ts.map +1 -0
- package/dist/data/task-status.js +108 -0
- package/dist/data/task-status.js.map +1 -0
- package/dist/data.cjs +27 -0
- package/dist/data.cjs.map +1 -1
- package/dist/data.d.ts +9 -1
- package/dist/data.d.ts.map +1 -1
- package/dist/data.js +27 -0
- package/dist/data.js.map +1 -1
- package/dist/hooks/use-task-run.cjs +137 -0
- package/dist/hooks/use-task-run.cjs.map +1 -0
- package/dist/hooks/use-task-run.d.ts +35 -0
- package/dist/hooks/use-task-run.d.ts.map +1 -0
- package/dist/hooks/use-task-run.js +137 -0
- package/dist/hooks/use-task-run.js.map +1 -0
- package/dist/hooks.cjs +3 -0
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +1 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +3 -0
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +43 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/color.cjs +33 -0
- package/dist/lib/color.cjs.map +1 -0
- package/dist/lib/color.d.ts +10 -0
- package/dist/lib/color.d.ts.map +1 -0
- package/dist/lib/color.js +33 -0
- package/dist/lib/color.js.map +1 -0
- package/dist/lib/format.cjs +77 -0
- package/dist/lib/format.cjs.map +1 -0
- package/dist/lib/format.d.ts +30 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +77 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/overlay/DropdownMenu.cjs +18 -2
- package/dist/overlay/DropdownMenu.cjs.map +1 -1
- package/dist/overlay/DropdownMenu.d.ts +3 -1
- package/dist/overlay/DropdownMenu.d.ts.map +1 -1
- package/dist/overlay/DropdownMenu.js +18 -2
- package/dist/overlay/DropdownMenu.js.map +1 -1
- package/dist/rpc/types.cjs.map +1 -1
- package/dist/rpc/types.d.ts +4 -0
- package/dist/rpc/types.d.ts.map +1 -1
- package/dist/rpc/types.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils.cjs +6 -0
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +6 -0
- package/dist/utils.js.map +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { cn } from "./lib/utils.js";
|
|
2
2
|
import { AVATAR_PALETTE, fnv1a32, paletteClass } from "./lib/palette.js";
|
|
3
3
|
import { SIZE_TOKENS, resolveSize } from "./lib/size.js";
|
|
4
|
+
import { formatBytes, formatBytesPerSecond, formatDuration, formatShort, formatUnit } from "./lib/format.js";
|
|
4
5
|
import { ThemeProvider, useOptionalTheme, useResolvedTheme, useTheme } from "./hooks/use-theme.js";
|
|
5
6
|
import { DensityProvider, useDensity, useDensityValue } from "./hooks/use-density.js";
|
|
6
7
|
import { useSort } from "./hooks/use-sort.js";
|
|
7
8
|
import { useHistoryRoute } from "./hooks/use-history-route.js";
|
|
9
|
+
import { useTaskRun, useTaskRuns } from "./hooks/use-task-run.js";
|
|
8
10
|
import { Button, buttonVariants } from "./components/button.js";
|
|
11
|
+
import { SplitButton } from "./components/SplitButton.js";
|
|
12
|
+
import { CLICKY_FORMAT_OPTIONS, FormatOptionsDropdown } from "./components/FormatOptionsDropdown.js";
|
|
9
13
|
import { DateField } from "./components/DateField.js";
|
|
10
14
|
import { DatePicker } from "./components/DatePicker.js";
|
|
11
15
|
import { DateTimePicker } from "./components/DateTimePicker.js";
|
|
@@ -14,6 +18,7 @@ import { RangeSlider } from "./components/RangeSlider.js";
|
|
|
14
18
|
import { FilterBar } from "./components/FilterBar.js";
|
|
15
19
|
import { MultiSelect } from "./components/MultiSelect.js";
|
|
16
20
|
import { Select } from "./components/select.js";
|
|
21
|
+
import { Combobox } from "./components/Combobox.js";
|
|
17
22
|
import { ThemeSwitcher } from "./components/theme-switcher.js";
|
|
18
23
|
import { DensitySwitcher } from "./components/density-switcher.js";
|
|
19
24
|
import { IconMenuPicker } from "./components/icon-menu-picker.js";
|
|
@@ -48,15 +53,23 @@ import { ProgressBar } from "./data/ProgressBar.js";
|
|
|
48
53
|
import { SignedDeltaBar } from "./data/SignedDeltaBar.js";
|
|
49
54
|
import { SortableHeader } from "./data/SortableHeader.js";
|
|
50
55
|
import { TabButton } from "./data/TabButton.js";
|
|
56
|
+
import { TimeseriesPanel, resolveBreakdown, resolveSeries } from "./data/TimeseriesPanel.js";
|
|
57
|
+
import { TimeseriesGauge } from "./data/TimeseriesGauge.js";
|
|
58
|
+
import { StackedStatusBar, StatusRows, segment } from "./data/StatusBreakdown.js";
|
|
51
59
|
import { Tree } from "./data/Tree.js";
|
|
52
60
|
import { TreeNode } from "./data/TreeNode.js";
|
|
53
61
|
import { TreeGroupHeader } from "./data/TreeGroupHeader.js";
|
|
62
|
+
import { allGroupsTerminal, isTerminalStatus } from "./data/TaskSnapshot.js";
|
|
63
|
+
import { bucketTasks, logLevelColor, taskSegments, taskStatusBg, taskStatusColor, taskStatusIcon } from "./data/task-status.js";
|
|
64
|
+
import { TaskProgress } from "./data/TaskProgress.js";
|
|
65
|
+
import { TaskManager } from "./data/TaskManager.js";
|
|
54
66
|
import { DiagnosticsTree } from "./data/diagnostics/DiagnosticsTree.js";
|
|
55
67
|
import { DiagnosticsDetailPanel } from "./data/diagnostics/DiagnosticsDetailPanel.js";
|
|
56
68
|
import { countProcesses, findProcessByPID, processLabel, processStateColor, processStateIcon } from "./data/diagnostics/utils.js";
|
|
57
69
|
import { countGoroutinesByState, countStackByState, detectDumpFormat, parseGoroutineDump, parseStackDump } from "./data/diagnostics/stacktrace.js";
|
|
58
70
|
import { countThreadsByState, parseJvmThreadDump } from "./data/diagnostics/jvm-stacktrace.js";
|
|
59
71
|
import { JvmStackFrameRow, JvmStackTrace } from "./data/diagnostics/JvmStackTrace.js";
|
|
72
|
+
import { FrameSourceWindow, frameHasSource } from "./data/diagnostics/FrameSourceWindow.js";
|
|
60
73
|
import { StackTrace } from "./data/diagnostics/RenderedStackTrace.js";
|
|
61
74
|
import { parseJavaStackTrace } from "./data/diagnostics/stacktrace-parse.js";
|
|
62
75
|
import { CopyBadge, ErrorDetails, PrettyStackTrace } from "./data/diagnostics/ErrorDetails.js";
|
|
@@ -346,10 +359,12 @@ export {
|
|
|
346
359
|
AvatarBadge,
|
|
347
360
|
Badge,
|
|
348
361
|
Button,
|
|
362
|
+
CLICKY_FORMAT_OPTIONS,
|
|
349
363
|
Clicky,
|
|
350
364
|
ClickyNodeView,
|
|
351
365
|
ClickyTable,
|
|
352
366
|
CodeBlock,
|
|
367
|
+
Combobox,
|
|
353
368
|
CommandForm,
|
|
354
369
|
CommandOutput,
|
|
355
370
|
CopyBadge,
|
|
@@ -371,6 +386,8 @@ export {
|
|
|
371
386
|
FilterPill,
|
|
372
387
|
FilterPillGroup,
|
|
373
388
|
FilterSeparator,
|
|
389
|
+
FormatOptionsDropdown,
|
|
390
|
+
FrameSourceWindow,
|
|
374
391
|
Gauge,
|
|
375
392
|
HarPanel,
|
|
376
393
|
HoverCard,
|
|
@@ -402,15 +419,22 @@ export {
|
|
|
402
419
|
Select,
|
|
403
420
|
SignedDeltaBar,
|
|
404
421
|
SortableHeader,
|
|
422
|
+
SplitButton,
|
|
405
423
|
SplitPane,
|
|
406
424
|
StackTrace,
|
|
425
|
+
StackedStatusBar,
|
|
407
426
|
StatusDot,
|
|
427
|
+
StatusRows,
|
|
408
428
|
TabButton,
|
|
409
429
|
TagActionsProvider,
|
|
410
430
|
TagList,
|
|
431
|
+
TaskManager,
|
|
432
|
+
TaskProgress,
|
|
411
433
|
ThemeProvider,
|
|
412
434
|
ThemeSwitcher,
|
|
413
435
|
TimeRange,
|
|
436
|
+
TimeseriesGauge,
|
|
437
|
+
TimeseriesPanel,
|
|
414
438
|
Timestamp,
|
|
415
439
|
Tree,
|
|
416
440
|
TreeGroupHeader,
|
|
@@ -905,7 +929,9 @@ export {
|
|
|
905
929
|
UiZoomOut,
|
|
906
930
|
UiZoomOutFilled,
|
|
907
931
|
VIEW_OPTIONS,
|
|
932
|
+
allGroupsTerminal,
|
|
908
933
|
badgeVariants,
|
|
934
|
+
bucketTasks,
|
|
909
935
|
buttonVariants,
|
|
910
936
|
changeIconAliases,
|
|
911
937
|
chooseTimestampFormat,
|
|
@@ -921,12 +947,20 @@ export {
|
|
|
921
947
|
findListEndpoint,
|
|
922
948
|
findProcessByPID,
|
|
923
949
|
fnv1a32,
|
|
950
|
+
formatBytes,
|
|
951
|
+
formatBytesPerSecond,
|
|
952
|
+
formatDuration,
|
|
924
953
|
formatPropertyLabel,
|
|
954
|
+
formatShort,
|
|
925
955
|
formatTimestamp,
|
|
956
|
+
formatUnit,
|
|
957
|
+
frameHasSource,
|
|
926
958
|
getChangeIcon,
|
|
927
959
|
inferColumns,
|
|
928
960
|
isApplicationStackFrame,
|
|
929
961
|
isPositionalParam,
|
|
962
|
+
isTerminalStatus,
|
|
963
|
+
logLevelColor,
|
|
930
964
|
modeToFormat,
|
|
931
965
|
normalizeErrorDiagnostics,
|
|
932
966
|
normalizeLogsTableRows,
|
|
@@ -945,11 +979,18 @@ export {
|
|
|
945
979
|
processLabel,
|
|
946
980
|
processStateColor,
|
|
947
981
|
processStateIcon,
|
|
982
|
+
resolveBreakdown,
|
|
983
|
+
resolveSeries,
|
|
948
984
|
resolveSize,
|
|
985
|
+
segment,
|
|
949
986
|
setFallbackIconProvider,
|
|
950
987
|
splitTagToken,
|
|
951
988
|
tagActionsFromRecord,
|
|
952
989
|
tagFilterTokens,
|
|
990
|
+
taskSegments,
|
|
991
|
+
taskStatusBg,
|
|
992
|
+
taskStatusColor,
|
|
993
|
+
taskStatusIcon,
|
|
953
994
|
useDensity,
|
|
954
995
|
useDensityValue,
|
|
955
996
|
useHistoryRoute,
|
|
@@ -961,6 +1002,8 @@ export {
|
|
|
961
1002
|
useSort,
|
|
962
1003
|
useTagActions,
|
|
963
1004
|
useTagActionsValue,
|
|
1005
|
+
useTaskRun,
|
|
1006
|
+
useTaskRuns,
|
|
964
1007
|
useTheme
|
|
965
1008
|
};
|
|
966
1009
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const TAILWIND_COLOR_CLASS = /^(?:bg|text|border|fill|stroke)-/;
|
|
4
|
+
function isTailwindColorClass(color) {
|
|
5
|
+
return TAILWIND_COLOR_CLASS.test(color.trim());
|
|
6
|
+
}
|
|
7
|
+
const computedCache = /* @__PURE__ */ new Map();
|
|
8
|
+
function computeClassColor(cssClass) {
|
|
9
|
+
if (typeof document === "undefined") return void 0;
|
|
10
|
+
const probe = document.createElement("span");
|
|
11
|
+
probe.className = cssClass;
|
|
12
|
+
probe.style.position = "absolute";
|
|
13
|
+
probe.style.opacity = "0";
|
|
14
|
+
probe.style.pointerEvents = "none";
|
|
15
|
+
document.body.appendChild(probe);
|
|
16
|
+
const style = getComputedStyle(probe);
|
|
17
|
+
const usesText = /^(?:text|stroke|fill)-/.test(cssClass.trim());
|
|
18
|
+
const value = usesText ? style.color : style.backgroundColor;
|
|
19
|
+
document.body.removeChild(probe);
|
|
20
|
+
if (!value || value === "rgba(0, 0, 0, 0)" || value === "transparent") return void 0;
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function resolveCssColor(color) {
|
|
24
|
+
if (!isTailwindColorClass(color)) return color;
|
|
25
|
+
const cached = computedCache.get(color);
|
|
26
|
+
if (cached !== void 0) return cached;
|
|
27
|
+
const computed = computeClassColor(color) ?? color;
|
|
28
|
+
computedCache.set(color, computed);
|
|
29
|
+
return computed;
|
|
30
|
+
}
|
|
31
|
+
exports.isTailwindColorClass = isTailwindColorClass;
|
|
32
|
+
exports.resolveCssColor = resolveCssColor;
|
|
33
|
+
//# sourceMappingURL=color.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.cjs","sources":["../../src/lib/color.ts"],"sourcesContent":["// Resolves a series/segment \"color\" that may be expressed either as a CSS color\n// value (e.g. \"#10b981\", \"rgb(16 185 129)\", \"var(--chart-3)\") or as a Tailwind\n// utility class (e.g. \"bg-emerald-500\", \"text-rose-500\"). Consumers that need a\n// real CSS value — recharts stroke/fill, inline backgroundColor — call\n// resolveCssColor; the class→value resolution is done once per class via a probe\n// element and cached.\n\nconst TAILWIND_COLOR_CLASS = /^(?:bg|text|border|fill|stroke)-/;\n\n/** True when `color` looks like a Tailwind color utility class rather than a CSS value. */\nexport function isTailwindColorClass(color: string): boolean {\n return TAILWIND_COLOR_CLASS.test(color.trim());\n}\n\nconst computedCache = new Map<string, string>();\n\n/**\n * Reads the rendered color of a Tailwind class by mounting an off-screen probe\n * and reading getComputedStyle. `text-`/`stroke-`/`fill-` classes resolve from\n * `color`; everything else (incl. `bg-`/`border-`) from `backgroundColor`.\n * Returns undefined when no document is available (SSR) or the property is\n * empty/transparent (so callers can fall back). No inline color is set on the\n * probe — an inline value outranks the class and would mask the class's color.\n */\nfunction computeClassColor(cssClass: string): string | undefined {\n if (typeof document === \"undefined\") return undefined;\n const probe = document.createElement(\"span\");\n probe.className = cssClass;\n probe.style.position = \"absolute\";\n probe.style.opacity = \"0\";\n probe.style.pointerEvents = \"none\";\n document.body.appendChild(probe);\n const style = getComputedStyle(probe);\n const usesText = /^(?:text|stroke|fill)-/.test(cssClass.trim());\n const value = usesText ? style.color : style.backgroundColor;\n document.body.removeChild(probe);\n if (!value || value === \"rgba(0, 0, 0, 0)\" || value === \"transparent\") return undefined;\n return value;\n}\n\n/**\n * Returns a usable CSS color value for `color`. CSS values pass through\n * unchanged; Tailwind color classes are resolved to their computed value\n * (memoized). Falls back to the original string when resolution is impossible\n * (SSR, unknown class) so callers still get something to render.\n */\nexport function resolveCssColor(color: string): string {\n if (!isTailwindColorClass(color)) return color;\n const cached = computedCache.get(color);\n if (cached !== undefined) return cached;\n const computed = computeClassColor(color) ?? color;\n computedCache.set(color, computed);\n return computed;\n}\n"],"names":[],"mappings":";;AAOA,MAAM,uBAAuB;AAGtB,SAAS,qBAAqB,OAAwB;AAC3D,SAAO,qBAAqB,KAAK,MAAM,KAAA,CAAM;AAC/C;AAEA,MAAM,oCAAoB,IAAA;AAU1B,SAAS,kBAAkB,UAAsC;AAC/D,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,QAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,QAAM,YAAY;AAClB,QAAM,MAAM,WAAW;AACvB,QAAM,MAAM,UAAU;AACtB,QAAM,MAAM,gBAAgB;AAC5B,WAAS,KAAK,YAAY,KAAK;AAC/B,QAAM,QAAQ,iBAAiB,KAAK;AACpC,QAAM,WAAW,yBAAyB,KAAK,SAAS,MAAM;AAC9D,QAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM;AAC7C,WAAS,KAAK,YAAY,KAAK;AAC/B,MAAI,CAAC,SAAS,UAAU,sBAAsB,UAAU,cAAe,QAAO;AAC9E,SAAO;AACT;AAQO,SAAS,gBAAgB,OAAuB;AACrD,MAAI,CAAC,qBAAqB,KAAK,EAAG,QAAO;AACzC,QAAM,SAAS,cAAc,IAAI,KAAK;AACtC,MAAI,WAAW,OAAW,QAAO;AACjC,QAAM,WAAW,kBAAkB,KAAK,KAAK;AAC7C,gBAAc,IAAI,OAAO,QAAQ;AACjC,SAAO;AACT;;;"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** True when `color` looks like a Tailwind color utility class rather than a CSS value. */
|
|
2
|
+
export declare function isTailwindColorClass(color: string): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Returns a usable CSS color value for `color`. CSS values pass through
|
|
5
|
+
* unchanged; Tailwind color classes are resolved to their computed value
|
|
6
|
+
* (memoized). Falls back to the original string when resolution is impossible
|
|
7
|
+
* (SSR, unknown class) so callers still get something to render.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveCssColor(color: string): string;
|
|
10
|
+
//# sourceMappingURL=color.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/lib/color.ts"],"names":[],"mappings":"AASA,2FAA2F;AAC3F,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE3D;AA4BD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAOrD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const TAILWIND_COLOR_CLASS = /^(?:bg|text|border|fill|stroke)-/;
|
|
2
|
+
function isTailwindColorClass(color) {
|
|
3
|
+
return TAILWIND_COLOR_CLASS.test(color.trim());
|
|
4
|
+
}
|
|
5
|
+
const computedCache = /* @__PURE__ */ new Map();
|
|
6
|
+
function computeClassColor(cssClass) {
|
|
7
|
+
if (typeof document === "undefined") return void 0;
|
|
8
|
+
const probe = document.createElement("span");
|
|
9
|
+
probe.className = cssClass;
|
|
10
|
+
probe.style.position = "absolute";
|
|
11
|
+
probe.style.opacity = "0";
|
|
12
|
+
probe.style.pointerEvents = "none";
|
|
13
|
+
document.body.appendChild(probe);
|
|
14
|
+
const style = getComputedStyle(probe);
|
|
15
|
+
const usesText = /^(?:text|stroke|fill)-/.test(cssClass.trim());
|
|
16
|
+
const value = usesText ? style.color : style.backgroundColor;
|
|
17
|
+
document.body.removeChild(probe);
|
|
18
|
+
if (!value || value === "rgba(0, 0, 0, 0)" || value === "transparent") return void 0;
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
function resolveCssColor(color) {
|
|
22
|
+
if (!isTailwindColorClass(color)) return color;
|
|
23
|
+
const cached = computedCache.get(color);
|
|
24
|
+
if (cached !== void 0) return cached;
|
|
25
|
+
const computed = computeClassColor(color) ?? color;
|
|
26
|
+
computedCache.set(color, computed);
|
|
27
|
+
return computed;
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
isTailwindColorClass,
|
|
31
|
+
resolveCssColor
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=color.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.js","sources":["../../src/lib/color.ts"],"sourcesContent":["// Resolves a series/segment \"color\" that may be expressed either as a CSS color\n// value (e.g. \"#10b981\", \"rgb(16 185 129)\", \"var(--chart-3)\") or as a Tailwind\n// utility class (e.g. \"bg-emerald-500\", \"text-rose-500\"). Consumers that need a\n// real CSS value — recharts stroke/fill, inline backgroundColor — call\n// resolveCssColor; the class→value resolution is done once per class via a probe\n// element and cached.\n\nconst TAILWIND_COLOR_CLASS = /^(?:bg|text|border|fill|stroke)-/;\n\n/** True when `color` looks like a Tailwind color utility class rather than a CSS value. */\nexport function isTailwindColorClass(color: string): boolean {\n return TAILWIND_COLOR_CLASS.test(color.trim());\n}\n\nconst computedCache = new Map<string, string>();\n\n/**\n * Reads the rendered color of a Tailwind class by mounting an off-screen probe\n * and reading getComputedStyle. `text-`/`stroke-`/`fill-` classes resolve from\n * `color`; everything else (incl. `bg-`/`border-`) from `backgroundColor`.\n * Returns undefined when no document is available (SSR) or the property is\n * empty/transparent (so callers can fall back). No inline color is set on the\n * probe — an inline value outranks the class and would mask the class's color.\n */\nfunction computeClassColor(cssClass: string): string | undefined {\n if (typeof document === \"undefined\") return undefined;\n const probe = document.createElement(\"span\");\n probe.className = cssClass;\n probe.style.position = \"absolute\";\n probe.style.opacity = \"0\";\n probe.style.pointerEvents = \"none\";\n document.body.appendChild(probe);\n const style = getComputedStyle(probe);\n const usesText = /^(?:text|stroke|fill)-/.test(cssClass.trim());\n const value = usesText ? style.color : style.backgroundColor;\n document.body.removeChild(probe);\n if (!value || value === \"rgba(0, 0, 0, 0)\" || value === \"transparent\") return undefined;\n return value;\n}\n\n/**\n * Returns a usable CSS color value for `color`. CSS values pass through\n * unchanged; Tailwind color classes are resolved to their computed value\n * (memoized). Falls back to the original string when resolution is impossible\n * (SSR, unknown class) so callers still get something to render.\n */\nexport function resolveCssColor(color: string): string {\n if (!isTailwindColorClass(color)) return color;\n const cached = computedCache.get(color);\n if (cached !== undefined) return cached;\n const computed = computeClassColor(color) ?? color;\n computedCache.set(color, computed);\n return computed;\n}\n"],"names":[],"mappings":"AAOA,MAAM,uBAAuB;AAGtB,SAAS,qBAAqB,OAAwB;AAC3D,SAAO,qBAAqB,KAAK,MAAM,KAAA,CAAM;AAC/C;AAEA,MAAM,oCAAoB,IAAA;AAU1B,SAAS,kBAAkB,UAAsC;AAC/D,MAAI,OAAO,aAAa,YAAa,QAAO;AAC5C,QAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,QAAM,YAAY;AAClB,QAAM,MAAM,WAAW;AACvB,QAAM,MAAM,UAAU;AACtB,QAAM,MAAM,gBAAgB;AAC5B,WAAS,KAAK,YAAY,KAAK;AAC/B,QAAM,QAAQ,iBAAiB,KAAK;AACpC,QAAM,WAAW,yBAAyB,KAAK,SAAS,MAAM;AAC9D,QAAM,QAAQ,WAAW,MAAM,QAAQ,MAAM;AAC7C,WAAS,KAAK,YAAY,KAAK;AAC/B,MAAI,CAAC,SAAS,UAAU,sBAAsB,UAAU,cAAe,QAAO;AAC9E,SAAO;AACT;AAQO,SAAS,gBAAgB,OAAuB;AACrD,MAAI,CAAC,qBAAqB,KAAK,EAAG,QAAO;AACzC,QAAM,SAAS,cAAc,IAAI,KAAK;AACtC,MAAI,WAAW,OAAW,QAAO;AACjC,QAAM,WAAW,kBAAkB,KAAK,KAAK;AAC7C,gBAAc,IAAI,OAAO,QAAQ;AACjC,SAAO;AACT;"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const LOCALE = "en-US";
|
|
4
|
+
function intl(value, maxFractionDigits = 1) {
|
|
5
|
+
return new Intl.NumberFormat(LOCALE, { maximumFractionDigits: maxFractionDigits }).format(
|
|
6
|
+
Number.isFinite(value) ? value : 0
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
function trimZero(s) {
|
|
10
|
+
return s.endsWith(".0") ? s.slice(0, -2) : s;
|
|
11
|
+
}
|
|
12
|
+
const BYTE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB"];
|
|
13
|
+
function formatBytes(bytes, opts) {
|
|
14
|
+
const suffix = (opts == null ? void 0 : opts.suffix) ?? "";
|
|
15
|
+
if (bytes === void 0 || !Number.isFinite(bytes) || bytes <= 0) return `0 B${suffix}`;
|
|
16
|
+
const base = (opts == null ? void 0 : opts.base) ?? 1024;
|
|
17
|
+
let size = bytes;
|
|
18
|
+
let unit = 0;
|
|
19
|
+
while (size >= base && unit < BYTE_UNITS.length - 1) {
|
|
20
|
+
size /= base;
|
|
21
|
+
unit++;
|
|
22
|
+
}
|
|
23
|
+
const rendered = size >= 10 || unit === 0 ? size.toFixed(0) : trimZero(size.toFixed(1));
|
|
24
|
+
return `${rendered} ${BYTE_UNITS[unit]}${suffix}`;
|
|
25
|
+
}
|
|
26
|
+
function formatBytesPerSecond(bytes) {
|
|
27
|
+
return formatBytes(bytes, { suffix: "/s" });
|
|
28
|
+
}
|
|
29
|
+
const SHORT_UNITS = ["", "K", "M", "B", "T"];
|
|
30
|
+
function formatShort(value) {
|
|
31
|
+
if (value === void 0 || !Number.isFinite(value)) return "0";
|
|
32
|
+
const sign = value < 0 ? "-" : "";
|
|
33
|
+
let n = Math.abs(value);
|
|
34
|
+
if (n < 1e3) return `${sign}${intl(n)}`;
|
|
35
|
+
let unit = 0;
|
|
36
|
+
while (n >= 1e3 && unit < SHORT_UNITS.length - 1) {
|
|
37
|
+
n /= 1e3;
|
|
38
|
+
unit++;
|
|
39
|
+
}
|
|
40
|
+
const rendered = n >= 10 ? n.toFixed(0) : trimZero(n.toFixed(1));
|
|
41
|
+
return `${sign}${rendered}${SHORT_UNITS[unit]}`;
|
|
42
|
+
}
|
|
43
|
+
function formatDuration(value, opts) {
|
|
44
|
+
if (value === void 0 || !Number.isFinite(value)) return "0 ms";
|
|
45
|
+
const ms = (opts == null ? void 0 : opts.from) === "s" ? value * 1e3 : value;
|
|
46
|
+
const abs = Math.abs(ms);
|
|
47
|
+
if (abs < 1e3) return `${intl(ms, 0)} ms`;
|
|
48
|
+
if (abs < 6e4) return `${intl(ms / 1e3)} s`;
|
|
49
|
+
if (abs < 36e5) return `${intl(ms / 6e4)} min`;
|
|
50
|
+
return `${intl(ms / 36e5)} h`;
|
|
51
|
+
}
|
|
52
|
+
const UNIT_FORMATTERS = {
|
|
53
|
+
none: (v) => formatShort(v),
|
|
54
|
+
short: (v) => formatShort(v),
|
|
55
|
+
percent: (v) => `${intl(v)}%`,
|
|
56
|
+
percentunit: (v) => `${intl(v * 100)}%`,
|
|
57
|
+
"%": (v) => `${intl(v)}%`,
|
|
58
|
+
bytes: (v) => formatBytes(v, { base: 1024 }),
|
|
59
|
+
decbytes: (v) => formatBytes(v, { base: 1e3 }),
|
|
60
|
+
Bps: (v) => formatBytesPerSecond(v),
|
|
61
|
+
binBps: (v) => formatBytesPerSecond(v),
|
|
62
|
+
ms: (v) => formatDuration(v, { from: "ms" }),
|
|
63
|
+
s: (v) => formatDuration(v, { from: "s" })
|
|
64
|
+
};
|
|
65
|
+
function formatUnit(value, unit) {
|
|
66
|
+
const v = Number.isFinite(value) ? value : 0;
|
|
67
|
+
if (!unit) return intl(v);
|
|
68
|
+
const fmt = UNIT_FORMATTERS[unit];
|
|
69
|
+
if (fmt) return fmt(v);
|
|
70
|
+
return `${intl(v)}${unit}`;
|
|
71
|
+
}
|
|
72
|
+
exports.formatBytes = formatBytes;
|
|
73
|
+
exports.formatBytesPerSecond = formatBytesPerSecond;
|
|
74
|
+
exports.formatDuration = formatDuration;
|
|
75
|
+
exports.formatShort = formatShort;
|
|
76
|
+
exports.formatUnit = formatUnit;
|
|
77
|
+
//# sourceMappingURL=format.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.cjs","sources":["../../src/lib/format.ts"],"sourcesContent":["// Value formatters and a Grafana-style unit registry, shared by TimeseriesPanel\n// (and any other metric display). Pure — no React — so it is trivially testable.\n//\n// `formatUnit(value, unit)` dispatches on a Grafana unit identifier (e.g.\n// \"bytes\", \"Bps\", \"percent\", \"ms\", \"short\"). Unknown unit strings are treated as\n// a raw suffix appended to the formatted number, preserving callers that pass a\n// literal like \"%\" or \"req\".\n\nconst LOCALE = \"en-US\";\n\nfunction intl(value: number, maxFractionDigits = 1): string {\n return new Intl.NumberFormat(LOCALE, { maximumFractionDigits: maxFractionDigits }).format(\n Number.isFinite(value) ? value : 0,\n );\n}\n\n/** Drops a trailing \".0\" so whole values read \"1 KB\" rather than \"1.0 KB\". */\nfunction trimZero(s: string): string {\n return s.endsWith(\".0\") ? s.slice(0, -2) : s;\n}\n\nexport interface FormatBytesOptions {\n /** 1024 (IEC, the default) or 1000 (SI/decimal). */\n base?: 1000 | 1024;\n /** Appended after the unit label, e.g. \"/s\" for a rate. */\n suffix?: string;\n}\n\nconst BYTE_UNITS = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"] as const;\n\n/**\n * Human-readable byte size. 1024-based by default with B/KB/MB/GB/TB/PB labels,\n * matching the prior diagnostics formatter. Whole numbers and values >= 10 drop\n * the fraction; smaller fractional values keep one decimal.\n */\nexport function formatBytes(bytes?: number, opts?: FormatBytesOptions): string {\n const suffix = opts?.suffix ?? \"\";\n if (bytes === undefined || !Number.isFinite(bytes) || bytes <= 0) return `0 B${suffix}`;\n const base = opts?.base ?? 1024;\n let size = bytes;\n let unit = 0;\n while (size >= base && unit < BYTE_UNITS.length - 1) {\n size /= base;\n unit++;\n }\n const rendered = size >= 10 || unit === 0 ? size.toFixed(0) : trimZero(size.toFixed(1));\n return `${rendered} ${BYTE_UNITS[unit]}${suffix}`;\n}\n\n/** Byte rate, e.g. \"1.5 MB/s\". 1024-based. */\nexport function formatBytesPerSecond(bytes?: number): string {\n return formatBytes(bytes, { suffix: \"/s\" });\n}\n\nconst SHORT_UNITS = [\"\", \"K\", \"M\", \"B\", \"T\"] as const;\n\n/** SI abbreviation: 999 -> \"999\", 1200 -> \"1.2K\", 3_400_000 -> \"3.4M\". */\nexport function formatShort(value?: number): string {\n if (value === undefined || !Number.isFinite(value)) return \"0\";\n const sign = value < 0 ? \"-\" : \"\";\n let n = Math.abs(value);\n if (n < 1000) return `${sign}${intl(n)}`;\n let unit = 0;\n while (n >= 1000 && unit < SHORT_UNITS.length - 1) {\n n /= 1000;\n unit++;\n }\n const rendered = n >= 10 ? n.toFixed(0) : trimZero(n.toFixed(1));\n return `${sign}${rendered}${SHORT_UNITS[unit]}`;\n}\n\n/**\n * Duration rendered from a millisecond (default) or second input. Picks ms / s /\n * min / h by magnitude: 850 -> \"850 ms\", 1500 -> \"1.5 s\", 90_000 -> \"1.5 min\".\n */\nexport function formatDuration(value?: number, opts?: { from?: \"ms\" | \"s\" }): string {\n if (value === undefined || !Number.isFinite(value)) return \"0 ms\";\n const ms = opts?.from === \"s\" ? value * 1000 : value;\n const abs = Math.abs(ms);\n if (abs < 1000) return `${intl(ms, 0)} ms`;\n if (abs < 60_000) return `${intl(ms / 1000)} s`;\n if (abs < 3_600_000) return `${intl(ms / 60_000)} min`;\n return `${intl(ms / 3_600_000)} h`;\n}\n\n// formatters keyed by Grafana unit identifier. Keys not present here fall through\n// to the raw-suffix path in formatUnit.\nconst UNIT_FORMATTERS: Record<string, (v: number) => string> = {\n none: (v) => formatShort(v),\n short: (v) => formatShort(v),\n percent: (v) => `${intl(v)}%`,\n percentunit: (v) => `${intl(v * 100)}%`,\n \"%\": (v) => `${intl(v)}%`,\n bytes: (v) => formatBytes(v, { base: 1024 }),\n decbytes: (v) => formatBytes(v, { base: 1000 }),\n Bps: (v) => formatBytesPerSecond(v),\n binBps: (v) => formatBytesPerSecond(v),\n ms: (v) => formatDuration(v, { from: \"ms\" }),\n s: (v) => formatDuration(v, { from: \"s\" }),\n};\n\n/**\n * Formats a value for display per a Grafana-style unit key. Unknown units are\n * appended as a literal suffix (back-compat for callers passing \"%\", \"req\",\n * etc.); an absent unit yields the plain localized number.\n */\nexport function formatUnit(value: number, unit?: string): string {\n const v = Number.isFinite(value) ? value : 0;\n if (!unit) return intl(v);\n const fmt = UNIT_FORMATTERS[unit];\n if (fmt) return fmt(v);\n return `${intl(v)}${unit}`;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface FormatBytesOptions {
|
|
2
|
+
/** 1024 (IEC, the default) or 1000 (SI/decimal). */
|
|
3
|
+
base?: 1000 | 1024;
|
|
4
|
+
/** Appended after the unit label, e.g. "/s" for a rate. */
|
|
5
|
+
suffix?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Human-readable byte size. 1024-based by default with B/KB/MB/GB/TB/PB labels,
|
|
9
|
+
* matching the prior diagnostics formatter. Whole numbers and values >= 10 drop
|
|
10
|
+
* the fraction; smaller fractional values keep one decimal.
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatBytes(bytes?: number, opts?: FormatBytesOptions): string;
|
|
13
|
+
/** Byte rate, e.g. "1.5 MB/s". 1024-based. */
|
|
14
|
+
export declare function formatBytesPerSecond(bytes?: number): string;
|
|
15
|
+
/** SI abbreviation: 999 -> "999", 1200 -> "1.2K", 3_400_000 -> "3.4M". */
|
|
16
|
+
export declare function formatShort(value?: number): string;
|
|
17
|
+
/**
|
|
18
|
+
* Duration rendered from a millisecond (default) or second input. Picks ms / s /
|
|
19
|
+
* min / h by magnitude: 850 -> "850 ms", 1500 -> "1.5 s", 90_000 -> "1.5 min".
|
|
20
|
+
*/
|
|
21
|
+
export declare function formatDuration(value?: number, opts?: {
|
|
22
|
+
from?: "ms" | "s";
|
|
23
|
+
}): string;
|
|
24
|
+
/**
|
|
25
|
+
* Formats a value for display per a Grafana-style unit key. Unknown units are
|
|
26
|
+
* appended as a literal suffix (back-compat for callers passing "%", "req",
|
|
27
|
+
* etc.); an absent unit yields the plain localized number.
|
|
28
|
+
*/
|
|
29
|
+
export declare function formatUnit(value: number, unit?: string): string;
|
|
30
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/lib/format.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,kBAAkB;IACjC,oDAAoD;IACpD,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,MAAM,CAY7E;AAED,8CAA8C;AAC9C,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAE3D;AAID,0EAA0E;AAC1E,wBAAgB,WAAW,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAYlD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,IAAI,GAAG,GAAG,CAAA;CAAE,GAAG,MAAM,CAQnF;AAkBD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/D"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const LOCALE = "en-US";
|
|
2
|
+
function intl(value, maxFractionDigits = 1) {
|
|
3
|
+
return new Intl.NumberFormat(LOCALE, { maximumFractionDigits: maxFractionDigits }).format(
|
|
4
|
+
Number.isFinite(value) ? value : 0
|
|
5
|
+
);
|
|
6
|
+
}
|
|
7
|
+
function trimZero(s) {
|
|
8
|
+
return s.endsWith(".0") ? s.slice(0, -2) : s;
|
|
9
|
+
}
|
|
10
|
+
const BYTE_UNITS = ["B", "KB", "MB", "GB", "TB", "PB"];
|
|
11
|
+
function formatBytes(bytes, opts) {
|
|
12
|
+
const suffix = (opts == null ? void 0 : opts.suffix) ?? "";
|
|
13
|
+
if (bytes === void 0 || !Number.isFinite(bytes) || bytes <= 0) return `0 B${suffix}`;
|
|
14
|
+
const base = (opts == null ? void 0 : opts.base) ?? 1024;
|
|
15
|
+
let size = bytes;
|
|
16
|
+
let unit = 0;
|
|
17
|
+
while (size >= base && unit < BYTE_UNITS.length - 1) {
|
|
18
|
+
size /= base;
|
|
19
|
+
unit++;
|
|
20
|
+
}
|
|
21
|
+
const rendered = size >= 10 || unit === 0 ? size.toFixed(0) : trimZero(size.toFixed(1));
|
|
22
|
+
return `${rendered} ${BYTE_UNITS[unit]}${suffix}`;
|
|
23
|
+
}
|
|
24
|
+
function formatBytesPerSecond(bytes) {
|
|
25
|
+
return formatBytes(bytes, { suffix: "/s" });
|
|
26
|
+
}
|
|
27
|
+
const SHORT_UNITS = ["", "K", "M", "B", "T"];
|
|
28
|
+
function formatShort(value) {
|
|
29
|
+
if (value === void 0 || !Number.isFinite(value)) return "0";
|
|
30
|
+
const sign = value < 0 ? "-" : "";
|
|
31
|
+
let n = Math.abs(value);
|
|
32
|
+
if (n < 1e3) return `${sign}${intl(n)}`;
|
|
33
|
+
let unit = 0;
|
|
34
|
+
while (n >= 1e3 && unit < SHORT_UNITS.length - 1) {
|
|
35
|
+
n /= 1e3;
|
|
36
|
+
unit++;
|
|
37
|
+
}
|
|
38
|
+
const rendered = n >= 10 ? n.toFixed(0) : trimZero(n.toFixed(1));
|
|
39
|
+
return `${sign}${rendered}${SHORT_UNITS[unit]}`;
|
|
40
|
+
}
|
|
41
|
+
function formatDuration(value, opts) {
|
|
42
|
+
if (value === void 0 || !Number.isFinite(value)) return "0 ms";
|
|
43
|
+
const ms = (opts == null ? void 0 : opts.from) === "s" ? value * 1e3 : value;
|
|
44
|
+
const abs = Math.abs(ms);
|
|
45
|
+
if (abs < 1e3) return `${intl(ms, 0)} ms`;
|
|
46
|
+
if (abs < 6e4) return `${intl(ms / 1e3)} s`;
|
|
47
|
+
if (abs < 36e5) return `${intl(ms / 6e4)} min`;
|
|
48
|
+
return `${intl(ms / 36e5)} h`;
|
|
49
|
+
}
|
|
50
|
+
const UNIT_FORMATTERS = {
|
|
51
|
+
none: (v) => formatShort(v),
|
|
52
|
+
short: (v) => formatShort(v),
|
|
53
|
+
percent: (v) => `${intl(v)}%`,
|
|
54
|
+
percentunit: (v) => `${intl(v * 100)}%`,
|
|
55
|
+
"%": (v) => `${intl(v)}%`,
|
|
56
|
+
bytes: (v) => formatBytes(v, { base: 1024 }),
|
|
57
|
+
decbytes: (v) => formatBytes(v, { base: 1e3 }),
|
|
58
|
+
Bps: (v) => formatBytesPerSecond(v),
|
|
59
|
+
binBps: (v) => formatBytesPerSecond(v),
|
|
60
|
+
ms: (v) => formatDuration(v, { from: "ms" }),
|
|
61
|
+
s: (v) => formatDuration(v, { from: "s" })
|
|
62
|
+
};
|
|
63
|
+
function formatUnit(value, unit) {
|
|
64
|
+
const v = Number.isFinite(value) ? value : 0;
|
|
65
|
+
if (!unit) return intl(v);
|
|
66
|
+
const fmt = UNIT_FORMATTERS[unit];
|
|
67
|
+
if (fmt) return fmt(v);
|
|
68
|
+
return `${intl(v)}${unit}`;
|
|
69
|
+
}
|
|
70
|
+
export {
|
|
71
|
+
formatBytes,
|
|
72
|
+
formatBytesPerSecond,
|
|
73
|
+
formatDuration,
|
|
74
|
+
formatShort,
|
|
75
|
+
formatUnit
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sources":["../../src/lib/format.ts"],"sourcesContent":["// Value formatters and a Grafana-style unit registry, shared by TimeseriesPanel\n// (and any other metric display). Pure — no React — so it is trivially testable.\n//\n// `formatUnit(value, unit)` dispatches on a Grafana unit identifier (e.g.\n// \"bytes\", \"Bps\", \"percent\", \"ms\", \"short\"). Unknown unit strings are treated as\n// a raw suffix appended to the formatted number, preserving callers that pass a\n// literal like \"%\" or \"req\".\n\nconst LOCALE = \"en-US\";\n\nfunction intl(value: number, maxFractionDigits = 1): string {\n return new Intl.NumberFormat(LOCALE, { maximumFractionDigits: maxFractionDigits }).format(\n Number.isFinite(value) ? value : 0,\n );\n}\n\n/** Drops a trailing \".0\" so whole values read \"1 KB\" rather than \"1.0 KB\". */\nfunction trimZero(s: string): string {\n return s.endsWith(\".0\") ? s.slice(0, -2) : s;\n}\n\nexport interface FormatBytesOptions {\n /** 1024 (IEC, the default) or 1000 (SI/decimal). */\n base?: 1000 | 1024;\n /** Appended after the unit label, e.g. \"/s\" for a rate. */\n suffix?: string;\n}\n\nconst BYTE_UNITS = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\"] as const;\n\n/**\n * Human-readable byte size. 1024-based by default with B/KB/MB/GB/TB/PB labels,\n * matching the prior diagnostics formatter. Whole numbers and values >= 10 drop\n * the fraction; smaller fractional values keep one decimal.\n */\nexport function formatBytes(bytes?: number, opts?: FormatBytesOptions): string {\n const suffix = opts?.suffix ?? \"\";\n if (bytes === undefined || !Number.isFinite(bytes) || bytes <= 0) return `0 B${suffix}`;\n const base = opts?.base ?? 1024;\n let size = bytes;\n let unit = 0;\n while (size >= base && unit < BYTE_UNITS.length - 1) {\n size /= base;\n unit++;\n }\n const rendered = size >= 10 || unit === 0 ? size.toFixed(0) : trimZero(size.toFixed(1));\n return `${rendered} ${BYTE_UNITS[unit]}${suffix}`;\n}\n\n/** Byte rate, e.g. \"1.5 MB/s\". 1024-based. */\nexport function formatBytesPerSecond(bytes?: number): string {\n return formatBytes(bytes, { suffix: \"/s\" });\n}\n\nconst SHORT_UNITS = [\"\", \"K\", \"M\", \"B\", \"T\"] as const;\n\n/** SI abbreviation: 999 -> \"999\", 1200 -> \"1.2K\", 3_400_000 -> \"3.4M\". */\nexport function formatShort(value?: number): string {\n if (value === undefined || !Number.isFinite(value)) return \"0\";\n const sign = value < 0 ? \"-\" : \"\";\n let n = Math.abs(value);\n if (n < 1000) return `${sign}${intl(n)}`;\n let unit = 0;\n while (n >= 1000 && unit < SHORT_UNITS.length - 1) {\n n /= 1000;\n unit++;\n }\n const rendered = n >= 10 ? n.toFixed(0) : trimZero(n.toFixed(1));\n return `${sign}${rendered}${SHORT_UNITS[unit]}`;\n}\n\n/**\n * Duration rendered from a millisecond (default) or second input. Picks ms / s /\n * min / h by magnitude: 850 -> \"850 ms\", 1500 -> \"1.5 s\", 90_000 -> \"1.5 min\".\n */\nexport function formatDuration(value?: number, opts?: { from?: \"ms\" | \"s\" }): string {\n if (value === undefined || !Number.isFinite(value)) return \"0 ms\";\n const ms = opts?.from === \"s\" ? value * 1000 : value;\n const abs = Math.abs(ms);\n if (abs < 1000) return `${intl(ms, 0)} ms`;\n if (abs < 60_000) return `${intl(ms / 1000)} s`;\n if (abs < 3_600_000) return `${intl(ms / 60_000)} min`;\n return `${intl(ms / 3_600_000)} h`;\n}\n\n// formatters keyed by Grafana unit identifier. Keys not present here fall through\n// to the raw-suffix path in formatUnit.\nconst UNIT_FORMATTERS: Record<string, (v: number) => string> = {\n none: (v) => formatShort(v),\n short: (v) => formatShort(v),\n percent: (v) => `${intl(v)}%`,\n percentunit: (v) => `${intl(v * 100)}%`,\n \"%\": (v) => `${intl(v)}%`,\n bytes: (v) => formatBytes(v, { base: 1024 }),\n decbytes: (v) => formatBytes(v, { base: 1000 }),\n Bps: (v) => formatBytesPerSecond(v),\n binBps: (v) => formatBytesPerSecond(v),\n ms: (v) => formatDuration(v, { from: \"ms\" }),\n s: (v) => formatDuration(v, { from: \"s\" }),\n};\n\n/**\n * Formats a value for display per a Grafana-style unit key. Unknown units are\n * appended as a literal suffix (back-compat for callers passing \"%\", \"req\",\n * etc.); an absent unit yields the plain localized number.\n */\nexport function formatUnit(value: number, unit?: string): string {\n const v = Number.isFinite(value) ? value : 0;\n if (!unit) return intl(v);\n const fmt = UNIT_FORMATTERS[unit];\n if (fmt) return fmt(v);\n return `${intl(v)}${unit}`;\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -16,12 +16,19 @@ function DropdownMenu({
|
|
|
16
16
|
items,
|
|
17
17
|
children,
|
|
18
18
|
align = "right",
|
|
19
|
+
onOpenChange,
|
|
19
20
|
title,
|
|
20
21
|
className,
|
|
21
22
|
menuClassName
|
|
22
23
|
}) {
|
|
23
24
|
const [open, setOpen] = react.useState(false);
|
|
24
25
|
const wrapperRef = react.useRef(null);
|
|
26
|
+
const onOpenChangeRef = react.useRef(onOpenChange);
|
|
27
|
+
onOpenChangeRef.current = onOpenChange;
|
|
28
|
+
react.useEffect(() => {
|
|
29
|
+
var _a;
|
|
30
|
+
(_a = onOpenChangeRef.current) == null ? void 0 : _a.call(onOpenChangeRef, open);
|
|
31
|
+
}, [open]);
|
|
25
32
|
react.useEffect(() => {
|
|
26
33
|
if (!open) return;
|
|
27
34
|
const onMouseDown = (e) => {
|
|
@@ -40,8 +47,17 @@ function DropdownMenu({
|
|
|
40
47
|
}, [open]);
|
|
41
48
|
const closeMenu = () => setOpen(false);
|
|
42
49
|
const toggle = () => setOpen((v) => !v);
|
|
43
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("relative inline-
|
|
44
|
-
trigger ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
50
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: utils.cn("relative inline-flex", className), ref: wrapperRef, children: [
|
|
51
|
+
trigger ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
52
|
+
"span",
|
|
53
|
+
{
|
|
54
|
+
className: "contents",
|
|
55
|
+
onClick: toggle,
|
|
56
|
+
"aria-haspopup": "menu",
|
|
57
|
+
"aria-expanded": open,
|
|
58
|
+
children: trigger
|
|
59
|
+
}
|
|
60
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
45
61
|
button.Button,
|
|
46
62
|
{
|
|
47
63
|
variant,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenu.cjs","sources":["../../src/overlay/DropdownMenu.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button, type ButtonProps } from \"../components/button\";\nimport { Icon, type StaticIconComponent } from \"../data/Icon\";\nimport { UiChevronDown } from \"../icons\";\n\nexport type DropdownMenuItem = {\n /** Visible label. */\n label: ReactNode;\n /** Called when the item is chosen. */\n onSelect: () => void;\n /** Iconify name or imported icon component rendered before the label. */\n icon?: string | StaticIconComponent;\n /** Browser tooltip for the item. */\n title?: string;\n /** Disable selection. */\n disabled?: boolean;\n};\n\nexport type DropdownMenuProps = {\n /** Trigger label. Ignored when `trigger` is provided. */\n label?: ReactNode;\n /** Icon shown before the trigger label. Ignored when `trigger` is provided. */\n icon?: string | StaticIconComponent;\n /** Hide the trailing chevron on the default trigger. */\n hideChevron?: boolean;\n /** Variant forwarded to the default Button trigger. */\n variant?: ButtonProps[\"variant\"];\n /** Size forwarded to the default Button trigger. */\n size?: ButtonProps[\"size\"];\n /** Fully custom trigger. Receives no props; the menu wraps it with open state. */\n trigger?: ReactNode;\n /** Declarative menu items. Provide this or `children`, not both. */\n items?: DropdownMenuItem[];\n /** Custom menu content. Use `closeMenu` to dismiss after a selection. */\n children?: (closeMenu: () => void) => ReactNode;\n /** Horizontal alignment of the menu relative to the trigger. */\n align?: \"left\" | \"right\";\n /** Browser tooltip / accessible label for the default trigger. */\n title?: string;\n /** Classes applied to the wrapper. */\n className?: string;\n /** Classes applied to the floating menu. */\n menuClassName?: string;\n};\n\nexport function DropdownMenu({\n label,\n icon,\n hideChevron = false,\n variant = \"outline\",\n size = \"sm\",\n trigger,\n items,\n children,\n align = \"right\",\n title,\n className,\n menuClassName,\n}: DropdownMenuProps) {\n const [open, setOpen] = useState(false);\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!open) return;\n const onMouseDown = (e: MouseEvent) => {\n if (!wrapperRef.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onMouseDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"mousedown\", onMouseDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [open]);\n\n const closeMenu = () => setOpen(false);\n const toggle = () => setOpen((v) => !v);\n\n return (\n <div className={cn(\"relative inline-
|
|
1
|
+
{"version":3,"file":"DropdownMenu.cjs","sources":["../../src/overlay/DropdownMenu.tsx"],"sourcesContent":["import { useEffect, useRef, useState, type ReactNode } from \"react\";\nimport { cn } from \"../lib/utils\";\nimport { Button, type ButtonProps } from \"../components/button\";\nimport { Icon, type StaticIconComponent } from \"../data/Icon\";\nimport { UiChevronDown } from \"../icons\";\n\nexport type DropdownMenuItem = {\n /** Visible label. */\n label: ReactNode;\n /** Called when the item is chosen. */\n onSelect: () => void;\n /** Iconify name or imported icon component rendered before the label. */\n icon?: string | StaticIconComponent;\n /** Browser tooltip for the item. */\n title?: string;\n /** Disable selection. */\n disabled?: boolean;\n};\n\nexport type DropdownMenuProps = {\n /** Trigger label. Ignored when `trigger` is provided. */\n label?: ReactNode;\n /** Icon shown before the trigger label. Ignored when `trigger` is provided. */\n icon?: string | StaticIconComponent;\n /** Hide the trailing chevron on the default trigger. */\n hideChevron?: boolean;\n /** Variant forwarded to the default Button trigger. */\n variant?: ButtonProps[\"variant\"];\n /** Size forwarded to the default Button trigger. */\n size?: ButtonProps[\"size\"];\n /** Fully custom trigger. Receives no props; the menu wraps it with open state. */\n trigger?: ReactNode;\n /** Declarative menu items. Provide this or `children`, not both. */\n items?: DropdownMenuItem[];\n /** Custom menu content. Use `closeMenu` to dismiss after a selection. */\n children?: (closeMenu: () => void) => ReactNode;\n /** Horizontal alignment of the menu relative to the trigger. */\n align?: \"left\" | \"right\";\n /** Notified whenever the menu opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Browser tooltip / accessible label for the default trigger. */\n title?: string;\n /** Classes applied to the wrapper. */\n className?: string;\n /** Classes applied to the floating menu. */\n menuClassName?: string;\n};\n\nexport function DropdownMenu({\n label,\n icon,\n hideChevron = false,\n variant = \"outline\",\n size = \"sm\",\n trigger,\n items,\n children,\n align = \"right\",\n onOpenChange,\n title,\n className,\n menuClassName,\n}: DropdownMenuProps) {\n const [open, setOpen] = useState(false);\n const wrapperRef = useRef<HTMLDivElement>(null);\n\n const onOpenChangeRef = useRef(onOpenChange);\n onOpenChangeRef.current = onOpenChange;\n useEffect(() => {\n onOpenChangeRef.current?.(open);\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n const onMouseDown = (e: MouseEvent) => {\n if (!wrapperRef.current?.contains(e.target as Node)) setOpen(false);\n };\n const onKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onMouseDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"mousedown\", onMouseDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [open]);\n\n const closeMenu = () => setOpen(false);\n const toggle = () => setOpen((v) => !v);\n\n return (\n <div className={cn(\"relative inline-flex\", className)} ref={wrapperRef}>\n {trigger ? (\n <span\n className=\"contents\"\n onClick={toggle}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n >\n {trigger}\n </span>\n ) : (\n <Button\n variant={variant}\n size={size}\n onClick={toggle}\n title={title}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n >\n {icon && <Icon {...(typeof icon === \"string\" ? { name: icon } : { icon })} />}\n {label}\n {!hideChevron && <Icon icon={UiChevronDown} />}\n </Button>\n )}\n {open && (\n <div\n role=\"menu\"\n className={cn(\n \"absolute z-20 mt-1 min-w-[8rem] rounded-md border border-border bg-popover py-1 shadow-md\",\n align === \"right\" ? \"right-0\" : \"left-0\",\n menuClassName,\n )}\n >\n {children\n ? children(closeMenu)\n : items?.map((item, i) => (\n <button\n key={i}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n title={item.title}\n onClick={() => {\n item.onSelect();\n closeMenu();\n }}\n className=\"flex w-full items-center gap-2 px-3 py-1.5 text-left text-xs text-popover-foreground hover:bg-accent hover:text-accent-foreground disabled:pointer-events-none disabled:opacity-50\"\n >\n {item.icon && (\n <Icon\n {...(typeof item.icon === \"string\"\n ? { name: item.icon }\n : { icon: item.icon })}\n />\n )}\n {item.label}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n"],"names":["useState","useRef","useEffect","jsxs","cn","jsx","Button","Icon","UiChevronDown"],"mappings":"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"}
|
|
@@ -32,6 +32,8 @@ export type DropdownMenuProps = {
|
|
|
32
32
|
children?: (closeMenu: () => void) => ReactNode;
|
|
33
33
|
/** Horizontal alignment of the menu relative to the trigger. */
|
|
34
34
|
align?: "left" | "right";
|
|
35
|
+
/** Notified whenever the menu opens or closes. */
|
|
36
|
+
onOpenChange?: (open: boolean) => void;
|
|
35
37
|
/** Browser tooltip / accessible label for the default trigger. */
|
|
36
38
|
title?: string;
|
|
37
39
|
/** Classes applied to the wrapper. */
|
|
@@ -39,5 +41,5 @@ export type DropdownMenuProps = {
|
|
|
39
41
|
/** Classes applied to the floating menu. */
|
|
40
42
|
menuClassName?: string;
|
|
41
43
|
};
|
|
42
|
-
export declare function DropdownMenu({ label, icon, hideChevron, variant, size, trigger, items, children, align, title, className, menuClassName, }: DropdownMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
44
|
+
export declare function DropdownMenu({ label, icon, hideChevron, variant, size, trigger, items, children, align, onOpenChange, title, className, menuClassName, }: DropdownMenuProps): import("react/jsx-runtime").JSX.Element;
|
|
43
45
|
//# sourceMappingURL=DropdownMenu.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../src/overlay/DropdownMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpE,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAQ,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAG9D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,qBAAqB;IACrB,KAAK,EAAE,SAAS,CAAC;IACjB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACpC,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,yDAAyD;IACzD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACpC,wDAAwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACjC,oDAAoD;IACpD,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,kFAAkF;IAClF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,oEAAoE;IACpE,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,IAAI,KAAK,SAAS,CAAC;IAChD,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,IAAI,EACJ,WAAmB,EACnB,OAAmB,EACnB,IAAW,EACX,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAe,EACf,KAAK,EACL,SAAS,EACT,aAAa,GACd,EAAE,iBAAiB,
|
|
1
|
+
{"version":3,"file":"DropdownMenu.d.ts","sourceRoot":"","sources":["../../src/overlay/DropdownMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA+B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpE,OAAO,EAAU,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EAAQ,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAG9D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,qBAAqB;IACrB,KAAK,EAAE,SAAS,CAAC;IACjB,sCAAsC;IACtC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,yEAAyE;IACzE,IAAI,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACpC,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yBAAyB;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,yDAAyD;IACzD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,+EAA+E;IAC/E,IAAI,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAAC;IACpC,wDAAwD;IACxD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,OAAO,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC;IACjC,oDAAoD;IACpD,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,kFAAkF;IAClF,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,oEAAoE;IACpE,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,IAAI,KAAK,SAAS,CAAC;IAChD,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,kDAAkD;IAClD,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,IAAI,EACJ,WAAmB,EACnB,OAAmB,EACnB,IAAW,EACX,OAAO,EACP,KAAK,EACL,QAAQ,EACR,KAAe,EACf,YAAY,EACZ,KAAK,EACL,SAAS,EACT,aAAa,GACd,EAAE,iBAAiB,2CA4FnB"}
|
|
@@ -14,12 +14,19 @@ function DropdownMenu({
|
|
|
14
14
|
items,
|
|
15
15
|
children,
|
|
16
16
|
align = "right",
|
|
17
|
+
onOpenChange,
|
|
17
18
|
title,
|
|
18
19
|
className,
|
|
19
20
|
menuClassName
|
|
20
21
|
}) {
|
|
21
22
|
const [open, setOpen] = useState(false);
|
|
22
23
|
const wrapperRef = useRef(null);
|
|
24
|
+
const onOpenChangeRef = useRef(onOpenChange);
|
|
25
|
+
onOpenChangeRef.current = onOpenChange;
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
var _a;
|
|
28
|
+
(_a = onOpenChangeRef.current) == null ? void 0 : _a.call(onOpenChangeRef, open);
|
|
29
|
+
}, [open]);
|
|
23
30
|
useEffect(() => {
|
|
24
31
|
if (!open) return;
|
|
25
32
|
const onMouseDown = (e) => {
|
|
@@ -38,8 +45,17 @@ function DropdownMenu({
|
|
|
38
45
|
}, [open]);
|
|
39
46
|
const closeMenu = () => setOpen(false);
|
|
40
47
|
const toggle = () => setOpen((v) => !v);
|
|
41
|
-
return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-
|
|
42
|
-
trigger ? /* @__PURE__ */ jsx(
|
|
48
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("relative inline-flex", className), ref: wrapperRef, children: [
|
|
49
|
+
trigger ? /* @__PURE__ */ jsx(
|
|
50
|
+
"span",
|
|
51
|
+
{
|
|
52
|
+
className: "contents",
|
|
53
|
+
onClick: toggle,
|
|
54
|
+
"aria-haspopup": "menu",
|
|
55
|
+
"aria-expanded": open,
|
|
56
|
+
children: trigger
|
|
57
|
+
}
|
|
58
|
+
) : /* @__PURE__ */ jsxs(
|
|
43
59
|
Button,
|
|
44
60
|
{
|
|
45
61
|
variant,
|