mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-06-04 20:43:01 +00:00
cleanup
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import { JSX, For, createSignal, createContext, useContext, ParentComponent, splitProps, children, Accessor } from "solid-js";
|
||||
import type { ResolvedChildren } from "solid-js";
|
||||
|
||||
// Context for tab state
|
||||
interface TabsContextValue {
|
||||
selectedTab: Accessor<string>;
|
||||
setSelectedTab: (id: string) => void;
|
||||
}
|
||||
|
||||
const TabsContext = createContext<TabsContextValue>();
|
||||
|
||||
const useTabs = () => {
|
||||
const context = useContext(TabsContext);
|
||||
if (!context) {
|
||||
throw new Error("useTabs must be used within a Tabs component");
|
||||
}
|
||||
return context;
|
||||
};
|
||||
|
||||
// Tabs Root Component
|
||||
interface TabsProps {
|
||||
defaultValue: string;
|
||||
value?: string;
|
||||
onValueChange?: (value: string) => void;
|
||||
children: JSX.Element;
|
||||
class?: string;
|
||||
}
|
||||
|
||||
export const Tabs: ParentComponent<TabsProps> = (props) => {
|
||||
const [local, rest] = splitProps(props, ["defaultValue", "value", "onValueChange", "children", "class"]);
|
||||
const [selectedTab, setSelectedTabInternal] = createSignal(local.defaultValue);
|
||||
|
||||
const setSelectedTab = (id: string) => {
|
||||
setSelectedTabInternal(id);
|
||||
local.onValueChange?.(id);
|
||||
};
|
||||
|
||||
// If controlled, use the provided value
|
||||
const currentTab = () => local.value ?? selectedTab();
|
||||
|
||||
const contextValue: TabsContextValue = {
|
||||
selectedTab: currentTab,
|
||||
setSelectedTab,
|
||||
};
|
||||
|
||||
return (
|
||||
<TabsContext.Provider value={contextValue}>
|
||||
<div class={local.class} {...rest}>
|
||||
{local.children}
|
||||
</div>
|
||||
</TabsContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
// Tabs List Component
|
||||
interface TabsListProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
||||
variant?: "default" | "pills" | "underline";
|
||||
}
|
||||
|
||||
export const TabsList: ParentComponent<TabsListProps> = (props) => {
|
||||
const [local, rest] = splitProps(props, ["variant", "children", "class"]);
|
||||
|
||||
const variantClasses = {
|
||||
default: "bg-canvas-muted p-1 rounded-card",
|
||||
pills: "gap-1",
|
||||
underline: "border-b border-border gap-4",
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
"flex items-center",
|
||||
variantClasses[local.variant || "default"],
|
||||
local.class || "",
|
||||
].join(" ")}
|
||||
role="tablist"
|
||||
{...rest}
|
||||
>
|
||||
{local.children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Tab Trigger Component
|
||||
interface TabsTriggerProps extends JSX.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const TabsTrigger: ParentComponent<TabsTriggerProps> = (props) => {
|
||||
const [local, rest] = splitProps(props, ["value", "children", "class"]);
|
||||
const tabs = useTabs();
|
||||
const isSelected = () => tabs.selectedTab() === local.value;
|
||||
|
||||
return (
|
||||
<button
|
||||
role="tab"
|
||||
aria-selected={isSelected()}
|
||||
class={[
|
||||
"px-4 py-2 text-sm font-display font-medium transition-all duration-200",
|
||||
"focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 focus-visible:ring-offset-2",
|
||||
"rounded-button",
|
||||
isSelected()
|
||||
? "bg-canvas text-ink shadow-sm"
|
||||
: "text-ink-muted hover:text-ink hover:bg-canvas-subtle",
|
||||
local.class || "",
|
||||
].join(" ")}
|
||||
onClick={() => tabs.setSelectedTab(local.value)}
|
||||
{...rest}
|
||||
>
|
||||
{local.children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
// Tab Content Component
|
||||
interface TabsContentProps extends JSX.HTMLAttributes<HTMLDivElement> {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const TabsContent: ParentComponent<TabsContentProps> = (props) => {
|
||||
const [local, rest] = splitProps(props, ["value", "children", "class"]);
|
||||
const tabs = useTabs();
|
||||
const isSelected = () => tabs.selectedTab() === local.value;
|
||||
|
||||
return (
|
||||
<div
|
||||
role="tabpanel"
|
||||
class={[
|
||||
"mt-4",
|
||||
isSelected() ? "block animate-fade-in" : "hidden",
|
||||
local.class || "",
|
||||
].join(" ")}
|
||||
{...rest}
|
||||
>
|
||||
{local.children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user