52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import type { KeysOfUnion } from "type-fest"
|
|
|
|
export type WidthProps =
|
|
| { minContent?: true }
|
|
| { tiny?: true }
|
|
| { buttonWidth?: true }
|
|
| { small?: true }
|
|
| { medium?: true }
|
|
| { auto?: true }
|
|
| { full?: true }
|
|
export type Key = KeysOfUnion<WidthProps>
|
|
|
|
const styles : Record<Key, string> = {
|
|
minContent: 'width: min-content;',
|
|
tiny: "width: 124px; grid-column: span 2;",
|
|
buttonWidth: "width: 136px; grid-column: span 2; flex-grow:0;",
|
|
small: "width: 202px; grid-column: span 3;",
|
|
medium: "width: 280px; grid-column: span 4;",
|
|
auto: "width: auto;",
|
|
full: "width: auto; grid-column: 1 / -1; align-self: auto; flex-grow:1;",
|
|
};
|
|
|
|
// All keys are exclusive
|
|
const conflicts: Set<Key>[] = [
|
|
new Set(Object.keys(styles) as Key[])
|
|
]
|
|
|
|
/**
|
|
* Add a width style to your component.
|
|
* Widths are designed to work both in a page-grid context and in a flex or normal context.
|
|
*
|
|
* (1) Add `& WidthProps` to your `Props` type
|
|
* (2) Call `v-bind="propsToWidth(props)"` on your component template
|
|
* (3) Now your component accepts width props such as `small`, `medium`, `stretch`.
|
|
*
|
|
* @param props Your component's props (or ...rest props if you have destructured them already)
|
|
* @returns the corresponding `style` object
|
|
*/
|
|
export const width = (props: Partial<WidthProps>, defaults: Key[] = []) => ({
|
|
style:
|
|
Object.entries(props).reduce(
|
|
((acc, [key, value]) =>
|
|
value && key in styles ?
|
|
acc.filter(accKey => !conflicts.find(set => set.has(accKey) && set.has(key as Key)))
|
|
.concat([key as Key])
|
|
: acc
|
|
),
|
|
defaults
|
|
).map(key => styles[key])
|
|
.join(' ')
|
|
})
|