UNPKG

@spark-ui/components

Version:

Spark (Leboncoin design system) components.

1,678 lines (1,636 loc) 47.6 kB
"use strict"; 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