tailwind-header-tabs
Version:
`HeaderTabs` is a customizable and accessible React component for displaying tabbed navigation with optional icons, count badges, and multi-tab selection via an auto-complete input.
153 lines (152 loc) • 4.93 kB
JavaScript
import { jsxs as p, jsx as l } from "react/jsx-runtime";
import j, { useState as y, useRef as k, useEffect as L, useMemo as N } from "react";
const V = ({
data: c,
selectedData: s,
onCountrySelect: m
}) => {
const [a, f] = y(""), [h, i] = y(!1), u = k(null), o = c.filter(
(t) => t.toLowerCase().includes(a.toLowerCase()) && !s.find((d) => d.label === t)
);
L(() => {
const t = (d) => {
u.current && !u.current.contains(d.target) && i(!1);
};
return document.addEventListener("mousedown", t), () => document.removeEventListener("mousedown", t);
}, []);
const b = (t) => {
m(t), f(""), i(!1);
};
return o.length ? /* @__PURE__ */ p(
"li",
{
className: `relative ${s.length ? "bottom-[-3px]" : "mb-1 w-full"}`,
ref: u,
children: [
/* @__PURE__ */ l(
"input",
{
type: "text",
value: a,
onFocus: () => i(!0),
onChange: (t) => f(t.target.value),
className: "border border-slate-200 rounded-lg p-2 w-full",
placeholder: "Select country..."
}
),
h && o.length > 0 && /* @__PURE__ */ l("ul", { className: "absolute z-10 w-full mt-1 max-h-60 overflow-y-auto bg-white border border-gray-200 rounded-md shadow-lg", children: o.map((t) => /* @__PURE__ */ l(
"li",
{
className: "px-4 py-2 hover:bg-gray-100 cursor-pointer text-start",
onClick: () => b(t),
children: t
},
t
)) })
]
}
) : null;
}, x = {
active: "#2563eb",
inactive: "#6b7280"
}, z = ({
tabs: c,
activeTab: s,
showCountBadges: m,
icons: a,
onClickTab: f,
activeIconColor: h = x.active,
inactiveIconColor: i = x.inactive,
countLabel: u = {},
selectable: o = !1,
containerClasses: b = ""
}) => {
const [t, d] = j.useState([]), v = k({}), I = N(() => (e, r) => typeof a == "function" ? a(r)[e] : null, [a]), S = N(() => (e) => /* @__PURE__ */ l("span", { className: "inline-flex items-center capitalize text-xs font-semibold bg-gray-100 text-gray-600 px-2 py-[1px] rounded-md ms-2", children: e }), []), R = (e) => {
const r = v.current[e.id];
r && r.scrollIntoView({
behavior: "smooth",
block: "center",
inline: "center"
}), f(e);
}, $ = (e) => {
d(
(r) => r.filter((n) => n.id !== e)
);
};
return /* @__PURE__ */ l("div", { className: "border-b border-gray-200 dark:border-gray-700", children: /* @__PURE__ */ p(
"ul",
{
className: `flex flex-none -mb-px text-sm font-medium text-gray-500 dark:text-gray-400 overflow-hidden gap-x-2 ${b}`,
children: [
(o ? t : c).map((e) => {
const r = (s == null ? void 0 : s.id) === e.id, n = r ? h : i, w = I(e.label, n);
let g = 0;
m && (g = u[e.label] || 0);
const E = `inline-flex items-center justify-center border-b-2 rounded-t-lg group ${r ? "text-blue-600 border-blue-600 dark:text-blue-500 dark:border-blue-500" : "border-transparent hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300"}`;
return /* @__PURE__ */ l(
"li",
{
ref: (C) => {
C && (v.current[e.id] = C);
},
children: /* @__PURE__ */ p("button", { "data-id": e.id, className: E, children: [
/* @__PURE__ */ p(
"span",
{
onClick: () => R(e),
className: "flex items-center p-2 md:p-3 w-max",
children: [
w,
/* @__PURE__ */ l(
"span",
{
className: `${w && "ps-2"} text-[${n}] md:text-base text-[13px]`,
children: e.label
}
),
m && g > 0 && S(g)
]
}
),
o && /* @__PURE__ */ l(
"span",
{
onClick: () => $(e.id),
className: "px-2",
children: "×"
}
)
] })
},
e.id
);
}),
o && /* @__PURE__ */ l(
V,
{
data: c.map((e) => e.label),
selectedData: t,
onCountrySelect: (e) => {
if (t.some((n) => n.label === e))
return;
const r = c.find(
(n) => n.label === e
);
r && d((n) => [
...n,
r
]);
}
}
)
]
}
) });
};
z.defaultProps = {
activeIconColor: x.active,
inactiveIconColor: x.inactive
};
export {
z as default
};