// Stack.vue
<template>
<component
:is="tag"
class="stack"
:style="stackStyle"
v-bind="attrs"
>
<slot />
</component>
</template>
<script setup lang="ts">
import { computed, useAttrs } from 'vue';
import type { CSSProperties } from 'vue';
type AlignItems = NonNullable<CSSProperties['alignItems']>;
type JustifyContent = NonNullable<CSSProperties['justifyContent']>;
type FlexWrap = NonNullable<CSSProperties['flexWrap']>;
type FlexDirection = NonNullable<CSSProperties['flexDirection']>;
type Gap = NonNullable<CSSProperties['gap']>;
interface Props {
tag?: string;
align?: AlignItems;
justify?: JustifyContent;
direction?: FlexDirection;
gap?: Gap;
wrap?: FlexWrap;
}
const props = withDefaults(defineProps<Props>(), {
tag: 'div',
align: 'stretch',
justify: 'flex-start',
direction: 'row',
gap: '0',
wrap: 'nowrap',
});
const attrs = useAttrs();
const stackStyle = computed(() => ({
'--stack-align': props.align,
'--stack-justify': props.justify,
'--stack-direction': props.direction,
'--stack-gap': `${props.gap}px`,
'--stack-wrap': props.wrap,
}));
</script>
<style lang="scss" scoped>
.stack {
@include flex(
var(--stack-align),
var(--stack-justify),
var(--stack-direction),
var(--stack-gap),
var(--stack-wrap)
);
}
</style>
// Stack Component Usage
<Stack :gap="2" :direction="'column'" class="parent-container">
<Stack :gap="3" :direction="column" class="parent-sub-container"></Stack>
</Stack>