@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
403 lines (391 loc) • 10.5 kB
JavaScript
'use client';
import { jsx as l, jsxs as C } from "react/jsx-runtime";
import { useTheme as T } from "../../../theme/context.js";
import { getColorVariant as x } from "../../../theme/styled.js";
import { css as i } from "@emotion/react";
import g from "@emotion/styled";
import P, { useState as V, useRef as Z, useEffect as _, useMemo as M, useCallback as E } from "react";
const ee = (e) => {
const { theme: n, variant: d = "flat", color: a = "primary" } = e, o = x(n, a, 500);
switch (d) {
case "flat":
return i`
background-color: ${n.colors.background.secondary};
border: 1px solid transparent;
`;
case "bordered":
return i`
background-color: ${n.colors.background.primary};
border: 1px solid ${n.colors.border.primary};
`;
case "light":
return i`
background-color: ${x(n, a, 50)};
border: 1px solid transparent;
`;
case "solid":
return i`
background-color: ${o};
border: 1px solid ${o};
color: ${n.colors.text.inverse};
`;
default:
return i``;
}
}, te = (e) => {
const { theme: n, itemHeight: d = "md" } = e;
switch (d) {
case "sm":
return i`
min-height: ${n.spacing[8]};
padding: ${n.spacing[2]} ${n.spacing[3]};
font-size: ${n.fontSizes.sm};
`;
case "md":
return i`
min-height: ${n.spacing[10]};
padding: ${n.spacing[3]} ${n.spacing[4]};
font-size: ${n.fontSizes.base};
`;
case "lg":
return i`
min-height: ${n.spacing[12]};
padding: ${n.spacing[4]} ${n.spacing[6]};
font-size: ${n.fontSizes.lg};
`;
default:
return i``;
}
}, ne = (e) => {
const { theme: n, isSelected: d, isFocused: a, isDisabled: o, color: c = "primary" } = e, y = x(n, c, 500), w = x(n, c, 50);
if (o)
return i`
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
`;
let f = i`
cursor: pointer;
transition: all ${n.transitions.fast};
&:hover {
background-color: ${n.colors.background.tertiary};
}
`;
return d && (f = i`
${f}
background-color: ${w};
color: ${x(n, c, 700)};
&:hover {
background-color: ${x(n, c, 100)};
}
`), a && (f = i`
${f}
outline: 2px solid ${y};
outline-offset: -2px;
`), f;
}, re = g.div`
position: relative;
border-radius: ${(e) => e.theme.borderRadius.lg};
overflow: hidden;
outline: none;
${ee}
${(e) => e.maxHeight && i`
max-height: ${typeof e.maxHeight == "number" ? `${e.maxHeight}px` : e.maxHeight};
overflow-y: auto;
`}
/* Custom scrollbar */
&::-webkit-scrollbar {
width: 6px;
}
&::-webkit-scrollbar-track {
background: ${(e) => e.theme.colors.neutral[100]};
}
&::-webkit-scrollbar-thumb {
background: ${(e) => e.theme.colors.neutral[300]};
border-radius: 3px;
}
&::-webkit-scrollbar-thumb:hover {
background: ${(e) => e.theme.colors.neutral[400]};
}
/* Custom CSS prop */
${(e) => e.css}
`, oe = g.div`
display: flex;
align-items: center;
gap: ${(e) => e.theme.spacing[3]};
position: relative;
user-select: none;
${te}
${ne}
${(e) => e.css}
`, se = g.div`
display: flex;
flex-direction: column;
flex: 1;
min-width: 0;
gap: ${(e) => e.theme.spacing[1]};
`, ie = g.div`
font-weight: ${(e) => e.theme.fontWeights.medium};
color: inherit;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`, le = g.div`
font-size: ${(e) => e.theme.fontSizes.sm};
color: ${(e) => e.theme.colors.text.secondary};
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`, ae = g.div`
display: flex;
align-items: center;
justify-content: center;
padding: ${(e) => e.theme.spacing[8]} ${(e) => e.theme.spacing[4]};
color: ${(e) => e.theme.colors.text.secondary};
font-size: ${(e) => e.theme.fontSizes.sm};
text-align: center;
`, ce = g.div`
display: flex;
align-items: center;
justify-content: center;
padding: ${(e) => e.theme.spacing[6]} ${(e) => e.theme.spacing[4]};
gap: ${(e) => e.theme.spacing[2]};
color: ${(e) => e.theme.colors.text.secondary};
font-size: ${(e) => e.theme.fontSizes.sm};
`, de = g.div`
height: 1px;
background-color: ${(e) => e.theme.colors.border.primary};
margin: ${(e) => e.theme.spacing[1]} 0;
`, fe = () => (
// biome-ignore lint/a11y/noSvgWithoutTitle: <explanation>
/* @__PURE__ */ l(
"svg",
{
width: "16",
height: "16",
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
strokeWidth: "2",
strokeLinecap: "round",
strokeLinejoin: "round",
children: /* @__PURE__ */ l("polyline", { points: "20,6 9,17 4,12" })
}
)
), he = () => (
// biome-ignore lint/a11y/noSvgWithoutTitle: <explanation>
/* @__PURE__ */ l(
"svg",
{
width: "16",
height: "16",
viewBox: "0 0 24 24",
fill: "none",
stroke: "currentColor",
strokeWidth: "2",
style: { animation: "spin 1s linear infinite" },
children: /* @__PURE__ */ l("path", { d: "M21 12a9 9 0 11-6.219-8.56" })
}
)
), U = ({
item: e,
isSelected: n = !1,
isFocused: d = !1,
isDisabled: a = !1,
selectionMode: o = "single",
hideSelectedIcon: c = !1,
itemHeight: y = "md",
color: w = "primary",
className: f,
css: I,
onPress: k,
...L
}) => {
const { theme: u } = T(), m = {
item: e,
isSelected: n,
isFocused: d,
isDisabled: a || e.isDisabled,
selectionMode: o,
hideSelectedIcon: c,
itemHeight: y,
color: w,
className: f,
theme: u,
css: I
};
return /* @__PURE__ */ C(
oe,
{
...m,
...L,
onClick: () => {
m.isDisabled || k?.();
},
onKeyDown: (b) => {
(b.key === "Enter" || b.key === " ") && !m.isDisabled && (b.preventDefault(), k?.());
},
tabIndex: d ? 0 : -1,
role: "option",
"aria-selected": n,
"aria-disabled": m.isDisabled,
children: [
e.startContent,
/* @__PURE__ */ C(se, { theme: u, children: [
/* @__PURE__ */ l(ie, { theme: u, children: e.label }),
e.description && /* @__PURE__ */ l(le, { theme: u, children: e.description })
] }),
e.endContent,
!c && o !== "none" && n && /* @__PURE__ */ l(fe, {})
]
}
);
}, ge = P.forwardRef(
({
items: e = [],
selectedKeys: n,
defaultSelectedKeys: d,
disabledKeys: a = /* @__PURE__ */ new Set(),
selectionMode: o = "single",
selectionBehavior: c = "toggle",
emptyContent: y = "No items found",
isLoading: w = !1,
loadingContent: f,
variant: I = "flat",
color: k = "primary",
itemHeight: L = "md",
maxHeight: u,
hideSelectedIcon: m = !1,
showDividers: j = !1,
shouldFocusWrap: v = !0,
autoFocus: b = !1,
className: W,
css: q,
onSelectionChange: R,
onAction: z,
...A
}, B) => {
const { theme: D } = T(), [F, G] = V(d || /* @__PURE__ */ new Set()), [$, N] = V(null), J = Z(null), K = n !== void 0, p = K ? n : F;
_(() => {
if (b && e.length > 0) {
const t = e.find(
(r) => !r.isDisabled && !a.has(r.key)
);
t && N(t.key);
}
}, [b, e, a]);
const h = M(
() => e.filter((t) => !t.isDisabled && !a.has(t.key)),
[e, a]
), S = E(
(t) => {
K || G(t), R?.(t);
},
[K, R]
), H = E(
(t) => {
if (o === "none") {
z?.(t);
return;
}
let r;
o === "single" ? c === "toggle" && p !== "all" && p.has(t) ? r = /* @__PURE__ */ new Set() : r = /* @__PURE__ */ new Set([t]) : p === "all" ? r = new Set(
e.map((s) => s.key).filter((s) => s !== t)
) : (r = new Set(p), r.has(t) ? c === "toggle" && r.delete(t) : r.add(t)), S(r), z?.(t);
},
[
o,
c,
p,
e,
S,
z
]
), O = E(
(t) => {
if (h.length === 0) return;
const r = $ ? h.findIndex((Y) => Y.key === $) : -1;
let s = r;
switch (t.key) {
case "ArrowDown":
t.preventDefault(), s = r + 1, s >= h.length && (s = v ? 0 : h.length - 1);
break;
case "ArrowUp":
t.preventDefault(), s = r - 1, s < 0 && (s = v ? h.length - 1 : 0);
break;
case "Home":
t.preventDefault(), s = 0;
break;
case "End":
t.preventDefault(), s = h.length - 1;
break;
case "Enter":
case " ":
t.preventDefault(), $ !== null && H($);
return;
case "a":
(t.ctrlKey || t.metaKey) && (t.preventDefault(), o === "multiple" && S("all"));
return;
default:
return;
}
s !== r && h[s] && N(h[s].key);
},
[
h,
$,
v,
H,
o,
S
]
), Q = {
variant: I,
color: k,
maxHeight: u,
className: W,
css: q
}, X = (t) => p === "all" ? !0 : p.has(t);
return /* @__PURE__ */ l(
re,
{
ref: B || J,
theme: D,
...Q,
...A,
role: "listbox",
"aria-multiselectable": o === "multiple",
tabIndex: 0,
onKeyDown: O,
children: w ? /* @__PURE__ */ C(ce, { theme: D, children: [
/* @__PURE__ */ l(he, {}),
f || "Loading...",
/* @__PURE__ */ l("style", { children: "@keyframes spin { to { transform: rotate(360deg); } }" })
] }) : e.length === 0 ? /* @__PURE__ */ l(ae, { theme: D, children: y }) : e.map((t, r) => /* @__PURE__ */ C(P.Fragment, { children: [
j && r > 0 && /* @__PURE__ */ l(de, { theme: D }),
/* @__PURE__ */ l(
U,
{
item: t,
isSelected: X(t.key),
isFocused: $ === t.key,
isDisabled: t.isDisabled || a.has(t.key),
selectionMode: o,
hideSelectedIcon: m,
itemHeight: L,
color: k,
onPress: () => H(t.key)
}
)
] }, t.key))
}
);
}
);
ge.displayName = "Listbox";
U.displayName = "ListboxItem";
export {
ge as Listbox,
U as ListboxItem
};
//# sourceMappingURL=listbox.js.map