I am looking to create a Spacer element in svelte. I have accomplished what I have set out to which is allow a user to wrap elements in a <Space></Space> tag and pass props to space them evenly vertically/horizontally or even align the interior elements center/start/end/baseline. The issue I have is that I have to wrap each child element to <Space></Space> with a <SpaceItem></SpaceItem> to get the desired effect. Here is the example code:
App.svelte
<script>
import {Space, SpaceItem} from './components/Space';
</script>
<Space>
<SpaceItem>
<Button primary>Primary</Button>
</SpaceItem>
<SpaceItem>
<Button primary icon="add">Primary</Button>
</SpaceItem>
<SpaceItem>
<Button danger>Danger</Button>
</SpaceItem>
</Space>
Space.svelte
<script>
import { SPACE } from './SpaceContext.svelte';
import { setContext } from 'svelte';
import { readable } from 'svelte/store';
export let vertical = false;
export let horizontal = true;
export let alignCenter = false;
export let alignStart = false;
export let alignEnd = false;
export let alignBaseline = false;
export let large = false;
export let middle = false;
export let size = null;
horizontal = vertical ? false : true;
size = size ? size : large ? 24 : middle ? 16 : 8;
const gap = readable(size);
const direction = readable(horizontal ? 'horizontal' : 'vertical');
setContext(SPACE, {
gap,
direction,
});
</script>
<style>
.space {
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
}
.vertical {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.align-center {
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.align-start {
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
}
.align-end {
-webkit-box-align: end;
-ms-flex-align: end;
align-items: flex-end;
}
.align-baseline {
-webkit-box-align: baseline;
-ms-flex-align: baseline;
align-items: baseline;
}
</style>
<div
class="space"
class:horizontal
class:vertical
class:size
class:align-center={alignCenter}
class:align-start={alignStart}
class:align-end={alignEnd}
class:align-baseline={alignBaseline}>
<slot />
</div>
SpaceItem
<script>
import { SPACE } from './SpaceContext.svelte';
import { getContext } from 'svelte';
const { gap, direction } = getContext(SPACE);
let style;
if ($direction === 'horizontal') {
style = `margin-right: ${$gap}px;`;
} else {
style = `margin-bottom: ${$gap}px;`;
}
</script>
<style>
</style>
<div class="item" {style}>
<slot />
</div>
Is there a way to eliminate the <SpaceItem></SpaceItem> element and for <Space></Space> to wrap each element passed to its <slot /> with the <SpaceItem></SpaceItem>? I would like to only have to wrap all elements in one Space tag and not wrap each individual one in a SpaceItem tag.
Desired effect is for me to be able to write:
App.svelte
<script>
import {Space, SpaceItem} from './components/Space';
</script>
<Space>
<Button primary>Primary</Button>
<Button primary icon="add">Primary</Button>
<Button danger>Danger</Button>
</Space>
And still wrap each button with <SpaceItem></SpaceItem> within the Space.svelte file.