import { cssVarName, keys } from '@knapsack/utils'; import type { SlotOptions, SlotOptionsComputed, TokenSrcValueInfo, } from '@knapsack/types'; import { themeDefinitionToAttributes } from './theming.js'; type TokensWithStringStaticVal = Extract< TokenSrcValueInfo, { kind: 'static'; value: string } >; /** * Helper function to convert a `TokenSrcValueInfo` to a string value. */ const tokenSrcValueInfoToValue = ( tokenSrcValueInfo: TokenSrcValueInfo, ): string => { return tokenSrcValueInfo.kind === 'static' ? tokenSrcValueInfo.value : `var(${cssVarName(tokenSrcValueInfo.referencedTokenId)})`; }; export function convertSlotOptions({ slotOptions: { cssClasses = [], wrappingElementName = 'div', ...slotOptions }, collectionsParentKey = 'collections', }: { slotOptions: SlotOptions; collectionsParentKey: string; }): SlotOptionsComputed { return keys(slotOptions).reduce( (acc, id) => { switch (id) { case 'gap': { const tokenSrcValueInfo = slotOptions[id]; if (!tokenSrcValueInfo) return acc; acc.styles.display = 'flex'; acc.styles.gap = tokenSrcValueInfoToValue(tokenSrcValueInfo.value); break; } case 'align': { const option = slotOptions[id]; if (!option) return acc; acc.styles.display = 'flex'; switch (option.value) { case 'top-left': { acc.styles.alignItems = 'start'; acc.styles.justifyContent = 'start'; break; } case 'top-center': { acc.styles.alignItems = 'start'; acc.styles.justifyContent = 'center'; break; } case 'top-right': { acc.styles.alignItems = 'start'; acc.styles.justifyContent = 'end'; break; } case 'right': { acc.styles.alignItems = 'center'; acc.styles.justifyContent = 'end'; break; } case 'bottom-right': { acc.styles.alignItems = 'end'; acc.styles.justifyContent = 'end'; break; } case 'bottom-center': { acc.styles.alignItems = 'end'; acc.styles.justifyContent = 'center'; break; } case 'bottom-left': { acc.styles.alignItems = 'end'; acc.styles.justifyContent = 'start'; break; } case 'center': { acc.styles.alignItems = 'center'; acc.styles.justifyContent = 'center'; break; } case 'left': { acc.styles.alignItems = 'center'; acc.styles.justifyContent = 'start'; break; } default: { const _exhaustiveCheck: never = option.value; } } break; } case 'layout': { const option = slotOptions[id]; if (!option) return acc; acc.styles.display = 'flex'; acc.styles.width = '100%'; switch (option.value) { case 'horizontal': { acc.styles.flexFlow = 'row'; break; } case 'vertical': { acc.styles.flexFlow = 'column'; break; } case 'wrap': { acc.styles.flexFlow = 'wrap'; break; } default: { const _exhaustiveCheck: never = option.value; } } break; } case 'paddingHorizontal': { const tokenSrcValueInfo = slotOptions[id]; if (!tokenSrcValueInfo) return acc; const [paddingLeft, paddingRight] = tokenSrcValueInfo.value; // Left if (paddingLeft?.kind) { acc.styles.paddingLeft = tokenSrcValueInfoToValue(paddingLeft); } // Right if (paddingRight?.kind) { acc.styles.paddingRight = tokenSrcValueInfoToValue(paddingRight); } break; } case 'paddingVertical': { const tokenSrcValueInfo = slotOptions[id]; if (!tokenSrcValueInfo) return acc; const [paddingTop, paddingBottom] = tokenSrcValueInfo.value; // Top if (paddingTop?.kind) { acc.styles.paddingTop = tokenSrcValueInfoToValue(paddingTop); } // Bottom if (paddingBottom?.kind) { acc.styles.paddingBottom = tokenSrcValueInfoToValue(paddingBottom); } break; } case 'theme': { const themeDef = slotOptions[id]; if (!themeDef) return acc; acc.attributes = themeDefinitionToAttributes({ collectionsParentKey, themeDefinition: themeDef, }); break; } default: { const _exhaustiveCheck: never = id; } } return acc; }, { wrappingElementName, cssClasses, attributes: {}, styles: {}, } satisfies SlotOptionsComputed, ); }