UNPKG

@spark-ui/components

Version:

Spark (Leboncoin design system) components.

362 lines (350 loc) 11.3 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/rating/index.ts var rating_exports = {}; __export(rating_exports, { Rating: () => Rating }); module.exports = __toCommonJS(rating_exports); // src/rating/Rating.tsx var import_use_combined_state = require("@spark-ui/hooks/use-combined-state"); var import_class_variance_authority4 = require("class-variance-authority"); var import_react3 = require("react"); // src/rating/RatingStar.tsx var import_StarFill = require("@spark-ui/icons/StarFill"); var import_StarOutline = require("@spark-ui/icons/StarOutline"); var import_class_variance_authority3 = require("class-variance-authority"); // src/icon/Icon.tsx var import_react2 = require("react"); // src/slot/Slot.tsx var import_radix_ui = require("radix-ui"); var import_react = require("react"); var import_jsx_runtime = require("react/jsx-runtime"); var Slottable = import_radix_ui.Slot.Slottable; var Slot = ({ ref, ...props }) => { return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_radix_ui.Slot.Root, { ref, ...props }); }; // src/visually-hidden/VisuallyHidden.tsx var import_jsx_runtime2 = require("react/jsx-runtime"); var VisuallyHidden = ({ asChild = false, ref, ...props }) => { const Component = asChild ? Slot : "span"; return /* @__PURE__ */ (0, import_jsx_runtime2.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_authority = require("class-variance-authority"); var iconStyles = (0, import_class_variance_authority.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_runtime3 = require("react/jsx-runtime"); var Icon = ({ label, className, size = "current", intent = "current", children, ...others }) => { const child = import_react2.Children.only(children); return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [ (0, import_react2.cloneElement)(child, { className: iconStyles({ className, size, intent }), "data-spark-component": "icon", "aria-hidden": "true", focusable: "false", ...others }), label && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(VisuallyHidden, { children: label }) ] }); }; Icon.displayName = "Icon"; // src/rating/RatingStar.styles.ts var import_class_variance_authority2 = require("class-variance-authority"); var emptyRemainingStarsOnHoverClass = (0, import_class_variance_authority2.cx)("[&_>_div]:peer-hover:w-0!"); var ratingStarStyles = (0, import_class_variance_authority2.cva)( ["peer", "after:inset-0", "group", "relative", "after:block after:absolute"], { variants: { disabled: { true: "opacity-dim-3", false: "" }, readOnly: { true: "", false: "" }, gap: { sm: ["after:w-[calc(100%+(var(--spacing-sm)))]", "last-of-type:after:content-none"], md: ["after:w-[calc(100%+(var(--spacing-md)))]", "last-of-type:after:content-none"] } }, compoundVariants: [ { readOnly: false, disabled: false, className: (0, import_class_variance_authority2.cx)(emptyRemainingStarsOnHoverClass, "cursor-pointer") } ], defaultVariants: { disabled: false, readOnly: false, gap: "sm" } } ); var ratingStarIconStyles = (0, import_class_variance_authority2.cva)("", { variants: { size: { sm: "text-caption-link", md: "text-body-1", lg: "text-display-1" }, design: { filled: [ "text-main-variant", "group-[[data-part=star][data-hovered]]:text-main-variant-hovered" ], outlined: ["text-on-surface/dim-3"] } } }); // src/rating/RatingStar.tsx var import_jsx_runtime4 = require("react/jsx-runtime"); var RatingStar = ({ value, size, disabled, readOnly, onClick, onMouseEnter, ref: forwardedRef }) => { return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)( "div", { ref: forwardedRef, onMouseEnter, className: ratingStarStyles({ gap: size === "lg" ? "md" : "sm", disabled, readOnly }), "data-part": "star", onClick, children: [ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( "div", { className: (0, import_class_variance_authority3.cx)( "z-raised absolute overflow-hidden", "group-[[data-part=star][data-hovered]]:overflow-visible" ), style: { width: value * 100 + "%" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)( Icon, { className: ratingStarIconStyles({ size, design: "filled" }), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_StarFill.StarFill, {}) } ) } ), /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Icon, { className: ratingStarIconStyles({ size, design: "outlined" }), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_StarOutline.StarOutline, {}) }) ] } ); }; // src/rating/utils.ts function getNearestHalfDecimal(num) { return Math.round(num / 0.5) * 0.5; } function getStarValue({ value, index }) { if (value === void 0) return 0; const starPosition = index + 1; const formattedValue = getNearestHalfDecimal(value); if (Math.ceil(formattedValue) < starPosition) return 0; return formattedValue >= starPosition ? 1 : 0.5; } function splitAt(arr, index) { const prev = arr.slice(0, index); const next = arr.slice(index); return [prev, next]; } // src/rating/Rating.tsx var import_jsx_runtime5 = require("react/jsx-runtime"); var Rating = ({ defaultValue, value: propValue, onValueChange, size = "md", disabled, readOnly, name, id, "aria-label": ariaLabel, ref, ...rest }) => { const inputRef = (0, import_react3.useRef)(null); const starRefList = (0, import_react3.useRef)([]); const [value, setRatingValue] = (0, import_use_combined_state.useCombinedState)(propValue, defaultValue, onValueChange); const valueRef = (0, import_react3.useRef)(value); const isInteractive = !(disabled || readOnly); function onStarClick(index) { if (!inputRef.current) return; setRatingValue(index + 1); valueRef.current = index + 1; inputRef.current.focus(); inputRef.current.setAttribute("data-clicked", ""); } function onInputChange(event) { if (valueRef.current === Number(event.target.value) || Number(event.target.value) === 0) { return; } valueRef.current = Number(event.target.value); setRatingValue(Number(event.target.value)); } function onStarMouseEnter({ currentTarget }) { const currentStarIndex = starRefList.current.findIndex((star) => star === currentTarget); const [previousStars, followingStars] = splitAt(starRefList.current, currentStarIndex + 1); previousStars.forEach((star) => star.setAttribute("data-hovered", "")); followingStars.forEach((star) => star.removeAttribute("data-hovered")); } const handleStarRef = (0, import_react3.useCallback)((elm) => { if (!elm) return; starRefList.current.push(elm); }, []); function resetDataPartInputAttr() { inputRef.current?.removeAttribute("data-clicked"); } function resetDataPartStarAttr() { starRefList.current.forEach((star) => star.removeAttribute("data-hovered")); } return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)( "div", { className: "relative inline-flex", ref, "data-spark-component": "rating", ...rest, onMouseLeave: resetDataPartStarAttr, children: [ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "input", { name, id, "aria-label": ariaLabel, ref: inputRef, "data-part": "input", className: "peer absolute inset-0 opacity-0", type: "range", min: "0", max: "5", step: readOnly ? 0.5 : 1, disabled, readOnly, value: getNearestHalfDecimal(value ?? 0), onChange: (event) => isInteractive && onInputChange(event), onBlur: resetDataPartInputAttr } ), /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( "div", { className: (0, import_class_variance_authority4.cx)( size === "lg" ? "gap-x-md" : "gap-x-sm", "flex", "peer-focus-visible:u-outline peer-[[data-part=input][data-clicked]]:shadow-none" ), children: Array.from({ length: 5 }).map((_, index) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)( RatingStar, { disabled, readOnly, size, onClick: () => isInteractive && onStarClick(index), onMouseEnter: (event) => isInteractive && onStarMouseEnter(event), ref: handleStarRef, value: getStarValue({ index, value }) }, index )) } ) ] } ); }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Rating }); //# sourceMappingURL=index.js.map