kaze-design-system 0.2.5 → 0.3.1
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 +118 -0
- package/dist/components/EmptyState/EmptyState.js +15 -6
- package/dist/components/HelpButton/HelpButton.js +127 -0
- package/dist/components/Stats/Stats.js +3 -2
- 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/Stats/Stats.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
|
@@ -1446,6 +1446,11 @@
|
|
|
1446
1446
|
color: var(--color-fg-secondary);
|
|
1447
1447
|
}
|
|
1448
1448
|
|
|
1449
|
+
.stat__description {
|
|
1450
|
+
font-size: var(--font-size-xs);
|
|
1451
|
+
color: var(--color-fg-muted);
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1449
1454
|
/* ── Pricing ─────────────────────────────────────────────── */
|
|
1450
1455
|
.pricing-grid {
|
|
1451
1456
|
display: grid;
|
|
@@ -3241,17 +3246,46 @@
|
|
|
3241
3246
|
gap: var(--space-3);
|
|
3242
3247
|
}
|
|
3243
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
|
+
|
|
3244
3264
|
.empty-state__icon {
|
|
3245
3265
|
color: var(--color-fg-tertiary);
|
|
3246
3266
|
margin-bottom: var(--space-2);
|
|
3247
3267
|
}
|
|
3248
3268
|
|
|
3269
|
+
.empty-state--sm .empty-state__icon {
|
|
3270
|
+
margin-bottom: 0;
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3249
3273
|
.empty-state__title {
|
|
3250
3274
|
font-size: var(--font-size-lg);
|
|
3251
3275
|
font-weight: var(--font-weight-semibold);
|
|
3252
3276
|
color: var(--color-fg);
|
|
3253
3277
|
}
|
|
3254
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
|
+
|
|
3255
3289
|
.empty-state__description {
|
|
3256
3290
|
font-size: var(--font-size-sm);
|
|
3257
3291
|
color: var(--color-fg-secondary);
|
|
@@ -3259,6 +3293,10 @@
|
|
|
3259
3293
|
line-height: var(--line-height-relaxed);
|
|
3260
3294
|
}
|
|
3261
3295
|
|
|
3296
|
+
.empty-state--sm .empty-state__description {
|
|
3297
|
+
font-size: var(--font-size-xs);
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3262
3300
|
.empty-state__actions {
|
|
3263
3301
|
display: flex;
|
|
3264
3302
|
gap: var(--space-3);
|
|
@@ -3950,3 +3988,83 @@
|
|
|
3950
3988
|
font-size: var(--font-size-sm);
|
|
3951
3989
|
color: var(--color-fg-tertiary);
|
|
3952
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
|
+
};
|
|
@@ -8,10 +8,11 @@ const Stats = forwardRef(
|
|
|
8
8
|
);
|
|
9
9
|
Stats.displayName = "Stats";
|
|
10
10
|
const StatItem = forwardRef(
|
|
11
|
-
({ value, label, className, ...rest }, ref) => {
|
|
11
|
+
({ value, label, description, className, ...rest }, ref) => {
|
|
12
12
|
return /* @__PURE__ */ jsxs("div", { ref, className: cn("stat", className), ...rest, children: [
|
|
13
13
|
/* @__PURE__ */ jsx("span", { className: "stat__value", children: value }),
|
|
14
|
-
/* @__PURE__ */ jsx("span", { className: "stat__label", children: label })
|
|
14
|
+
/* @__PURE__ */ jsx("span", { className: "stat__label", children: label }),
|
|
15
|
+
description && /* @__PURE__ */ jsx("span", { className: "stat__description", children: description })
|
|
15
16
|
] });
|
|
16
17
|
}
|
|
17
18
|
);
|
|
@@ -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>>;
|
|
@@ -5,5 +5,7 @@ export declare const Stats: import("react").ForwardRefExoticComponent<StatsProps
|
|
|
5
5
|
export interface StatItemProps extends HTMLAttributes<HTMLDivElement> {
|
|
6
6
|
value: string;
|
|
7
7
|
label: string;
|
|
8
|
+
/** Optional description / sub-text below the label */
|
|
9
|
+
description?: string;
|
|
8
10
|
}
|
|
9
11
|
export declare const StatItem: import("react").ForwardRefExoticComponent<StatItemProps & import("react").RefAttributes<HTMLDivElement>>;
|
|
@@ -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 {};
|