import type { Optional, StylesheetModel } from '../index.js' import type { MergeInterfaces, Unformatted } from '../utils/value.js' import { TypeDefinitions } from './definition.js' import { Details } from './details.js' import * as RuleMethods from './methods/rule.js' import { Props } from './props.js' import { isTypeInCategory, TypesByCategory, Category } from './definition.js' import type { Type } from './type.js' export type Rule = RuleByType[T] export namespace Rule { export type Basic = Rule export type Aspect = Rule export type Element = Rule export type Concept = Rule export type ElementAspect = Rule> export type ElementWithAspect = Rule> } export namespace RuleCollection { export type Element = RuleWithProps< 'collection', TypeDefinitions.collection.Props > } export type RuleCollection = RuleWithProps<'collection', TypeDefinitions.collection.Props> export interface Empty { type: Type } export type RuleMerged = RuleWithProps>> export interface RuleWithProps { type: T props: P details: Details } export type typeOf> = R extends RuleWithProps ? T : never export type typesOf[]> = R extends RuleWithProps[] ? T : never export type RuleByType = { [id in Type]: RuleWithProps } export type AspectsByType = { [key in (typeof TypeDefinitions)[T]['aspects'][number]]: Rule[] } export type AspectByType = { [key in (typeof TypeDefinitions)[T]['aspects'][number]]: Rule } export function RuleConstructor({ type, details, props }: { type: T details?: Unformatted> props?: Unformatted }): Rule { return { type, details: Details({ exampleContent: type === 'text' || type === 'typography' ? 'Example' : null, ...details, title: type == 'font' && !details?.title ? (props as Props['font'])?.familyName : details?.title || '' }), props: TypeDefinitions[type] ? TypeDefinitions[type].Props(props) : props } as Rule } export const RuleShortcuts = { fix(style: Rule, rules: Rule[]): Rule { var { type, details, props } = style return Rule({ type, details: { ...details, slug: details.slug || Rule.getSlug(style as Rule, rules) }, props: Props.fix(type, props, rules) }) }, /** Ensure that basic shape of a style is correct */ isValid(rule: Rule) { return rule.type && rule.details.title && rule.details.id && rule.props }, isInCategory(style: Rule, category: T): style is Rule { return isTypeInCategory(style.type, category) }, /** A constructor for newly created rules for a given collection. Assigns some default values */ forCollection(collection: Rule<'collection'>) { const style = RuleConstructor({ type: collection.props.type, details: { collectionId: collection.details.id } }) if (style.type === 'color') { style.props = { red: 255, green: 255, blue: 255, alpha: 1 } } if (style.type === 'text' || style.type === 'inline' || style.type === 'block') { // @ts-ignore style.props = Object.keys(style.props).reduce((acc, prop) => { return { ...acc, [prop]: ['blank-' + prop.replace('Ids', '')] } }, {}) } return style } } export type RuleError = Partial<{ details?: Partial props?: { [key in keyof T['props']]: string } }> | null export const Rule = Object.assign(RuleConstructor, RuleMethods, RuleShortcuts)