kaze-design-system 0.2.6 → 0.3.0
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/components.css +113 -0
- package/dist/components/EmptyState/EmptyState.js +15 -6
- package/dist/components/HelpButton/HelpButton.js +127 -0
- package/dist/components/StatusBadge/StatusBadge.js +31 -0
- package/dist/hooks/useLegendToggle.js +49 -0
- package/dist/hooks.js +2 -0
- package/dist/index.js +4 -0
- package/dist/types/components/EmptyState/EmptyState.d.ts +3 -1
- package/dist/types/components/EmptyState/index.d.ts +1 -1
- package/dist/types/components/HelpButton/HelpButton.d.ts +19 -0
- package/dist/types/components/HelpButton/index.d.ts +2 -0
- package/dist/types/components/StatusBadge/StatusBadge.d.ts +8 -0
- package/dist/types/components/StatusBadge/index.d.ts +2 -0
- package/dist/types/components/index.d.ts +5 -1
- package/dist/types/hooks/index.d.ts +2 -0
- package/dist/types/hooks/useLegendToggle.d.ts +38 -0
- package/package.json +1 -1
package/components.css
CHANGED
|
@@ -3246,17 +3246,46 @@
|
|
|
3246
3246
|
gap: var(--space-3);
|
|
3247
3247
|
}
|
|
3248
3248
|
|
|
3249
|
+
.empty-state--sm {
|
|
3250
|
+
padding: var(--space-3) var(--space-2);
|
|
3251
|
+
gap: var(--space-1);
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
.empty-state--md {
|
|
3255
|
+
padding: var(--space-8) var(--space-4);
|
|
3256
|
+
gap: var(--space-2);
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
.empty-state--lg {
|
|
3260
|
+
padding: var(--space-12) var(--space-6);
|
|
3261
|
+
gap: var(--space-3);
|
|
3262
|
+
}
|
|
3263
|
+
|
|
3249
3264
|
.empty-state__icon {
|
|
3250
3265
|
color: var(--color-fg-tertiary);
|
|
3251
3266
|
margin-bottom: var(--space-2);
|
|
3252
3267
|
}
|
|
3253
3268
|
|
|
3269
|
+
.empty-state--sm .empty-state__icon {
|
|
3270
|
+
margin-bottom: 0;
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3254
3273
|
.empty-state__title {
|
|
3255
3274
|
font-size: var(--font-size-lg);
|
|
3256
3275
|
font-weight: var(--font-weight-semibold);
|
|
3257
3276
|
color: var(--color-fg);
|
|
3258
3277
|
}
|
|
3259
3278
|
|
|
3279
|
+
.empty-state--sm .empty-state__title {
|
|
3280
|
+
font-size: var(--font-size-sm);
|
|
3281
|
+
font-weight: var(--font-weight-medium);
|
|
3282
|
+
color: var(--color-fg-secondary);
|
|
3283
|
+
}
|
|
3284
|
+
|
|
3285
|
+
.empty-state--md .empty-state__title {
|
|
3286
|
+
font-size: var(--font-size-base);
|
|
3287
|
+
}
|
|
3288
|
+
|
|
3260
3289
|
.empty-state__description {
|
|
3261
3290
|
font-size: var(--font-size-sm);
|
|
3262
3291
|
color: var(--color-fg-secondary);
|
|
@@ -3264,6 +3293,10 @@
|
|
|
3264
3293
|
line-height: var(--line-height-relaxed);
|
|
3265
3294
|
}
|
|
3266
3295
|
|
|
3296
|
+
.empty-state--sm .empty-state__description {
|
|
3297
|
+
font-size: var(--font-size-xs);
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3267
3300
|
.empty-state__actions {
|
|
3268
3301
|
display: flex;
|
|
3269
3302
|
gap: var(--space-3);
|
|
@@ -3955,3 +3988,83 @@
|
|
|
3955
3988
|
font-size: var(--font-size-sm);
|
|
3956
3989
|
color: var(--color-fg-tertiary);
|
|
3957
3990
|
}
|
|
3991
|
+
|
|
3992
|
+
/* ================================================================
|
|
3993
|
+
HelpButton
|
|
3994
|
+
================================================================ */
|
|
3995
|
+
|
|
3996
|
+
.help-button {
|
|
3997
|
+
display: inline-flex;
|
|
3998
|
+
align-items: center;
|
|
3999
|
+
justify-content: center;
|
|
4000
|
+
width: 18px;
|
|
4001
|
+
height: 18px;
|
|
4002
|
+
padding: 0;
|
|
4003
|
+
border: 1px solid var(--color-border);
|
|
4004
|
+
border-radius: var(--radius-full);
|
|
4005
|
+
background: var(--color-bg);
|
|
4006
|
+
color: var(--color-fg-tertiary);
|
|
4007
|
+
font-size: 11px;
|
|
4008
|
+
font-weight: var(--font-weight-medium);
|
|
4009
|
+
line-height: 1;
|
|
4010
|
+
cursor: pointer;
|
|
4011
|
+
transition: color var(--duration-fast) var(--ease-out),
|
|
4012
|
+
border-color var(--duration-fast) var(--ease-out),
|
|
4013
|
+
background-color var(--duration-fast) var(--ease-out);
|
|
4014
|
+
}
|
|
4015
|
+
|
|
4016
|
+
.help-button:hover,
|
|
4017
|
+
.help-button[aria-expanded="true"] {
|
|
4018
|
+
color: var(--color-fg);
|
|
4019
|
+
border-color: var(--color-border-strong, var(--color-fg-tertiary));
|
|
4020
|
+
background: var(--color-bg-subtle, var(--color-bg));
|
|
4021
|
+
}
|
|
4022
|
+
|
|
4023
|
+
.help-button:focus-visible {
|
|
4024
|
+
outline: 2px solid var(--color-focus, var(--color-primary));
|
|
4025
|
+
outline-offset: 2px;
|
|
4026
|
+
}
|
|
4027
|
+
|
|
4028
|
+
.help-popover {
|
|
4029
|
+
position: absolute;
|
|
4030
|
+
z-index: 1000;
|
|
4031
|
+
background: var(--color-surface, var(--color-bg));
|
|
4032
|
+
border: 1px solid var(--color-border);
|
|
4033
|
+
border-radius: var(--radius-md);
|
|
4034
|
+
box-shadow: var(--shadow-lg);
|
|
4035
|
+
padding: var(--space-3) var(--space-4);
|
|
4036
|
+
font-size: var(--font-size-sm);
|
|
4037
|
+
color: var(--color-fg);
|
|
4038
|
+
line-height: var(--line-height-relaxed);
|
|
4039
|
+
}
|
|
4040
|
+
|
|
4041
|
+
.help-popover--sm {
|
|
4042
|
+
max-width: 220px;
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
.help-popover--md {
|
|
4046
|
+
max-width: 300px;
|
|
4047
|
+
}
|
|
4048
|
+
|
|
4049
|
+
.help-popover--lg {
|
|
4050
|
+
max-width: 420px;
|
|
4051
|
+
}
|
|
4052
|
+
|
|
4053
|
+
.help-popover__title {
|
|
4054
|
+
font-size: var(--font-size-sm);
|
|
4055
|
+
font-weight: var(--font-weight-semibold);
|
|
4056
|
+
color: var(--color-fg);
|
|
4057
|
+
margin: 0 0 var(--space-2) 0;
|
|
4058
|
+
}
|
|
4059
|
+
|
|
4060
|
+
.help-popover__body {
|
|
4061
|
+
color: var(--color-fg-secondary);
|
|
4062
|
+
}
|
|
4063
|
+
|
|
4064
|
+
.help-popover__body p {
|
|
4065
|
+
margin: 0 0 var(--space-2) 0;
|
|
4066
|
+
}
|
|
4067
|
+
|
|
4068
|
+
.help-popover__body p:last-child {
|
|
4069
|
+
margin-bottom: 0;
|
|
4070
|
+
}
|
|
@@ -2,12 +2,21 @@ import { jsxs, jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { forwardRef } from "react";
|
|
3
3
|
import { cn } from "../../lib/utils.js";
|
|
4
4
|
const EmptyState = forwardRef(
|
|
5
|
-
({ icon, title, description, actions, className, ...rest }, ref) => /* @__PURE__ */ jsxs(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
({ icon, title, description, actions, size = "md", className, ...rest }, ref) => /* @__PURE__ */ jsxs(
|
|
6
|
+
"div",
|
|
7
|
+
{
|
|
8
|
+
ref,
|
|
9
|
+
role: "status",
|
|
10
|
+
className: cn("empty-state", `empty-state--${size}`, className),
|
|
11
|
+
...rest,
|
|
12
|
+
children: [
|
|
13
|
+
icon && /* @__PURE__ */ jsx("span", { className: "empty-state__icon", children: icon }),
|
|
14
|
+
/* @__PURE__ */ jsx("h3", { className: "empty-state__title", children: title }),
|
|
15
|
+
description && /* @__PURE__ */ jsx("p", { className: "empty-state__description", children: description }),
|
|
16
|
+
actions && /* @__PURE__ */ jsx("div", { className: "empty-state__actions", children: actions })
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
)
|
|
11
20
|
);
|
|
12
21
|
EmptyState.displayName = "EmptyState";
|
|
13
22
|
export {
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs, Fragment, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { forwardRef, useState, useRef, useId, useCallback, useEffect } from "react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
import { cn } from "../../lib/utils.js";
|
|
6
|
+
const GAP = 8;
|
|
7
|
+
function computePosition(trigger, pop, side) {
|
|
8
|
+
const sy = window.scrollY;
|
|
9
|
+
const sx = window.scrollX;
|
|
10
|
+
switch (side) {
|
|
11
|
+
case "top":
|
|
12
|
+
return {
|
|
13
|
+
top: trigger.top - pop.height - GAP + sy,
|
|
14
|
+
left: trigger.left + trigger.width / 2 - pop.width / 2 + sx
|
|
15
|
+
};
|
|
16
|
+
case "bottom":
|
|
17
|
+
return {
|
|
18
|
+
top: trigger.bottom + GAP + sy,
|
|
19
|
+
left: trigger.left + trigger.width / 2 - pop.width / 2 + sx
|
|
20
|
+
};
|
|
21
|
+
case "left":
|
|
22
|
+
return {
|
|
23
|
+
top: trigger.top + trigger.height / 2 - pop.height / 2 + sy,
|
|
24
|
+
left: trigger.left - pop.width - GAP + sx
|
|
25
|
+
};
|
|
26
|
+
case "right":
|
|
27
|
+
return {
|
|
28
|
+
top: trigger.top + trigger.height / 2 - pop.height / 2 + sy,
|
|
29
|
+
left: trigger.right + GAP + sx
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const HelpButton = forwardRef(
|
|
34
|
+
({
|
|
35
|
+
title,
|
|
36
|
+
children,
|
|
37
|
+
position = "bottom",
|
|
38
|
+
size = "md",
|
|
39
|
+
icon,
|
|
40
|
+
ariaLabel = "ヘルプ",
|
|
41
|
+
className
|
|
42
|
+
}, ref) => {
|
|
43
|
+
const [open, setOpen] = useState(false);
|
|
44
|
+
const [coords, setCoords] = useState({
|
|
45
|
+
top: 0,
|
|
46
|
+
left: 0
|
|
47
|
+
});
|
|
48
|
+
const triggerRef = useRef(null);
|
|
49
|
+
const popRef = useRef(null);
|
|
50
|
+
const popoverId = useId();
|
|
51
|
+
const updatePosition = useCallback(() => {
|
|
52
|
+
if (!triggerRef.current || !popRef.current) return;
|
|
53
|
+
const t = triggerRef.current.getBoundingClientRect();
|
|
54
|
+
const p = popRef.current.getBoundingClientRect();
|
|
55
|
+
setCoords(computePosition(t, p, position));
|
|
56
|
+
}, [position]);
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
if (!open) return;
|
|
59
|
+
requestAnimationFrame(updatePosition);
|
|
60
|
+
const onClickOutside = (e) => {
|
|
61
|
+
const target = e.target;
|
|
62
|
+
if (popRef.current?.contains(target) || triggerRef.current?.contains(target)) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
setOpen(false);
|
|
66
|
+
};
|
|
67
|
+
const onKeyDown = (e) => {
|
|
68
|
+
if (e.key === "Escape") {
|
|
69
|
+
setOpen(false);
|
|
70
|
+
triggerRef.current?.focus();
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
const onScroll = () => updatePosition();
|
|
74
|
+
document.addEventListener("mousedown", onClickOutside);
|
|
75
|
+
document.addEventListener("keydown", onKeyDown);
|
|
76
|
+
window.addEventListener("scroll", onScroll, true);
|
|
77
|
+
window.addEventListener("resize", onScroll);
|
|
78
|
+
return () => {
|
|
79
|
+
document.removeEventListener("mousedown", onClickOutside);
|
|
80
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
81
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
82
|
+
window.removeEventListener("resize", onScroll);
|
|
83
|
+
};
|
|
84
|
+
}, [open, updatePosition]);
|
|
85
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
86
|
+
/* @__PURE__ */ jsx(
|
|
87
|
+
"button",
|
|
88
|
+
{
|
|
89
|
+
type: "button",
|
|
90
|
+
ref: (node) => {
|
|
91
|
+
triggerRef.current = node;
|
|
92
|
+
if (typeof ref === "function") ref(node);
|
|
93
|
+
else if (ref) ref.current = node;
|
|
94
|
+
},
|
|
95
|
+
className: cn("help-button", className),
|
|
96
|
+
"aria-label": ariaLabel,
|
|
97
|
+
"aria-expanded": open,
|
|
98
|
+
"aria-controls": open ? popoverId : void 0,
|
|
99
|
+
onClick: () => setOpen((v) => !v),
|
|
100
|
+
children: icon ?? "?"
|
|
101
|
+
}
|
|
102
|
+
),
|
|
103
|
+
open && typeof document !== "undefined" && createPortal(
|
|
104
|
+
/* @__PURE__ */ jsxs(
|
|
105
|
+
"div",
|
|
106
|
+
{
|
|
107
|
+
ref: popRef,
|
|
108
|
+
id: popoverId,
|
|
109
|
+
role: "dialog",
|
|
110
|
+
"aria-modal": "false",
|
|
111
|
+
className: cn("help-popover", `help-popover--${size}`),
|
|
112
|
+
style: { top: coords.top, left: coords.left },
|
|
113
|
+
children: [
|
|
114
|
+
title && /* @__PURE__ */ jsx("p", { className: "help-popover__title", children: title }),
|
|
115
|
+
/* @__PURE__ */ jsx("div", { className: "help-popover__body", children })
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
),
|
|
119
|
+
document.body
|
|
120
|
+
)
|
|
121
|
+
] });
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
HelpButton.displayName = "HelpButton";
|
|
125
|
+
export {
|
|
126
|
+
HelpButton
|
|
127
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef } from "react";
|
|
3
|
+
import { Badge } from "../Badge/Badge.js";
|
|
4
|
+
const STATUS_CONFIG = {
|
|
5
|
+
live: { variant: "positive", label: "自動更新" },
|
|
6
|
+
stale: { variant: "warning", label: "要更新" },
|
|
7
|
+
missing: { variant: "negative", label: "欠損" },
|
|
8
|
+
manual: { variant: "default", label: "手動" },
|
|
9
|
+
loading: { variant: "info", label: "取得中" }
|
|
10
|
+
};
|
|
11
|
+
const StatusBadge = forwardRef(
|
|
12
|
+
({ status, label, dot = true, live, ...rest }, ref) => {
|
|
13
|
+
const config = STATUS_CONFIG[status];
|
|
14
|
+
const isLive = live ?? (status === "live" || status === "loading");
|
|
15
|
+
return /* @__PURE__ */ jsx(
|
|
16
|
+
Badge,
|
|
17
|
+
{
|
|
18
|
+
ref,
|
|
19
|
+
variant: config.variant,
|
|
20
|
+
dot,
|
|
21
|
+
live: isLive,
|
|
22
|
+
...rest,
|
|
23
|
+
children: label ?? config.label
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
StatusBadge.displayName = "StatusBadge";
|
|
29
|
+
export {
|
|
30
|
+
StatusBadge
|
|
31
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useState, useCallback, useMemo } from "react";
|
|
4
|
+
function useLegendToggle() {
|
|
5
|
+
const [hiddenSeries, setHiddenSeries] = useState(/* @__PURE__ */ new Set());
|
|
6
|
+
const toggle = useCallback((dataKey) => {
|
|
7
|
+
setHiddenSeries((prev) => {
|
|
8
|
+
const next = new Set(prev);
|
|
9
|
+
if (next.has(dataKey)) next.delete(dataKey);
|
|
10
|
+
else next.add(dataKey);
|
|
11
|
+
return next;
|
|
12
|
+
});
|
|
13
|
+
}, []);
|
|
14
|
+
const isHidden = useCallback(
|
|
15
|
+
(dataKey) => hiddenSeries.has(dataKey),
|
|
16
|
+
[hiddenSeries]
|
|
17
|
+
);
|
|
18
|
+
const reset = useCallback(() => setHiddenSeries(/* @__PURE__ */ new Set()), []);
|
|
19
|
+
const legendProps = useMemo(
|
|
20
|
+
() => ({
|
|
21
|
+
wrapperStyle: {
|
|
22
|
+
fontSize: 12,
|
|
23
|
+
cursor: "pointer"
|
|
24
|
+
},
|
|
25
|
+
onClick: (e) => {
|
|
26
|
+
if (e?.dataKey != null) toggle(String(e.dataKey));
|
|
27
|
+
},
|
|
28
|
+
formatter: (value, entry) => {
|
|
29
|
+
const key = entry?.dataKey != null ? String(entry.dataKey) : "";
|
|
30
|
+
const hidden = hiddenSeries.has(key);
|
|
31
|
+
return /* @__PURE__ */ jsx(
|
|
32
|
+
"span",
|
|
33
|
+
{
|
|
34
|
+
style: {
|
|
35
|
+
color: hidden ? "var(--color-fg-tertiary, #a1a1aa)" : entry?.color,
|
|
36
|
+
transition: "color 0.15s ease"
|
|
37
|
+
},
|
|
38
|
+
children: value
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}),
|
|
43
|
+
[hiddenSeries, toggle]
|
|
44
|
+
);
|
|
45
|
+
return { isHidden, toggle, reset, legendProps };
|
|
46
|
+
}
|
|
47
|
+
export {
|
|
48
|
+
useLegendToggle
|
|
49
|
+
};
|
package/dist/hooks.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { ThemeProvider, useTheme } from "./hooks/useTheme.js";
|
|
3
3
|
import { useFocusTrap } from "./hooks/useFocusTrap.js";
|
|
4
|
+
import { useLegendToggle } from "./hooks/useLegendToggle.js";
|
|
4
5
|
export {
|
|
5
6
|
ThemeProvider,
|
|
6
7
|
useFocusTrap,
|
|
8
|
+
useLegendToggle,
|
|
7
9
|
useTheme
|
|
8
10
|
};
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ import { FilterPill } from "./components/FilterPill/FilterPill.js";
|
|
|
25
25
|
import { FormField } from "./components/FormField/FormField.js";
|
|
26
26
|
import { Grid } from "./components/Grid/Grid.js";
|
|
27
27
|
import { Heading } from "./components/Heading/Heading.js";
|
|
28
|
+
import { HelpButton } from "./components/HelpButton/HelpButton.js";
|
|
28
29
|
import { Hero } from "./components/Hero/Hero.js";
|
|
29
30
|
import { Icon } from "./components/Icon/Icon.js";
|
|
30
31
|
import { Input } from "./components/Input/Input.js";
|
|
@@ -47,6 +48,7 @@ import { Skeleton } from "./components/Skeleton/Skeleton.js";
|
|
|
47
48
|
import { Sparkline } from "./components/Sparkline/Sparkline.js";
|
|
48
49
|
import { SplitSection } from "./components/SplitSection/SplitSection.js";
|
|
49
50
|
import { StatItem, Stats } from "./components/Stats/Stats.js";
|
|
51
|
+
import { StatusBadge } from "./components/StatusBadge/StatusBadge.js";
|
|
50
52
|
import { Stepper } from "./components/Stepper/Stepper.js";
|
|
51
53
|
import { Switch } from "./components/Switch/Switch.js";
|
|
52
54
|
import { Tab, TabGroup, TabPanel, Tabs } from "./components/Tabs/Tabs.js";
|
|
@@ -102,6 +104,7 @@ export {
|
|
|
102
104
|
FormField,
|
|
103
105
|
Grid,
|
|
104
106
|
Heading,
|
|
107
|
+
HelpButton,
|
|
105
108
|
Hero,
|
|
106
109
|
Icon,
|
|
107
110
|
Input,
|
|
@@ -134,6 +137,7 @@ export {
|
|
|
134
137
|
SplitSection,
|
|
135
138
|
StatItem,
|
|
136
139
|
Stats,
|
|
140
|
+
StatusBadge,
|
|
137
141
|
Stepper,
|
|
138
142
|
Switch,
|
|
139
143
|
Tab,
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type ReactNode, type HTMLAttributes } from "react";
|
|
2
|
+
export type EmptyStateSize = "sm" | "md" | "lg";
|
|
2
3
|
export interface EmptyStateProps extends HTMLAttributes<HTMLDivElement> {
|
|
3
4
|
icon?: ReactNode;
|
|
4
5
|
title: string;
|
|
5
|
-
description?:
|
|
6
|
+
description?: ReactNode;
|
|
6
7
|
actions?: ReactNode;
|
|
8
|
+
size?: EmptyStateSize;
|
|
7
9
|
}
|
|
8
10
|
export declare const EmptyState: import("react").ForwardRefExoticComponent<EmptyStateProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { EmptyState } from "./EmptyState";
|
|
2
|
-
export type { EmptyStateProps } from "./EmptyState";
|
|
2
|
+
export type { EmptyStateProps, EmptyStateSize } from "./EmptyState";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type HelpButtonPosition = "top" | "bottom" | "left" | "right";
|
|
3
|
+
export type HelpButtonSize = "sm" | "md" | "lg";
|
|
4
|
+
export interface HelpButtonProps {
|
|
5
|
+
/** Popover title */
|
|
6
|
+
title?: string;
|
|
7
|
+
/** Popover body content */
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
/** Preferred side the popover appears on */
|
|
10
|
+
position?: HelpButtonPosition;
|
|
11
|
+
/** Popover width */
|
|
12
|
+
size?: HelpButtonSize;
|
|
13
|
+
/** Icon shown inside the trigger button (defaults to "?") */
|
|
14
|
+
icon?: ReactNode;
|
|
15
|
+
/** Accessible label for the trigger */
|
|
16
|
+
ariaLabel?: string;
|
|
17
|
+
className?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare const HelpButton: import("react").ForwardRefExoticComponent<HelpButtonProps & import("react").RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type BadgeProps } from "../Badge";
|
|
2
|
+
export type StatusBadgeStatus = "live" | "stale" | "missing" | "manual" | "loading";
|
|
3
|
+
export interface StatusBadgeProps extends Omit<BadgeProps, "variant" | "children"> {
|
|
4
|
+
status: StatusBadgeStatus;
|
|
5
|
+
/** Overrides the default label for the given status */
|
|
6
|
+
label?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare const StatusBadge: import("react").ForwardRefExoticComponent<StatusBadgeProps & import("react").RefAttributes<HTMLSpanElement>>;
|
|
@@ -6,6 +6,10 @@ export { Card, CardHeader, CardTitle, CardDescription, CardBody, CardFooter, } f
|
|
|
6
6
|
export type { CardProps, CardVariant, CardHeaderProps, CardTitleProps, CardDescriptionProps, CardBodyProps, CardFooterProps, } from "./Card";
|
|
7
7
|
export { Badge } from "./Badge";
|
|
8
8
|
export type { BadgeProps, BadgeVariant } from "./Badge";
|
|
9
|
+
export { StatusBadge } from "./StatusBadge";
|
|
10
|
+
export type { StatusBadgeProps, StatusBadgeStatus } from "./StatusBadge";
|
|
11
|
+
export { HelpButton } from "./HelpButton";
|
|
12
|
+
export type { HelpButtonProps, HelpButtonPosition, HelpButtonSize, } from "./HelpButton";
|
|
9
13
|
export { FilterPill } from "./FilterPill";
|
|
10
14
|
export type { FilterPillProps } from "./FilterPill";
|
|
11
15
|
export { Input } from "./Input";
|
|
@@ -79,7 +83,7 @@ export type { SwitchProps } from "./Switch";
|
|
|
79
83
|
export { Skeleton } from "./Skeleton";
|
|
80
84
|
export type { SkeletonProps } from "./Skeleton";
|
|
81
85
|
export { EmptyState } from "./EmptyState";
|
|
82
|
-
export type { EmptyStateProps } from "./EmptyState";
|
|
86
|
+
export type { EmptyStateProps, EmptyStateSize } from "./EmptyState";
|
|
83
87
|
export { Breadcrumb } from "./Breadcrumb";
|
|
84
88
|
export type { BreadcrumbProps, BreadcrumbItem } from "./Breadcrumb";
|
|
85
89
|
export { Pagination } from "./Pagination";
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { useTheme, ThemeProvider } from "./useTheme";
|
|
2
2
|
export type { Theme, ThemeContextValue, ThemeProviderProps } from "./useTheme";
|
|
3
3
|
export { useFocusTrap } from "./useFocusTrap";
|
|
4
|
+
export { useLegendToggle } from "./useLegendToggle";
|
|
5
|
+
export type { UseLegendToggleResult } from "./useLegendToggle";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
|
+
interface RechartsLegendClickEvent {
|
|
3
|
+
dataKey?: string | number;
|
|
4
|
+
value?: string;
|
|
5
|
+
color?: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface UseLegendToggleResult {
|
|
9
|
+
/** Whether a given dataKey is currently hidden */
|
|
10
|
+
isHidden: (dataKey: string) => boolean;
|
|
11
|
+
/** Toggle visibility for a given dataKey */
|
|
12
|
+
toggle: (dataKey: string) => void;
|
|
13
|
+
/** Reset all series to visible */
|
|
14
|
+
reset: () => void;
|
|
15
|
+
/** Props to spread onto a Recharts `<Legend />` */
|
|
16
|
+
legendProps: {
|
|
17
|
+
wrapperStyle: CSSProperties;
|
|
18
|
+
onClick: (e: RechartsLegendClickEvent) => void;
|
|
19
|
+
formatter: (value: string, entry: {
|
|
20
|
+
dataKey?: string | number;
|
|
21
|
+
color?: string;
|
|
22
|
+
}) => React.ReactNode;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Hook for toggling Recharts legend entries to hide/show individual series.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* const { isHidden, legendProps } = useLegendToggle();
|
|
30
|
+
* return (
|
|
31
|
+
* <BarChart data={data}>
|
|
32
|
+
* <Legend {...legendProps} />
|
|
33
|
+
* <Bar dataKey="revenue" hide={isHidden("revenue")} />
|
|
34
|
+
* </BarChart>
|
|
35
|
+
* );
|
|
36
|
+
*/
|
|
37
|
+
export declare function useLegendToggle(): UseLegendToggleResult;
|
|
38
|
+
export {};
|