@spark-ui/components
Version:
Spark (Leboncoin design system) components.
391 lines (376 loc) • 11.5 kB
JavaScript
import {
Button
} from "../chunk-USSL4UZ5.mjs";
import "../chunk-MUNDKRAE.mjs";
import {
Icon
} from "../chunk-AESXFMCC.mjs";
import "../chunk-NBZKMCHF.mjs";
import "../chunk-4F5DOL57.mjs";
// src/tabs/Tabs.tsx
import { Tabs as RadixTabs } from "radix-ui";
// src/tabs/TabsContext.tsx
import { createContext, useContext } from "react";
var TabsContext = createContext({});
var useTabsContext = () => {
const context = useContext(TabsContext);
if (!context) {
throw Error("useTabsContext must be used within a TabsContext Provider");
}
return context;
};
// src/tabs/TabsRoot.styles.ts
import { cva } from "class-variance-authority";
var rootStyles = cva([
"flex",
"data-[orientation=horizontal]:flex-col",
"data-[orientation=vertical]:flex-row",
"max-w-full"
]);
// src/tabs/Tabs.tsx
import { jsx } from "react/jsx-runtime";
var Tabs = ({
intent = "basic",
size = "md",
/**
* Default Radix Primitive values
* see https://www.radix-ui.com/docs/primitives/components/tabs#root
*/
asChild = false,
forceMount = false,
orientation = "horizontal",
children,
className,
ref,
...rest
}) => {
return /* @__PURE__ */ jsx(
TabsContext.Provider,
{
value: {
intent,
size,
orientation,
forceMount
},
children: /* @__PURE__ */ jsx(
RadixTabs.Root,
{
ref,
asChild,
orientation,
className: rootStyles({ className }),
"data-spark-component": "tabs",
activationMode: "automatic",
...rest,
children
}
)
}
);
};
Tabs.displayName = "Tabs";
// src/tabs/TabsContent.tsx
import { Tabs as RadixTabs2 } from "radix-ui";
// src/tabs/TabsContent.styles.ts
import { cva as cva2 } from "class-variance-authority";
var contentStyles = cva2(["w-full p-lg", "focus-visible:u-outline-inset"], {
variants: {
forceMount: {
true: "data-[state=inactive]:hidden",
false: ""
}
}
});
// src/tabs/TabsContent.tsx
import { jsx as jsx2 } from "react/jsx-runtime";
var TabsContent = ({
/**
* Default Radix Primitive values
* see https://www.radix-ui.com/docs/primitives/components/tabs#content
*/
children,
asChild = false,
className,
ref,
...rest
}) => {
const { forceMount } = useTabsContext();
return /* @__PURE__ */ jsx2(
RadixTabs2.Content,
{
ref,
forceMount: forceMount || rest.forceMount,
className: contentStyles({ className, forceMount }),
asChild,
...rest,
children
}
);
};
TabsContent.displayName = "Tabs.Content";
// src/tabs/TabsList.tsx
import { ArrowVerticalLeft } from "@spark-ui/icons/ArrowVerticalLeft";
import { ArrowVerticalRight } from "@spark-ui/icons/ArrowVerticalRight";
import { Tabs as RadixTabs3 } from "radix-ui";
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
// src/tabs/TabsList.styles.ts
import { cva as cva3 } from "class-variance-authority";
var wrapperStyles = cva3(["relative flex"]);
var listStyles = cva3([
"flex w-full",
"data-[orientation=horizontal]:flex-row",
"data-[orientation=vertical]:flex-col",
"overflow-y-hidden u-no-scrollbar data-[orientation=vertical]:overflow-x-hidden",
"after:flex after:shrink after:grow after:border-outline",
"data-[orientation=horizontal]:after:border-b-sm",
"data-[orientation=vertical]:after:border-r-sm"
]);
var navigationArrowStyles = cva3([
"h-auto! flex-none",
"border-b-sm border-outline",
"outline-hidden",
"focus-visible:border-none focus-visible:bg-surface-hovered focus-visible:u-outline-inset!"
]);
// src/tabs/useResizeObserver.ts
import { useEffect, useRef, useState } from "react";
var useResizeObserver = (target, onResize) => {
const [size, setSize] = useState({ width: void 0, height: void 0 });
const resizeObserverRef = useRef(null);
const resizeCallbackRef = useRef(onResize);
useEffect(() => {
resizeCallbackRef.current = onResize;
}, [onResize]);
useEffect(() => {
const targetElm = target && "current" in target ? target.current : target;
if (!targetElm || resizeObserverRef.current) {
return;
}
resizeObserverRef.current = new ResizeObserver(([entry]) => {
const { inlineSize: width, blockSize: height } = entry?.borderBoxSize?.[0] ?? {};
resizeCallbackRef.current?.(entry);
setSize({ width, height });
});
resizeObserverRef.current.observe(targetElm);
return () => {
resizeObserverRef.current && resizeObserverRef.current.unobserve(targetElm);
};
}, [target, resizeObserverRef, resizeCallbackRef]);
return size;
};
// src/tabs/TabsList.tsx
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
var TabsList = ({
/**
* Default Radix Primitive values
* see https://www.radix-ui.com/docs/primitives/components/tabs#list
*/
asChild = false,
loop = false,
children,
className,
ref,
...rest
}) => {
const wrapperRef = useRef2(null);
const innerRef = useRef2(null);
const listRef = ref || innerRef;
const { orientation } = useTabsContext();
const { width } = useResizeObserver(wrapperRef);
const [arrows, setArrows] = useState2({
prev: "hidden",
next: "hidden"
});
useEffect2(() => {
if (typeof listRef === "function" || !listRef.current) {
return;
}
if (orientation !== "horizontal") {
setArrows({ prev: "hidden", next: "hidden" });
} else {
setArrows({
prev: listRef.current.scrollWidth > listRef.current.clientWidth ? "visible" : "hidden",
next: listRef.current.scrollWidth > listRef.current.clientWidth ? "visible" : "hidden"
});
}
}, [orientation, listRef, width]);
useEffect2(() => {
if (typeof listRef === "function" || !listRef.current || arrows.prev === "hidden" || loop) {
return;
}
const toggleArrowsVisibility = (target) => {
setArrows({
prev: target.scrollLeft > 0 ? "visible" : "disabled",
next: target.scrollLeft + target.clientWidth < target.scrollWidth ? "visible" : "disabled"
});
};
const currentList = listRef.current;
toggleArrowsVisibility(currentList);
currentList.addEventListener(
"scroll",
({ target }) => toggleArrowsVisibility(target)
);
return () => currentList.removeEventListener(
"scroll",
({ target }) => toggleArrowsVisibility(target)
);
}, [listRef, arrows.prev, loop]);
const handlePrevClick = () => {
if (typeof listRef === "function" || !listRef.current) {
return;
}
const shouldLoopForward = loop && listRef.current.scrollLeft <= 0;
listRef.current.scrollTo({
left: shouldLoopForward ? listRef.current.scrollLeft + listRef.current.scrollWidth - listRef.current.clientWidth : listRef.current.scrollLeft - listRef.current.clientWidth,
behavior: "smooth"
});
};
const handleNextClick = () => {
if (typeof listRef === "function" || !listRef.current) {
return;
}
const shouldLoopBackward = loop && listRef.current.scrollLeft + listRef.current.clientWidth >= listRef.current.scrollWidth;
listRef.current.scrollTo({
left: shouldLoopBackward ? 0 : listRef.current.scrollLeft + listRef.current.clientWidth,
behavior: "smooth"
});
};
return /* @__PURE__ */ jsxs("div", { className: wrapperStyles({ className }), ref: wrapperRef, children: [
arrows.prev !== "hidden" && /* @__PURE__ */ jsx3(
Button,
{
shape: "square",
intent: "surface",
size: "sm",
className: navigationArrowStyles(),
onClick: handlePrevClick,
disabled: arrows.prev === "disabled",
"aria-label": "Scroll left",
children: /* @__PURE__ */ jsx3(Icon, { children: /* @__PURE__ */ jsx3(ArrowVerticalLeft, {}) })
}
),
/* @__PURE__ */ jsx3(
RadixTabs3.List,
{
ref: listRef,
className: listStyles(),
asChild,
loop,
...rest,
children
}
),
arrows.next !== "hidden" && /* @__PURE__ */ jsx3(
Button,
{
shape: "square",
intent: "surface",
size: "sm",
className: navigationArrowStyles(),
onClick: handleNextClick,
disabled: arrows.next === "disabled",
"aria-label": "Scroll right",
children: /* @__PURE__ */ jsx3(Icon, { children: /* @__PURE__ */ jsx3(ArrowVerticalRight, {}) })
}
)
] });
};
TabsList.displayName = "Tabs.List";
// src/tabs/TabsTrigger.tsx
import { Tabs as RadixTabs4 } from "radix-ui";
// src/tabs/TabsTrigger.styles.ts
import { makeVariants } from "@spark-ui/internal-utils";
import { cva as cva4 } from "class-variance-authority";
var triggerVariants = cva4(
[
"px-md",
"relative flex flex-none items-center",
"border-outline",
"outline-hidden",
"hover:bg-surface-hovered",
"after:absolute",
"data-[orientation=horizontal]:border-b-sm data-[orientation=horizontal]:after:inset-x-0 data-[orientation=horizontal]:after:bottom-[-1px] data-[orientation=horizontal]:after:h-sz-2",
"data-[orientation=vertical]:border-r-sm data-[orientation=vertical]:after:inset-y-0 data-[orientation=vertical]:after:right-[-1px] data-[orientation=vertical]:after:w-sz-2",
"focus-visible:border-none focus-visible:bg-surface-hovered focus-visible:u-outline-inset",
"disabled:cursor-not-allowed disabled:opacity-dim-3",
"duration-300 ease-linear",
"gap-md [&>*:first-child]:ml-md [&>*:last-child]:mr-md",
"[&>svg:last-child:first-child]:mx-auto"
],
{
variants: {
/**
* Change the color scheme of the tabs
* @default basic
*/
intent: makeVariants({
main: ["data-[state=active]:text-main data-[state=active]:after:bg-main"],
support: ["data-[state=active]:text-support data-[state=active]:after:bg-support"],
basic: ["data-[state=active]:text-basic data-[state=active]:after:bg-basic"]
}),
/**
* Change the size of the tabs
* @default md
*/
size: {
xs: ["h-sz-32 min-w-sz-32 text-caption"],
sm: ["h-sz-36 min-w-sz-36 text-body-2"],
md: ["h-sz-40 min-w-sz-40 text-body-1"]
}
},
defaultVariants: {
intent: "basic",
size: "md"
}
}
);
// src/tabs/TabsTrigger.tsx
import { jsx as jsx4 } from "react/jsx-runtime";
var TabsTrigger = ({
/**
* Default Radix Primitive values
* see https://www.radix-ui.com/docs/primitives/components/tabs#trigger
*/
asChild = false,
value,
disabled = false,
children,
className,
ref,
...rest
}) => {
const { intent, size } = useTabsContext();
const scrollToFocusedElement = ({ target }) => target.scrollIntoView({
behavior: "smooth",
block: "nearest",
inline: "nearest"
});
return /* @__PURE__ */ jsx4(
RadixTabs4.Trigger,
{
ref,
className: triggerVariants({ intent, size, className }),
asChild,
disabled,
value,
onFocus: scrollToFocusedElement,
...rest,
children
}
);
};
TabsTrigger.displayName = "Tabs.Trigger";
// src/tabs/index.ts
var Tabs2 = Object.assign(Tabs, {
List: TabsList,
Trigger: TabsTrigger,
Content: TabsContent
});
Tabs2.displayName = "Tabs";
TabsList.displayName = "Tabs.List";
TabsTrigger.displayName = "Tabs.Trigger";
TabsContent.displayName = "Tabs.Content";
export {
Tabs2 as Tabs
};
//# sourceMappingURL=index.mjs.map