@spark-ui/components
Version:
Spark (Leboncoin design system) components.
1,678 lines (1,636 loc) • 47.6 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/carousel/index.ts
var carousel_exports = {};
__export(carousel_exports, {
Carousel: () => Carousel2
});
module.exports = __toCommonJS(carousel_exports);
// src/carousel/Carousel.tsx
var import_class_variance_authority = require("class-variance-authority");
var import_react7 = require("react");
// src/carousel/useCarousel.ts
var import_react6 = require("react");
// src/carousel/useEvent.ts
var import_react = require("react");
function useEvent(callback) {
const ref = (0, import_react.useRef)(() => {
throw new Error("Cannot call an event handler while rendering.");
});
(0, import_react.useLayoutEffect)(() => {
ref.current = callback;
});
return (0, import_react.useCallback)((...args) => ref.current?.(...args), []);
}
// src/carousel/useIsMounted.ts
var import_react2 = require("react");
var useIsMounted = () => {
const isMounted = (0, import_react2.useRef)(false);
(0, import_react2.useEffect)(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return isMounted;
};
// src/carousel/useScrollEnd.ts
var import_react3 = require("react");
function useScrollEnd(scrollRef, callback) {
const scrollLeft = (0, import_react3.useRef)(0);
const safariTimeout = (0, import_react3.useRef)(null);
(0, import_react3.useEffect)(() => {
const element = scrollRef.current;
if (!element) return;
const supportsScrollend = "onscrollend" in window;
const handleScrollEnd = () => {
callback();
};
const handleSafariScroll = () => {
if (safariTimeout.current) {
clearTimeout(safariTimeout.current);
}
if (scrollRef.current) {
scrollLeft.current = scrollRef.current.scrollLeft;
safariTimeout.current = setTimeout(() => {
if (scrollRef.current) {
handleScrollEnd();
}
}, 150);
}
};
if (supportsScrollend) {
element.addEventListener("scrollend", handleScrollEnd);
} else {
element.addEventListener("scroll", handleSafariScroll);
}
return () => {
if (safariTimeout.current) {
clearTimeout(safariTimeout.current);
}
if (supportsScrollend) {
element.removeEventListener("scrollend", handleScrollEnd);
} else {
element.removeEventListener("scroll", handleSafariScroll);
}
};
}, [callback, scrollRef]);
}
// src/carousel/useSnapPoints.ts
var import_react5 = require("react");
// src/carousel/useResizeObserver.ts
var import_react4 = require("react");
function useResizeObserver(ref, callback) {
(0, import_react4.useLayoutEffect)(() => {
const element = ref.current;
if (!element) return;
const observer = new ResizeObserver((entries) => {
for (const entry of entries) {
callback(entry.contentRect.width);
}
});
observer.observe(element);
return () => observer.disconnect();
}, [ref, callback]);
}
// src/carousel/utils.ts
function getSnapIndices({
totalSlides,
slidesPerMove,
slidesPerPage
}) {
const slideBy = slidesPerMove === "auto" ? slidesPerPage : slidesPerMove;
const snapPoints = [];
const lastSnapIndex = Math.floor((totalSlides - slidesPerPage) / slideBy) * slideBy;
for (let i = 0; i <= lastSnapIndex; i += slideBy) {
snapPoints.push(i);
}
if (snapPoints[snapPoints.length - 1] !== totalSlides - slidesPerPage) {
snapPoints.push(totalSlides - slidesPerPage);
}
return snapPoints;
}
function getSlideElements(container) {
return container ? Array.from(container.querySelectorAll('[data-part="item"]')) : [];
}
function isSnapPoint(slideIndex, {
container,
slidesPerMove,
slidesPerPage
}) {
return getSnapIndices({
totalSlides: getSlideElements(container).length,
slidesPerPage,
slidesPerMove
}).includes(slideIndex);
}
function getSnapPositions({
container,
slidesPerMove,
slidesPerPage
}) {
if (!container) return [];
return getSlideElements(container).filter((_, index) => {
return isSnapPoint(index, {
slidesPerMove,
slidesPerPage,
container
});
}).map((slide) => slide.offsetLeft);
}
// src/carousel/useSnapPoints.ts
function useSnapPoints(initialSnapPoints = [], {
carouselRef,
slidesPerMove,
slidesPerPage
}) {
const [pageSnapPoints, setPageSnapPoints] = (0, import_react5.useState)(initialSnapPoints);
const stableSnapPoints = (0, import_react5.useMemo)(() => pageSnapPoints, [pageSnapPoints]);
useResizeObserver(carouselRef, () => {
const newSnapPoints = getSnapPositions({
slidesPerMove,
slidesPerPage,
container: carouselRef.current
});
if (JSON.stringify(pageSnapPoints) !== JSON.stringify(newSnapPoints)) {
setPageSnapPoints(newSnapPoints);
}
});
return [stableSnapPoints, setPageSnapPoints];
}
// src/carousel/useCarousel.ts
var DATA_SCOPE = "carousel";
var DIRECTION = "ltr";
var useCarousel = ({
defaultPage,
gap = 16,
snapType = "mandatory",
snapStop = "always",
scrollPadding = 0,
slidesPerPage = 1,
slidesPerMove = "auto",
scrollBehavior = "smooth",
loop = false,
// state control
page: controlledPage,
onPageChange: onPageChangeProp
}) => {
const carouselId = (0, import_react6.useId)();
const [pageState, setPageState] = (0, import_react6.useState)(defaultPage || controlledPage || 0);
const carouselRef = (0, import_react6.useRef)(null);
const pageIndicatorsRefs = (0, import_react6.useRef)([]);
const isMountedRef = useIsMounted();
const isMounted = isMountedRef.current;
const onPageChange = useEvent(onPageChangeProp);
const [pageSnapPoints] = useSnapPoints([], {
carouselRef,
slidesPerMove,
slidesPerPage
});
const canScrollPrev = (0, import_react6.useRef)(loop || pageState > 0);
const canScrollNext = (0, import_react6.useRef)(loop || pageState < pageSnapPoints.length - 1);
canScrollPrev.current = loop || pageState > 0;
canScrollNext.current = loop || pageState < pageSnapPoints.length - 1;
const handlePageChange = (0, import_react6.useCallback)(
(page) => {
if (page !== pageState) {
setPageState(page);
onPageChange?.(page);
}
},
[onPageChange, pageState]
);
const scrollTo = (0, import_react6.useCallback)(
(page, behavior) => {
if (carouselRef.current) {
carouselRef.current.scrollTo({
left: pageSnapPoints[page],
behavior: behavior === "instant" ? "auto" : "smooth"
});
handlePageChange(page);
}
},
[handlePageChange, pageSnapPoints]
);
const scrollPrev = (0, import_react6.useCallback)(
(cb) => {
if (canScrollPrev) {
const targetPage = loop && pageState === 0 ? pageSnapPoints.length - 1 : Math.max(pageState - 1, 0);
scrollTo(targetPage, scrollBehavior);
cb?.(targetPage);
}
},
[loop, pageSnapPoints, pageState, scrollBehavior, scrollTo]
);
const scrollNext = (0, import_react6.useCallback)(
(cb) => {
if (canScrollNext) {
const targetPage = loop && pageState === pageSnapPoints.length - 1 ? 0 : Math.min(pageState + 1, pageSnapPoints.length - 1);
scrollTo(targetPage, scrollBehavior);
cb?.(targetPage);
}
},
[loop, pageSnapPoints, pageState, scrollBehavior, scrollTo]
);
(0, import_react6.useEffect)(() => {
if (controlledPage != null) {
scrollTo(controlledPage, scrollBehavior);
}
}, [controlledPage, scrollBehavior, scrollTo]);
(0, import_react6.useLayoutEffect)(() => {
if (defaultPage != null && !isMounted && carouselRef.current) {
const snapPositions = getSnapPositions({
container: carouselRef.current,
slidesPerMove,
slidesPerPage
});
carouselRef.current.scrollTo({
left: snapPositions[defaultPage],
behavior: "instant"
});
}
}, [defaultPage, isMounted, slidesPerMove, slidesPerPage]);
const syncPageStateWithScrollPosition = (0, import_react6.useCallback)(() => {
if (!carouselRef.current || pageSnapPoints.length === 0) return;
const { scrollLeft } = carouselRef.current;
const distances = pageSnapPoints.map((pagePosition) => Math.abs(scrollLeft - pagePosition));
const pageInViewport = distances.indexOf(Math.min(...distances));
if (pageInViewport !== -1) {
handlePageChange(pageInViewport);
}
}, [pageSnapPoints, handlePageChange]);
useScrollEnd(carouselRef, syncPageStateWithScrollPosition);
const contextValue = {
ref: carouselRef,
pageIndicatorsRefs,
// props
gap,
snapType,
snapStop,
scrollPadding,
slidesPerPage,
slidesPerMove,
scrollBehavior,
loop,
// computed state
page: pageState,
pageSnapPoints,
canScrollNext: canScrollNext.current,
canScrollPrev: canScrollPrev.current,
scrollTo,
scrollPrev,
scrollNext,
// anatomy
getRootProps: () => ({
id: `carousel::${carouselId}:`,
role: "region",
"aria-roledescription": "carousel",
"data-scope": DATA_SCOPE,
"data-part": "root",
"data-orientation": "horizontal",
dir: DIRECTION,
style: {
"--slides-per-page": slidesPerPage,
"--slide-spacing": `${gap}px`,
"--slide-item-size": "calc(100% / var(--slides-per-page) - var(--slide-spacing) * (var(--slides-per-page) - 1) / var(--slides-per-page))"
}
}),
getControlProps: () => ({
"data-scope": DATA_SCOPE,
"data-part": "control",
"data-orientation": "horizontal"
}),
getPrevTriggerProps: () => ({
id: `carousel::${carouselId}::prev-trigger`,
"aria-controls": `carousel::${carouselId}::item-group`,
"data-scope": DATA_SCOPE,
"data-part": "prev-trigger",
"data-orientation": "horizontal",
type: "button",
dir: DIRECTION,
disabled: !canScrollPrev.current,
onClick: () => scrollPrev()
}),
getNextTriggerProps: () => ({
id: `carousel::${carouselId}::next-trigger`,
"aria-controls": `carousel::${carouselId}::item-group`,
"data-scope": DATA_SCOPE,
"data-part": "next-trigger",
"data-orientation": "horizontal",
type: "button",
dir: DIRECTION,
disabled: !canScrollNext.current,
onClick: () => scrollNext()
}),
getSlidesContainerProps: () => ({
id: `carousel::${carouselId}::item-group`,
"aria-live": slidesPerPage > 1 ? "off" : "polite",
"data-scope": DATA_SCOPE,
"data-part": "item-group",
"data-orientation": "horizontal",
dir: DIRECTION,
tabIndex: 0,
style: {
display: "grid",
gap: "var(--slide-spacing)",
scrollSnapType: `x ${snapType}`,
gridAutoFlow: "column",
scrollbarWidth: "none",
overscrollBehavior: "contain",
gridAutoColumns: "var(--slide-item-size)",
overflowX: "auto"
},
ref: carouselRef
}),
getSlideProps: ({ index }) => {
const isStopPoint = isSnapPoint(index, {
container: carouselRef.current,
slidesPerMove,
slidesPerPage
});
return {
id: `carousel::${carouselId}::item:${index}`,
role: "group",
"aria-roledescription": "slide",
"data-scope": DATA_SCOPE,
"data-part": "item",
"data-index": index,
"data-orientation": "horizontal",
dir: DIRECTION,
style: {
...isStopPoint && {
scrollSnapAlign: "start",
scrollSnapStop: snapStop
}
}
};
},
getIndicatorGroupProps: () => ({
role: "radiogroup",
id: `carousel::${carouselId}::indicator-group`,
"data-scope": DATA_SCOPE,
"data-part": "indicator-group",
"data-orientation": "horizontal",
dir: DIRECTION
}),
getIndicatorProps: ({ index }) => {
const isActivePage = index === pageState;
return {
role: "radio",
id: `carousel::${carouselId}::indicator:${index}`,
"aria-checked": isActivePage,
"data-scope": DATA_SCOPE,
"data-part": "indicator",
"data-orientation": "horizontal",
"data-index": index,
"data-state": isActivePage ? "active" : "inactive",
tabIndex: isActivePage ? 0 : -1,
onClick: () => {
scrollTo(index, scrollBehavior);
},
onKeyDown: (event) => {
const focusActiveIndicator = (page) => {
pageIndicatorsRefs.current[page]?.focus();
};
if (event.key === "ArrowRight" && canScrollNext) {
scrollNext(focusActiveIndicator);
} else if (event.key === "ArrowLeft" && canScrollPrev) {
scrollPrev(focusActiveIndicator);
}
}
};
}
};
return contextValue;
};
// src/carousel/Carousel.tsx
var import_jsx_runtime = require("react/jsx-runtime");
var CarouselContext = (0, import_react7.createContext)(null);
var Carousel = ({
className,
snapType = "mandatory",
snapStop = "always",
scrollBehavior = "smooth",
slidesPerMove = "auto",
slidesPerPage = 1,
loop = false,
children,
gap = 16,
defaultPage,
page,
onPageChange
}) => {
const carouselApi = useCarousel({
defaultPage,
slidesPerPage,
slidesPerMove,
loop,
gap,
scrollBehavior,
snapStop,
snapType,
page,
onPageChange
});
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
CarouselContext.Provider,
{
value: {
...carouselApi,
scrollBehavior
},
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"div",
{
className: (0, import_class_variance_authority.cx)("gap-lg relative box-border flex flex-col", className),
...carouselApi.getRootProps(),
children
}
)
}
);
};
Carousel.displayName = "Carousel";
var useCarouselContext = () => {
const context = (0, import_react7.useContext)(CarouselContext);
if (!context) {
throw Error("useCarouselContext must be used within a Carousel provider");
}
return context;
};
// src/carousel/CarouselControls.tsx
var import_jsx_runtime2 = require("react/jsx-runtime");
var CarouselControls = ({ children }) => {
const ctx = useCarouselContext();
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"div",
{
className: "default:px-lg pointer-events-none absolute inset-0 flex flex-row items-center justify-between",
...ctx.getControlProps(),
children
}
);
};
CarouselControls.displayName = "Carousel.Controls";
// src/carousel/CarouselNextButton.tsx
var import_ArrowVerticalRight = require("@spark-ui/icons/ArrowVerticalRight");
// src/icon/Icon.tsx
var import_react9 = require("react");
// src/slot/Slot.tsx
var import_radix_ui = require("radix-ui");
var import_react8 = require("react");
var import_jsx_runtime3 = require("react/jsx-runtime");
var Slottable = import_radix_ui.Slot.Slottable;
var Slot = ({ ref, ...props }) => {
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_radix_ui.Slot.Root, { ref, ...props });
};
var wrapPolymorphicSlot = (asChild, children, callback) => {
if (!asChild) return callback(children);
return (0, import_react8.isValidElement)(children) ? (0, import_react8.cloneElement)(
children,
void 0,
callback(children.props.children)
) : null;
};
// src/visually-hidden/VisuallyHidden.tsx
var import_jsx_runtime4 = require("react/jsx-runtime");
var VisuallyHidden = ({ asChild = false, ref, ...props }) => {
const Component = asChild ? Slot : "span";
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
Component,
{
...props,
ref,
style: {
// See: https://github.com/twbs/bootstrap/blob/main/scss/mixins/_visually-hidden.scss
position: "absolute",
border: 0,
width: 1,
height: 1,
padding: 0,
margin: -1,
overflow: "hidden",
clip: "rect(0, 0, 0, 0)",
whiteSpace: "nowrap",
wordWrap: "normal",
...props.style
}
}
);
};
VisuallyHidden.displayName = "VisuallyHidden";
// src/icon/Icon.styles.tsx
var import_internal_utils = require("@spark-ui/internal-utils");
var import_class_variance_authority2 = require("class-variance-authority");
var iconStyles = (0, import_class_variance_authority2.cva)(["fill-current shrink-0"], {
variants: {
/**
* Color scheme of the icon.
*/
intent: (0, import_internal_utils.makeVariants)({
current: ["text-current"],
main: ["text-main"],
support: ["text-support"],
accent: ["text-accent"],
basic: ["text-basic"],
success: ["text-success"],
alert: ["text-alert"],
error: ["text-error"],
info: ["text-info"],
neutral: ["text-neutral"]
}),
/**
* Sets the size of the icon.
*/
size: (0, import_internal_utils.makeVariants)({
current: ["u-current-font-size"],
sm: ["w-sz-16", "h-sz-16"],
md: ["w-sz-24", "h-sz-24"],
lg: ["w-sz-32", "h-sz-32"],
xl: ["w-sz-40", "h-sz-40"]
})
}
});
// src/icon/Icon.tsx
var import_jsx_runtime5 = require("react/jsx-runtime");
var Icon = ({
label,
className,
size = "current",
intent = "current",
children,
...others
}) => {
const child = import_react9.Children.only(children);
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
(0, import_react9.cloneElement)(child, {
className: iconStyles({ className, size, intent }),
"data-spark-component": "icon",
"aria-hidden": "true",
focusable: "false",
...others
}),
label && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(VisuallyHidden, { children: label })
] });
};
Icon.displayName = "Icon";
// src/button/Button.tsx
var import_class_variance_authority5 = require("class-variance-authority");
var import_react10 = require("react");
// src/spinner/Spinner.styles.tsx
var import_internal_utils2 = require("@spark-ui/internal-utils");
var import_class_variance_authority3 = require("class-variance-authority");
var defaultVariants = {
intent: "current",
size: "current",
isBackgroundVisible: false
};
var spinnerStyles = (0, import_class_variance_authority3.cva)(
["inline-block", "border-solid", "rounded-full", "border-md", "animate-spin"],
{
variants: {
/**
* Use `size` prop to set the size of the spinner. If you want to set the full size for the spinner, don't forget to add a wrapping container with its own size.
*/
size: {
current: ["u-current-font-size"],
sm: ["w-sz-20", "h-sz-20"],
md: ["w-sz-28", "h-sz-28"],
full: ["w-full", "h-full"]
},
/**
* Color scheme of the spinner.
*/
intent: (0, import_internal_utils2.makeVariants)({
current: ["border-current"],
main: ["border-main"],
support: ["border-support"],
accent: ["border-accent"],
basic: ["border-basic"],
success: ["border-success"],
alert: ["border-alert"],
error: ["border-error"],
info: ["border-info"],
neutral: ["border-neutral"]
}),
/**
* Size of the button.
*/
isBackgroundVisible: {
true: ["border-b-neutral-container", "border-l-neutral-container"],
false: ["border-b-transparent", "border-l-transparent"]
}
},
defaultVariants
}
);
// src/spinner/Spinner.tsx
var import_jsx_runtime6 = require("react/jsx-runtime");
var Spinner = ({
className,
size = "current",
intent = "current",
label,
isBackgroundVisible,
ref,
...others
}) => {
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
"span",
{
role: "status",
"data-spark-component": "spinner",
ref,
className: spinnerStyles({ className, size, intent, isBackgroundVisible }),
...others,
children: label && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(VisuallyHidden, { children: label })
}
);
};
// src/button/Button.styles.tsx
var import_internal_utils8 = require("@spark-ui/internal-utils");
var import_class_variance_authority4 = require("class-variance-authority");
// src/button/variants/filled.ts
var import_internal_utils3 = require("@spark-ui/internal-utils");
var filledVariants = [
// Main
{
intent: "main",
design: "filled",
class: (0, import_internal_utils3.tw)([
"bg-main",
"text-on-main",
"hover:bg-main-hovered",
"enabled:active:bg-main-hovered",
"focus-visible:bg-main-hovered"
])
},
// Support
{
intent: "support",
design: "filled",
class: (0, import_internal_utils3.tw)([
"bg-support",
"text-on-support",
"hover:bg-support-hovered",
"enabled:active:bg-support-hovered",
"focus-visible:bg-support-hovered"
])
},
// Accent
{
intent: "accent",
design: "filled",
class: (0, import_internal_utils3.tw)([
"bg-accent",
"text-on-accent",
"hover:bg-accent-hovered",
"enabled:active:bg-accent-hovered",
"focus-visible:bg-accent-hovered"
])
},
// Basic
{
intent: "basic",
design: "filled",
class: (0, import_internal_utils3.tw)([
"bg-basic",
"text-on-basic",
"hover:bg-basic-hovered",
"enabled:active:bg-basic-hovered",
"focus-visible:bg-basic-hovered"
])
},
// Success
{
intent: "success",
design: "filled",
class: (0, import_internal_utils3.tw)([
"bg-success",
"text-on-success",
"hover:bg-success-hovered",
"enabled:active:bg-success-hovered",
"focus-visible:bg-success-hovered"
])
},
// Alert
{
intent: "alert",
design: "filled",
class: (0, import_internal_utils3.tw)([
"bg-alert",
"text-on-alert",
"hover:bg-alert-hovered",
"enabled:active:bg-alert-hovered",
"focus-visible:bg-alert-hovered"
])
},
// Danger
{
intent: "danger",
design: "filled",
class: (0, import_internal_utils3.tw)([
"text-on-error bg-error",
"hover:bg-error-hovered enabled:active:bg-error-hovered",
"focus-visible:bg-error-hovered"
])
},
// Info
{
intent: "info",
design: "filled",
class: (0, import_internal_utils3.tw)([
"text-on-error bg-info",
"hover:bg-info-hovered enabled:active:bg-info-hovered",
"focus-visible:bg-info-hovered"
])
},
// Neutral
{
intent: "neutral",
design: "filled",
class: (0, import_internal_utils3.tw)([
"bg-neutral",
"text-on-neutral",
"hover:bg-neutral-hovered",
"enabled:active:bg-neutral-hovered",
"focus-visible:bg-neutral-hovered"
])
},
// Surface
{
intent: "surface",
design: "filled",
class: (0, import_internal_utils3.tw)([
"bg-surface",
"text-on-surface",
"hover:bg-surface-hovered",
"enabled:active:bg-surface-hovered",
"focus-visible:bg-surface-hovered"
])
}
];
// src/button/variants/ghost.ts
var import_internal_utils4 = require("@spark-ui/internal-utils");
var ghostVariants = [
{
intent: "main",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-main",
"hover:bg-main/dim-5",
"enabled:active:bg-main/dim-5",
"focus-visible:bg-main/dim-5"
])
},
{
intent: "support",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-support",
"hover:bg-support/dim-5",
"enabled:active:bg-support/dim-5",
"focus-visible:bg-support/dim-5"
])
},
{
intent: "accent",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-accent",
"hover:bg-accent/dim-5",
"enabled:active:bg-accent/dim-5",
"focus-visible:bg-accent/dim-5"
])
},
{
intent: "basic",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-basic",
"hover:bg-basic/dim-5",
"enabled:active:bg-basic/dim-5",
"focus-visible:bg-basic/dim-5"
])
},
{
intent: "success",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-success",
"hover:bg-success/dim-5",
"enabled:active:bg-success/dim-5",
"focus-visible:bg-success/dim-5"
])
},
{
intent: "alert",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-alert",
"hover:bg-alert/dim-5",
"enabled:active:bg-alert/dim-5",
"focus-visible:bg-alert/dim-5"
])
},
{
intent: "danger",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-error",
"hover:bg-error/dim-5",
"enabled:active:bg-error/dim-5",
"focus-visible:bg-error/dim-5"
])
},
{
intent: "info",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-info",
"hover:bg-info/dim-5",
"enabled:active:bg-info/dim-5",
"focus-visible:bg-info/dim-5"
])
},
{
intent: "neutral",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-neutral",
"hover:bg-neutral/dim-5",
"enabled:active:bg-neutral/dim-5",
"focus-visible:bg-neutral/dim-5"
])
},
{
intent: "surface",
design: "ghost",
class: (0, import_internal_utils4.tw)([
"text-surface",
"hover:bg-surface/dim-5",
"enabled:active:bg-surface/dim-5",
"focus-visible:bg-surface/dim-5"
])
}
];
// src/button/variants/outlined.ts
var import_internal_utils5 = require("@spark-ui/internal-utils");
var outlinedVariants = [
{
intent: "main",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-main/dim-5",
"enabled:active:bg-main/dim-5",
"focus-visible:bg-main/dim-5",
"text-main"
])
},
{
intent: "support",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-support/dim-5",
"enabled:active:bg-support/dim-5",
"focus-visible:bg-support/dim-5",
"text-support"
])
},
{
intent: "accent",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-accent/dim-5",
"enabled:active:bg-accent/dim-5",
"focus-visible:bg-accent/dim-5",
"text-accent"
])
},
{
intent: "basic",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-basic/dim-5",
"enabled:active:bg-basic/dim-5",
"focus-visible:bg-basic/dim-5",
"text-basic"
])
},
{
intent: "success",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-success/dim-5",
"enabled:active:bg-success/dim-5",
"focus-visible:bg-success/dim-5",
"text-success"
])
},
{
intent: "alert",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-alert/dim-5",
"enabled:active:bg-alert/dim-5",
"focus-visible:bg-alert/dim-5",
"text-alert"
])
},
{
intent: "danger",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-error/dim-5",
"enabled:active:bg-error/dim-5",
"focus-visible:bg-error/dim-5",
"text-error"
])
},
{
intent: "info",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-info/dim-5",
"enabled:active:bg-info/dim-5",
"focus-visible:bg-info/dim-5",
"text-info"
])
},
{
intent: "neutral",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-neutral/dim-5",
"enabled:active:bg-neutral/dim-5",
"focus-visible:bg-neutral/dim-5",
"text-neutral"
])
},
{
intent: "surface",
design: "outlined",
class: (0, import_internal_utils5.tw)([
"hover:bg-surface/dim-5",
"enabled:active:bg-surface/dim-5",
"focus-visible:bg-surface/dim-5",
"text-surface"
])
}
];
// src/button/variants/tinted.ts
var import_internal_utils6 = require("@spark-ui/internal-utils");
var tintedVariants = [
{
intent: "main",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-main-container",
"text-on-main-container",
"hover:bg-main-container-hovered",
"enabled:active:bg-main-container-hovered",
"focus-visible:bg-main-container-hovered"
])
},
{
intent: "support",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-support-container",
"text-on-support-container",
"hover:bg-support-container-hovered",
"enabled:active:bg-support-container-hovered",
"focus-visible:bg-support-container-hovered"
])
},
{
intent: "accent",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-accent-container",
"text-on-accent-container",
"hover:bg-accent-container-hovered",
"enabled:active:bg-accent-container-hovered",
"focus-visible:bg-accent-container-hovered"
])
},
{
intent: "basic",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-basic-container",
"text-on-basic-container",
"hover:bg-basic-container-hovered",
"enabled:active:bg-basic-container-hovered",
"focus-visible:bg-basic-container-hovered"
])
},
{
intent: "success",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-success-container",
"text-on-success-container",
"hover:bg-success-container-hovered",
"enabled:active:bg-success-container-hovered",
"focus-visible:bg-success-container-hovered"
])
},
{
intent: "alert",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-alert-container",
"text-on-alert-container",
"hover:bg-alert-container-hovered",
"enabled:active:bg-alert-container-hovered",
"focus-visible:bg-alert-container-hovered"
])
},
{
intent: "danger",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-error-container",
"text-on-error-container",
"hover:bg-error-container-hovered",
"enabled:active:bg-error-container-hovered",
"focus-visible:bg-error-container-hovered"
])
},
{
intent: "info",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-info-container",
"text-on-info-container",
"hover:bg-info-container-hovered",
"enabled:active:bg-info-container-hovered",
"focus-visible:bg-info-container-hovered"
])
},
{
intent: "neutral",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-neutral-container",
"text-on-neutral-container",
"hover:bg-neutral-container-hovered",
"enabled:active:bg-neutral-container-hovered",
"focus-visible:bg-neutral-container-hovered"
])
},
{
intent: "surface",
design: "tinted",
class: (0, import_internal_utils6.tw)([
"bg-surface",
"text-on-surface",
"hover:bg-surface-hovered",
"enabled:active:bg-surface-hovered",
"focus-visible:bg-surface-hovered"
])
}
];
// src/button/variants/contrast.ts
var import_internal_utils7 = require("@spark-ui/internal-utils");
var contrastVariants = [
{
intent: "main",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-main",
"hover:bg-main-container-hovered",
"enabled:active:bg-main-container-hovered",
"focus-visible:bg-main-container-hovered"
])
},
{
intent: "support",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-support",
"hover:bg-support-container-hovered",
"enabled:active:bg-support-container-hovered",
"focus-visible:bg-support-container-hovered"
])
},
{
intent: "accent",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-accent",
"hover:bg-accent-container-hovered",
"enabled:active:bg-accent-container-hovered",
"focus-visible:bg-accent-container-hovered"
])
},
{
intent: "basic",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-basic",
"hover:bg-basic-container-hovered",
"enabled:active:bg-basic-container-hovered",
"focus-visible:bg-basic-container-hovered"
])
},
{
intent: "success",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-success",
"hover:bg-success-container-hovered",
"enabled:active:bg-success-container-hovered",
"focus-visible:bg-success-container-hovered"
])
},
{
intent: "alert",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-alert",
"hover:bg-alert-container-hovered",
"enabled:active:bg-alert-container-hovered",
"focus-visible:bg-alert-container-hovered"
])
},
{
intent: "danger",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-error",
"hover:bg-error-container-hovered",
"enabled:active:bg-error-container-hovered",
"focus-visible:bg-error-container-hovered"
])
},
{
intent: "info",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-info",
"hover:bg-info-container-hovered",
"enabled:active:bg-info-container-hovered",
"focus-visible:bg-info-container-hovered"
])
},
{
intent: "neutral",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-neutral",
"hover:bg-neutral-container-hovered",
"enabled:active:bg-neutral-container-hovered",
"focus-visible:bg-neutral-container-hovered"
])
},
{
intent: "surface",
design: "contrast",
class: (0, import_internal_utils7.tw)([
"text-on-surface",
"hover:bg-surface-hovered",
"enabled:active:bg-surface-hovered",
"focus-visible:bg-surface-hovered"
])
}
];
// src/button/Button.styles.tsx
var buttonStyles = (0, import_class_variance_authority4.cva)(
[
"u-shadow-border-transition",
"box-border inline-flex items-center justify-center gap-md whitespace-nowrap",
"px-lg",
"text-body-1 font-bold",
"focus-visible:u-outline"
],
{
variants: {
/**
* Main style of the button.
*
* - `filled`: Button will be plain.
*
* - `outlined`: Button will be transparent with an outline.
*
* - `tinted`: Button will be filled but using a lighter color scheme.
*
* - `ghost`: Button will look like a link. No borders, plain text.
*
* - `contrast`: Button will be surface filled. No borders, plain text.
*
*/
design: (0, import_internal_utils8.makeVariants)({
filled: [],
outlined: ["bg-transparent", "border-sm", "border-current"],
tinted: [],
ghost: [],
contrast: ["bg-surface"]
}),
/**
* Color scheme of the button.
*/
intent: (0, import_internal_utils8.makeVariants)({
main: [],
support: [],
accent: [],
basic: [],
success: [],
alert: [],
danger: [],
info: [],
neutral: [],
surface: []
}),
/**
* Size of the button.
*/
size: (0, import_internal_utils8.makeVariants)({
sm: ["min-w-sz-32", "h-sz-32"],
md: ["min-w-sz-44", "h-sz-44"],
lg: ["min-w-sz-56", "h-sz-56"]
}),
/**
* Shape of the button.
*/
shape: (0, import_internal_utils8.makeVariants)({
rounded: ["rounded-lg"],
square: ["rounded-0"],
pill: ["rounded-full"]
}),
/**
* Disable the button, preventing user interaction and adding opacity.
*/
disabled: {
true: ["cursor-not-allowed", "opacity-dim-3"],
false: ["cursor-pointer"]
}
},
compoundVariants: [
...filledVariants,
...outlinedVariants,
...tintedVariants,
...ghostVariants,
...contrastVariants
],
defaultVariants: {
design: "filled",
intent: "main",
size: "md",
shape: "rounded"
}
}
);
// src/button/Button.tsx
var import_jsx_runtime7 = require("react/jsx-runtime");
var blockedEventHandlers = [
"onClick",
"onMouseDown",
"onMouseUp",
"onMouseEnter",
"onMouseLeave",
"onMouseOver",
"onMouseOut",
"onKeyDown",
"onKeyPress",
"onKeyUp",
"onSubmit"
];
var Button = ({
children,
design = "filled",
disabled = false,
intent = "main",
isLoading = false,
loadingLabel,
loadingText,
shape = "rounded",
size = "md",
asChild,
className,
ref,
...others
}) => {
const Component = asChild ? Slot : "button";
const shouldNotInteract = !!disabled || isLoading;
const disabledEventHandlers = (0, import_react10.useMemo)(() => {
const result = {};
if (shouldNotInteract) {
blockedEventHandlers.forEach((eventHandler) => result[eventHandler] = void 0);
}
return result;
}, [shouldNotInteract]);
const spinnerProps = {
size: "current",
className: loadingText ? "inline-block" : "absolute",
...loadingLabel && { "aria-label": loadingLabel }
};
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
Component,
{
"data-spark-component": "button",
...Component === "button" && { type: "button" },
ref,
className: buttonStyles({
className,
design,
disabled: shouldNotInteract,
intent,
shape,
size
}),
disabled: !!disabled,
"aria-busy": isLoading,
"aria-live": isLoading ? "assertive" : "off",
...others,
...disabledEventHandlers,
children: wrapPolymorphicSlot(
asChild,
children,
(slotted) => isLoading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Spinner, { ...spinnerProps }),
loadingText && loadingText,
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
"div",
{
"aria-hidden": true,
className: (0, import_class_variance_authority5.cx)("gap-md", loadingText ? "hidden" : "inline-flex opacity-0"),
children: slotted
}
)
] }) : slotted
)
}
);
};
Button.displayName = "Button";
// src/icon-button/IconButton.styles.tsx
var import_internal_utils9 = require("@spark-ui/internal-utils");
var import_class_variance_authority6 = require("class-variance-authority");
var iconButtonStyles = (0, import_class_variance_authority6.cva)(["pl-0 pr-0"], {
variants: {
/**
* Sets the size of the icon.
*/
size: (0, import_internal_utils9.makeVariants)({
sm: ["text-body-1"],
md: ["text-body-1"],
lg: ["text-display-3"]
})
}
});
// src/icon-button/IconButton.tsx
var import_jsx_runtime8 = require("react/jsx-runtime");
var IconButton = ({
design = "filled",
disabled = false,
intent = "main",
shape = "rounded",
size = "md",
className,
ref,
...others
}) => {
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
Button,
{
ref,
className: iconButtonStyles({ size, className }),
design,
disabled,
intent,
shape,
size,
...others
}
);
};
IconButton.displayName = "IconButton";
// src/carousel/CarouselNextButton.tsx
var import_jsx_runtime9 = require("react/jsx-runtime");
var CarouselNextButton = ({
"aria-label": ariaLabel,
...buttonProps
}) => {
const ctx = useCarouselContext();
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
IconButton,
{
...ctx.getNextTriggerProps(),
intent: "surface",
design: "filled",
className: "pointer-events-auto cursor-pointer shadow-sm disabled:invisible",
"aria-label": ariaLabel,
...buttonProps,
children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Icon, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_ArrowVerticalRight.ArrowVerticalRight, {}) })
}
);
};
CarouselNextButton.displayName = "Carousel.NextButton";
// src/carousel/CarouselPageIndicator.tsx
var import_class_variance_authority7 = require("class-variance-authority");
var import_react11 = require("react");
var import_jsx_runtime10 = require("react/jsx-runtime");
var CarouselPageIndicator = ({
children,
unstyled = false,
index,
"aria-label": ariaLabel,
className
}) => {
const ctx = useCarouselContext();
const ref = (0, import_react11.useRef)(null);
(0, import_react11.useEffect)(() => {
if (ctx.pageIndicatorsRefs.current) {
ctx.pageIndicatorsRefs.current[index] = ref.current;
}
});
const styles = (0, import_class_variance_authority7.cx)(
"group h-sz-16 relative flex",
"hover:cursor-pointer",
"w-sz-16 data-[state=active]:w-sz-44"
);
const dotsStyles = (0, import_class_variance_authority7.cx)(
"before:rounded-sm before:block before:size-md",
"before:absolute before:left-1/2 before:top-1/2 before:-translate-x-1/2 before:-translate-y-1/2",
"data-[state=active]:before:w-sz-32 data-[state=active]:before:bg-basic",
"data-[state=inactive]:before:bg-on-surface/dim-3"
);
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
"button",
{
ref,
...ctx.getIndicatorProps({ index }),
"aria-label": ariaLabel,
className: (0, import_class_variance_authority7.cx)(
{
[styles]: !unstyled,
[dotsStyles]: !unstyled
},
className
),
children
},
index
);
};
CarouselPageIndicator.displayName = "Carousel.PageIndicator";
// src/carousel/CarouselPagePicker.tsx
var import_class_variance_authority8 = require("class-variance-authority");
var import_jsx_runtime11 = require("react/jsx-runtime");
var CarouselPagePicker = ({ children, className }) => {
const ctx = useCarouselContext();
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
"div",
{
...ctx.getIndicatorGroupProps(),
className: (0, import_class_variance_authority8.cx)(
"default:min-h-sz-16 flex w-full flex-wrap items-center justify-center",
className
),
children: ctx.pageSnapPoints.length <= 1 ? null : children({
...ctx,
pages: Array.from({ length: ctx.pageSnapPoints.length }, (_, i) => i)
})
}
) });
};
CarouselPagePicker.displayName = "Carousel.PagePicker";
// src/carousel/CarouselPrevButton.tsx
var import_ArrowVerticalLeft = require("@spark-ui/icons/ArrowVerticalLeft");
var import_jsx_runtime12 = require("react/jsx-runtime");
var CarouselPrevButton = ({
"aria-label": ariaLabel,
...buttonProps
}) => {
const ctx = useCarouselContext();
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
IconButton,
{
...ctx.getPrevTriggerProps(),
intent: "surface",
design: "filled",
className: "pointer-events-auto cursor-pointer shadow-sm disabled:invisible",
"aria-label": ariaLabel,
...buttonProps,
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ArrowVerticalLeft.ArrowVerticalLeft, {}) })
}
);
};
CarouselPrevButton.displayName = "Carousel.PrevButton";
// src/carousel/CarouselSlide.tsx
var import_class_variance_authority9 = require("class-variance-authority");
var import_react13 = require("react");
// src/carousel/useIsVisible.ts
var import_react12 = require("react");
function useIsVisible(elementRef, parentRef) {
const [isVisible, setIsVisible] = (0, import_react12.useState)(true);
(0, import_react12.useLayoutEffect)(() => {
const el = elementRef.current;
const parent = parentRef.current;
if (!parent || !el) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry) {
setIsVisible(entry.isIntersecting);
}
},
{ root: parent, threshold: 0.2 }
);
observer.observe(el);
return () => observer.disconnect();
});
return isVisible;
}
// src/carousel/CarouselSlide.tsx
var import_jsx_runtime13 = require("react/jsx-runtime");
var CarouselSlide = ({
children,
index = 0,
totalSlides,
className = "",
...props
}) => {
const itemRef = (0, import_react13.useRef)(null);
const ctx = useCarouselContext();
const isVisible = useIsVisible(itemRef, ctx.ref);
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"div",
{
ref: itemRef,
...ctx.getSlideProps({ index, totalSlides }),
className: (0, import_class_variance_authority9.cx)("default:bg-surface relative overflow-hidden", className),
"aria-hidden": !isVisible,
inert: !isVisible,
...props,
children
}
);
};
CarouselSlide.displayName = "Carousel.Slide";
// src/carousel/CarouselSlides.tsx
var import_class_variance_authority10 = require("class-variance-authority");
var import_react14 = require("react");
var import_jsx_runtime14 = require("react/jsx-runtime");
var CarouselSlides = ({ children, className = "" }) => {
const ctx = useCarouselContext();
const childrenElements = import_react14.Children.toArray(children);
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
"div",
{
...ctx.getSlidesContainerProps(),
className: (0, import_class_variance_authority10.cx)(
"focus-visible:u-outline relative w-full",
"[-ms-overflow-style:none] [scrollbar-width:none] [&::-webkit-scrollbar]:hidden",
className
),
children: childrenElements.map(
(child, index) => (0, import_react14.isValidElement)(child) ? (0, import_react14.cloneElement)(child, {
index,
totalSlides: childrenElements.length
}) : child
)
}
);
};
CarouselSlides.displayName = "Carousel.Slides";
// src/carousel/CarouselViewport.tsx
var import_jsx_runtime15 = require("react/jsx-runtime");
var CarouselViewport = ({ children }) => {
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "relative flex items-center justify-around p-0", children });
};
CarouselViewport.displayName = "Carousel.Viewport";
// src/carousel/index.ts
var Carousel2 = Object.assign(Carousel, {
Controls: CarouselControls,
NextButton: CarouselNextButton,
PrevButton: CarouselPrevButton,
Slide: CarouselSlide,
Slides: CarouselSlides,
Viewport: CarouselViewport,
PagePicker: CarouselPagePicker,
PageIndicator: CarouselPageIndicator
});
Carousel2.displayName = "Carousel";
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Carousel
});
//# sourceMappingURL=index.js.map
;