Created
February 6, 2023 08:43
-
-
Save lsdsjy/26e9243838cc894b6d69cd8edd4e6d55 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type { CSSProperties } from '@vue/runtime-dom'; | |
import { rpx2vws } from './utils/rpx2vw'; | |
const STANDALONE = [ | |
'items-end', | |
'overflow-hidden', | |
'flex', | |
'flex-col', | |
'number', | |
'bold', | |
'inline-block', | |
'items-center', | |
'content-center', | |
'justify-between', | |
'justify-center', | |
'ellipsis', | |
] as const; | |
const PREFIX = [ | |
'color', | |
'opacity', | |
'mt', | |
'mb', | |
'ml', | |
'mr', | |
'mx', | |
'text', | |
'leading', | |
'w', | |
'h', | |
'rounded', | |
'bg', | |
'max-w', | |
] as const; | |
type AllStandalone = typeof STANDALONE[number]; | |
type AllPrefix = typeof PREFIX[number]; | |
type AllPrefixed = `${AllPrefix}${string}`; | |
const MAP: Record<AllStandalone, CSSProperties> & Record<AllPrefix, keyof CSSProperties | (keyof CSSProperties)[]> = { | |
ellipsis: { | |
'word-break': 'break-all', | |
whiteSpace: 'nowrap', | |
textOverflow: 'ellipsis', | |
overflow: 'hidden', | |
}, | |
'items-end': { alignItems: 'flex-end' }, | |
'overflow-hidden': { overflow: 'hidden' }, | |
'justify-center': { justifyContent: 'center' }, | |
'flex-col': { flexDirection: 'column' }, | |
'justify-between': { justifyContent: 'space-between' }, | |
'items-center': { alignItems: 'center' }, | |
'content-center': { justifyContent: 'center' }, | |
'inline-block': { display: 'inline-block' }, | |
flex: { display: 'flex' }, | |
bold: { fontWeight: 'bold' }, | |
number: { fontFamily: 'number' }, | |
ml: 'marginLeft', | |
mr: 'marginRight', | |
mt: 'marginTop', | |
mb: 'marginBottom', | |
mx: ['marginLeft', 'marginRight'], | |
text: 'fontSize', | |
leading: 'lineHeight', | |
w: 'width', | |
h: 'height', | |
'max-w': 'max-width', | |
rounded: 'borderRadius', | |
bg: 'background', | |
color: 'color', | |
opacity: 'opacity', | |
}; | |
function processParam(prefix: AllPrefix, param: string) { | |
if (prefix === 'opacity') { | |
return String(Number(param) / 100); | |
} | |
return param; | |
} | |
type Check<T extends [...unknown[]], Standalone = AllStandalone, Prefix extends string = AllPrefix> = T extends [ | |
infer A, | |
...infer Rest, | |
] | |
? A extends Standalone | |
? [A, ...Check<Rest, Exclude<Standalone, A>, Prefix>] | |
: A extends `${Prefix}-${infer S}` | |
? `` extends S | |
? never | |
: A extends `${infer P}-${S}` | |
? [A, ...Check<Rest, Standalone, Exclude<Prefix, P>>] | |
: never | |
: never | |
: T; | |
function isPrefixed(x: string): x is AllPrefixed { | |
return PREFIX.some((p) => x.startsWith(p + '-')); | |
} | |
function isStandalone(x: string): x is AllStandalone { | |
return STANDALONE.includes(x as any); | |
} | |
type SplitBySpace<S extends string> = S extends `${infer H} ${infer T}` ? [H, ...SplitBySpace<T>] : [S]; | |
const cache = new Map<string, CSSProperties>(); | |
export function style<S extends string, T extends unknown[] = SplitBySpace<S>>( | |
s: S & (Check<T> extends never ? never : S), | |
): CSSProperties { | |
if (cache.has(s)) { | |
return cache.get(s)!; | |
} | |
const items = s.split(' ') as (AllStandalone | AllPrefixed)[]; | |
const result: Record<string, string> = {}; | |
for (const item of items) { | |
if (isPrefixed(item)) { | |
const seg = item.lastIndexOf('-'); | |
const prefix = item.slice(0, seg) as AllPrefix; | |
const rawValue = item.slice(seg + 1); | |
let value = processParam(prefix, rawValue); | |
const number = Number(value); | |
if (Number.isInteger(number)) { | |
value = rpx2vws(number); | |
} | |
let properties = MAP[prefix as AllPrefix]; | |
if (!Array.isArray(properties)) { | |
properties = [properties]; | |
} | |
for (const property of properties) { | |
result[property] = value; | |
} | |
} else if (isStandalone(item)) { | |
Object.assign(result, MAP[item]); | |
} else { | |
throw new Error('invalid style params'); | |
} | |
} | |
cache.set(s, result); | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment