Closed cristianvogel closed 1 month ago
Hey Cristian, Tweakpane really likes the vertical stack layout, so going horizontal is generally a bit uphill. (With the exception of the <ButtonGrid>
and <RadioGrid>
components.)
There's also a third-party table plugin for vanilla Tweakpane, but this is not integrated with Svelte Tweakpane UI because the approach it takes (managing its own nested Pane instances) isn't really compatible.
For the example you've shared, one thing to remember is the implicit pane feature in Svelte Tweakpane UI, which automatically wraps any component that is not somewhere inside an explicit <Pane>
component in an "implicit" <Pane>
with position inline
, so the extra panes wrapping your checkboxes are probably not necessary. (This is a tricky feature, but it's probably worth it... internally, there's no way for a Tweakpane control to exist without a parent Pane, but I wanted people to be able to get started without worrying about that.)
Also, you can set a theme
prop value directly on any stand-alone component.
One thing that will also help is the bladeValueWidth
theme value, which changes the width of the right "column" vs. the left inside the Tweakpane blade.
Here's an example combining these points, and using CSS grid for the layout:
<script lang="ts">
import { Checkbox, Slider } from 'svelte-tweakpane-ui';
let colors = 0.95;
let darkMode = true;
let numbers = true;
</script>
<div class="grid-wrapper">
<Slider
bind:value={colors}
min={0}
max={1}
label="Colors"
theme={{ baseBorderRadius: '0', bladeValueWidth: '244px' }}
/>
<Checkbox
bind:value={darkMode}
label="Dark Mode"
theme={{ baseBorderRadius: '0', bladeValueWidth: '75.5px' }}
/>
<Checkbox
bind:value={numbers}
label="Numbers"
theme={{ baseBorderRadius: '0', bladeValueWidth: '80px' }}
/>
</div>
<style>
div.grid-wrapper {
display: grid;
grid-template-columns: repeat(2, 1fr);
max-width: 337px;
}
div.grid-wrapper > :global(div:first-child) {
grid-column: span 2;
}
</style>
Which gives a component like this:
As you can see the bladeValueWidth
s are a little fussy...
Tweakpane positions the checkboxes for nice alignment with the vertical column established by the other controls, so I think they feel a bit orphaned when laid out horizontally, and again without the vertical grid the strangeness of having labels to the right of the checkbox control sticks out more. (Though they could probably be flipped around with more aggressive CSS...)
Also worth noting, bladeValueWidth
can take a % value just fine if you want dynamic widths.
So, it's not easy, but it's possible!
Thanks Eric, that's going to work for me. Although I would like to see a bit more horizontal layout friendliness, as often a lowly checkbox can garner more attention than it ought to. In such control panes, they are usually controlling a relatively minor feature in the state
One more thing;
I was wrapping them explicitly in extra <Pane>
tags, because I want to override the expanded, user-expandable attributes, as I do not need the default behaviour that they auto show and hide when they are inline.
Can that also be done on a component basis?
Ok, sounds good. I'll respond in sections since we're talking about a few different things here. 😅
Auto show / hide
Can you clarify what you mean by this? Is this something happening programmatically elsewhere to show / hide the checkboxes when needed? I don't think the user has any means to expand / collapse an inline Pane unless it has its title
prop is set, making the title bar visible... or on a per-component basis if there's a collapsible component like a <Folder>
(which does expose userExpandable
).
Panes
There's no real harm in specifying extra panes since they would be created (implicitly) anyway, though there are probably minor performance improvements (and some conceptual sanity) to be found in creating a single <Pane>
to wrap everything when you can.
Single pane grid approach
There is another strategy to accomplish the horizontal layout with a single explicit <Pane>
, based on your original flexbox approach, which makes more sense than grid here.
The CSS is just a bit more brittle than the previous example in my opinion, since it messes with Tweakpane classes directly instead of using a wrapper div.
Also flex-direction: row-reverse;
solves the "checkbox on the wrong side" problem nicely, but leaves the issue of making the labels clickable.
<script lang="ts">
import { Checkbox, Pane, Slider } from 'svelte-tweakpane-ui';
let colors = 0.95;
let darkMode = true;
let numbers = false;
let oneMore = true;
</script>
<Pane position="inline" theme={{ bladeValueWidth: '244px' }} width={337}>
<Slider bind:value={colors} min={0} max={1} label="Colors" />
<Checkbox bind:value={darkMode} label="Dark Mode" />
<Checkbox bind:value={numbers} label="Numbers" />
<Checkbox bind:value={oneMore} label="One More" />
</Pane>
<style>
:global(div.tp-rotv_c) {
display: flex;
flex-wrap: wrap;
}
:global(div.tp-lblv) {
flex-grow: 1;
}
:global(.tp-lblv:has(.tp-ckbv)) {
flex-direction: row-reverse;
flex-grow: 0;
}
:global(.tp-lblv_v:has(.tp-ckbv)) {
width: fit-content;
}
</style>
Ends up looking like:
Closing this since it looks like you have a fix, but feel free to re-open if needed.
Hey, me again!
So now , I can't seem to get the layout I need from inline positioning. I've tried using
width
on an explicit<Pane>
that wraps them but I can't seem to get it right.