Closed cristianvogel closed 2 months ago
Hey, thanks for taking a look at the code... it's a bit dense / weird in places since component inheritance is not a super common pattern in Svelte.
The value
prop that most higher-level components use is first defined here in GenericBinding.svelte, which is in charge of creating and managing an object containing the value that can be passed into Tweakpane.
Here value
is defined as a required prop, with no default value, since nothing is assigned in its export let
statement. This behavior is then inherited by all the more specialized components.
I'm probably misunderstanding your question, but currently I think of the default value as being whatever initial value
is passed to the component, e.g. this trivial example of a slider with an initial value of 20:
<script>
import { Slider } from 'svelte-tweakpane-ui';
let value = 20;
</script>
<Slider bind:value min={0} max={100} />
Do you mind clarifying a bit what you're looking for beyond this existing behavior?
Yeah it's an interesting architecture for me, hadn't seen anything quite like that in Svelte, and also noticed use of generics in the script tag , which I hadn't come across yet. Its impressive how complex stateful UI libraries can get.
I think I was stumbling a bit on understanding the two way binding.
I have a set of controls, that are declared in a manifest. They should get instantiated with a default value, but I was finding it complicated to instance the components in the Svelte markup using for each, whilst also setting the value to it's default on create. I just think that, although it might seem redundant, the default value is quite important , and it would be easier to manage I think as part of the constructor props. Like min or max or step even.
In my case, I am recalling defaults from persistent state, but also need a default for when there is no state persisting yet and things get a bit confusing
Yeah the generics attribute in the script tag is a little strange, my understanding is that the Svelte team went through a couple different ideas before landing on it — though you still sometimes see the alternative $$Generic
syntax in the wild.
Thanks for clarifying the defaults situation, I think I'm following.
It might be somewhat similar to what I'm doing in tweakpane-css, which uses svelte-persistent-store to take care of both managing defaults and syncing to the browser's local storage. The Tweakpane CSS component derives the UI and certain options from the store, with default values used if nothing is yet available in the local store. In Svelte Tweakpane component instantiations, value
is bound directly to the store object or to specific keys in the store.
It's not the cleanest component, but in this section you can see the defaultOptions
object:
const defaultOptions: Options = {
autoFolders: false,
includeCalculated: false,
prettyNames: true,
showUnits: true,
sortNames: false,
}
Which is assigned as the default value to a prop and then passed as the default value when the store is created, in case the local store values are not yet set:
export let options: Options = defaultOptions
...
let optionsStore: Writable<Options> = persisted('css-options', options)
(Assigning to the options
prop is just an implementation detail which allows the user to further override the initial options, otherwise defaultOptions
could be passed as persisted
's second argument.)
Then passed to a Svelte Tweakpane UI <AutoObject>
component in the markup:
<Folder bind:expanded={$expandedStateStore[optionsExpandedStateKey]} title="Options">
<AutoObject bind:object={$optionsStore} />
<Button on:click={resetOptions} title="Reset Options" />
</Folder>
Two-way binding of $optionsStore
means that any changes from the Tweakpane are automatically persisted locally, overriding defaults on future loads after the first write to local storage.
This basically pushes the question of defaults out of the UI library and into the store instead. (This pattern is also used internally in Svelte Tweakpane UI to manage draggable pane position defaults and persistence.)
Adding a defaultValue
prop to the Svelte Tweakpane UI components just seems tricky to me since value
is already a required prop, and, at least in my mental model, value
would immediately override anything set in a hypothetical defaultValue
. It might make more sense if the value
prop was optional, but that change would have some interesting and possibly more confusing consequences across the library.
Maybe that helps, or apologies if I'm still not completely getting it.
Closing this since I hope the example of managing defaults outside Svelte Tweakpane UI helps — but feel free to re-open if needed.
Hi.
I tried to add this in to a local fork, but the codebase is a bit too specialised for me to do it. Its pretty cool though, and I'm gonna try to study it more... nevertheless
I'd like to be able to specify starting, default values on at least a slider. It seems like they do have some kind of default, but I don't see where that is set.