@flanksource/clicky-ui
Version:
Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.
127 lines (126 loc) • 4.55 kB
JavaScript
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
import { useRef, useState, useEffect } from "react";
import { Button } from "../components/button.js";
import { Icon } from "../data/Icon.js";
import { cn } from "../lib/utils.js";
const ACCEPT_OPTIONS = [
{ value: "application/json", label: "JSON" },
{ value: "application/clicky+json", label: "Clicky" },
{ value: "text/markdown", label: "Markdown" },
{ value: "text/html", label: "HTML" },
{ value: "application/x-yaml", label: "YAML" },
{ value: "text/csv", label: "CSV" },
{ value: "application/pdf", label: "PDF" },
{ value: "text/plain", label: "Pretty" }
];
const VIEW_OPTIONS = [
{ value: "application/json", label: "JSON" },
{ value: "application/clicky+json", label: "Clicky" },
{ value: "application/pdf", label: "PDF" }
];
const PREVIEW_OPTIONS = [
{ value: "curl", label: "Show cURL preview" },
{ value: "cli", label: "Show CLI preview" },
{ value: "hidden", label: "Hide preview" }
];
function AcceptPicker({
value,
onChange,
size = "md",
options = ACCEPT_OPTIONS,
previewMode = "hidden",
onPreviewModeChange,
className
}) {
const rootRef = useRef(null);
const [open, setOpen] = useState(false);
const pad = size === "sm" ? "px-2 py-0.5" : "px-2.5 py-1";
useEffect(() => {
if (!open) return;
const onPointerDown = (event) => {
var _a;
if (!((_a = rootRef.current) == null ? void 0 : _a.contains(event.target))) {
setOpen(false);
}
};
const onKeyDown = (event) => {
if (event.key === "Escape") setOpen(false);
};
document.addEventListener("pointerdown", onPointerDown);
document.addEventListener("keydown", onKeyDown);
return () => {
document.removeEventListener("pointerdown", onPointerDown);
document.removeEventListener("keydown", onKeyDown);
};
}, [open]);
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative flex flex-wrap gap-1", className), children: [
options.map((opt) => /* @__PURE__ */ jsx(
"button",
{
type: "button",
onClick: () => onChange(opt.value),
className: cn(
"rounded-md border text-xs transition-colors",
pad,
value === opt.value ? "border-emerald-500 bg-emerald-50 font-medium text-emerald-700 dark:border-emerald-600 dark:bg-emerald-950/30 dark:text-emerald-400" : "text-muted-foreground hover:border-foreground/20 hover:text-foreground"
),
children: opt.label
},
opt.value
)),
onPreviewModeChange && /* @__PURE__ */ jsxs(Fragment, { children: [
/* @__PURE__ */ jsx(
Button,
{
type: "button",
variant: "outline",
size: "sm",
"aria-label": "Open preview menu",
"aria-haspopup": "menu",
"aria-expanded": open,
className: cn("h-auto", pad),
onClick: () => setOpen((current) => !current),
children: /* @__PURE__ */ jsx(Icon, { name: "codicon:ellipsis" })
}
),
open && /* @__PURE__ */ jsx(
"div",
{
role: "menu",
"aria-label": "Preview options",
className: "absolute right-0 top-[calc(100%+0.375rem)] z-50 min-w-[12rem] rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-lg shadow-black/5",
children: PREVIEW_OPTIONS.map((option) => {
const active = option.value === previewMode;
return /* @__PURE__ */ jsxs(
"button",
{
type: "button",
role: "menuitemradio",
"aria-checked": active,
className: cn(
"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm transition-colors",
"hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none"
),
onClick: () => {
onPreviewModeChange(option.value);
setOpen(false);
},
children: [
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1", children: option.label }),
active ? /* @__PURE__ */ jsx(Icon, { name: "ph:check", className: "shrink-0" }) : null
]
},
option.value
);
})
}
)
] })
] });
}
export {
ACCEPT_OPTIONS,
AcceptPicker,
VIEW_OPTIONS
};
//# sourceMappingURL=AcceptPicker.js.map