aboutsummaryrefslogtreecommitdiff
path: root/src/services/theme_data/theme_data_3.service.js
diff options
context:
space:
mode:
authorHenry Jameson <me@hjkos.com>2024-02-19 20:05:49 +0200
committerHenry Jameson <me@hjkos.com>2024-02-19 20:05:49 +0200
commit23dc2d1a5b6b3db7e5daa30c71eda1add2273e34 (patch)
treef3e04631c09551b9a78d292c5191e52510d4e62e /src/services/theme_data/theme_data_3.service.js
parent4a10417ed47cdfe08b2ff4939212116dba3e965f (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.js128
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 = {}