UNPKG

@spark-ui/components

Version:

Spark (Leboncoin design system) components.

467 lines (450 loc) 12.8 kB
import { Icon } from "../chunk-UMUMFMFB.mjs"; import "../chunk-KEGAAGJW.mjs"; import "../chunk-6QCEPQ3U.mjs"; // src/select/SelectContext.tsx import { useFormFieldControl } from "@spark-ui/components/form-field"; import { useCombinedState } from "@spark-ui/hooks/use-combined-state"; import { createContext, useContext, useEffect, useId, useState } from "react"; // src/select/utils.ts import { Children, isValidElement } from "react"; var findElement = (children) => (name) => { const validChildren = Children.toArray(children).filter(isValidElement); return validChildren.find((child) => { return getElementDisplayName(child)?.includes(name); }); }; var getElementDisplayName = (element) => { return element ? element.type.displayName : ""; }; var getOrderedItems = (children, result = []) => { Children.forEach(children, (child) => { if (!isValidElement(child)) return; if (getElementDisplayName(child) === "Select.Item" || getElementDisplayName(child) === "Select.Placeholder") { const childProps = child.props; result.push({ value: childProps.value, disabled: !!childProps.disabled, text: childProps.children }); } if (child.props.children) { getOrderedItems(child.props.children, result); } }); return result; }; var getItemsFromChildren = (children) => { const newMap = /* @__PURE__ */ new Map(); getOrderedItems(children).forEach((itemData) => { newMap.set(itemData.value, itemData); }); return newMap; }; // src/select/SelectContext.tsx import { jsx } from "react/jsx-runtime"; var SelectContext = createContext(null); var ID_PREFIX = ":select"; var SelectProvider = ({ children, defaultValue, value: valueProp, onValueChange, disabled: disabledProp = false, readOnly: readOnlyProp = false, state: stateProp, itemsComponent, name: nameProp, required: requiredProp }) => { const [value, setValue] = useCombinedState(valueProp, defaultValue, onValueChange); const [placeholder, setPlaceholder] = useState(void 0); const [itemsMap, setItemsMap] = useState(getItemsFromChildren(itemsComponent)); const [ariaLabel, setAriaLabel] = useState(); const firstItem = itemsMap.entries().next()?.value?.[1]; const selectedItem = typeof value === "string" ? itemsMap.get(value) : firstItem; const isControlled = valueProp != null; const field = useFormFieldControl(); const state = field.state || stateProp; const internalFieldID = `${ID_PREFIX}-field-${useId()}`; const fieldId = field.id || internalFieldID; const fieldLabelId = field.labelId; const disabled = field.disabled ?? disabledProp; const readOnly = field.readOnly ?? readOnlyProp; const name = field.name ?? nameProp; const required = !!(field.isRequired ?? requiredProp); useEffect(() => { const newMap = getItemsFromChildren(itemsComponent); const previousItems = [...itemsMap.values()]; const newItems = [...newMap.values()]; const hasItemsChanges = previousItems.length !== newItems.length || previousItems.some((item, index) => { const hasUpdatedValue = item.value !== newItems[index]?.value; const hasUpdatedText = item.text !== newItems[index]?.text; return hasUpdatedValue || hasUpdatedText; }); if (hasItemsChanges) { setItemsMap(newMap); } }, [children]); return /* @__PURE__ */ jsx( SelectContext.Provider, { value: { disabled, readOnly, itemsMap, state, itemsComponent, selectedItem, setValue, isControlled, onValueChange, ariaLabel, setAriaLabel, fieldId, fieldLabelId, name, required, placeholder, setPlaceholder }, children } ); }; var useSelectContext = () => { const context = useContext(SelectContext); if (!context) { throw Error("useSelectContext must be used within a Select provider"); } return context; }; // src/select/Select.tsx import { jsx as jsx2 } from "react/jsx-runtime"; var Select = ({ children, ...props }) => { const finder = findElement(children); const trigger = finder("Trigger"); const items = finder("Items"); return /* @__PURE__ */ jsx2(SelectProvider, { ...props, itemsComponent: items, children: trigger }); }; Select.displayName = "Select"; // src/select/SelectGroup.tsx import { cx } from "class-variance-authority"; // src/select/SelectItemsGroupContext.tsx import { createContext as createContext2, useContext as useContext2, useState as useState2 } from "react"; import { jsx as jsx3 } from "react/jsx-runtime"; var SelectGroupContext = createContext2(null); var SelectGroupProvider = ({ children }) => { const [groupLabel, setGroupLabel] = useState2(""); return /* @__PURE__ */ jsx3(SelectGroupContext.Provider, { value: { groupLabel, setGroupLabel }, children }); }; var useSelectGroupContext = () => { const context = useContext2(SelectGroupContext); if (!context) { throw Error("useSelectGroupContext must be used within a SelectGroup provider"); } return context; }; // src/select/SelectGroup.tsx import { jsx as jsx4 } from "react/jsx-runtime"; var Group = ({ children, ref: forwardedRef, ...props }) => { return /* @__PURE__ */ jsx4(SelectGroupProvider, { children: /* @__PURE__ */ jsx4(GroupContent, { ref: forwardedRef, ...props, children }) }); }; var GroupContent = ({ children, className, ref: forwardedRef }) => { const { groupLabel } = useSelectGroupContext(); return /* @__PURE__ */ jsx4( "optgroup", { "data-spark-component": "select-group", ref: forwardedRef, className: cx(className), label: groupLabel, children } ); }; Group.displayName = "Select.Group"; // src/select/SelectItem.tsx import { jsx as jsx5 } from "react/jsx-runtime"; var Item = ({ disabled = false, value, children, ref: forwardedRef }) => { return /* @__PURE__ */ jsx5( "option", { "data-spark-component": "select-item", ref: forwardedRef, value, disabled, children }, value ); }; Item.displayName = "Select.Item"; // src/select/SelectItems.tsx import { cva } from "class-variance-authority"; import { jsx as jsx6 } from "react/jsx-runtime"; var styles = cva( [ "absolute left-0 top-0 size-full rounded-lg opacity-0", "min-h-sz-44", // outline styles "ring-1 outline-hidden ring-inset focus:ring-2" ], { variants: { state: { undefined: "ring-outline focus:ring-outline-high", error: "ring-error", alert: "ring-alert", success: "ring-success" }, disabled: { true: "cursor-not-allowed" }, readOnly: { true: "cursor-default" } }, compoundVariants: [ { disabled: false, state: void 0, class: "hover:ring-outline-high" } ] } ); var Items = ({ children, className, ref, ...rest }) => { const { state, disabled, readOnly, ariaLabel, fieldLabelId, isControlled, onValueChange, selectedItem, setValue, name, required, fieldId } = useSelectContext(); const handleChange = (event) => { if (isControlled) { event.preventDefault(); onValueChange?.(event.target.value); } else { setValue(event.target.value); } }; return /* @__PURE__ */ jsx6( "select", { "data-spark-component": "select-items", ref, disabled: disabled || readOnly, name, required, "aria-labelledby": fieldLabelId, ...ariaLabel && { "aria-label": ariaLabel }, className: styles({ className, state, disabled, readOnly }), value: selectedItem?.value, onChange: handleChange, id: fieldId, ...rest, children } ); }; Items.displayName = "Select.Items"; // src/select/SelectLabel.tsx import { useEffect as useEffect2 } from "react"; var Label = ({ children }) => { const { setGroupLabel } = useSelectGroupContext(); useEffect2(() => { setGroupLabel(children); }, [children]); return null; }; Label.displayName = "Select.Label"; // src/select/SelectLeadingIcon.tsx import { jsx as jsx7 } from "react/jsx-runtime"; var LeadingIcon = ({ children }) => { return /* @__PURE__ */ jsx7(Icon, { size: "sm", className: "shrink-0", children }); }; LeadingIcon.displayName = "Select.LeadingIcon"; // src/select/SelectPlaceholder.tsx import { useEffect as useEffect3 } from "react"; import { jsx as jsx8 } from "react/jsx-runtime"; var Placeholder = ({ disabled = false, children, ref: forwardedRef }) => { const { setPlaceholder } = useSelectContext(); useEffect3(() => { setPlaceholder(children); }, [children]); return /* @__PURE__ */ jsx8( "option", { "data-spark-component": "select-placeholder", ref: forwardedRef, value: "", disabled, children }, "placeholder" ); }; Placeholder.displayName = "Select.Placeholder"; // src/select/SelectTrigger.tsx import { ArrowHorizontalDown } from "@spark-ui/icons/ArrowHorizontalDown"; import { useEffect as useEffect4 } from "react"; // src/select/SelectTrigger.styles.tsx import { cva as cva2 } from "class-variance-authority"; var styles2 = cva2( [ "relative flex w-full items-center justify-between", "min-h-sz-44 rounded-lg px-lg", "text-body-1", // outline styles "ring-1 outline-hidden ring-inset" ], { variants: { state: { undefined: "ring-outline", error: "ring-error", alert: "ring-alert", success: "ring-success" }, disabled: { false: "focus-within:ring-2" }, readOnly: { true: "" } }, compoundVariants: [ { readOnly: false, disabled: false, class: "bg-surface text-on-surface" }, { readOnly: true, class: "bg-on-surface/dim-5 text-on-surface cursor-default" }, { disabled: true, class: ["bg-on-surface/dim-5 text-on-surface/dim-3", "cursor-not-allowed"] }, { disabled: false, state: void 0, class: "hover:ring-outline-high focus-within:ring-outline-high" } ] } ); // src/select/SelectTrigger.tsx import { jsx as jsx9, jsxs } from "react/jsx-runtime"; var Trigger = ({ "aria-label": ariaLabel, children, className, ref: forwardedRef }) => { const { disabled, readOnly, state, setAriaLabel, itemsComponent } = useSelectContext(); useEffect4(() => { if (ariaLabel) { setAriaLabel(ariaLabel); } }, [ariaLabel]); return /* @__PURE__ */ jsxs( "div", { "data-spark-component": "select-trigger", ref: forwardedRef, className: styles2({ className, state, disabled, readOnly }), children: [ /* @__PURE__ */ jsx9("span", { className: "gap-md flex items-center justify-start", children }), /* @__PURE__ */ jsx9(Icon, { className: "ml-md shrink-0", size: "sm", children: /* @__PURE__ */ jsx9(ArrowHorizontalDown, {}) }), itemsComponent ] } ); }; Trigger.displayName = "Select.Trigger"; // src/select/SelectValue.tsx import { cx as cx2 } from "class-variance-authority"; import { jsx as jsx10 } from "react/jsx-runtime"; var Value = ({ children, className, placeholder: customPlaceholder, ref: forwardedRef }) => { const { selectedItem, placeholder, disabled } = useSelectContext(); const isPlaceholderSelected = selectedItem?.value == null; const valuePlaceholder = customPlaceholder || placeholder; return /* @__PURE__ */ jsx10( "span", { role: "presentation", "data-spark-component": "select-value", ref: forwardedRef, className: cx2("flex shrink items-center text-left", className), children: /* @__PURE__ */ jsx10( "span", { className: cx2( "line-clamp-1 flex-1 overflow-hidden break-all text-ellipsis", isPlaceholderSelected && !disabled && "text-on-surface/dim-1" ), children: isPlaceholderSelected ? valuePlaceholder : children || selectedItem?.text } ) } ); }; Value.displayName = "Select.Value"; // src/select/index.ts var Select2 = Object.assign(Select, { Group, Item, Items, Placeholder, Label, Trigger, Value, LeadingIcon }); Select2.displayName = "Select"; Group.displayName = "Select.Group"; Items.displayName = "Select.Items"; Item.displayName = "Select.Item"; Placeholder.displayName = "Select.Placeholder"; Label.displayName = "Select.Label"; Trigger.displayName = "Select.Trigger"; Value.displayName = "Select.Value"; LeadingIcon.displayName = "Select.LeadingIcon"; export { Select2 as Select, SelectProvider, useSelectContext }; //# sourceMappingURL=index.mjs.map