diff options
| author | Henry Jameson <me@hjkos.com> | 2024-02-19 20:05:49 +0200 |
|---|---|---|
| committer | Henry Jameson <me@hjkos.com> | 2024-02-19 20:05:49 +0200 |
| commit | 23dc2d1a5b6b3db7e5daa30c71eda1add2273e34 (patch) | |
| tree | f3e04631c09551b9a78d292c5191e52510d4e62e /src/services/theme_data/theme_data_3.service.js | |
| parent | 4a10417ed47cdfe08b2ff4939212116dba3e965f (diff) | |
refactor ISS stuff into separate file
Diffstat (limited to 'src/services/theme_data/theme_data_3.service.js')
| -rw-r--r-- | src/services/theme_data/theme_data_3.service.js | 128 |
1 files changed, 9 insertions, 119 deletions
diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js index af40758c..c4dfdc4c 100644 --- a/src/services/theme_data/theme_data_3.service.js +++ b/src/services/theme_data/theme_data_3.service.js @@ -13,6 +13,14 @@ import { process } from './theme3_slot_functions.js' +import { + unroll, + getAllPossibleCombinations, + genericRuleToSelector, + normalizeCombination, + findRules +} from './iss_utils.js' + const DEBUG = false // Ensuring the order of components @@ -109,125 +117,7 @@ componentsContext.keys().forEach(key => { components[component.name] = component }) -// "Unrolls" a tree structure of item: { parent: { ...item2, parent: { ...item3, parent: {...} } }} -// into an array [item2, item3] for iterating -const unroll = (item) => { - const out = [] - let currentParent = item - while (currentParent) { - out.push(currentParent) - currentParent = currentParent.parent - } - return out -} - -// This gives you an array of arrays of all possible unique (i.e. order-insensitive) combinations -export const getAllPossibleCombinations = (array) => { - const combos = [array.map(x => [x])] - for (let comboSize = 2; comboSize <= array.length; comboSize++) { - const previous = combos[combos.length - 1] - const selfSet = new Set() - const newCombos = previous.map(self => { - self.forEach(x => selfSet.add(x)) - const nonSelf = array.filter(x => !selfSet.has(x)) - return nonSelf.map(x => [...self, x]) - }) - const flatCombos = newCombos.reduce((acc, x) => [...acc, ...x], []) - combos.push(flatCombos) - } - return combos.reduce((acc, x) => [...acc, ...x], []) -} - -// Converts rule, parents and their criteria into a CSS (or path if ignoreOutOfTreeSelector == true) selector -export const ruleToSelector = (rule, ignoreOutOfTreeSelector, isParent) => { - if (!rule && !isParent) return null - const component = components[rule.component] - const { states, variants, selector, outOfTreeSelector } = component - - const applicableStates = ((rule.state || []).filter(x => x !== 'normal')).map(state => states[state]) - - const applicableVariantName = (rule.variant || 'normal') - let applicableVariant = '' - if (applicableVariantName !== 'normal') { - applicableVariant = variants[applicableVariantName] - } else { - applicableVariant = variants?.normal ?? '' - } - - let realSelector - if (selector === ':root') { - realSelector = '' - } else if (isParent) { - realSelector = selector - } else { - if (outOfTreeSelector && !ignoreOutOfTreeSelector) realSelector = outOfTreeSelector - else realSelector = selector - } - - const selectors = [realSelector, applicableVariant, ...applicableStates] - .toSorted((a, b) => { - if (a.startsWith(':')) return 1 - if (/^[a-z]/.exec(a)) return -1 - else return 0 - }) - .join('') - - if (rule.parent) { - return (ruleToSelector(rule.parent, ignoreOutOfTreeSelector, true) + ' ' + selectors).trim() - } - return selectors.trim() -} - -const combinationsMatch = (criteria, subject, strict) => { - if (criteria.component !== subject.component) return false - - // All variants inherit from normal - if (subject.variant !== 'normal' || strict) { - if (criteria.variant !== subject.variant) return false - } - - // Subject states > 1 essentially means state is "normal" and therefore matches - if (subject.state.length > 1 || strict) { - const subjectStatesSet = new Set(subject.state) - const criteriaStatesSet = new Set(criteria.state) - - const setsAreEqual = - [...criteriaStatesSet].every(state => subjectStatesSet.has(state)) && - [...subjectStatesSet].every(state => criteriaStatesSet.has(state)) - - if (!setsAreEqual) return false - } - return true -} - -const findRules = (criteria, strict) => subject => { - // If we searching for "general" rules - ignore "specific" ones - if (criteria.parent === null && !!subject.parent) return false - if (!combinationsMatch(criteria, subject, strict)) return false - - if (criteria.parent !== undefined && criteria.parent !== null) { - if (!subject.parent && !strict) return true - const pathCriteria = unroll(criteria) - const pathSubject = unroll(subject) - if (pathCriteria.length < pathSubject.length) return false - - // Search: .a .b .c - // Matches: .a .b .c; .b .c; .c; .z .a .b .c - // Does not match .a .b .c .d, .a .b .e - for (let i = 0; i < pathCriteria.length; i++) { - const criteriaParent = pathCriteria[i] - const subjectParent = pathSubject[i] - if (!subjectParent) return true - if (!combinationsMatch(criteriaParent, subjectParent, strict)) return false - } - } - return true -} - -const normalizeCombination = rule => { - rule.variant = rule.variant ?? 'normal' - rule.state = [...new Set(['normal', ...(rule.state || [])])] -} +const ruleToSelector = genericRuleToSelector(components) export const init = (extraRuleset, palette) => { const stacked = {} |
