@threlte/flex
createClassParser
The prop class
can be used on <Box>
and <Flex>
to easily configure the
flexbox with predefined class names just as you would do in CSS. In order to use
the prop, you need to create a ClassParser
which accepts a single string and
returns NodeProps
. The function createClassParser
is a helper function that
provides the proper types.
Let’s assume, you want to create a parser that supports the following class names but in 3D space:
.container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: stretch;
gap: 10px;
padding: 10px;
}
.item {
width: auto;
height: auto;
flex: 1;
}
You then need to create a ClassParser
which returns the corresponding props:
import { createClassParser } from '@threlte/flex'
const classParser = createClassParser((string, props) => {
const classNames = string.split(' ')
for (const className of classNames) {
switch (className) {
case 'container':
props.flexDirection = 'Row'
props.justifyContent = 'Center'
props.alignItems = 'Stretch'
props.gap = 10
props.padding = 10
break
case 'item':
props.width = 'auto'
props.height = 'auto'
props.flex = 1
}
}
return props
})
Now you can use the prop class
on <Flex>
and <Box>
to configure the flexbox:
<script lang="ts">
import { Canvas, T } from '@threlte/core'
import Scene from './Scene.svelte'
import { NoToneMapping } from 'three'
import { OrbitControls } from '@threlte/extras'
let innerWidth = 0
</script>
<svelte:window bind:innerWidth />
<div class="relative h-screen w-screen">
<Canvas toneMapping={NoToneMapping}>
<T.OrthographicCamera
makeDefault
position.z={1000}
zoom={innerWidth / 500}
>
<OrbitControls />
</T.OrthographicCamera>
<Scene />
</Canvas>
</div>
<script lang="ts">
import { T } from '@threlte/core'
import { Shape, ShapeGeometry } from 'three'
export let color: string = 'white'
export let height = 1
export let width = 1
export let radius = 5
export let depth = 0
let x = 1
let y = 1
const createGeometry = (width: number, height: number, radius: number): ShapeGeometry => {
let shape = new Shape()
shape.moveTo(x, y + radius)
shape.lineTo(x, y + height - radius)
shape.quadraticCurveTo(x, y + height, x + radius, y + height)
shape.lineTo(x + width - radius, y + height)
shape.quadraticCurveTo(x + width, y + height, x + width, y + height - radius)
shape.lineTo(x + width, y + radius)
shape.quadraticCurveTo(x + width, y, x + width - radius, y)
shape.lineTo(x + radius, y)
shape.quadraticCurveTo(x, y, x, y + radius)
const geometry = new ShapeGeometry(shape)
geometry.center()
return geometry
}
$: geometry = createGeometry(width, height, radius)
</script>
<T.Mesh
position.z={depth * 20}
renderOrder={depth}
>
<T is={geometry} />
<T.MeshBasicMaterial {color} />
</T.Mesh>
<script lang="ts">
import { Box, Flex, createClassParser } from '@threlte/flex'
import RoundedPlane from './RoundedPlane.svelte'
const classParser = createClassParser((string, props) => {
const classNames = string.split(' ')
for (const className of classNames) {
switch (className) {
case 'container':
props.flexDirection = 'Row'
props.justifyContent = 'Center'
props.alignItems = 'Stretch'
props.gap = 10
props.padding = 10
break
case 'item':
props.width = 'auto'
props.height = 'auto'
props.flex = 1
}
}
return props
})
</script>
<Flex
width={300}
height={150}
{classParser}
class="container"
>
<RoundedPlane
radius={15}
color="#FE3D00"
width={300}
height={150}
/>
<Box class="item">
{#snippet children({ width, height })}
<RoundedPlane
color="#EB1688"
{width}
{height}
depth={1}
/>
{/snippet}
</Box>
<Box class="item">
{#snippet children({ width, height })}
<RoundedPlane
color="#113BFA"
{width}
{height}
depth={1}
/>
{/snippet}
</Box>
<Box class="item">
{#snippet children({ width, height })}
<RoundedPlane
color="#590C65"
{width}
{height}
depth={1}
/>
{/snippet}
</Box>
</Flex>