|
| 1 | +const _ = require('lodash') |
| 2 | +const flatten = require('flat') |
| 3 | + |
| 4 | + |
| 5 | +const FLATTEN_CONFIG = { delimiter: '-', maxDepth: 2 } |
| 6 | +const handleName = (name, className) => { |
| 7 | + const split = name.split(`${className}-`) |
| 8 | + const prefixedName = `${split[0]}${prefixNegativeModifiers(className, split[1])}` |
| 9 | + |
| 10 | + return prefixedName.split('-default').join('') |
| 11 | +} |
| 12 | +const prefixNegativeModifiers = function(base, modifier) { |
| 13 | + return _.startsWith(modifier, '-') |
| 14 | + ? `-${base}-${modifier.slice(1)}` |
| 15 | + : `${base}-${modifier}` |
| 16 | +} |
| 17 | + |
| 18 | + |
| 19 | +module.exports = function () { |
| 20 | + return function ({ |
| 21 | + addUtilities, addComponents, addBase, addVariant, |
| 22 | + e, prefix, theme, variants, config, |
| 23 | + }) { |
| 24 | + const buildConfig = (themeKey, ...fallbackKeys) => { |
| 25 | + return buildConfigFromTheme(themeKey, ...fallbackKeys) || buildConfigFromArray(themeKey) |
| 26 | + } |
| 27 | + const buildConfigFromTheme = (themeKey, ...fallbackKeys) => { |
| 28 | + const buildObject = ([ modifier, value ]) => [ modifier, { [themeKey]: value } ] |
| 29 | + const getThemeSettings = (themeKey, fallbackKeys) => { |
| 30 | + const [newThemeKey, ...newFallbackKeys] = fallbackKeys || [] |
| 31 | + |
| 32 | + return theme(themeKey, false) || (fallbackKeys.length && getThemeSettings(newThemeKey, [...newFallbackKeys])) |
| 33 | + } |
| 34 | + |
| 35 | + const themeSettings = getThemeSettings(themeKey, fallbackKeys) |
| 36 | + const themeObject = _.isArray(themeSettings) ? _.zipObject(themeSettings, themeSettings) : themeSettings |
| 37 | + const themeEntries = themeSettings && Object |
| 38 | + .entries(flatten(themeObject, FLATTEN_CONFIG)) |
| 39 | + .map(entry => buildObject(entry)) |
| 40 | + |
| 41 | + return themeSettings ? _.fromPairs(themeEntries) : false |
| 42 | + } |
| 43 | + const buildConfigFromArray = (property) => { |
| 44 | + const defaultSettings = defaultValues[property] |
| 45 | + const defaultEntries = defaultSettings && defaultSettings |
| 46 | + .map(value => ([value, { [property]: value }])) |
| 47 | + |
| 48 | + return defaultSettings ? _.fromPairs(defaultEntries) : false |
| 49 | + } |
| 50 | + |
| 51 | + const buildPluginUtilityObject = ({ color, size, border, speed }) => { |
| 52 | + return { |
| 53 | + 'position': 'relative', |
| 54 | + 'color': 'transparent !important', |
| 55 | + 'pointer-events': 'none', |
| 56 | + |
| 57 | + '&::after': { |
| 58 | + 'content': `''`, |
| 59 | + |
| 60 | + 'position': 'absolute !important', |
| 61 | + 'top': `calc(50% - (${size} / 2))`, |
| 62 | + 'left': `calc(50% - (${size} / 2))`, |
| 63 | + |
| 64 | + 'display': 'block', |
| 65 | + 'width': size, |
| 66 | + 'height': size, |
| 67 | + |
| 68 | + 'border': `${border} solid ${color}`, |
| 69 | + 'border-radius': '9999px', |
| 70 | + 'border-right-color': 'transparent', |
| 71 | + 'border-top-color': 'transparent', |
| 72 | + |
| 73 | + 'animation': `spinAround ${speed} infinite linear`, |
| 74 | + }, |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + const buildDefaultValuesObject = (defaultConfig, themeKey, ...fallbackKeys) => { |
| 79 | + const defaultEntries = Object.entries(theme(themeKey, { default: defaultConfig })) |
| 80 | + .map(([ modifier, config ]) => [ modifier, buildPluginUtilityObject({ ...defaultConfig, ...config }) ]) |
| 81 | + |
| 82 | + return _.fromPairs(defaultEntries) |
| 83 | + } |
| 84 | + |
| 85 | + const defaultValues = {} |
| 86 | + const defaultConfig = { |
| 87 | + color: 'currentColor', |
| 88 | + size: '1em', |
| 89 | + border: '2px', |
| 90 | + speed: '500ms', |
| 91 | + } |
| 92 | + |
| 93 | + const pluginUtilities = { |
| 94 | + spinner: buildDefaultValuesObject(defaultConfig, 'spinner'), |
| 95 | + } |
| 96 | + |
| 97 | + Object.entries(pluginUtilities) |
| 98 | + .filter(([ modifier, values ]) => !_.isEmpty(values)) |
| 99 | + .forEach(([ modifier, values ]) => { |
| 100 | + const className = _.kebabCase(modifier) |
| 101 | + const variantName = Object.keys(Object.entries(values)[0][1])[0] |
| 102 | + const utilities = flatten({ [`.${e(`${className}`)}`]: values }, FLATTEN_CONFIG) |
| 103 | + |
| 104 | + addUtilities( |
| 105 | + _.mapKeys(utilities, (value, key) => handleName(key, className)), |
| 106 | + variants(variantName, ['responsive']) |
| 107 | + ) |
| 108 | + }) |
| 109 | + |
| 110 | + addUtilities({ |
| 111 | + '@keyframes spinAround': { |
| 112 | + 'from': { 'transform': 'rotate(0deg)' }, |
| 113 | + 'to': { 'transform': 'rotate(360deg)' }, |
| 114 | + }, |
| 115 | + }) |
| 116 | + } |
| 117 | +} |
0 commit comments