Cross-framework compatibility utilities and adapters for building Vue components that work seamlessly across Vue 2, Vue 2.7, and Vue 3
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The CSS Class Utilities provide comprehensive tools for managing CSS classes including Tailwind CSS class merging, object/array stringification, and deduplication. These utilities enable dynamic class composition and consistent styling across components.
Advanced CSS class merging that intelligently handles Tailwind CSS class conflicts and deduplication.
/**
* Merge CSS classes with Tailwind-aware conflict resolution
* @param cssClasses - Variable number of CSS class inputs
* @returns Merged and deduplicated class string
*/
function mergeClass(...cssClasses: CssClass[]): string;
type CssClass = string | CssClassObject | CssClassArray;
interface CssClassObject {
[key: string]: any;
}
type CssClassArray = Array<string | CssClassObject>;Usage Examples:
import { mergeClass } from "@opentiny/vue-common";
// Merge simple class strings
const classes = mergeClass('btn', 'text-blue-500', 'hover:text-blue-700');
// Result: "btn text-blue-500 hover:text-blue-700"
// Handle Tailwind conflicts (later classes override earlier ones)
const conflictResolved = mergeClass('text-red-500', 'text-blue-500');
// Result: "text-blue-500" (blue overrides red)
// Mix strings, objects, and arrays
const mixed = mergeClass(
'base-class',
{ 'active': isActive, 'disabled': !enabled },
['flex', 'items-center'],
conditionalClass && 'extra-class'
);
// Responsive classes
const responsive = mergeClass(
'w-full',
'sm:w-1/2',
'md:w-1/3',
'lg:w-1/4'
);Utilities for converting various CSS class formats to strings.
/**
* Convert CSS classes to string format
* @param cssClasses - CSS classes in any supported format
* @returns Stringified CSS classes
*/
function stringifyCssClass(cssClasses: CssClass[] | CssClass): string;
/**
* Convert CSS class object to string
* @param cssClassObject - Object with class names as keys and boolean values
* @returns Space-separated class string
*/
function stringifyCssClassObject(cssClassObject: CssClassObject): string;
/**
* Convert CSS class array to string
* @param cssClassArray - Array of strings and/or objects
* @returns Space-separated class string
*/
function stringifyCssClassArray(cssClassArray: CssClassArray): string;Usage Examples:
import {
stringifyCssClass,
stringifyCssClassObject,
stringifyCssClassArray
} from "@opentiny/vue-common";
// Object to string conversion
const objectClasses = stringifyCssClassObject({
'btn': true,
'btn-primary': isPrimary,
'btn-disabled': !enabled,
'btn-large': size === 'large'
});
// Array to string conversion
const arrayClasses = stringifyCssClassArray([
'flex',
'items-center',
{ 'justify-between': spaceBetween },
isVisible && 'opacity-100'
]);
// Mixed formats to string
const mixedClasses = stringifyCssClass([
'container',
{ 'mx-auto': centered },
['px-4', 'py-2'],
'shadow-md'
]);Remove duplicate CSS classes while preserving order and handling complex class structures.
/**
* Remove duplicate CSS classes
* @param cssClasses - CSS classes in any supported format
* @returns Deduplicated class string
*/
function deduplicateCssClass(cssClasses: CssClass[] | CssClass): string;Usage Examples:
import { deduplicateCssClass } from "@opentiny/vue-common";
// Remove duplicates from mixed sources
const deduplicated = deduplicateCssClass([
'btn btn-primary',
{ 'btn': true, 'hover:btn-hover': true },
['btn-primary', 'focus:outline-none'],
'btn btn-primary' // duplicates will be removed
]);
// Result: "btn btn-primary hover:btn-hover focus:outline-none"
// Handle complex nested structures
const complex = deduplicateCssClass([
'flex items-center',
{ 'flex': true, 'space-x-2': hasSpacing },
['items-center', 'justify-center'],
spaced && 'space-x-2'
]);Patterns for applying classes based on component state and props.
import { mergeClass, hooks } from "@opentiny/vue-common";
export default {
setup(props) {
// Computed classes based on props
const containerClasses = hooks.computed(() => mergeClass(
'component-base',
{
'component-primary': props.type === 'primary',
'component-secondary': props.type === 'secondary',
'component-disabled': props.disabled,
'component-loading': props.loading
},
props.size === 'small' && 'component-sm',
props.size === 'large' && 'component-lg',
props.customClass
));
// Responsive classes
const responsiveClasses = hooks.computed(() => mergeClass(
'w-full',
'sm:w-1/2 sm:max-w-md',
'md:w-1/3 md:max-w-lg',
'lg:w-1/4 lg:max-w-xl'
));
return {
containerClasses,
responsiveClasses
};
}
};Integration with theme systems for dynamic styling.
import { mergeClass, hooks } from "@opentiny/vue-common";
export default {
setup(props) {
const theme = hooks.inject('theme', 'light');
const themeClasses = hooks.computed(() => {
const baseClasses = 'transition-colors duration-200';
const themeMap = {
light: 'bg-white text-gray-900 border-gray-200',
dark: 'bg-gray-900 text-white border-gray-700',
auto: 'bg-white dark:bg-gray-900 text-gray-900 dark:text-white'
};
return mergeClass(
baseClasses,
themeMap[theme.value] || themeMap.light,
props.variant === 'outlined' && 'border-2',
props.variant === 'filled' && 'shadow-md'
);
});
return {
themeClasses
};
}
};Common patterns for form controls with validation states.
import { mergeClass, hooks } from "@opentiny/vue-common";
export default {
setup(props) {
const inputClasses = hooks.computed(() => mergeClass(
// Base styles
'block w-full rounded-md border-0 py-1.5 px-3',
'text-gray-900 shadow-sm ring-1 ring-inset',
'placeholder:text-gray-400 focus:ring-2 focus:ring-inset',
'sm:text-sm sm:leading-6',
// Size variants
{
'py-1 px-2 text-xs': props.size === 'small',
'py-2 px-4 text-base': props.size === 'large'
},
// State-based styles
{
'ring-gray-300 focus:ring-indigo-600': !props.error && !props.success,
'ring-red-300 focus:ring-red-600': props.error,
'ring-green-300 focus:ring-green-600': props.success,
'bg-gray-50 cursor-not-allowed': props.disabled
}
));
const labelClasses = hooks.computed(() => mergeClass(
'block text-sm font-medium leading-6',
{
'text-gray-900': !props.error,
'text-red-600': props.error,
'text-green-600': props.success
}
));
return {
inputClasses,
labelClasses
};
}
};Integration with custom design token systems.
import { mergeClass, customDesignConfig } from "@opentiny/vue-common";
// Configure custom design system
customDesignConfig.designConfig = {
tokens: {
colors: {
primary: 'blue-600',
secondary: 'gray-600'
},
spacing: {
small: '0.5rem',
medium: '1rem',
large: '2rem'
}
}
};
// Use design tokens in components
export default {
setup(props) {
const buttonClasses = hooks.computed(() => mergeClass(
'inline-flex items-center justify-center',
'rounded-md font-medium transition-colors',
// Use design tokens
props.variant === 'primary' && `bg-${customDesignConfig.designConfig.tokens.colors.primary}`,
props.size === 'small' && `px-3 py-1.5 text-sm`,
props.size === 'medium' && `px-4 py-2 text-sm`,
props.size === 'large' && `px-6 py-3 text-base`
));
return {
buttonClasses
};
}
};The CSS utilities are optimized for performance:
Install with Tessl CLI
npx tessl i tessl/npm-opentiny--vue-common