import { pluralize, singularize, titleize, underscore } from 'inflection' import type * as Style from '../index.js' import * as Conventions from './conventions.js' import * as Rule from './rule.js' import * as Definitions from './definitions.js' export function filterByType(styles: Style.Rule[], type: T): Style.Rule[] { return styles.filter((s) => Rule.isOfType(s, type)) as Style.Rule[] } export function filterByInstanceId(styles: Style.Rule[], instanceId: string) { return styles.filter((s) => s.details.instanceId == instanceId) } export const findByTypeAndId = (rules: Style.Rule[], type: T, id: Style.RuleId): Style.Rule => findById(rules, id) as Style.Rule export const findById = (rules: Style.Rule[], id: Style.RuleId): Style.Rule => rules.find((s) => s.details.id === id) as Style.Rule export const findBlank = (rules: Style.Rule[], type: T): Style.Rule => findByTypeAndId(rules, type, `blank-${type}`) export const findBlankId = (styles: Style.Rule[], type: T): Style.RuleId => findBlank(styles, type)?.details.id export function findStyle(styles: Style.Rule[], style: S): S { return styles.find((s) => s.details.id == style.details.id) as S } export function findBySlug(styles: Style.Rule[], type: T, slug: string): Style.Rule { return styles.find((s) => s.type == type && s.details.slug == slug) as any } export function findByClassName(styles: Style.Rule[], className: string) { return styles.find((s) => Rule.getClassName(s) == className) } export function filterByCollectionId(styles: Style.Rule[], collectionId: string) { return styles.filter((s) => s.details.collectionId == collectionId) } export function filterCollectionsForType( styles: Style.Rule[], type: T ): Style.RuleCollection[] { return filterByType(styles, 'collection').filter((s) => s.props.type == type) as Style.RuleCollection[] } export function getDefaultCollections(styles: Style.Rule[]) { return filterByType(styles, 'collection').filter((style) => style.details.isInternal) } export function getElementDefinitions(styles: Style.Rule[]) { return filterByType(styles, 'collection') .filter( (s) => (s.props.type == 'text' || s.props.type == 'block' || s.props.type == 'inline') && !s.details.isInternal ) .map((s: Style.RuleCollection.Element) => { var placeholder const type = s.props.type if (type == 'inline') { placeholder = 'Inline element' } else if (type == 'text') { placeholder = titleize(underscore(singularize(type))) } const name = Rule.getEffectiveSlug(s, styles) const description = s.details.description return { label: Conventions.getLabelByName(s.details.slug), name: s.details.slug, id: s.details.id, description, isCustom: true, type: type as Style.Type.Element, htmlTagName: null, isImplicit: false, title: pluralize(s.details.title), placeholder, className: `-${type}--${name}` } as Style.ElementDefinition }) .concat(Definitions.all as readonly Style.ElementDefinition[]) } // Merges two sets of styles. If style exists in both collection, prefers one from second export function join(styles: Style.Rule[], contextStyles: Style.Rule[]) { return styles .map((style) => contextStyles.find((r) => r.details.id == style.details.id) || style) .concat(contextStyles.filter((r) => !styles.find((s) => s.details.id == r.details.id))) } export function getAspectDefault(styles: RuleAspect[]) { return styles[0] } export function getAspectDefaultOriginal( styles: Style.Rule[], options: RuleAspect[] ) { return findStyle(styles, getAspectDefault(options)) } export function getAspectCustomizationType( styles: Style.Rule[], style: Style.Rule.Aspect, options: Style.Rule.Aspect[] ) { const defaultStyle = getAspectDefaultOriginal(styles, options) return style.details.instanceId ? 'oneOff' : style.details.id === defaultStyle?.details.id ? 'default' : options.find((s) => s.details.id === style.details.id) ? 'allowed' : 'nonAllowed' } /** Return element rule corresponding to given combo id */ export function findElementByComboId(styles: Style.Rule[], comboId: string) { return findElementByThemeAndComboId(styles, findThemeByComboId(styles, comboId), comboId) } /** Return theme where there is exists a combo with given id */ export function findThemeByComboId(styles: Style.Rule[], comboId: string): Style.Rule<'theme'> { for (const theme of filterByType(styles, 'theme')) { const category = Object.keys(theme.props).find((prop: keyof Style.Theme.Props) => theme.props[prop].find((c) => c.id === comboId) ) as keyof Style.Theme.Props if (category) return theme } return null } /** Return theme where there is exists a combo with given id */ export function findCombo(styles: Style.Rule[], comboId: string): Style.Theme.Combo { return Rule.findComboInTheme(findThemeByComboId(styles, comboId), comboId) ?? null } /** In given theme find a combo with given id */ export function findElementByThemeAndComboId( styles: Style.Rule[], theme: Style.Rule<'theme'>, comboId: string ): Style.Rule.Element { if (!theme) return const category = Object.keys(theme.props).find((prop: keyof Style.Theme.Props) => theme.props[prop].find((c) => c.id === comboId) ) as keyof Style.Theme.Props if (!category) return null const combo = theme.props[category].find((c) => c.id === comboId) return findById(styles, combo.refId) as Style.Rule.Element }