react-class-variants
Version:
Type-safe React variants API for dynamic CSS class composition
214 lines (210 loc) • 7.36 kB
JavaScript
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
target[prop] = source[prop];
}
return target;
};
// src/index.ts
import {
cloneElement,
createElement,
isValidElement as isValidElement2
} from "react";
// src/utils.ts
import {
isValidElement,
useMemo
} from "react";
function hasOwnProperty(object, prop) {
if (typeof Object.hasOwn === "function") {
return Object.hasOwn(object, prop);
}
return Object.prototype.hasOwnProperty.call(object, prop);
}
function isValidElementWithRef(element) {
if (!element) return false;
if (!isValidElement(element)) return false;
if ("ref" in element.props) return true;
if ("ref" in element) return true;
return false;
}
function getRefProperty(element) {
if (!isValidElementWithRef(element)) return null;
const props = __spreadValues({}, element.props);
return props.ref || element.ref;
}
function setRef(ref, value) {
if (typeof ref === "function") {
ref(value);
} else if (ref) {
ref.current = value;
}
}
function mergeProps(base, overrides) {
const props = __spreadValues({}, base);
for (const key in overrides) {
if (!hasOwnProperty(overrides, key)) continue;
if (key === "className") {
const prop = "className";
props[prop] = base[prop] ? `${base[prop]} ${overrides[prop]}` : overrides[prop];
continue;
}
if (key === "style") {
const prop = "style";
props[prop] = base[prop] ? __spreadValues(__spreadValues({}, base[prop]), overrides[prop]) : overrides[prop];
continue;
}
const overrideValue = overrides[key];
if (typeof overrideValue === "function" && key.startsWith("on")) {
const baseValue = base[key];
if (typeof baseValue === "function") {
props[key] = (...args) => {
overrideValue(...args);
baseValue(...args);
};
continue;
}
}
props[key] = overrideValue;
}
return props;
}
function useMergeRefs(...refs) {
return useMemo(() => {
if (!refs.some(Boolean)) return;
return (value) => {
for (const ref of refs) {
setRef(ref, value);
}
};
}, refs);
}
// src/index.ts
function defineConfig(options) {
const { onClassesMerged } = options != null ? options : {};
function mergeClassNames(...classNames) {
const flattened = classNames.flat(Infinity);
const filtered = flattened.filter((cls) => Boolean(cls));
const joined = filtered.join(" ");
return onClassesMerged ? onClassesMerged(joined) : joined;
}
function variants(config) {
const { base, variants: variants2, compoundVariants, defaultVariants } = config;
if (!("variants" in config) || !config.variants) {
return (props) => mergeClassNames(base, props == null ? void 0 : props.className);
}
function isBooleanVariant(name) {
const variant = variants2 == null ? void 0 : variants2[name];
return variant && ("false" in variant || "true" in variant);
}
return function(...[props]) {
var _a;
const result = [base];
const getSelectedVariant = (name) => {
var _a2, _b;
return (_b = (_a2 = props == null ? void 0 : props[name]) != null ? _a2 : defaultVariants == null ? void 0 : defaultVariants[name]) != null ? _b : isBooleanVariant(name) ? false : void 0;
};
for (let name in variants2) {
const selected = getSelectedVariant(name);
if (selected !== void 0) result.push((_a = variants2[name]) == null ? void 0 : _a[selected]);
}
for (let { variants: variants3, className } of compoundVariants != null ? compoundVariants : []) {
let isSelectedVariant2 = function(name) {
const selected = getSelectedVariant(name);
const cvSelector = variants3[name];
return Array.isArray(cvSelector) ? cvSelector.includes(selected) : selected === cvSelector;
};
var isSelectedVariant = isSelectedVariant2;
if (Object.keys(variants3).every(isSelectedVariant2)) {
result.push(className);
}
}
if (props == null ? void 0 : props.className) {
result.push(props.className);
}
return mergeClassNames(result);
};
}
function variantPropsResolver(config) {
const _a = config, { forwardProps, withoutRenderProp } = _a, variantsConfig = __objRest(_a, ["forwardProps", "withoutRenderProp"]);
const variantsResolver = variants(variantsConfig);
return function(props) {
const result = __spreadValues({}, props);
const onlyVariantProps = {
className: result.className
};
if (config.variants) {
for (const variantKey in config.variants) {
if (hasOwnProperty(config.variants, variantKey) && hasOwnProperty(result, variantKey)) {
onlyVariantProps[variantKey] = result[variantKey];
if (!forwardProps || !forwardProps.includes(variantKey)) {
delete result[variantKey];
}
}
}
}
result.className = variantsResolver(onlyVariantProps);
return result;
};
}
function variantComponent(elementType, config) {
const { withoutRenderProp } = config;
const resolveProps = variantPropsResolver(config);
if (typeof elementType !== "string" || withoutRenderProp) {
return ((props) => {
return createElement(elementType, resolveProps(props));
});
}
const component = ((props) => {
const _a = props, { render } = _a, rest = __objRest(_a, ["render"]);
const mergedRef = useMergeRefs(
rest.ref,
getRefProperty(render)
);
const resolvedProps = resolveProps(rest);
if (render) {
if (isValidElement2(render)) {
const renderProps = __spreadProps(__spreadValues({}, render.props), { ref: mergedRef });
return cloneElement(render, mergeProps(resolvedProps, renderProps));
} else {
return render(resolvedProps);
}
}
return createElement(elementType, __spreadProps(__spreadValues({}, resolvedProps), { ref: mergedRef }));
});
return component;
}
return {
variants,
variantPropsResolver,
variantComponent
};
}
export {
defineConfig
};