UNPKG

@casoon/dragonfly

Version:

Modular, lightweight CSS framework and design system for modern web projects. Optimized for Astro JS, LightningCSS and Container Queries with @layer-based architecture and comprehensive accessibility.

233 lines (209 loc) 5.87 kB
/** * Array Helper Functions * * Utilities for array manipulation, filtering, and transformation. */ /** * Remove duplicates from array * * Keeps arrays clean without verbose logic. Works with primitives and objects. * * @param {Array} arr - Array to deduplicate * @param {Function|string} keyFn - Key function or property name for objects * @returns {Array} Array with duplicates removed * * @example * // Simple array * uniqueArray([1, 2, 2, 3, 1]) // [1, 2, 3] * * @example * // String array * const tags = uniqueArray([...userTags, ...defaultTags]); * * @example * // Object array by property * uniqueArray(users, 'id') // Remove users with duplicate IDs * * @example * // Object array by custom function * uniqueArray(users, user => user.email.toLowerCase()) */ export function uniqueArray(arr, keyFn = null) { if (!Array.isArray(arr)) return []; if (!keyFn) { // Simple deduplication for primitives return [...new Set(arr)]; } const seen = new Set(); const getKey = typeof keyFn === 'string' ? (item) => item[keyFn] : keyFn; return arr.filter((item) => { const key = getKey(item); if (seen.has(key)) { return false; } seen.add(key); return true; }); } /** * Group array items by key * * @param {Array} arr - Array to group * @param {Function|string} keyFn - Key function or property name * @returns {Object} Object with grouped items * * @example * const users = [ * { name: 'John', role: 'admin' }, * { name: 'Jane', role: 'user' }, * { name: 'Bob', role: 'admin' } * ]; * * groupBy(users, 'role') * // { * // admin: [{ name: 'John', role: 'admin' }, { name: 'Bob', role: 'admin' }], * // user: [{ name: 'Jane', role: 'user' }] * // } */ export function groupBy(arr, keyFn) { if (!Array.isArray(arr)) return {}; const getKey = typeof keyFn === 'string' ? (item) => item[keyFn] : keyFn; return arr.reduce((groups, item) => { const key = getKey(item); if (!groups[key]) { groups[key] = []; } groups[key].push(item); return groups; }, {}); } /** * Chunk array into smaller arrays * * @param {Array} arr - Array to chunk * @param {number} size - Size of each chunk * @returns {Array} Array of chunks * * @example * chunk([1, 2, 3, 4, 5, 6], 2) // [[1, 2], [3, 4], [5, 6]] * chunk([1, 2, 3, 4, 5], 3) // [[1, 2, 3], [4, 5]] */ export function chunk(arr, size) { if (!Array.isArray(arr) || size <= 0) return []; const chunks = []; for (let i = 0; i < arr.length; i += size) { chunks.push(arr.slice(i, i + size)); } return chunks; } /** * Shuffle array randomly * * @param {Array} arr - Array to shuffle * @returns {Array} New shuffled array * * @example * shuffle([1, 2, 3, 4, 5]) // [3, 1, 5, 2, 4] (random order) */ export function shuffle(arr) { if (!Array.isArray(arr)) return []; const shuffled = [...arr]; for (let i = shuffled.length - 1; i > 0; i--) { const j = Math.floor(Math.random() * (i + 1)); [shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]; } return shuffled; } /** * Get random item(s) from array * * @param {Array} arr - Source array * @param {number} count - Number of items to get (default: 1) * @returns {*|Array} Single item or array of items * * @example * randomItem([1, 2, 3, 4, 5]) // 3 (random single item) * randomItem([1, 2, 3, 4, 5], 2) // [2, 5] (random 2 items) */ export function randomItem(arr, count = 1) { if (!Array.isArray(arr) || arr.length === 0) { return count === 1 ? undefined : []; } if (count === 1) { return arr[Math.floor(Math.random() * arr.length)]; } const shuffled = shuffle(arr); return shuffled.slice(0, Math.min(count, arr.length)); } /** * Sort array by multiple criteria * * @param {Array} arr - Array to sort * @param {...(string|Function|Object)} criteria - Sort criteria * @returns {Array} New sorted array * * @example * const users = [ * { name: 'John', age: 30, role: 'admin' }, * { name: 'Jane', age: 25, role: 'user' }, * { name: 'Bob', age: 30, role: 'user' } * ]; * * // Sort by age (desc), then by name (asc) * sortBy(users, { key: 'age', desc: true }, 'name') */ export function sortBy(arr, ...criteria) { if (!Array.isArray(arr)) return []; return [...arr].sort((a, b) => { for (const criterion of criteria) { let aVal; let bVal; let desc = false; if (typeof criterion === 'string') { aVal = a[criterion]; bVal = b[criterion]; } else if (typeof criterion === 'function') { aVal = criterion(a); bVal = criterion(b); } else if (typeof criterion === 'object') { const { key, desc: isDesc } = criterion; desc = isDesc; aVal = typeof key === 'function' ? key(a) : a[key]; bVal = typeof key === 'function' ? key(b) : b[key]; } if (aVal < bVal) return desc ? 1 : -1; if (aVal > bVal) return desc ? -1 : 1; } return 0; }); } /** * Find intersection of multiple arrays * * @param {...Array} arrays - Arrays to intersect * @returns {Array} Array of common elements * * @example * intersection([1, 2, 3], [2, 3, 4], [3, 4, 5]) // [3] */ export function intersection(...arrays) { if (arrays.length === 0) return []; if (arrays.length === 1) return [...arrays[0]]; return arrays.reduce((acc, arr) => acc.filter((item) => arr.includes(item))); } /** * Find difference between arrays * * @param {Array} arr1 - First array * @param {Array} arr2 - Second array * @returns {Array} Elements in arr1 but not in arr2 * * @example * difference([1, 2, 3, 4], [2, 4]) // [1, 3] */ export function difference(arr1, arr2) { if (!Array.isArray(arr1)) return []; if (!Array.isArray(arr2)) return [...arr1]; return arr1.filter((item) => !arr2.includes(item)); } export { uniqueArray as default };