@lablup/ui-common 0.1.0-alpha.18 → 0.1.0-alpha.19
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/assets/components/Select/Select.css +1 -0
- package/dist/components/Select/Select.d.ts +38 -0
- package/dist/components/Select/Select2.js +313 -0
- package/dist/components/Select/Select2.js.map +1 -0
- package/dist/components/Select/index.d.ts +2 -0
- package/dist/components/Select/index.js +2 -0
- package/dist/components/Skeleton/Skeleton.d.ts +11 -1
- package/dist/components/Skeleton/Skeleton2.js +8 -6
- package/dist/components/Skeleton/Skeleton2.js.map +1 -1
- package/dist/components/Skeleton/SkeletonCard.d.ts +1 -1
- package/dist/components/Skeleton/SkeletonCard2.js +10 -9
- package/dist/components/Skeleton/SkeletonCard2.js.map +1 -1
- package/dist/components/Skeleton/SkeletonChart2.js +5 -0
- package/dist/components/Skeleton/SkeletonChart2.js.map +1 -1
- package/dist/components/Skeleton/SkeletonRow.d.ts +1 -1
- package/dist/components/Skeleton/SkeletonRow2.js +6 -5
- package/dist/components/Skeleton/SkeletonRow2.js.map +1 -1
- package/dist/components/Skeleton/SkeletonText.d.ts +1 -1
- package/dist/components/Skeleton/SkeletonText2.js +2 -1
- package/dist/components/Skeleton/SkeletonText2.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -7
- package/dist/styles/base.css +7 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.select{display:inline-block;position:relative}.select--full-width{width:100%;display:block}.select--labelled{gap:var(--token-paddingXS);flex-direction:column;display:flex}.select__label{font-size:var(--token-fontSizeSM);color:var(--token-colorTextSecondary);font-weight:500}.select__trigger{justify-content:space-between;align-items:center;gap:var(--token-paddingSM);width:100%;min-height:var(--token-controlHeight);padding:var(--token-paddingXS) var(--token-padding);font-size:var(--token-fontSize);font-family:var(--token-fontFamily);color:var(--token-colorText);background-color:var(--token-colorBgContainer);border:1px solid var(--token-colorBorder);border-radius:var(--token-borderRadius);cursor:pointer;transition:all var(--token-motionDurationFast);text-align:left;display:flex}.select__trigger:hover:not(:disabled){border-color:var(--token-colorPrimary)}.select__trigger:focus{border-color:color-mix(in srgb, var(--token-colorPrimary) 70%, var(--token-colorText));box-shadow:0 0 0 2px var(--token-colorPrimaryBg);outline:none}.select--open .select__trigger{border-color:var(--token-colorPrimary);box-shadow:0 0 0 2px var(--token-colorPrimaryBg);border-bottom-right-radius:0;border-bottom-left-radius:0}.select--disabled .select__trigger{cursor:not-allowed;opacity:.6;background-color:var(--token-colorFillTertiary)}.select--small .select__trigger{min-height:var(--token-controlHeightSM);padding:var(--token-paddingXS) var(--token-paddingSM);font-size:var(--token-fontSizeSM)}.select--medium .select__trigger{min-height:var(--token-controlHeight);padding:var(--token-paddingXS) var(--token-padding);font-size:var(--token-fontSize)}.select--large .select__trigger{min-height:var(--token-controlHeightLG);padding:var(--token-paddingSM) var(--token-padding);font-size:var(--token-fontSize)}.select__trigger{min-width:120px}.select__value{align-items:center;gap:var(--token-paddingSM);flex:1;min-width:0;display:flex;overflow:hidden}.select__value-icon{color:var(--token-colorTextSecondary);flex-shrink:0;justify-content:center;align-items:center;display:flex}.select__value-label{text-overflow:ellipsis;white-space:nowrap;font-weight:500;overflow:hidden}.select__placeholder{color:var(--token-colorTextTertiary)}.select__chevron{color:var(--token-colorTextSecondary);transition:transform var(--token-motionDurationFast);flex-shrink:0;justify-content:center;align-items:center;display:flex}.select__chevron--open{transform:rotate(180deg)}.select__dropdown{z-index:var(--token-zIndexPopover);background:var(--token-colorBgElevated);border:1px solid var(--token-colorPrimary);border-radius:0 0 var(--token-borderRadius) var(--token-borderRadius);box-shadow:var(--token-boxShadowSecondary);border-top:none;flex-direction:column;max-height:240px;animation:.15s ease-out selectDropdownOpen;display:flex;position:absolute;top:100%;left:0;right:0;overflow:hidden}.select__dropdown--portal{border:1px solid var(--token-colorBorder);border-radius:var(--token-borderRadius);z-index:var(--token-zIndexTooltip);position:fixed}.select__search{padding:var(--token-paddingSM);background:var(--token-colorBgElevated);border-bottom:1px solid var(--token-colorBorderSecondary);flex-shrink:0}.select__search-input{box-sizing:border-box;width:100%;padding:var(--token-paddingXS) var(--token-paddingSM);font-family:var(--token-fontFamily);font-size:var(--token-fontSize);color:var(--token-colorText);background:var(--token-colorBgContainer);border:1px solid var(--token-colorBorder);border-radius:var(--token-borderRadiusSM);transition:border-color var(--token-motionDurationFast), box-shadow var(--token-motionDurationFast)}.select__search-input::placeholder{color:var(--token-colorTextPlaceholder)}.select__search-input:focus-visible{border-color:color-mix(in srgb, var(--token-colorPrimary) 70%, var(--token-colorText));box-shadow:0 0 0 2px var(--token-colorPrimaryBg);outline:none}.select__options{min-height:0;overflow-y:auto}@keyframes selectDropdownOpen{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.select__options::-webkit-scrollbar{width:var(--token-scrollbarSize);height:var(--token-scrollbarSize)}.select__options::-webkit-scrollbar-track{background:0 0}.select__options::-webkit-scrollbar-thumb{background-color:var(--token-colorBorder);border-radius:var(--token-scrollbarRadius)}.select__options::-webkit-scrollbar-thumb:hover{background-color:var(--token-colorTextTertiary)}.select__option{align-items:center;gap:var(--token-paddingSM);padding:var(--token-paddingSM) var(--token-padding);font-size:var(--token-fontSize);color:var(--token-colorText);cursor:pointer;transition:background-color var(--token-motionDurationFast);-webkit-user-select:none;user-select:none;display:flex}.select__option--disabled{color:var(--token-colorTextDisabled);cursor:not-allowed}.select__option:first-child{border-radius:0}.select__option:last-child{border-radius:0 0 var(--token-borderRadius) var(--token-borderRadius)}.select__option:hover:not(.select__option--disabled),.select__option--focused:not(.select__option--disabled){background-color:var(--token-colorFillSecondary)}.select__option--selected{background-color:var(--token-colorPrimaryBg)}.select__option--selected:hover,.select__option--selected.select__option--focused{background-color:var(--token-colorPrimaryBgHover)}.select__option-icon{width:20px;height:20px;color:var(--token-colorTextSecondary);flex-shrink:0;justify-content:center;align-items:center;display:flex}.select__option--selected .select__option-icon{color:var(--token-colorPrimary)}.select__option-content{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.select__option-label{font-weight:500}.select__option--selected .select__option-label{color:var(--token-colorPrimary)}.select__option-description{font-size:var(--token-fontSizeSM);color:var(--token-colorTextTertiary)}.select__option-check{color:var(--token-colorPrimary);flex-shrink:0;justify-content:center;align-items:center;display:flex}.select__empty{padding:var(--token-padding) var(--token-paddingMD);color:var(--token-colorTextTertiary);text-align:center;font-style:italic}.select--large .select__option{padding:var(--token-paddingSM) var(--token-paddingMD);font-size:var(--token-fontSize)}.select--large .select__option-icon{width:24px;height:24px}.select--large .select__option-description{font-size:var(--token-fontSizeSM)}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export interface SelectOption<T extends string = string> {
|
|
3
|
+
value: T;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
icon?: ReactNode;
|
|
7
|
+
/** Keep an unavailable choice visible while preventing its selection. */
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface SelectProps<T extends string = string> {
|
|
11
|
+
value: T;
|
|
12
|
+
onChange: (value: T) => void;
|
|
13
|
+
onBlur?: () => void;
|
|
14
|
+
options: SelectOption<T>[];
|
|
15
|
+
/**
|
|
16
|
+
* Field label rendered above the trigger, the way `TextInput` renders its
|
|
17
|
+
* own. Names the trigger and the listbox through `aria-labelledby`, so a
|
|
18
|
+
* caller that supplies it does not also need `aria-label`.
|
|
19
|
+
*/
|
|
20
|
+
label?: ReactNode;
|
|
21
|
+
placeholder?: string;
|
|
22
|
+
disabled?: boolean;
|
|
23
|
+
size?: "small" | "default" | "medium" | "large";
|
|
24
|
+
fullWidth?: boolean;
|
|
25
|
+
className?: string;
|
|
26
|
+
searchable?: boolean;
|
|
27
|
+
searchPlaceholder?: string;
|
|
28
|
+
"aria-label"?: string;
|
|
29
|
+
"aria-describedby"?: string;
|
|
30
|
+
invalid?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Shown in place of the list when a search matches nothing. English default,
|
|
33
|
+
* because this package cannot resolve a consumer's locale key: a product that
|
|
34
|
+
* localises passes its own words.
|
|
35
|
+
*/
|
|
36
|
+
noOptionsLabel?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function Select<T extends string = string>({ value, onChange, onBlur, options, label, placeholder, disabled, size, fullWidth, className, searchable, searchPlaceholder, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, invalid, noOptionsLabel, }: SelectProps<T>): import("react").JSX.Element;
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/* empty css */
|
|
2
|
+
import { useCallback as e, useEffect as t, useId as n, useMemo as r, useRef as i, useState as a } from "react";
|
|
3
|
+
import { jsx as o, jsxs as s } from "react/jsx-runtime";
|
|
4
|
+
import { createPortal as c } from "react-dom";
|
|
5
|
+
//#region src/components/Select/Select.tsx
|
|
6
|
+
function l({ value: l, onChange: u, onBlur: d, options: f, label: p, placeholder: ee = "Select...", disabled: m = !1, size: h = "default", fullWidth: g = !1, className: _ = "", searchable: v = !1, searchPlaceholder: y, "aria-label": b, "aria-describedby": x, invalid: S = !1, noOptionsLabel: C = "No options" }) {
|
|
7
|
+
let [w, T] = a(!1), [E, D] = a(-1), [O, k] = a(""), [A, te] = a({
|
|
8
|
+
top: 0,
|
|
9
|
+
left: 0,
|
|
10
|
+
width: 0
|
|
11
|
+
}), j = i(null), M = i(null), N = i(null), P = i(null), F = i([]), I = n(), L = n(), R = n(), z = p != null && p !== !1, B = f.find((e) => e.value === l), V = r(() => {
|
|
12
|
+
let e = O.trim().toLowerCase();
|
|
13
|
+
return !v || e.length === 0 ? f : f.filter((t) => [
|
|
14
|
+
t.label,
|
|
15
|
+
t.value,
|
|
16
|
+
t.description ?? ""
|
|
17
|
+
].some((t) => t.toLowerCase().includes(e)));
|
|
18
|
+
}, [
|
|
19
|
+
f,
|
|
20
|
+
O,
|
|
21
|
+
v
|
|
22
|
+
]), H = e((e, t) => {
|
|
23
|
+
for (let n = e; n >= 0 && n < V.length; n += t) {
|
|
24
|
+
let e = V[n];
|
|
25
|
+
if (e && !e.disabled) return n;
|
|
26
|
+
}
|
|
27
|
+
return -1;
|
|
28
|
+
}, [V]), U = (e) => `${L}-option-${String(e)}`, W = E >= 0 ? U(E) : void 0, G = e(() => {
|
|
29
|
+
if (!M.current) return;
|
|
30
|
+
let e = M.current.getBoundingClientRect();
|
|
31
|
+
te({
|
|
32
|
+
top: e.bottom + 4,
|
|
33
|
+
left: e.left,
|
|
34
|
+
width: e.width
|
|
35
|
+
});
|
|
36
|
+
}, []), K = e(() => {
|
|
37
|
+
if (m) return;
|
|
38
|
+
G(), T(!0);
|
|
39
|
+
let e = V.findIndex((e) => e.value === l && !e.disabled);
|
|
40
|
+
D(e === -1 ? H(0, 1) : e);
|
|
41
|
+
}, [
|
|
42
|
+
m,
|
|
43
|
+
V,
|
|
44
|
+
l,
|
|
45
|
+
G,
|
|
46
|
+
H
|
|
47
|
+
]), q = e(() => {
|
|
48
|
+
T(!1), D(-1), k(""), M.current?.focus();
|
|
49
|
+
}, []), J = e((e, t) => {
|
|
50
|
+
t && (t.stopPropagation(), t.preventDefault()), !e.disabled && (u(e.value), q());
|
|
51
|
+
}, [u, q]);
|
|
52
|
+
t(() => {
|
|
53
|
+
let e = (e) => {
|
|
54
|
+
if (!w) return;
|
|
55
|
+
let t = e.target, n = j.current && !j.current.contains(t), r = N.current && !N.current.contains(t);
|
|
56
|
+
n && r && q();
|
|
57
|
+
}, t = (e) => {
|
|
58
|
+
e.key === "Escape" && w && q();
|
|
59
|
+
};
|
|
60
|
+
return w && (document.addEventListener("mousedown", e), document.addEventListener("keydown", t)), () => {
|
|
61
|
+
document.removeEventListener("mousedown", e), document.removeEventListener("keydown", t);
|
|
62
|
+
};
|
|
63
|
+
}, [w, q]), t(() => {
|
|
64
|
+
if (!w) return;
|
|
65
|
+
let e = () => {
|
|
66
|
+
G();
|
|
67
|
+
};
|
|
68
|
+
return window.addEventListener("resize", e), window.addEventListener("scroll", e, !0), () => {
|
|
69
|
+
window.removeEventListener("resize", e), window.removeEventListener("scroll", e, !0);
|
|
70
|
+
};
|
|
71
|
+
}, [w, G]), t(() => {
|
|
72
|
+
w && v && P.current?.focus();
|
|
73
|
+
}, [w, v]), t(() => {
|
|
74
|
+
if (!w || !v) return;
|
|
75
|
+
F.current = [];
|
|
76
|
+
let e = V.findIndex((e) => e.value === l && !e.disabled);
|
|
77
|
+
D(e >= 0 ? e : H(0, 1));
|
|
78
|
+
}, [
|
|
79
|
+
w,
|
|
80
|
+
O,
|
|
81
|
+
v,
|
|
82
|
+
l,
|
|
83
|
+
V,
|
|
84
|
+
H
|
|
85
|
+
]);
|
|
86
|
+
let Y = e((e) => {
|
|
87
|
+
if (!m) switch (e.key) {
|
|
88
|
+
case "Enter":
|
|
89
|
+
case " ":
|
|
90
|
+
if (e.preventDefault(), w) {
|
|
91
|
+
let e = V[E];
|
|
92
|
+
e && J(e);
|
|
93
|
+
} else K();
|
|
94
|
+
break;
|
|
95
|
+
case "Escape":
|
|
96
|
+
e.preventDefault(), w && q();
|
|
97
|
+
break;
|
|
98
|
+
case "ArrowDown":
|
|
99
|
+
if (e.preventDefault(), !w) K();
|
|
100
|
+
else {
|
|
101
|
+
let e = H(E + 1, 1);
|
|
102
|
+
e >= 0 && D(e);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case "ArrowUp":
|
|
106
|
+
if (e.preventDefault(), w) {
|
|
107
|
+
let e = H(E - 1, -1);
|
|
108
|
+
e >= 0 && D(e);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
case "Tab": w && q();
|
|
112
|
+
}
|
|
113
|
+
}, [
|
|
114
|
+
m,
|
|
115
|
+
w,
|
|
116
|
+
E,
|
|
117
|
+
V,
|
|
118
|
+
H,
|
|
119
|
+
K,
|
|
120
|
+
q,
|
|
121
|
+
J
|
|
122
|
+
]), X = e((e) => {
|
|
123
|
+
switch (e.key) {
|
|
124
|
+
case "Enter": {
|
|
125
|
+
e.preventDefault();
|
|
126
|
+
let t = V[E];
|
|
127
|
+
t && J(t);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
case "Escape":
|
|
131
|
+
e.preventDefault(), e.stopPropagation(), q();
|
|
132
|
+
break;
|
|
133
|
+
case "ArrowDown":
|
|
134
|
+
e.preventDefault(), D((e) => {
|
|
135
|
+
let t = H(e + 1, 1);
|
|
136
|
+
return t >= 0 ? t : e;
|
|
137
|
+
});
|
|
138
|
+
break;
|
|
139
|
+
case "ArrowUp":
|
|
140
|
+
e.preventDefault(), D((e) => {
|
|
141
|
+
let t = H(e - 1, -1);
|
|
142
|
+
return t >= 0 ? t : e;
|
|
143
|
+
});
|
|
144
|
+
break;
|
|
145
|
+
case "Tab": q();
|
|
146
|
+
}
|
|
147
|
+
}, [
|
|
148
|
+
q,
|
|
149
|
+
E,
|
|
150
|
+
J,
|
|
151
|
+
V,
|
|
152
|
+
H
|
|
153
|
+
]);
|
|
154
|
+
t(() => {
|
|
155
|
+
let e = F.current[E];
|
|
156
|
+
w && E >= 0 && e && e.scrollIntoView({
|
|
157
|
+
block: "nearest",
|
|
158
|
+
behavior: "smooth"
|
|
159
|
+
});
|
|
160
|
+
}, [w, E]);
|
|
161
|
+
let Z = h === "default" ? "" : `select--${h}`, ne = g ? "select--full-width" : "", re = z ? "select--labelled" : "", Q = z ? R : void 0, $ = y ?? b;
|
|
162
|
+
return /* @__PURE__ */ s("div", {
|
|
163
|
+
ref: j,
|
|
164
|
+
className: `select ${Z} ${ne} ${re} ${w ? "select--open" : ""} ${m ? "select--disabled" : ""} ${_}`,
|
|
165
|
+
children: [
|
|
166
|
+
z && /* @__PURE__ */ o("span", {
|
|
167
|
+
className: "select__label",
|
|
168
|
+
id: R,
|
|
169
|
+
children: p
|
|
170
|
+
}),
|
|
171
|
+
/* @__PURE__ */ s("button", {
|
|
172
|
+
ref: M,
|
|
173
|
+
type: "button",
|
|
174
|
+
className: "select__trigger",
|
|
175
|
+
onClick: () => {
|
|
176
|
+
w ? q() : K();
|
|
177
|
+
},
|
|
178
|
+
onKeyDown: Y,
|
|
179
|
+
onBlur: d,
|
|
180
|
+
disabled: m,
|
|
181
|
+
"aria-haspopup": "listbox",
|
|
182
|
+
"aria-expanded": w,
|
|
183
|
+
"aria-controls": w ? I : void 0,
|
|
184
|
+
"aria-activedescendant": w ? W : void 0,
|
|
185
|
+
"aria-label": b,
|
|
186
|
+
"aria-labelledby": Q,
|
|
187
|
+
"aria-describedby": x,
|
|
188
|
+
"aria-invalid": S || void 0,
|
|
189
|
+
children: [B ? /* @__PURE__ */ s("span", {
|
|
190
|
+
className: "select__value",
|
|
191
|
+
children: [B.icon && /* @__PURE__ */ o("span", {
|
|
192
|
+
className: "select__value-icon",
|
|
193
|
+
children: B.icon
|
|
194
|
+
}), /* @__PURE__ */ o("span", {
|
|
195
|
+
className: "select__value-label",
|
|
196
|
+
children: B.label
|
|
197
|
+
})]
|
|
198
|
+
}) : /* @__PURE__ */ o("span", {
|
|
199
|
+
className: "select__placeholder",
|
|
200
|
+
children: ee
|
|
201
|
+
}), /* @__PURE__ */ o("span", {
|
|
202
|
+
className: `select__chevron ${w ? "select__chevron--open" : ""}`,
|
|
203
|
+
children: /* @__PURE__ */ o("svg", {
|
|
204
|
+
width: "10",
|
|
205
|
+
height: "6",
|
|
206
|
+
viewBox: "0 0 10 6",
|
|
207
|
+
fill: "none",
|
|
208
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
209
|
+
children: /* @__PURE__ */ o("path", {
|
|
210
|
+
d: "M1 1L5 5L9 1",
|
|
211
|
+
stroke: "currentColor",
|
|
212
|
+
strokeWidth: "1.5",
|
|
213
|
+
strokeLinecap: "round",
|
|
214
|
+
strokeLinejoin: "round"
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
})]
|
|
218
|
+
}),
|
|
219
|
+
w && c(/* @__PURE__ */ s("div", {
|
|
220
|
+
ref: N,
|
|
221
|
+
className: "select__dropdown select__dropdown--portal",
|
|
222
|
+
style: {
|
|
223
|
+
position: "fixed",
|
|
224
|
+
top: `${String(A.top)}px`,
|
|
225
|
+
left: `${String(A.left)}px`,
|
|
226
|
+
width: `${String(A.width)}px`
|
|
227
|
+
},
|
|
228
|
+
children: [v && /* @__PURE__ */ o("div", {
|
|
229
|
+
className: "select__search",
|
|
230
|
+
children: /* @__PURE__ */ o("input", {
|
|
231
|
+
ref: P,
|
|
232
|
+
className: "select__search-input",
|
|
233
|
+
type: "search",
|
|
234
|
+
value: O,
|
|
235
|
+
onChange: (e) => k(e.currentTarget.value),
|
|
236
|
+
onKeyDown: X,
|
|
237
|
+
placeholder: y,
|
|
238
|
+
"aria-label": $,
|
|
239
|
+
"aria-labelledby": $ ? void 0 : Q,
|
|
240
|
+
"aria-controls": I,
|
|
241
|
+
"aria-activedescendant": W,
|
|
242
|
+
autoComplete: "off",
|
|
243
|
+
spellCheck: !1
|
|
244
|
+
})
|
|
245
|
+
}), /* @__PURE__ */ o("div", {
|
|
246
|
+
className: "select__options",
|
|
247
|
+
role: "listbox",
|
|
248
|
+
id: I,
|
|
249
|
+
"aria-label": b,
|
|
250
|
+
"aria-labelledby": Q,
|
|
251
|
+
children: V.length === 0 ? /* @__PURE__ */ o("div", {
|
|
252
|
+
className: "select__empty",
|
|
253
|
+
children: C
|
|
254
|
+
}) : V.map((e, t) => /* @__PURE__ */ s("div", {
|
|
255
|
+
id: U(t),
|
|
256
|
+
ref: (e) => {
|
|
257
|
+
F.current[t] = e;
|
|
258
|
+
},
|
|
259
|
+
className: `select__option ${e.value === l ? "select__option--selected" : ""} ${t === E ? "select__option--focused" : ""} ${e.disabled ? "select__option--disabled" : ""}`,
|
|
260
|
+
role: "option",
|
|
261
|
+
"aria-selected": e.value === l,
|
|
262
|
+
"aria-disabled": e.disabled || void 0,
|
|
263
|
+
"aria-label": e.description ? e.label + ". " + e.description : void 0,
|
|
264
|
+
onClick: (t) => {
|
|
265
|
+
J(e, t);
|
|
266
|
+
},
|
|
267
|
+
onMouseEnter: () => {
|
|
268
|
+
e.disabled || D(t);
|
|
269
|
+
},
|
|
270
|
+
children: [
|
|
271
|
+
e.icon && /* @__PURE__ */ o("span", {
|
|
272
|
+
className: "select__option-icon",
|
|
273
|
+
children: e.icon
|
|
274
|
+
}),
|
|
275
|
+
/* @__PURE__ */ s("div", {
|
|
276
|
+
className: "select__option-content",
|
|
277
|
+
children: [/* @__PURE__ */ o("span", {
|
|
278
|
+
className: "select__option-label",
|
|
279
|
+
children: e.label
|
|
280
|
+
}), e.description && /* @__PURE__ */ o("span", {
|
|
281
|
+
className: "select__option-description",
|
|
282
|
+
children: e.description
|
|
283
|
+
})]
|
|
284
|
+
}),
|
|
285
|
+
e.value === l && /* @__PURE__ */ o("span", {
|
|
286
|
+
className: "select__option-check",
|
|
287
|
+
children: /* @__PURE__ */ o("svg", {
|
|
288
|
+
width: "14",
|
|
289
|
+
height: "10",
|
|
290
|
+
viewBox: "0 0 14 10",
|
|
291
|
+
fill: "none",
|
|
292
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
293
|
+
children: /* @__PURE__ */ o("path", {
|
|
294
|
+
d: "M1 5L5 9L13 1",
|
|
295
|
+
stroke: "currentColor",
|
|
296
|
+
strokeWidth: "2",
|
|
297
|
+
strokeLinecap: "round",
|
|
298
|
+
strokeLinejoin: "round"
|
|
299
|
+
})
|
|
300
|
+
})
|
|
301
|
+
})
|
|
302
|
+
]
|
|
303
|
+
}, e.value))
|
|
304
|
+
})]
|
|
305
|
+
}), document.body)
|
|
306
|
+
]
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
//#endregion
|
|
310
|
+
export { l as Select };
|
|
311
|
+
|
|
312
|
+
//# sourceMappingURL=Select2.js.map
|
|
313
|
+
import "../../assets/components/Select/Select.css";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Select2.js","names":[],"sources":["../../../src/components/Select/Select.tsx"],"sourcesContent":["/**\n * Select Component\n *\n * Single-select listbox with an optional search filter, icons, descriptions and\n * a disabled-but-visible option state. The listbox is portalled, so a select\n * near the bottom of a scrolling panel is not clipped by it.\n *\n * Every string it renders arrives as a prop with an English default, so the\n * component resolves no locale key of its own.\n */\n\nimport { useState, useRef, useEffect, useCallback, useId, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport \"./Select.css\";\n\nexport interface SelectOption<T extends string = string> {\n value: T;\n label: string;\n description?: string;\n icon?: ReactNode;\n /** Keep an unavailable choice visible while preventing its selection. */\n disabled?: boolean;\n}\n\nexport interface SelectProps<T extends string = string> {\n value: T;\n onChange: (value: T) => void;\n onBlur?: () => void;\n options: SelectOption<T>[];\n /**\n * Field label rendered above the trigger, the way `TextInput` renders its\n * own. Names the trigger and the listbox through `aria-labelledby`, so a\n * caller that supplies it does not also need `aria-label`.\n */\n label?: ReactNode;\n placeholder?: string;\n disabled?: boolean;\n size?: \"small\" | \"default\" | \"medium\" | \"large\";\n fullWidth?: boolean;\n className?: string;\n searchable?: boolean;\n searchPlaceholder?: string;\n \"aria-label\"?: string;\n \"aria-describedby\"?: string;\n invalid?: boolean;\n /**\n * Shown in place of the list when a search matches nothing. English default,\n * because this package cannot resolve a consumer's locale key: a product that\n * localises passes its own words.\n */\n noOptionsLabel?: string;\n}\n\nexport function Select<T extends string = string>({\n value,\n onChange,\n onBlur,\n options,\n label,\n placeholder = \"Select...\",\n disabled = false,\n size = \"default\",\n fullWidth = false,\n className = \"\",\n searchable = false,\n searchPlaceholder,\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n invalid = false,\n noOptionsLabel = \"No options\",\n}: SelectProps<T>) {\n const [isOpen, setIsOpen] = useState(false);\n const [focusedIndex, setFocusedIndex] = useState(-1);\n const [searchQuery, setSearchQuery] = useState(\"\");\n const [dropdownPosition, setDropdownPosition] = useState({\n top: 0,\n left: 0,\n width: 0,\n });\n\n const containerRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLButtonElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const searchInputRef = useRef<HTMLInputElement>(null);\n const optionsRef = useRef<(HTMLDivElement | null)[]>([]);\n const listboxId = useId();\n const optionIdPrefix = useId();\n const labelId = useId();\n const hasLabel = label !== undefined && label !== null && label !== false;\n\n // Find selected option\n const selectedOption = options.find((opt) => opt.value === value);\n const visibleOptions = useMemo(() => {\n const normalizedQuery = searchQuery.trim().toLowerCase();\n if (!searchable || normalizedQuery.length === 0) return options;\n return options.filter((option) =>\n [option.label, option.value, option.description ?? \"\"].some((candidate) =>\n candidate.toLowerCase().includes(normalizedQuery),\n ),\n );\n }, [options, searchQuery, searchable]);\n\n const findEnabledIndex = useCallback(\n (start: number, step: 1 | -1): number => {\n for (\n let index = start;\n index >= 0 && index < visibleOptions.length;\n index += step\n ) {\n const option = visibleOptions[index];\n if (option && !option.disabled) return index;\n }\n return -1;\n },\n [visibleOptions],\n );\n\n // Generate unique option ID\n const getOptionId = (index: number) => `${optionIdPrefix}-option-${String(index)}`;\n\n // Get active descendant ID for screen readers\n const activeDescendantId = focusedIndex >= 0 ? getOptionId(focusedIndex) : undefined;\n\n // Calculate dropdown position\n const updateDropdownPosition = useCallback(() => {\n if (!triggerRef.current) return;\n\n const rect = triggerRef.current.getBoundingClientRect();\n setDropdownPosition({\n top: rect.bottom + 4,\n left: rect.left,\n width: rect.width, // Use trigger width as minimum, but allow expansion\n });\n }, []);\n\n // Open dropdown\n const openDropdown = useCallback(() => {\n if (disabled) return;\n updateDropdownPosition();\n setIsOpen(true);\n const selectedIndex = visibleOptions.findIndex(\n (opt) => opt.value === value && !opt.disabled,\n );\n setFocusedIndex(selectedIndex !== -1 ? selectedIndex : findEnabledIndex(0, 1));\n }, [disabled, visibleOptions, value, updateDropdownPosition, findEnabledIndex]);\n\n // Close dropdown\n const closeDropdown = useCallback(() => {\n setIsOpen(false);\n setFocusedIndex(-1);\n setSearchQuery(\"\");\n triggerRef.current?.focus();\n }, []);\n\n // Handle option selection\n const selectOption = useCallback(\n (option: SelectOption<T>, e?: React.MouseEvent) => {\n if (e) {\n e.stopPropagation();\n e.preventDefault();\n }\n if (option.disabled) return;\n onChange(option.value);\n closeDropdown();\n },\n [onChange, closeDropdown],\n );\n\n // Handle click outside to close\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (!isOpen) return;\n const target = event.target as Node;\n // Check if click is outside both the container and the dropdown (which is portaled)\n const isOutsideContainer =\n containerRef.current && !containerRef.current.contains(target);\n const isOutsideDropdown =\n dropdownRef.current && !dropdownRef.current.contains(target);\n if (isOutsideContainer && isOutsideDropdown) {\n closeDropdown();\n }\n };\n\n const handleEscape = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" && isOpen) {\n closeDropdown();\n }\n };\n\n if (isOpen) {\n document.addEventListener(\"mousedown\", handleClickOutside);\n document.addEventListener(\"keydown\", handleEscape);\n }\n\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n document.removeEventListener(\"keydown\", handleEscape);\n };\n }, [isOpen, closeDropdown]);\n\n // Handle window resize/scroll to update dropdown position\n useEffect(() => {\n if (!isOpen) return;\n\n const handlePositionUpdate = () => {\n updateDropdownPosition();\n };\n\n window.addEventListener(\"resize\", handlePositionUpdate);\n window.addEventListener(\"scroll\", handlePositionUpdate, true);\n\n return () => {\n window.removeEventListener(\"resize\", handlePositionUpdate);\n window.removeEventListener(\"scroll\", handlePositionUpdate, true);\n };\n }, [isOpen, updateDropdownPosition]);\n\n useEffect(() => {\n if (isOpen && searchable) {\n searchInputRef.current?.focus();\n }\n }, [isOpen, searchable]);\n\n useEffect(() => {\n if (!isOpen || !searchable) return;\n optionsRef.current = [];\n const selectedIndex = visibleOptions.findIndex(\n (option) => option.value === value && !option.disabled,\n );\n setFocusedIndex(selectedIndex >= 0 ? selectedIndex : findEnabledIndex(0, 1));\n }, [isOpen, searchQuery, searchable, value, visibleOptions, findEnabledIndex]);\n\n // Keyboard navigation\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled) return;\n\n switch (e.key) {\n case \"Enter\":\n case \" \":\n e.preventDefault();\n if (isOpen) {\n const focusedOption = visibleOptions[focusedIndex];\n if (focusedOption) {\n selectOption(focusedOption);\n }\n } else {\n openDropdown();\n }\n break;\n\n case \"Escape\":\n e.preventDefault();\n if (isOpen) {\n closeDropdown();\n }\n break;\n\n case \"ArrowDown\":\n e.preventDefault();\n if (!isOpen) {\n openDropdown();\n } else {\n const nextIndex = findEnabledIndex(focusedIndex + 1, 1);\n if (nextIndex >= 0) setFocusedIndex(nextIndex);\n }\n break;\n\n case \"ArrowUp\":\n e.preventDefault();\n if (isOpen) {\n const previousIndex = findEnabledIndex(focusedIndex - 1, -1);\n if (previousIndex >= 0) setFocusedIndex(previousIndex);\n }\n break;\n\n case \"Tab\":\n if (isOpen) {\n closeDropdown();\n }\n break;\n }\n },\n [\n disabled,\n isOpen,\n focusedIndex,\n visibleOptions,\n findEnabledIndex,\n openDropdown,\n closeDropdown,\n selectOption,\n ],\n );\n\n const handleSearchKeyDown = useCallback(\n (event: React.KeyboardEvent<HTMLInputElement>) => {\n switch (event.key) {\n case \"Enter\": {\n event.preventDefault();\n const focusedOption = visibleOptions[focusedIndex];\n if (focusedOption) selectOption(focusedOption);\n break;\n }\n case \"Escape\":\n event.preventDefault();\n event.stopPropagation();\n closeDropdown();\n break;\n case \"ArrowDown\":\n event.preventDefault();\n setFocusedIndex((current) => {\n const nextIndex = findEnabledIndex(current + 1, 1);\n return nextIndex >= 0 ? nextIndex : current;\n });\n break;\n case \"ArrowUp\":\n event.preventDefault();\n setFocusedIndex((current) => {\n const previousIndex = findEnabledIndex(current - 1, -1);\n return previousIndex >= 0 ? previousIndex : current;\n });\n break;\n case \"Tab\":\n closeDropdown();\n break;\n }\n },\n [closeDropdown, focusedIndex, selectOption, visibleOptions, findEnabledIndex],\n );\n\n // Scroll focused option into view\n useEffect(() => {\n const focusedElement = optionsRef.current[focusedIndex];\n if (isOpen && focusedIndex >= 0 && focusedElement) {\n focusedElement.scrollIntoView({\n block: \"nearest\",\n behavior: \"smooth\",\n });\n }\n }, [isOpen, focusedIndex]);\n\n const sizeClass = size !== \"default\" ? `select--${size}` : \"\";\n const widthClass = fullWidth ? \"select--full-width\" : \"\";\n const labelledClass = hasLabel ? \"select--labelled\" : \"\";\n // aria-labelledby wins over aria-label in the accessible-name calculation,\n // so a caller may pass either; the rendered label is preferred when present.\n const labelledBy = hasLabel ? labelId : undefined;\n const searchFieldLabel = searchPlaceholder ?? ariaLabel;\n\n return (\n <div\n ref={containerRef}\n className={`select ${sizeClass} ${widthClass} ${labelledClass} ${isOpen ? \"select--open\" : \"\"} ${disabled ? \"select--disabled\" : \"\"} ${className}`}\n >\n {hasLabel && (\n <span className=\"select__label\" id={labelId}>\n {label}\n </span>\n )}\n <button\n ref={triggerRef}\n type=\"button\"\n className=\"select__trigger\"\n onClick={() => {\n if (isOpen) {\n closeDropdown();\n } else {\n openDropdown();\n }\n }}\n onKeyDown={handleKeyDown}\n onBlur={onBlur}\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={isOpen}\n aria-controls={isOpen ? listboxId : undefined}\n aria-activedescendant={isOpen ? activeDescendantId : undefined}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n aria-describedby={ariaDescribedBy}\n aria-invalid={invalid || undefined}\n >\n {selectedOption ? (\n <span className=\"select__value\">\n {selectedOption.icon && (\n <span className=\"select__value-icon\">{selectedOption.icon}</span>\n )}\n <span className=\"select__value-label\">{selectedOption.label}</span>\n </span>\n ) : (\n <span className=\"select__placeholder\">{placeholder}</span>\n )}\n <span className={`select__chevron ${isOpen ? \"select__chevron--open\" : \"\"}`}>\n <svg\n width=\"10\"\n height=\"6\"\n viewBox=\"0 0 10 6\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M1 1L5 5L9 1\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n </button>\n\n {isOpen &&\n createPortal(\n <div\n ref={dropdownRef}\n className=\"select__dropdown select__dropdown--portal\"\n style={{\n position: \"fixed\",\n top: `${String(dropdownPosition.top)}px`,\n left: `${String(dropdownPosition.left)}px`,\n width: `${String(dropdownPosition.width)}px`,\n }}\n >\n {searchable && (\n <div className=\"select__search\">\n <input\n ref={searchInputRef}\n className=\"select__search-input\"\n type=\"search\"\n value={searchQuery}\n onChange={(event) => setSearchQuery(event.currentTarget.value)}\n onKeyDown={handleSearchKeyDown}\n placeholder={searchPlaceholder}\n aria-label={searchFieldLabel}\n aria-labelledby={searchFieldLabel ? undefined : labelledBy}\n aria-controls={listboxId}\n aria-activedescendant={activeDescendantId}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </div>\n )}\n <div\n className=\"select__options\"\n role=\"listbox\"\n id={listboxId}\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n >\n {visibleOptions.length === 0 ? (\n <div className=\"select__empty\">{noOptionsLabel}</div>\n ) : (\n visibleOptions.map((option, index) => (\n <div\n key={option.value}\n id={getOptionId(index)}\n ref={(el) => {\n optionsRef.current[index] = el;\n }}\n className={`select__option ${\n option.value === value ? \"select__option--selected\" : \"\"\n } ${index === focusedIndex ? \"select__option--focused\" : \"\"} ${option.disabled ? \"select__option--disabled\" : \"\"}`}\n role=\"option\"\n aria-selected={option.value === value}\n aria-disabled={option.disabled || undefined}\n aria-label={\n option.description\n ? option.label + \". \" + option.description\n : undefined\n }\n onClick={(e) => {\n selectOption(option, e);\n }}\n onMouseEnter={() => {\n if (!option.disabled) setFocusedIndex(index);\n }}\n >\n {option.icon && (\n <span className=\"select__option-icon\">{option.icon}</span>\n )}\n <div className=\"select__option-content\">\n <span className=\"select__option-label\">{option.label}</span>\n {option.description && (\n <span className=\"select__option-description\">\n {option.description}\n </span>\n )}\n </div>\n {option.value === value && (\n <span className=\"select__option-check\">\n <svg\n width=\"14\"\n height=\"10\"\n viewBox=\"0 0 14 10\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M1 5L5 9L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </span>\n )}\n </div>\n ))\n )}\n </div>\n </div>,\n document.body,\n )}\n </div>\n );\n}\n"],"mappings":";;;;;AAsDA,SAAgB,EAAkC,EAChD,UACA,aACA,WACA,YACA,UACA,kBAAc,aACd,cAAW,IACX,UAAO,WACP,eAAY,IACZ,eAAY,IACZ,gBAAa,IACb,sBACA,cAAc,GACd,oBAAoB,GACpB,aAAU,IACV,oBAAiB,gBACA;CACjB,IAAM,CAAC,GAAQ,KAAa,EAAS,EAAK,GACpC,CAAC,GAAc,KAAmB,EAAS,EAAE,GAC7C,CAAC,GAAa,KAAkB,EAAS,EAAE,GAC3C,CAAC,GAAkB,MAAuB,EAAS;EACvD,KAAK;EACL,MAAM;EACN,OAAO;CACT,CAAC,GAEK,IAAe,EAAuB,IAAI,GAC1C,IAAa,EAA0B,IAAI,GAC3C,IAAc,EAAuB,IAAI,GACzC,IAAiB,EAAyB,IAAI,GAC9C,IAAa,EAAkC,CAAC,CAAC,GACjD,IAAY,EAAM,GAClB,IAAiB,EAAM,GACvB,IAAU,EAAM,GAChB,IAAW,KAAiC,QAAQ,MAAU,IAG9D,IAAiB,EAAQ,MAAM,MAAQ,EAAI,UAAU,CAAK,GAC1D,IAAiB,QAAc;EACnC,IAAM,IAAkB,EAAY,KAAK,CAAC,CAAC,YAAY;EAEvD,OADI,CAAC,KAAc,EAAgB,WAAW,IAAU,IACjD,EAAQ,QAAQ,MACrB;GAAC,EAAO;GAAO,EAAO;GAAO,EAAO,eAAe;EAAE,CAAC,CAAC,MAAM,MAC3D,EAAU,YAAY,CAAC,CAAC,SAAS,CAAe,CAClD,CACF;CACF,GAAG;EAAC;EAAS;EAAa;CAAU,CAAC,GAE/B,IAAmB,GACtB,GAAe,MAAyB;EACvC,KACE,IAAI,IAAQ,GACZ,KAAS,KAAK,IAAQ,EAAe,QACrC,KAAS,GACT;GACA,IAAM,IAAS,EAAe;GAC9B,IAAI,KAAU,CAAC,EAAO,UAAU,OAAO;EACzC;EACA,OAAO;CACT,GACA,CAAC,CAAc,CACjB,GAGM,KAAe,MAAkB,GAAG,EAAe,UAAU,OAAO,CAAK,KAGzE,IAAqB,KAAgB,IAAI,EAAY,CAAY,IAAI,KAAA,GAGrE,IAAyB,QAAkB;EAC/C,IAAI,CAAC,EAAW,SAAS;EAEzB,IAAM,IAAO,EAAW,QAAQ,sBAAsB;EACtD,GAAoB;GAClB,KAAK,EAAK,SAAS;GACnB,MAAM,EAAK;GACX,OAAO,EAAK;EACd,CAAC;CACH,GAAG,CAAC,CAAC,GAGC,IAAe,QAAkB;EACrC,IAAI,GAAU;EAEd,AADA,EAAuB,GACvB,EAAU,EAAI;EACd,IAAM,IAAgB,EAAe,WAClC,MAAQ,EAAI,UAAU,KAAS,CAAC,EAAI,QACvC;EACA,EAAgB,MAAkB,KAAqB,EAAiB,GAAG,CAAC,IAArC,CAAsC;CAC/E,GAAG;EAAC;EAAU;EAAgB;EAAO;EAAwB;CAAgB,CAAC,GAGxE,IAAgB,QAAkB;EAItC,AAHA,EAAU,EAAK,GACf,EAAgB,EAAE,GAClB,EAAe,EAAE,GACjB,EAAW,SAAS,MAAM;CAC5B,GAAG,CAAC,CAAC,GAGC,IAAe,GAClB,GAAyB,MAAyB;EACjD,AAAI,MACF,EAAE,gBAAgB,GAClB,EAAE,eAAe,IAEf,GAAO,aACX,EAAS,EAAO,KAAK,GACrB,EAAc;CAChB,GACA,CAAC,GAAU,CAAa,CAC1B;CAyDA,AAtDA,QAAgB;EACd,IAAM,KAAsB,MAAsB;GAChD,IAAI,CAAC,GAAQ;GACb,IAAM,IAAS,EAAM,QAEf,IACJ,EAAa,WAAW,CAAC,EAAa,QAAQ,SAAS,CAAM,GACzD,IACJ,EAAY,WAAW,CAAC,EAAY,QAAQ,SAAS,CAAM;GAC7D,AAAI,KAAsB,KACxB,EAAc;EAElB,GAEM,KAAgB,MAAyB;GAC7C,AAAI,EAAM,QAAQ,YAAY,KAC5B,EAAc;EAElB;EAOA,OALI,MACF,SAAS,iBAAiB,aAAa,CAAkB,GACzD,SAAS,iBAAiB,WAAW,CAAY,UAGtC;GAEX,AADA,SAAS,oBAAoB,aAAa,CAAkB,GAC5D,SAAS,oBAAoB,WAAW,CAAY;EACtD;CACF,GAAG,CAAC,GAAQ,CAAa,CAAC,GAG1B,QAAgB;EACd,IAAI,CAAC,GAAQ;EAEb,IAAM,UAA6B;GACjC,EAAuB;EACzB;EAKA,OAHA,OAAO,iBAAiB,UAAU,CAAoB,GACtD,OAAO,iBAAiB,UAAU,GAAsB,EAAI,SAE/C;GAEX,AADA,OAAO,oBAAoB,UAAU,CAAoB,GACzD,OAAO,oBAAoB,UAAU,GAAsB,EAAI;EACjE;CACF,GAAG,CAAC,GAAQ,CAAsB,CAAC,GAEnC,QAAgB;EACd,AAAI,KAAU,KACZ,EAAe,SAAS,MAAM;CAElC,GAAG,CAAC,GAAQ,CAAU,CAAC,GAEvB,QAAgB;EACd,IAAI,CAAC,KAAU,CAAC,GAAY;EAC5B,EAAW,UAAU,CAAC;EACtB,IAAM,IAAgB,EAAe,WAClC,MAAW,EAAO,UAAU,KAAS,CAAC,EAAO,QAChD;EACA,EAAgB,KAAiB,IAAI,IAAgB,EAAiB,GAAG,CAAC,CAAC;CAC7E,GAAG;EAAC;EAAQ;EAAa;EAAY;EAAO;EAAgB;CAAgB,CAAC;CAG7E,IAAM,IAAgB,GACnB,MAA2B;EACtB,QAEJ,QAAQ,EAAE,KAAV;GACE,KAAK;GACL,KAAK;IAEH,IADA,EAAE,eAAe,GACb,GAAQ;KACV,IAAM,IAAgB,EAAe;KACrC,AAAI,KACF,EAAa,CAAa;IAE9B,OACE,EAAa;IAEf;GAEF,KAAK;IAEH,AADA,EAAE,eAAe,GACb,KACF,EAAc;IAEhB;GAEF,KAAK;IAEH,IADA,EAAE,eAAe,GACb,CAAC,GACH,EAAa;SACR;KACL,IAAM,IAAY,EAAiB,IAAe,GAAG,CAAC;KACtD,AAAI,KAAa,KAAG,EAAgB,CAAS;IAC/C;IACA;GAEF,KAAK;IAEH,IADA,EAAE,eAAe,GACb,GAAQ;KACV,IAAM,IAAgB,EAAiB,IAAe,GAAG,EAAE;KAC3D,AAAI,KAAiB,KAAG,EAAgB,CAAa;IACvD;IACA;GAEF,KAAK,OACH,AAAI,KACF,EAAc;EAGpB;CACF,GACA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CACF,GAEM,IAAsB,GACzB,MAAiD;EAChD,QAAQ,EAAM,KAAd;GACE,KAAK,SAAS;IACZ,EAAM,eAAe;IACrB,IAAM,IAAgB,EAAe;IACrC,AAAI,KAAe,EAAa,CAAa;IAC7C;GACF;GACA,KAAK;IAGH,AAFA,EAAM,eAAe,GACrB,EAAM,gBAAgB,GACtB,EAAc;IACd;GACF,KAAK;IAEH,AADA,EAAM,eAAe,GACrB,GAAiB,MAAY;KAC3B,IAAM,IAAY,EAAiB,IAAU,GAAG,CAAC;KACjD,OAAO,KAAa,IAAI,IAAY;IACtC,CAAC;IACD;GACF,KAAK;IAEH,AADA,EAAM,eAAe,GACrB,GAAiB,MAAY;KAC3B,IAAM,IAAgB,EAAiB,IAAU,GAAG,EAAE;KACtD,OAAO,KAAiB,IAAI,IAAgB;IAC9C,CAAC;IACD;GACF,KAAK,OACH,EAAc;EAElB;CACF,GACA;EAAC;EAAe;EAAc;EAAc;EAAgB;CAAgB,CAC9E;CAGA,QAAgB;EACd,IAAM,IAAiB,EAAW,QAAQ;EAC1C,AAAI,KAAU,KAAgB,KAAK,KACjC,EAAe,eAAe;GAC5B,OAAO;GACP,UAAU;EACZ,CAAC;CAEL,GAAG,CAAC,GAAQ,CAAY,CAAC;CAEzB,IAAM,IAAY,MAAS,YAAgC,KAApB,WAAW,KAC5C,KAAa,IAAY,uBAAuB,IAChD,KAAgB,IAAW,qBAAqB,IAGhD,IAAa,IAAW,IAAU,KAAA,GAClC,IAAmB,KAAqB;CAE9C,OACE,kBAAC,OAAD;EACE,KAAK;EACL,WAAW,UAAU,EAAU,GAAG,GAAW,GAAG,GAAc,GAAG,IAAS,iBAAiB,GAAG,GAAG,IAAW,qBAAqB,GAAG,GAAG;EAFzI,UAAA;GAIG,KACC,kBAAC,QAAD;IAAM,WAAU;IAAgB,IAAI;IACjC,UAAA;GACG,CAAA;GAER,kBAAC,UAAD;IACE,KAAK;IACL,MAAK;IACL,WAAU;IACV,eAAe;KACb,AAAI,IACF,EAAc,IAEd,EAAa;IAEjB;IACA,WAAW;IACH;IACE;IACV,iBAAc;IACd,iBAAe;IACf,iBAAe,IAAS,IAAY,KAAA;IACpC,yBAAuB,IAAS,IAAqB,KAAA;IACrD,cAAY;IACZ,mBAAiB;IACjB,oBAAkB;IAClB,gBAAc,KAAW,KAAA;IArB3B,UAAA,CAuBG,IACC,kBAAC,QAAD;KAAM,WAAU;KAAhB,UAAA,CACG,EAAe,QACd,kBAAC,QAAD;MAAM,WAAU;MAAsB,UAAA,EAAe;KAAW,CAAA,GAElE,kBAAC,QAAD;MAAM,WAAU;MAAuB,UAAA,EAAe;KAAY,CAAA,CAC9D;IAEN,CAAA,IAAA,kBAAC,QAAD;KAAM,WAAU;KAAuB,UAAA;IAAkB,CAAA,GAE3D,kBAAC,QAAD;KAAM,WAAW,mBAAmB,IAAS,0BAA0B;KACrE,UAAA,kBAAC,OAAD;MACE,OAAM;MACN,QAAO;MACP,SAAQ;MACR,MAAK;MACL,OAAM;MAEN,UAAA,kBAAC,QAAD;OACE,GAAE;OACF,QAAO;OACP,aAAY;OACZ,eAAc;OACd,gBAAe;MAChB,CAAA;KACE,CAAA;IACD,CAAA,CACA;;GAEP,KACC,EACE,kBAAC,OAAD;IACE,KAAK;IACL,WAAU;IACV,OAAO;KACL,UAAU;KACV,KAAK,GAAG,OAAO,EAAiB,GAAG,EAAE;KACrC,MAAM,GAAG,OAAO,EAAiB,IAAI,EAAE;KACvC,OAAO,GAAG,OAAO,EAAiB,KAAK,EAAE;IAC3C;IARF,UAAA,CAUG,KACC,kBAAC,OAAD;KAAK,WAAU;KACb,UAAA,kBAAC,SAAD;MACE,KAAK;MACL,WAAU;MACV,MAAK;MACL,OAAO;MACP,WAAW,MAAU,EAAe,EAAM,cAAc,KAAK;MAC7D,WAAW;MACX,aAAa;MACb,cAAY;MACZ,mBAAiB,IAAmB,KAAA,IAAY;MAChD,iBAAe;MACf,yBAAuB;MACvB,cAAa;MACb,YAAY;KACb,CAAA;IACE,CAAA,GAEP,kBAAC,OAAD;KACE,WAAU;KACV,MAAK;KACL,IAAI;KACJ,cAAY;KACZ,mBAAiB;KAEhB,UAAA,EAAe,WAAW,IACzB,kBAAC,OAAD;MAAK,WAAU;MAAiB,UAAA;KAAoB,CAAA,IAEpD,EAAe,KAAK,GAAQ,MAC1B,kBAAC,OAAD;MAEE,IAAI,EAAY,CAAK;MACrB,MAAM,MAAO;OACX,EAAW,QAAQ,KAAS;MAC9B;MACA,WAAW,kBACT,EAAO,UAAU,IAAQ,6BAA6B,GACvD,GAAG,MAAU,IAAe,4BAA4B,GAAG,GAAG,EAAO,WAAW,6BAA6B;MAC9G,MAAK;MACL,iBAAe,EAAO,UAAU;MAChC,iBAAe,EAAO,YAAY,KAAA;MAClC,cACE,EAAO,cACH,EAAO,QAAQ,OAAO,EAAO,cAC7B,KAAA;MAEN,UAAU,MAAM;OACd,EAAa,GAAQ,CAAC;MACxB;MACA,oBAAoB;OAClB,AAAK,EAAO,YAAU,EAAgB,CAAK;MAC7C;MAtBF,UAAA;OAwBG,EAAO,QACN,kBAAC,QAAD;QAAM,WAAU;QAAuB,UAAA,EAAO;OAAW,CAAA;OAE3D,kBAAC,OAAD;QAAK,WAAU;QAAf,UAAA,CACE,kBAAC,QAAD;SAAM,WAAU;SAAwB,UAAA,EAAO;QAAY,CAAA,GAC1D,EAAO,eACN,kBAAC,QAAD;SAAM,WAAU;SACb,UAAA,EAAO;QACJ,CAAA,CAEL;;OACJ,EAAO,UAAU,KAChB,kBAAC,QAAD;QAAM,WAAU;QACd,UAAA,kBAAC,OAAD;SACE,OAAM;SACN,QAAO;SACP,SAAQ;SACR,MAAK;SACL,OAAM;SAEN,UAAA,kBAAC,QAAD;UACE,GAAE;UACF,QAAO;UACP,aAAY;UACZ,eAAc;UACd,gBAAe;SAChB,CAAA;QACE,CAAA;OACD,CAAA;MAEL;KArDE,GAAA,EAAO,KAqDT,CACN;IAEA,CAAA,CACF;GACL,CAAA,GAAA,SAAS,IACX;EACC;;AAET"}
|
|
@@ -11,6 +11,16 @@ export interface SkeletonProps {
|
|
|
11
11
|
testId?: string;
|
|
12
12
|
/** Accessible label announced while the skeleton is visible. Default: "Loading" */
|
|
13
13
|
loadingLabel?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Render as decoration: `aria-hidden`, with no role, no `aria-busy` and no
|
|
16
|
+
* label.
|
|
17
|
+
*
|
|
18
|
+
* For a shape inside a composite that announces the wait itself. `role="status"`
|
|
19
|
+
* is an implicit polite live region, so a composite that fills its own region
|
|
20
|
+
* with named primitives mounts one live region per shape and announces the
|
|
21
|
+
* same wait once per shape.
|
|
22
|
+
*/
|
|
23
|
+
decorative?: boolean;
|
|
14
24
|
}
|
|
15
25
|
/**
|
|
16
26
|
* Skeleton provides a loading placeholder with shimmer animation.
|
|
@@ -21,5 +31,5 @@ export interface SkeletonProps {
|
|
|
21
31
|
* - Multiple shape variants
|
|
22
32
|
* - Accessible via aria-busy and aria-label
|
|
23
33
|
*/
|
|
24
|
-
export declare function Skeleton({ width, height, variant, className, testId, loadingLabel, }: SkeletonProps): import("react").JSX.Element;
|
|
34
|
+
export declare function Skeleton({ width, height, variant, className, testId, loadingLabel, decorative, }: SkeletonProps): import("react").JSX.Element;
|
|
25
35
|
export default Skeleton;
|
|
@@ -1,21 +1,23 @@
|
|
|
1
1
|
/* empty css */
|
|
2
2
|
import { jsx as e } from "react/jsx-runtime";
|
|
3
3
|
//#region src/components/Skeleton/Skeleton.tsx
|
|
4
|
-
function t({ width: t = "100%", height: n = "20px", variant: r = "rect", className: i = "", testId: a, loadingLabel: o = "Loading" }) {
|
|
5
|
-
let
|
|
4
|
+
function t({ width: t = "100%", height: n = "20px", variant: r = "rect", className: i = "", testId: a, loadingLabel: o = "Loading", decorative: s = !1 }) {
|
|
5
|
+
let c = [
|
|
6
6
|
"skeleton",
|
|
7
7
|
`skeleton--${r}`,
|
|
8
8
|
i
|
|
9
9
|
].filter(Boolean).join(" ");
|
|
10
10
|
return /* @__PURE__ */ e("div", {
|
|
11
|
-
className:
|
|
11
|
+
className: c,
|
|
12
12
|
style: {
|
|
13
13
|
width: t,
|
|
14
14
|
height: n
|
|
15
15
|
},
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
...s ? { "aria-hidden": !0 } : {
|
|
17
|
+
role: "status",
|
|
18
|
+
"aria-busy": !0,
|
|
19
|
+
"aria-label": o
|
|
20
|
+
},
|
|
19
21
|
"data-testid": a,
|
|
20
22
|
children: /* @__PURE__ */ e("span", { className: "skeleton__shimmer" })
|
|
21
23
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Skeleton2.js","names":[],"sources":["../../../src/components/Skeleton/Skeleton.tsx"],"sourcesContent":["/**\n * Skeleton Component\n *\n * Base skeleton component for loading states.\n * Provides a shimmer animation effect that respects prefers-reduced-motion.\n *\n * @example\n * // Basic usage\n * <Skeleton width=\"100%\" height=\"20px\" />\n *\n * @example\n * // Circle skeleton\n * <Skeleton width=\"40px\" height=\"40px\" variant=\"circle\" />\n */\n\nimport \"./Skeleton.css\";\n\nexport interface SkeletonProps {\n /** Width of the skeleton (CSS value) */\n width?: string;\n /** Height of the skeleton (CSS value) */\n height?: string;\n /** Visual variant */\n variant?: \"rect\" | \"circle\" | \"text\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible label announced while the skeleton is visible. Default: \"Loading\" */\n loadingLabel?: string;\n}\n\n/**\n * Skeleton provides a loading placeholder with shimmer animation.\n *\n * Features:\n * - Shimmer effect using CSS animation\n * - Reduced motion preference support\n * - Multiple shape variants\n * - Accessible via aria-busy and aria-label\n */\nexport function Skeleton({\n width = \"100%\",\n height = \"20px\",\n variant = \"rect\",\n className = \"\",\n testId,\n loadingLabel = \"Loading\",\n}: SkeletonProps) {\n const classNames = [\"skeleton\", `skeleton--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={classNames}\n style={{ width, height }}\n
|
|
1
|
+
{"version":3,"file":"Skeleton2.js","names":[],"sources":["../../../src/components/Skeleton/Skeleton.tsx"],"sourcesContent":["/**\n * Skeleton Component\n *\n * Base skeleton component for loading states.\n * Provides a shimmer animation effect that respects prefers-reduced-motion.\n *\n * @example\n * // Basic usage\n * <Skeleton width=\"100%\" height=\"20px\" />\n *\n * @example\n * // Circle skeleton\n * <Skeleton width=\"40px\" height=\"40px\" variant=\"circle\" />\n */\n\nimport \"./Skeleton.css\";\n\nexport interface SkeletonProps {\n /** Width of the skeleton (CSS value) */\n width?: string;\n /** Height of the skeleton (CSS value) */\n height?: string;\n /** Visual variant */\n variant?: \"rect\" | \"circle\" | \"text\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible label announced while the skeleton is visible. Default: \"Loading\" */\n loadingLabel?: string;\n /**\n * Render as decoration: `aria-hidden`, with no role, no `aria-busy` and no\n * label.\n *\n * For a shape inside a composite that announces the wait itself. `role=\"status\"`\n * is an implicit polite live region, so a composite that fills its own region\n * with named primitives mounts one live region per shape and announces the\n * same wait once per shape.\n */\n decorative?: boolean;\n}\n\n/**\n * Skeleton provides a loading placeholder with shimmer animation.\n *\n * Features:\n * - Shimmer effect using CSS animation\n * - Reduced motion preference support\n * - Multiple shape variants\n * - Accessible via aria-busy and aria-label\n */\nexport function Skeleton({\n width = \"100%\",\n height = \"20px\",\n variant = \"rect\",\n className = \"\",\n testId,\n loadingLabel = \"Loading\",\n decorative = false,\n}: SkeletonProps) {\n const classNames = [\"skeleton\", `skeleton--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n // A decorative shape is one of several inside a composite that already\n // announces the wait. It keeps its size and its shimmer and leaves the\n // accessibility tree, so a card built from seven of these is one live region\n // rather than seven.\n const announcement = decorative\n ? ({ \"aria-hidden\": true } as const)\n : ({\n role: \"status\",\n \"aria-busy\": true,\n \"aria-label\": loadingLabel,\n } as const);\n\n return (\n <div\n className={classNames}\n style={{ width, height }}\n {...announcement}\n data-testid={testId}\n >\n <span className=\"skeleton__shimmer\" />\n </div>\n );\n}\n\nexport default Skeleton;\n"],"mappings":";;;AAmDA,SAAgB,EAAS,EACvB,WAAQ,QACR,YAAS,QACT,aAAU,QACV,eAAY,IACZ,WACA,kBAAe,WACf,gBAAa,MACG;CAChB,IAAM,IAAa;EAAC;EAAY,aAAa;EAAW;CAAS,CAAC,CAC/D,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAcX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,OAAO;GAAE;GAAO;EAAO;EACvB,GAZiB,IAChB,EAAE,eAAe,GAAK,IACtB;GACC,MAAM;GACN,aAAa;GACb,cAAc;EAChB;EAOA,eAAa;EAEb,UAAA,kBAAC,QAAD,EAAM,WAAU,oBAAqB,CAAA;CAClC,CAAA;AAET"}
|
|
@@ -5,7 +5,7 @@ export interface SkeletonCardProps {
|
|
|
5
5
|
className?: string;
|
|
6
6
|
/** Test ID for testing */
|
|
7
7
|
testId?: string;
|
|
8
|
-
/** Accessible name for
|
|
8
|
+
/** Accessible name announced for the placeholder as a whole. Defaults to "Loading". */
|
|
9
9
|
loadingLabel?: string;
|
|
10
10
|
}
|
|
11
11
|
/**
|
|
@@ -13,21 +13,22 @@ function i({ variant: i = "default", className: a = "", testId: o, loadingLabel:
|
|
|
13
13
|
"data-testid": o,
|
|
14
14
|
role: "status",
|
|
15
15
|
"aria-busy": "true",
|
|
16
|
+
"aria-label": s ?? "Loading",
|
|
16
17
|
children: i === "stat" ? /* @__PURE__ */ n(t, { children: /* @__PURE__ */ r("div", {
|
|
17
18
|
className: "skeleton-card__header",
|
|
18
19
|
children: [/* @__PURE__ */ n(e, {
|
|
19
|
-
|
|
20
|
+
decorative: !0,
|
|
20
21
|
width: "48px",
|
|
21
22
|
height: "48px",
|
|
22
23
|
variant: "circle"
|
|
23
24
|
}), /* @__PURE__ */ r("div", {
|
|
24
25
|
className: "skeleton-card__header-text",
|
|
25
26
|
children: [/* @__PURE__ */ n(e, {
|
|
26
|
-
|
|
27
|
+
decorative: !0,
|
|
27
28
|
width: "60%",
|
|
28
29
|
height: "16px"
|
|
29
30
|
}), /* @__PURE__ */ n(e, {
|
|
30
|
-
|
|
31
|
+
decorative: !0,
|
|
31
32
|
width: "40%",
|
|
32
33
|
height: "24px"
|
|
33
34
|
})]
|
|
@@ -36,7 +37,7 @@ function i({ variant: i = "default", className: a = "", testId: o, loadingLabel:
|
|
|
36
37
|
/* @__PURE__ */ n("div", {
|
|
37
38
|
className: "skeleton-card__header",
|
|
38
39
|
children: /* @__PURE__ */ n(e, {
|
|
39
|
-
|
|
40
|
+
decorative: !0,
|
|
40
41
|
width: "70%",
|
|
41
42
|
height: "20px"
|
|
42
43
|
})
|
|
@@ -45,17 +46,17 @@ function i({ variant: i = "default", className: a = "", testId: o, loadingLabel:
|
|
|
45
46
|
className: "skeleton-card__content",
|
|
46
47
|
children: [
|
|
47
48
|
/* @__PURE__ */ n(e, {
|
|
48
|
-
|
|
49
|
+
decorative: !0,
|
|
49
50
|
width: "100%",
|
|
50
51
|
height: "16px"
|
|
51
52
|
}),
|
|
52
53
|
/* @__PURE__ */ n(e, {
|
|
53
|
-
|
|
54
|
+
decorative: !0,
|
|
54
55
|
width: "90%",
|
|
55
56
|
height: "16px"
|
|
56
57
|
}),
|
|
57
58
|
/* @__PURE__ */ n(e, {
|
|
58
|
-
|
|
59
|
+
decorative: !0,
|
|
59
60
|
width: "80%",
|
|
60
61
|
height: "16px"
|
|
61
62
|
})
|
|
@@ -64,11 +65,11 @@ function i({ variant: i = "default", className: a = "", testId: o, loadingLabel:
|
|
|
64
65
|
i !== "compact" && /* @__PURE__ */ r("div", {
|
|
65
66
|
className: "skeleton-card__footer",
|
|
66
67
|
children: [/* @__PURE__ */ n(e, {
|
|
67
|
-
|
|
68
|
+
decorative: !0,
|
|
68
69
|
width: "80px",
|
|
69
70
|
height: "32px"
|
|
70
71
|
}), /* @__PURE__ */ n(e, {
|
|
71
|
-
|
|
72
|
+
decorative: !0,
|
|
72
73
|
width: "80px",
|
|
73
74
|
height: "32px"
|
|
74
75
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletonCard2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonCard.tsx"],"sourcesContent":["/**\n * SkeletonCard Component\n *\n * Skeleton placeholder for card components (model cards, stat cards, etc.).\n * Mimics the structure of a typical card with header, content, and footer areas.\n *\n * @example\n * // Basic usage\n * <SkeletonCard />\n *\n * @example\n * // Compact variant\n * <SkeletonCard variant=\"compact\" />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonCard.css\";\n\nexport interface SkeletonCardProps {\n /** Card size variant */\n variant?: \"default\" | \"compact\" | \"stat\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name for
|
|
1
|
+
{"version":3,"file":"SkeletonCard2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonCard.tsx"],"sourcesContent":["/**\n * SkeletonCard Component\n *\n * Skeleton placeholder for card components (model cards, stat cards, etc.).\n * Mimics the structure of a typical card with header, content, and footer areas.\n *\n * @example\n * // Basic usage\n * <SkeletonCard />\n *\n * @example\n * // Compact variant\n * <SkeletonCard variant=\"compact\" />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonCard.css\";\n\nexport interface SkeletonCardProps {\n /** Card size variant */\n variant?: \"default\" | \"compact\" | \"stat\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name announced for the placeholder as a whole. Defaults to \"Loading\". */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonCard provides a loading placeholder for card components.\n *\n * Variants:\n * - default: Full card with header, content, and footer\n * - compact: Smaller card with reduced padding\n * - stat: Statistics card layout\n */\nexport function SkeletonCard({\n variant = \"default\",\n className = \"\",\n testId,\n loadingLabel,\n}: SkeletonCardProps) {\n const classNames = [\"skeleton-card\", `skeleton-card--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={classNames}\n data-testid={testId}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel ?? \"Loading\"}\n >\n {variant === \"stat\" ? (\n <>\n <div className=\"skeleton-card__header\">\n <Skeleton decorative width=\"48px\" height=\"48px\" variant=\"circle\" />\n <div className=\"skeleton-card__header-text\">\n <Skeleton decorative width=\"60%\" height=\"16px\" />\n <Skeleton decorative width=\"40%\" height=\"24px\" />\n </div>\n </div>\n </>\n ) : (\n <>\n <div className=\"skeleton-card__header\">\n <Skeleton decorative width=\"70%\" height=\"20px\" />\n </div>\n <div className=\"skeleton-card__content\">\n <Skeleton decorative width=\"100%\" height=\"16px\" />\n <Skeleton decorative width=\"90%\" height=\"16px\" />\n <Skeleton decorative width=\"80%\" height=\"16px\" />\n </div>\n {variant !== \"compact\" && (\n <div className=\"skeleton-card__footer\">\n <Skeleton decorative width=\"80px\" height=\"32px\" />\n <Skeleton decorative width=\"80px\" height=\"32px\" />\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n\nexport default SkeletonCard;\n"],"mappings":";;;;AAqCA,SAAgB,EAAa,EAC3B,aAAU,WACV,eAAY,IACZ,WACA,mBACoB;CACpB,IAAM,IAAa;EAAC;EAAiB,kBAAkB;EAAW;CAAS,CAAC,CACzE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,eAAa;EACb,MAAK;EACL,aAAU;EACV,cAAY,KAAgB;EAE3B,UAAA,MAAY,SACX,kBAAA,GAAA,EAAA,UACE,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,GAAD;IAAU,YAAA;IAAW,OAAM;IAAO,QAAO;IAAO,SAAQ;GAAU,CAAA,GAClE,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAM,QAAO;IAAQ,CAAA,GAChD,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAM,QAAO;IAAQ,CAAA,CAC7C;GACF,CAAA,CAAA;EACL,CAAA,EAAA,CAAA,IAEF,kBAAA,GAAA,EAAA,UAAA;GACE,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAM,QAAO;IAAQ,CAAA;GAC7C,CAAA;GACL,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA;KACE,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAO,QAAO;KAAQ,CAAA;KACjD,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAM,QAAO;KAAQ,CAAA;KAChD,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAM,QAAO;KAAQ,CAAA;IAC7C;;GACJ,MAAY,aACX,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,GACjD,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,CAC9C;;EAEP,EAAA,CAAA;CAED,CAAA;AAET"}
|
|
@@ -18,6 +18,7 @@ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId:
|
|
|
18
18
|
children: r === "pie" ? /* @__PURE__ */ n("div", {
|
|
19
19
|
className: "skeleton-chart__pie",
|
|
20
20
|
children: [/* @__PURE__ */ t(e, {
|
|
21
|
+
decorative: !0,
|
|
21
22
|
width: "100%",
|
|
22
23
|
height: "100%",
|
|
23
24
|
variant: "circle"
|
|
@@ -26,10 +27,12 @@ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId:
|
|
|
26
27
|
children: Array.from({ length: 4 }).map((r, i) => /* @__PURE__ */ n("div", {
|
|
27
28
|
className: "skeleton-chart__legend-item",
|
|
28
29
|
children: [/* @__PURE__ */ t(e, {
|
|
30
|
+
decorative: !0,
|
|
29
31
|
width: "16px",
|
|
30
32
|
height: "16px",
|
|
31
33
|
variant: "circle"
|
|
32
34
|
}), /* @__PURE__ */ t(e, {
|
|
35
|
+
decorative: !0,
|
|
33
36
|
width: "80px",
|
|
34
37
|
height: "14px"
|
|
35
38
|
})]
|
|
@@ -47,6 +50,7 @@ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId:
|
|
|
47
50
|
85,
|
|
48
51
|
65
|
|
49
52
|
].map((n, r) => /* @__PURE__ */ t(e, {
|
|
53
|
+
decorative: !0,
|
|
50
54
|
width: "100%",
|
|
51
55
|
height: `${String(n)}%`,
|
|
52
56
|
className: "skeleton-chart__bar"
|
|
@@ -54,6 +58,7 @@ function r({ variant: r = "bar", height: i = "300px", className: a = "", testId:
|
|
|
54
58
|
}) : /* @__PURE__ */ t("div", {
|
|
55
59
|
className: "skeleton-chart__line",
|
|
56
60
|
children: /* @__PURE__ */ t(e, {
|
|
61
|
+
decorative: !0,
|
|
57
62
|
width: "100%",
|
|
58
63
|
height: "100%"
|
|
59
64
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletonChart2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonChart.tsx"],"sourcesContent":["/**\n * SkeletonChart Component\n *\n * Skeleton placeholder for chart components.\n * Shows a simplified chart-like shape with bars or circular elements.\n *\n * @example\n * // Bar chart skeleton\n * <SkeletonChart variant=\"bar\" />\n *\n * @example\n * // Pie chart skeleton\n * <SkeletonChart variant=\"pie\" />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonChart.css\";\n\nexport interface SkeletonChartProps {\n /** Chart type variant */\n variant?: \"bar\" | \"line\" | \"pie\" | \"area\";\n /** Chart height */\n height?: string;\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible label announced while the chart is loading. Default: \"Loading chart\" */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonChart provides a loading placeholder for chart components.\n *\n * Variants:\n * - bar: Vertical bars of varying heights\n * - line: Line graph placeholder\n * - pie: Circular chart placeholder\n * - area: Area chart placeholder\n */\nexport function SkeletonChart({\n variant = \"bar\",\n height = \"300px\",\n className = \"\",\n testId,\n loadingLabel = \"Loading chart\",\n}: SkeletonChartProps) {\n const classNames = [\"skeleton-chart\", `skeleton-chart--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={classNames}\n style={{ height }}\n data-testid={testId}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel}\n >\n {variant === \"pie\" ? (\n <div className=\"skeleton-chart__pie\">\n <Skeleton width=\"100%\" height=\"100%\" variant=\"circle\" />\n <div className=\"skeleton-chart__legend\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"skeleton-chart__legend-item\">\n <Skeleton width=\"16px\" height=\"16px\" variant=\"circle\" />\n <Skeleton width=\"80px\" height=\"14px\" />\n </div>\n ))}\n </div>\n </div>\n ) : variant === \"bar\" ? (\n <div className=\"skeleton-chart__bars\">\n {[60, 80, 45, 90, 70, 55, 85, 65].map((barHeight, i) => (\n <Skeleton\n key={i}\n width=\"100%\"\n height={`${String(barHeight)}%`}\n className=\"skeleton-chart__bar\"\n />\n ))}\n </div>\n ) : (\n <div className=\"skeleton-chart__line\">\n <Skeleton width=\"100%\" height=\"100%\" />\n </div>\n )}\n </div>\n );\n}\n\nexport default SkeletonChart;\n"],"mappings":";;;;AAwCA,SAAgB,EAAc,EAC5B,aAAU,OACV,YAAS,SACT,eAAY,IACZ,WACA,kBAAe,mBACM;CACrB,IAAM,IAAa;EAAC;EAAkB,mBAAmB;EAAW;CAAS,CAAC,CAC3E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,OAAO,EAAE,UAAO;EAChB,eAAa;EACb,MAAK;EACL,aAAU;EACV,cAAY;EAEX,UAAA,MAAY,QACX,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,GAAD;IAAU,OAAM;IAAO,QAAO;IAAO,SAAQ;GAAU,CAAA,
|
|
1
|
+
{"version":3,"file":"SkeletonChart2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonChart.tsx"],"sourcesContent":["/**\n * SkeletonChart Component\n *\n * Skeleton placeholder for chart components.\n * Shows a simplified chart-like shape with bars or circular elements.\n *\n * @example\n * // Bar chart skeleton\n * <SkeletonChart variant=\"bar\" />\n *\n * @example\n * // Pie chart skeleton\n * <SkeletonChart variant=\"pie\" />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonChart.css\";\n\nexport interface SkeletonChartProps {\n /** Chart type variant */\n variant?: \"bar\" | \"line\" | \"pie\" | \"area\";\n /** Chart height */\n height?: string;\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible label announced while the chart is loading. Default: \"Loading chart\" */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonChart provides a loading placeholder for chart components.\n *\n * Variants:\n * - bar: Vertical bars of varying heights\n * - line: Line graph placeholder\n * - pie: Circular chart placeholder\n * - area: Area chart placeholder\n */\nexport function SkeletonChart({\n variant = \"bar\",\n height = \"300px\",\n className = \"\",\n testId,\n loadingLabel = \"Loading chart\",\n}: SkeletonChartProps) {\n const classNames = [\"skeleton-chart\", `skeleton-chart--${variant}`, className]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n className={classNames}\n style={{ height }}\n data-testid={testId}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel}\n >\n {variant === \"pie\" ? (\n <div className=\"skeleton-chart__pie\">\n <Skeleton decorative width=\"100%\" height=\"100%\" variant=\"circle\" />\n <div className=\"skeleton-chart__legend\">\n {Array.from({ length: 4 }).map((_, i) => (\n <div key={i} className=\"skeleton-chart__legend-item\">\n <Skeleton decorative width=\"16px\" height=\"16px\" variant=\"circle\" />\n <Skeleton decorative width=\"80px\" height=\"14px\" />\n </div>\n ))}\n </div>\n </div>\n ) : variant === \"bar\" ? (\n <div className=\"skeleton-chart__bars\">\n {[60, 80, 45, 90, 70, 55, 85, 65].map((barHeight, i) => (\n <Skeleton\n decorative\n key={i}\n width=\"100%\"\n height={`${String(barHeight)}%`}\n className=\"skeleton-chart__bar\"\n />\n ))}\n </div>\n ) : (\n <div className=\"skeleton-chart__line\">\n <Skeleton decorative width=\"100%\" height=\"100%\" />\n </div>\n )}\n </div>\n );\n}\n\nexport default SkeletonChart;\n"],"mappings":";;;;AAwCA,SAAgB,EAAc,EAC5B,aAAU,OACV,YAAS,SACT,eAAY,IACZ,WACA,kBAAe,mBACM;CACrB,IAAM,IAAa;EAAC;EAAkB,mBAAmB;EAAW;CAAS,CAAC,CAC3E,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CAEX,OACE,kBAAC,OAAD;EACE,WAAW;EACX,OAAO,EAAE,UAAO;EAChB,eAAa;EACb,MAAK;EACL,aAAU;EACV,cAAY;EAEX,UAAA,MAAY,QACX,kBAAC,OAAD;GAAK,WAAU;GAAf,UAAA,CACE,kBAAC,GAAD;IAAU,YAAA;IAAW,OAAM;IAAO,QAAO;IAAO,SAAQ;GAAU,CAAA,GAClE,kBAAC,OAAD;IAAK,WAAU;IACZ,UAAA,MAAM,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,MACjC,kBAAC,OAAD;KAAa,WAAU;KAAvB,UAAA,CACE,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAO,QAAO;MAAO,SAAQ;KAAU,CAAA,GAClE,kBAAC,GAAD;MAAU,YAAA;MAAW,OAAM;MAAO,QAAO;KAAQ,CAAA,CAC9C;IAHK,GAAA,CAGL,CACN;GACE,CAAA,CACF;EACH,CAAA,IAAA,MAAY,QACd,kBAAC,OAAD;GAAK,WAAU;GACZ,UAAA;IAAC;IAAI;IAAI;IAAI;IAAI;IAAI;IAAI;IAAI;GAAE,CAAC,CAAC,KAAK,GAAW,MAChD,kBAAC,GAAD;IACE,YAAA;IAEA,OAAM;IACN,QAAQ,GAAG,OAAO,CAAS,EAAE;IAC7B,WAAU;GACX,GAJM,CAIN,CACF;EACE,CAAA,IAEL,kBAAC,OAAD;GAAK,WAAU;GACb,UAAA,kBAAC,GAAD;IAAU,YAAA;IAAW,OAAM;IAAO,QAAO;GAAQ,CAAA;EAC9C,CAAA;CAEJ,CAAA;AAET"}
|
|
@@ -9,7 +9,7 @@ export interface SkeletonRowProps {
|
|
|
9
9
|
className?: string;
|
|
10
10
|
/** Test ID for testing */
|
|
11
11
|
testId?: string;
|
|
12
|
-
/** Accessible name for
|
|
12
|
+
/** Accessible name announced for the placeholder as a whole. Defaults to "Loading". */
|
|
13
13
|
loadingLabel?: string;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -9,11 +9,12 @@ function i({ showAvatar: i = !1, showActions: a = !1, count: o = 1, className: s
|
|
|
9
9
|
"data-testid": c ? `${c}-${String(o)}` : void 0,
|
|
10
10
|
role: "status",
|
|
11
11
|
"aria-busy": "true",
|
|
12
|
+
"aria-label": l ?? "Loading",
|
|
12
13
|
children: [
|
|
13
14
|
i && /* @__PURE__ */ n("div", {
|
|
14
15
|
className: "skeleton-row__avatar",
|
|
15
16
|
children: /* @__PURE__ */ n(e, {
|
|
16
|
-
|
|
17
|
+
decorative: !0,
|
|
17
18
|
width: "40px",
|
|
18
19
|
height: "40px",
|
|
19
20
|
variant: "circle"
|
|
@@ -22,11 +23,11 @@ function i({ showAvatar: i = !1, showActions: a = !1, count: o = 1, className: s
|
|
|
22
23
|
/* @__PURE__ */ r("div", {
|
|
23
24
|
className: "skeleton-row__content",
|
|
24
25
|
children: [/* @__PURE__ */ n(e, {
|
|
25
|
-
|
|
26
|
+
decorative: !0,
|
|
26
27
|
width: "25%",
|
|
27
28
|
height: "14px"
|
|
28
29
|
}), /* @__PURE__ */ n(e, {
|
|
29
|
-
|
|
30
|
+
decorative: !0,
|
|
30
31
|
width: "100%",
|
|
31
32
|
height: "16px"
|
|
32
33
|
})]
|
|
@@ -34,11 +35,11 @@ function i({ showAvatar: i = !1, showActions: a = !1, count: o = 1, className: s
|
|
|
34
35
|
a && /* @__PURE__ */ r("div", {
|
|
35
36
|
className: "skeleton-row__actions",
|
|
36
37
|
children: [/* @__PURE__ */ n(e, {
|
|
37
|
-
|
|
38
|
+
decorative: !0,
|
|
38
39
|
width: "32px",
|
|
39
40
|
height: "32px"
|
|
40
41
|
}), /* @__PURE__ */ n(e, {
|
|
41
|
-
|
|
42
|
+
decorative: !0,
|
|
42
43
|
width: "32px",
|
|
43
44
|
height: "32px"
|
|
44
45
|
})]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletonRow2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonRow.tsx"],"sourcesContent":["/**\n * SkeletonRow Component\n *\n * Skeleton placeholder for list rows and table rows.\n * Mimics the structure of a log entry or table row.\n *\n * @example\n * // Basic usage\n * <SkeletonRow />\n *\n * @example\n * // With avatar\n * <SkeletonRow showAvatar />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonRow.css\";\n\nexport interface SkeletonRowProps {\n /** Show avatar/icon on the left */\n showAvatar?: boolean;\n /** Show action buttons on the right */\n showActions?: boolean;\n /** Number of rows to display */\n count?: number;\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name for
|
|
1
|
+
{"version":3,"file":"SkeletonRow2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonRow.tsx"],"sourcesContent":["/**\n * SkeletonRow Component\n *\n * Skeleton placeholder for list rows and table rows.\n * Mimics the structure of a log entry or table row.\n *\n * @example\n * // Basic usage\n * <SkeletonRow />\n *\n * @example\n * // With avatar\n * <SkeletonRow showAvatar />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonRow.css\";\n\nexport interface SkeletonRowProps {\n /** Show avatar/icon on the left */\n showAvatar?: boolean;\n /** Show action buttons on the right */\n showActions?: boolean;\n /** Number of rows to display */\n count?: number;\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name announced for the placeholder as a whole. Defaults to \"Loading\". */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonRow provides a loading placeholder for list/table rows.\n *\n * Features:\n * - Optional avatar/icon\n * - Optional action buttons\n * - Multiple rows for lists\n */\nexport function SkeletonRow({\n showAvatar = false,\n showActions = false,\n count = 1,\n className = \"\",\n testId,\n loadingLabel,\n}: SkeletonRowProps) {\n const rows = Array.from({ length: count });\n\n return (\n <>\n {rows.map((_, index) => (\n <div\n key={index}\n className={`skeleton-row ${className}`}\n data-testid={testId ? `${testId}-${String(index)}` : undefined}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel ?? \"Loading\"}\n >\n {showAvatar && (\n <div className=\"skeleton-row__avatar\">\n <Skeleton decorative width=\"40px\" height=\"40px\" variant=\"circle\" />\n </div>\n )}\n <div className=\"skeleton-row__content\">\n <Skeleton decorative width=\"25%\" height=\"14px\" />\n <Skeleton decorative width=\"100%\" height=\"16px\" />\n </div>\n {showActions && (\n <div className=\"skeleton-row__actions\">\n <Skeleton decorative width=\"32px\" height=\"32px\" />\n <Skeleton decorative width=\"32px\" height=\"32px\" />\n </div>\n )}\n </div>\n ))}\n </>\n );\n}\n\nexport default SkeletonRow;\n"],"mappings":";;;;AAyCA,SAAgB,EAAY,EAC1B,gBAAa,IACb,iBAAc,IACd,WAAQ,GACR,eAAY,IACZ,WACA,mBACmB;CACnB,IAAM,IAAO,MAAM,KAAK,EAAE,QAAQ,EAAM,CAAC;CAEzC,OACE,kBAAA,GAAA,EAAA,UACG,EAAK,KAAK,GAAG,MACZ,kBAAC,OAAD;EAEE,WAAW,gBAAgB;EAC3B,eAAa,IAAS,GAAG,EAAO,GAAG,OAAO,CAAK,MAAM,KAAA;EACrD,MAAK;EACL,aAAU;EACV,cAAY,KAAgB;EAN9B,UAAA;GAQG,KACC,kBAAC,OAAD;IAAK,WAAU;IACb,UAAA,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;KAAO,SAAQ;IAAU,CAAA;GAC/D,CAAA;GAEP,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAM,QAAO;IAAQ,CAAA,GAChD,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,CAC9C;;GACJ,KACC,kBAAC,OAAD;IAAK,WAAU;IAAf,UAAA,CACE,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,GACjD,kBAAC,GAAD;KAAU,YAAA;KAAW,OAAM;KAAO,QAAO;IAAQ,CAAA,CAC9C;;EAEJ;CAtBE,GAAA,CAsBF,CACN,EACD,CAAA;AAEN"}
|
|
@@ -7,7 +7,7 @@ export interface SkeletonTextProps {
|
|
|
7
7
|
className?: string;
|
|
8
8
|
/** Test ID for testing */
|
|
9
9
|
testId?: string;
|
|
10
|
-
/** Accessible name for
|
|
10
|
+
/** Accessible name announced for the placeholder as a whole. Defaults to "Loading". */
|
|
11
11
|
loadingLabel?: string;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
@@ -13,8 +13,9 @@ function n({ lines: n = 3, spacing: r = "normal", className: i = "", testId: a,
|
|
|
13
13
|
"data-testid": a,
|
|
14
14
|
role: "status",
|
|
15
15
|
"aria-busy": "true",
|
|
16
|
+
"aria-label": o ?? "Loading",
|
|
16
17
|
children: c.map((n, r) => /* @__PURE__ */ t(e, {
|
|
17
|
-
|
|
18
|
+
decorative: !0,
|
|
18
19
|
width: n,
|
|
19
20
|
height: "1em",
|
|
20
21
|
variant: "text"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletonText2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonText.tsx"],"sourcesContent":["/**\n * SkeletonText Component\n *\n * Skeleton placeholder for text content.\n * Provides multiple lines with varying widths for natural appearance.\n *\n * @example\n * // Basic usage (3 lines)\n * <SkeletonText />\n *\n * @example\n * // Custom number of lines\n * <SkeletonText lines={5} />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonText.css\";\n\nexport interface SkeletonTextProps {\n /** Number of text lines to display */\n lines?: number;\n /** Spacing between lines */\n spacing?: \"compact\" | \"normal\" | \"relaxed\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name for
|
|
1
|
+
{"version":3,"file":"SkeletonText2.js","names":[],"sources":["../../../src/components/Skeleton/SkeletonText.tsx"],"sourcesContent":["/**\n * SkeletonText Component\n *\n * Skeleton placeholder for text content.\n * Provides multiple lines with varying widths for natural appearance.\n *\n * @example\n * // Basic usage (3 lines)\n * <SkeletonText />\n *\n * @example\n * // Custom number of lines\n * <SkeletonText lines={5} />\n */\n\nimport { Skeleton } from \"./Skeleton\";\nimport \"./SkeletonText.css\";\n\nexport interface SkeletonTextProps {\n /** Number of text lines to display */\n lines?: number;\n /** Spacing between lines */\n spacing?: \"compact\" | \"normal\" | \"relaxed\";\n /** Additional CSS class names */\n className?: string;\n /** Test ID for testing */\n testId?: string;\n /** Accessible name announced for the placeholder as a whole. Defaults to \"Loading\". */\n loadingLabel?: string;\n}\n\n/**\n * SkeletonText provides a loading placeholder for text content.\n *\n * Features:\n * - Multiple lines with varying widths\n * - Configurable line spacing\n * - Accessible via aria-busy\n */\nexport function SkeletonText({\n lines = 3,\n spacing = \"normal\",\n className = \"\",\n testId,\n loadingLabel,\n}: SkeletonTextProps) {\n const classNames = [\"skeleton-text\", `skeleton-text--${spacing}`, className]\n .filter(Boolean)\n .join(\" \");\n\n // Generate varying widths for natural appearance\n const widths = Array.from({ length: lines }, (_, i) => {\n if (i === lines - 1) {\n // Last line is shorter\n return \"60%\";\n }\n // Alternate between full and slightly shorter widths\n return i % 2 === 0 ? \"100%\" : \"95%\";\n });\n\n return (\n <div\n className={classNames}\n data-testid={testId}\n role=\"status\"\n aria-busy=\"true\"\n aria-label={loadingLabel ?? \"Loading\"}\n >\n {widths.map((width, index) => (\n <Skeleton decorative key={index} width={width} height=\"1em\" variant=\"text\" />\n ))}\n </div>\n );\n}\n\nexport default SkeletonText;\n"],"mappings":";;;;AAuCA,SAAgB,EAAa,EAC3B,WAAQ,GACR,aAAU,UACV,eAAY,IACZ,WACA,mBACoB;CACpB,IAAM,IAAa;EAAC;EAAiB,kBAAkB;EAAW;CAAS,CAAC,CACzE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,GAGL,IAAS,MAAM,KAAK,EAAE,QAAQ,EAAM,IAAI,GAAG,MAC3C,MAAM,IAAQ,IAET,QAGF,IAAI,KAAM,IAAI,SAAS,KAC/B;CAED,OACE,kBAAC,OAAD;EACE,WAAW;EACX,eAAa;EACb,MAAK;EACL,aAAU;EACV,cAAY,KAAgB;EAE3B,UAAA,EAAO,KAAK,GAAO,MAClB,kBAAC,GAAD;GAAU,YAAA;GAA8B;GAAO,QAAO;GAAM,SAAQ;EAAQ,GAAlD,CAAkD,CAC7E;CACE,CAAA;AAET"}
|
package/dist/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export * from './components/PageLayout';
|
|
|
24
24
|
export * from './components/ProgressBar';
|
|
25
25
|
export * from './components/Skeleton';
|
|
26
26
|
export * from './components/SmoothHeight';
|
|
27
|
+
export * from './components/Select';
|
|
27
28
|
export * from './components/StatCard';
|
|
28
29
|
export * from './components/StatusTag';
|
|
29
30
|
export * from './components/Tabs';
|
package/dist/index.js
CHANGED
|
@@ -14,10 +14,11 @@ import { SkeletonText as f } from "./components/Skeleton/SkeletonText2.js";
|
|
|
14
14
|
import { SkeletonChart as p } from "./components/Skeleton/SkeletonChart2.js";
|
|
15
15
|
import { SkeletonRow as m } from "./components/Skeleton/SkeletonRow2.js";
|
|
16
16
|
import { SmoothHeight as h } from "./components/SmoothHeight/SmoothHeight2.js";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
17
|
+
import { Select as g } from "./components/Select/Select2.js";
|
|
18
|
+
import { usePrefersReducedMotion as _ } from "./hooks/usePrefersReducedMotion.js";
|
|
19
|
+
import { StatCard as v } from "./components/StatCard/StatCard2.js";
|
|
20
|
+
import { formatCompactNumber as y } from "./components/StatCard/formatters.js";
|
|
21
|
+
import { StatusTag as b } from "./components/StatusTag/StatusTag2.js";
|
|
22
|
+
import { Tabs as x } from "./components/Tabs/Tabs2.js";
|
|
23
|
+
import { Tooltip as S } from "./components/Tooltip/Tooltip2.js";
|
|
24
|
+
export { t as Badge, e as BaseCard, n as Button, r as DataTable, i as Drawer, a as EmptyState, o as ErrorState, s as PageHeader, c as PageLayout, l as ProgressBar, g as Select, u as Skeleton, d as SkeletonCard, p as SkeletonChart, m as SkeletonRow, f as SkeletonText, h as SmoothHeight, v as StatCard, b as StatusTag, x as Tabs, S as Tooltip, y as formatCompactNumber, _ as usePrefersReducedMotion };
|
package/dist/styles/base.css
CHANGED
|
@@ -131,6 +131,7 @@
|
|
|
131
131
|
--token-colorPrimary: #ff7a00;
|
|
132
132
|
--token-colorPrimaryActive: #cc6200;
|
|
133
133
|
--token-colorPrimaryBg: rgba(255, 122, 0, 0.1);
|
|
134
|
+
--token-colorPrimaryBgHover: rgba(255, 122, 0, 0.16);
|
|
134
135
|
--token-colorPrimaryBorder: rgba(255, 122, 0, 0.2);
|
|
135
136
|
--token-colorSuccess: #007a63;
|
|
136
137
|
--token-colorSuccessActive: #005244;
|
|
@@ -140,6 +141,12 @@
|
|
|
140
141
|
--token-colorSuccessBoxShadow: 0 4px 12px rgba(0, 189, 155, 0.15);
|
|
141
142
|
--token-colorWarning: #9a5d00;
|
|
142
143
|
--token-colorText: #141414;
|
|
144
|
+
/* Both #767676 rather than the #bfbfbf a disabled or placeholder value is
|
|
145
|
+
* usually given: that measures 2.2:1 on white, and text a reader is expected
|
|
146
|
+
* to read (a placeholder naming the field, a disabled value explaining why it
|
|
147
|
+
* cannot be changed) is not exempt from the 4.5:1 floor. */
|
|
148
|
+
--token-colorTextDisabled: #767676;
|
|
149
|
+
--token-colorTextPlaceholder: #767676;
|
|
143
150
|
--token-colorTextQuaternary: #bfbfbf;
|
|
144
151
|
--token-colorTextSecondary: #595959;
|
|
145
152
|
--token-colorTextTertiary: #737373;
|
package/package.json
CHANGED