@spark-ui/components
Version:
Spark (Leboncoin design system) components.
581 lines (558 loc) • 17.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/select/index.ts
var select_exports = {};
__export(select_exports, {
Select: () => Select2,
SelectProvider: () => SelectProvider,
useSelectContext: () => useSelectContext
});
module.exports = __toCommonJS(select_exports);
// src/select/SelectContext.tsx
var import_form_field = require("@spark-ui/components/form-field");
var import_use_combined_state = require("@spark-ui/hooks/use-combined-state");
var import_react2 = require("react");
// src/select/utils.ts
var import_react = require("react");
var findElement = (children) => (name) => {
const validChildren = import_react.Children.toArray(children).filter(import_react.isValidElement);
return validChildren.find((child) => {
return getElementDisplayName(child)?.includes(name);
});
};
var getElementDisplayName = (element) => {
return element ? element.type.displayName : "";
};
var getOrderedItems = (children, result = []) => {
import_react.Children.forEach(children, (child) => {
if (!(0, import_react.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
var import_jsx_runtime = require("react/jsx-runtime");
var SelectContext = (0, import_react2.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] = (0, import_use_combined_state.useCombinedState)(valueProp, defaultValue, onValueChange);
const [placeholder, setPlaceholder] = (0, import_react2.useState)(void 0);
const [itemsMap, setItemsMap] = (0, import_react2.useState)(getItemsFromChildren(itemsComponent));
const [ariaLabel, setAriaLabel] = (0, import_react2.useState)();
const firstItem = itemsMap.entries().next()?.value?.[1];
const selectedItem = typeof value === "string" ? itemsMap.get(value) : firstItem;
const isControlled = valueProp != null;
const field = (0, import_form_field.useFormFieldControl)();
const state = field.state || stateProp;
const internalFieldID = `${ID_PREFIX}-field-${(0, import_react2.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);
(0, import_react2.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__ */ (0, import_jsx_runtime.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 = (0, import_react2.useContext)(SelectContext);
if (!context) {
throw Error("useSelectContext must be used within a Select provider");
}
return context;
};
// src/select/Select.tsx
var import_jsx_runtime2 = require("react/jsx-runtime");
var Select = ({ children, ...props }) => {
const finder = findElement(children);
const trigger = finder("Trigger");
const items = finder("Items");
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SelectProvider, { ...props, itemsComponent: items, children: trigger });
};
Select.displayName = "Select";
// src/select/SelectGroup.tsx
var import_class_variance_authority = require("class-variance-authority");
// src/select/SelectItemsGroupContext.tsx
var import_react3 = require("react");
var import_jsx_runtime3 = require("react/jsx-runtime");
var SelectGroupContext = (0, import_react3.createContext)(null);
var SelectGroupProvider = ({ children }) => {
const [groupLabel, setGroupLabel] = (0, import_react3.useState)("");
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SelectGroupContext.Provider, { value: { groupLabel, setGroupLabel }, children });
};
var useSelectGroupContext = () => {
const context = (0, import_react3.useContext)(SelectGroupContext);
if (!context) {
throw Error("useSelectGroupContext must be used within a SelectGroup provider");
}
return context;
};
// src/select/SelectGroup.tsx
var import_jsx_runtime4 = require("react/jsx-runtime");
var Group = ({ children, ref: forwardedRef, ...props }) => {
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(SelectGroupProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GroupContent, { ref: forwardedRef, ...props, children }) });
};
var GroupContent = ({ children, className, ref: forwardedRef }) => {
const { groupLabel } = useSelectGroupContext();
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
"optgroup",
{
"data-spark-component": "select-group",
ref: forwardedRef,
className: (0, import_class_variance_authority.cx)(className),
label: groupLabel,
children
}
);
};
Group.displayName = "Select.Group";
// src/select/SelectItem.tsx
var import_jsx_runtime5 = require("react/jsx-runtime");
var Item = ({ disabled = false, value, children, ref: forwardedRef }) => {
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
"option",
{
"data-spark-component": "select-item",
ref: forwardedRef,
value,
disabled,
children
},
value
);
};
Item.displayName = "Select.Item";
// src/select/SelectItems.tsx
var import_class_variance_authority2 = require("class-variance-authority");
var import_jsx_runtime6 = require("react/jsx-runtime");
var styles = (0, import_class_variance_authority2.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__ */ (0, import_jsx_runtime6.jsx)(
"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
var import_react4 = require("react");
var Label = ({ children }) => {
const { setGroupLabel } = useSelectGroupContext();
(0, import_react4.useEffect)(() => {
setGroupLabel(children);
}, [children]);
return null;
};
Label.displayName = "Select.Label";
// src/icon/Icon.tsx
var import_react6 = require("react");
// src/slot/Slot.tsx
var import_radix_ui = require("radix-ui");
var import_react5 = require("react");
var import_jsx_runtime7 = require("react/jsx-runtime");
var Slottable = import_radix_ui.Slot.Slottable;
var Slot = ({ ref, ...props }) => {
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_radix_ui.Slot.Root, { ref, ...props });
};
// src/visually-hidden/VisuallyHidden.tsx
var import_jsx_runtime8 = require("react/jsx-runtime");
var VisuallyHidden = ({ asChild = false, ref, ...props }) => {
const Component = asChild ? Slot : "span";
return /* @__PURE__ */ (0, import_jsx_runtime8.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_authority3 = require("class-variance-authority");
var iconStyles = (0, import_class_variance_authority3.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_runtime9 = require("react/jsx-runtime");
var Icon = ({
label,
className,
size = "current",
intent = "current",
children,
...others
}) => {
const child = import_react6.Children.only(children);
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
(0, import_react6.cloneElement)(child, {
className: iconStyles({ className, size, intent }),
"data-spark-component": "icon",
"aria-hidden": "true",
focusable: "false",
...others
}),
label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(VisuallyHidden, { children: label })
] });
};
Icon.displayName = "Icon";
// src/select/SelectLeadingIcon.tsx
var import_jsx_runtime10 = require("react/jsx-runtime");
var LeadingIcon = ({ children }) => {
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon, { size: "sm", className: "shrink-0", children });
};
LeadingIcon.displayName = "Select.LeadingIcon";
// src/select/SelectPlaceholder.tsx
var import_react7 = require("react");
var import_jsx_runtime11 = require("react/jsx-runtime");
var Placeholder = ({
disabled = false,
children,
ref: forwardedRef
}) => {
const { setPlaceholder } = useSelectContext();
(0, import_react7.useEffect)(() => {
setPlaceholder(children);
}, [children]);
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
"option",
{
"data-spark-component": "select-placeholder",
ref: forwardedRef,
value: "",
disabled,
children
},
"placeholder"
);
};
Placeholder.displayName = "Select.Placeholder";
// src/select/SelectTrigger.tsx
var import_ArrowHorizontalDown = require("@spark-ui/icons/ArrowHorizontalDown");
var import_react8 = require("react");
// src/select/SelectTrigger.styles.tsx
var import_class_variance_authority4 = require("class-variance-authority");
var styles2 = (0, import_class_variance_authority4.cva)(
[
"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
var import_jsx_runtime12 = require("react/jsx-runtime");
var Trigger = ({
"aria-label": ariaLabel,
children,
className,
ref: forwardedRef
}) => {
const { disabled, readOnly, state, setAriaLabel, itemsComponent } = useSelectContext();
(0, import_react8.useEffect)(() => {
if (ariaLabel) {
setAriaLabel(ariaLabel);
}
}, [ariaLabel]);
return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
"div",
{
"data-spark-component": "select-trigger",
ref: forwardedRef,
className: styles2({ className, state, disabled, readOnly }),
children: [
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "gap-md flex items-center justify-start", children }),
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Icon, { className: "ml-md shrink-0", size: "sm", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_ArrowHorizontalDown.ArrowHorizontalDown, {}) }),
itemsComponent
]
}
);
};
Trigger.displayName = "Select.Trigger";
// src/select/SelectValue.tsx
var import_class_variance_authority5 = require("class-variance-authority");
var import_jsx_runtime13 = require("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__ */ (0, import_jsx_runtime13.jsx)(
"span",
{
role: "presentation",
"data-spark-component": "select-value",
ref: forwardedRef,
className: (0, import_class_variance_authority5.cx)("flex shrink items-center text-left", className),
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
"span",
{
className: (0, import_class_variance_authority5.cx)(
"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";
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Select,
SelectProvider,
useSelectContext
});
//# sourceMappingURL=index.js.map
;