UNPKG

@flanksource/clicky-ui

Version:

Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.

154 lines (153 loc) 4.98 kB
import { jsxs, Fragment, jsx } from "react/jsx-runtime"; import { cn } from "../lib/utils.js"; import { Icon } from "./Icon.js"; function bodyClasses(mode) { switch (mode) { case "active": return "bg-primary/10 border-primary/40 text-primary font-medium"; case "include": return "bg-green-500/10 border-green-500/50 text-green-700 dark:text-green-400 font-medium"; case "exclude": return "bg-red-500/10 border-red-500/50 text-red-700 dark:text-red-400 font-medium"; case "neutral": default: return "border-border text-muted-foreground hover:bg-accent"; } } const SLOT_TRANSLATE = { exclude: "translate-x-0", neutral: "translate-x-4", include: "translate-x-8" }; function TristateSwitch({ mode, onChange, ariaLabel }) { const slot = mode === "exclude" ? "exclude" : mode === "include" ? "include" : "neutral"; const bg = slot === "exclude" ? "bg-red-500/80" : slot === "include" ? "bg-green-500/80" : "bg-muted"; return /* @__PURE__ */ jsx( "button", { type: "button", "aria-label": ariaLabel, title: ariaLabel, onClick: (event) => { event.preventDefault(); event.stopPropagation(); onChange(nextTriStateMode(mode)); }, className: cn( "relative inline-flex h-5 w-[52px] shrink-0 overflow-hidden rounded-full transition-colors duration-200", bg ), children: /* @__PURE__ */ jsx( "span", { "aria-hidden": true, className: cn( "pointer-events-none absolute left-0.5 top-0.5 z-20 flex size-4 items-center justify-center rounded-full bg-white shadow-sm transition-transform duration-150", SLOT_TRANSLATE[slot] ), children: slot !== "neutral" && /* @__PURE__ */ jsx( Icon, { name: slot === "exclude" ? "codicon:close" : "codicon:check", className: cn( "text-[10px]", slot === "exclude" && "text-red-600", slot === "include" && "text-green-600" ) } ) } ) } ); } function FilterPill({ mode = "neutral", label, count, icon, badge, onModeChange, onClick, title, togglePosition = "left", className }) { const triState = !!onModeChange; const content = /* @__PURE__ */ jsxs(Fragment, { children: [ count !== void 0 && /* @__PURE__ */ jsx( "span", { className: cn( "inline-flex items-center justify-center min-w-[16px] h-[16px] px-1 rounded-full text-[10px] font-bold text-white", badge ?? "bg-muted-foreground" ), children: count } ), icon && /* @__PURE__ */ jsx(Icon, { name: icon, className: "text-sm" }), /* @__PURE__ */ jsx("span", { className: "truncate", children: label }) ] }); if (triState) { const control = /* @__PURE__ */ jsx( TristateSwitch, { mode, onChange: onModeChange, ...title ? { ariaLabel: title } : {} } ); const labelContent = /* @__PURE__ */ jsx("span", { className: "inline-flex min-w-0 items-center gap-1.5 text-xs text-foreground", children: content }); return /* @__PURE__ */ jsx("span", { className: cn("inline-flex items-center gap-1.5 select-none", className), title, children: togglePosition === "right" ? /* @__PURE__ */ jsxs(Fragment, { children: [ labelContent, control ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [ control, labelContent ] }) }); } return /* @__PURE__ */ jsxs( "button", { type: "button", onClick, title, className: cn( "inline-flex items-center gap-1.5 text-xs px-2 py-0.5 rounded-full border transition-colors", bodyClasses(mode), className ), children: [ /* @__PURE__ */ jsx(LegacyMarker, { mode }), content ] } ); } function LegacyMarker({ mode }) { if (mode === "include") return /* @__PURE__ */ jsx(Icon, { name: "codicon:add", className: "text-xs" }); if (mode === "exclude") return /* @__PURE__ */ jsx(Icon, { name: "codicon:remove", className: "text-xs" }); if (mode === "active") return /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-current" }); return /* @__PURE__ */ jsx("span", { className: "w-2 h-2 rounded-full bg-current opacity-30" }); } function nextTriStateMode(mode) { if (mode === "include") return "exclude"; if (mode === "exclude") return "neutral"; return "include"; } function FilterPillGroup({ children, className }) { return /* @__PURE__ */ jsx("div", { className: cn("flex items-center gap-1.5 flex-wrap", className), children }); } function FilterSeparator() { return /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "text-border mx-0.5", children: "|" }); } export { FilterPill, FilterPillGroup, FilterSeparator }; //# sourceMappingURL=FilterPill.js.map