Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/grumpy-melons-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-object": patch
---

fix: missing values on existing object-value
9 changes: 9 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"python-envs.pythonProjects": [
{
"path": "svelte-object/stories/issues/infinite-recursion",
"envManager": "ms-python.python:venv",
"packageManager": "ms-python.python:pip"
}
]
}
562 changes: 285 additions & 277 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
"directory": "svelte-object/_package"
},
"dependencies": {
"svelte": "^5.35.0"
"svelte": "^5.35.2"
}
}
2 changes: 2 additions & 0 deletions svelte-object/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
"svelte": "^5"
},
"devDependencies": {
"@sveltejs/kit": "^2.46.5",
"@sveltejs/package": "^2",
"@sveltejs/vite-plugin-svelte": "^6.2.1",
"svelte": "^5",
"typescript": "^5"
},
Expand Down
28 changes: 11 additions & 17 deletions svelte-object/src/SvelteObject.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,8 @@

$effect.pre(() => {
for(const prescriptor of prescriptors) {
let debounced = false
let debouncer = () => {
if(debounced) return true
debounced = true
tick().then(() => debounced = false)
return false
}

$effect.pre(() => {
let itemValue = value?.[prescriptor.name]
// Prevent infinite recursion
if(debouncer()) return

let itemValue = value?.[prescriptor.name]
untrack(() => {
prescriptor.set(itemValue)
})
Expand All @@ -131,8 +120,6 @@
let itemValue = prescriptor.get()
prescriptor.name

// Always allow sending the value to the parent to sustain reactivity
debouncer()
untrack(() => {
value ??= {} as T
value[prescriptor.name] = itemValue
Expand All @@ -149,9 +136,16 @@
) {
const prescriptor = { name, get: getter, set: setter }

value ??= {} as T
value[prescriptor.name] = getter()

if(value) {
const current = value[name]
if(current === undefined || current === null) {
value[prescriptor.name] = getter()
}
else {
prescriptor.set(current)
}
}

prescriptors.push(prescriptor)
return () => {
prescriptors.splice(prescriptors.indexOf(prescriptor), 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<script module>
import { defineMeta } from '@storybook/addon-svelte-csf'
import Issue from './Issue.svelte'

const { Story } = defineMeta({})
</script>

<Story name='Reproduction'>
{#snippet template()}
<Issue />
{/snippet}
</Story>
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

<script lang='ts'>
import 'tailwindcss'
import I from '../../../src/index.svelte'
import { onMount } from 'svelte'

let value = $state({
value: 'example',
nested: {
value: 'nested example'
},
array: [
'value1',
'value2'
]
})

let show = $state(false)
onMount(() => {
setTimeout(() => show = true, 3000)
})

</script>
<!-- ---------------------------------------------- -->


<div class='p-4 border border-gray-300 rounded max-w-72 flex flex-col gap-4'>
<I.Object bind:value>
{#snippet children(object)}
{#if show}
<I.Value name='value'>
{#snippet children(value)}
<input class='border rounded px-4 py-2' bind:value={value.value} />
{/snippet}
</I.Value>
<I.Object name='nested'>
<I.Value name='value'>
{#snippet children(value)}
<input class='border rounded px-4 py-2' bind:value={value.value} />
{/snippet}
</I.Value>
</I.Object>
<I.Array name='array' value={[ 'value' ]}>
{#snippet children(array)}
{#each array.value as item, i (i)}
<input class='border rounded px-4 py-2' bind:value={array.value[i]} />
{/each}
<button
class='border px-2 py-2 bg-sky-500 hover:bg-sky-600 rounded text-white cursor-pointer'
onclick={() => array.value.push('')}
>
Add
</button>
{/snippet}
</I.Array>
<pre class='whitespace-pre-wrap'><code>{JSON.stringify(object.value, null, '\t')}</code></pre>
{/if}
{/snippet}

</I.Object>
</div>
<button
class='border px-2 py-2 bg-gray-500 hover:bg-gray-600 w-72 mt-4 rounded text-white cursor-pointer'
onclick={() => value = {value: '', array: [], nested: {value: ''}}}
>
Override value
</button>


<!-- ---------------------------------------------- -->
<style lang='postcss'>



</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
When a components (e.g. \<Value>) is rendered after `value` has been set,
they do not contain the values from `value`.

This causes unexpected missing data when toggling or lately adding components.
Original file line number Diff line number Diff line change
@@ -1,48 +1,12 @@
<script module>
import 'tailwindcss'
import { defineMeta } from '@storybook/addon-svelte-csf'

import I from '../../../src/index.svelte'
import Issue from './Issue.svelte'

const { Story } = defineMeta({})

let value = $state({})

</script>

<Story name='Reproduction'>
{#snippet template()}
<div class='p-4 border border-gray-300 rounded max-w-72 flex flex-col gap-4'>
<I.Object bind:value>
{#snippet children(object)}
<I.Value name='value'>
{#snippet children(value)}
<input class='border rounded px-4 py-2' bind:value={value.value} />
{/snippet}
</I.Value>
<I.Array name='array' value={[ 'value' ]}>
{#snippet children(array)}
{#each array.value as item, i (i)}
<input class='border rounded px-4 py-2' bind:value={array.value[i]} />
{/each}
<button
class='border px-2 py-2 bg-sky-500 hover:bg-sky-600 rounded text-white cursor-pointer'
onclick={() => array.value.push('')}
>
Add
</button>
{/snippet}
</I.Array>
<pre class='whitespace-pre-wrap'><code>{JSON.stringify(object.value, null, '\t')}</code></pre>
{/snippet}

</I.Object>
</div>
<button
class='border px-2 py-2 bg-gray-500 hover:bg-gray-600 w-72 mt-4 rounded text-white cursor-pointer'
onclick={() => value = { }}
>
Override value
</button>
<Issue />
{/snippet}
</Story>
51 changes: 51 additions & 0 deletions svelte-object/stories/issues/overriding-states/Issue.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@

<script lang='ts'>
import 'tailwindcss'
import I from '../../../src/index.svelte'

let value = $state({})

</script>
<!-- ---------------------------------------------- -->


<div class='p-4 border border-gray-300 rounded max-w-72 flex flex-col gap-4'>
<I.Object bind:value>
{#snippet children(object)}
<I.Value name='value'>
{#snippet children(value)}
<input class='border rounded px-4 py-2' bind:value={value.value} />
{/snippet}
</I.Value>
<I.Array name='array' value={[ 'value' ]}>
{#snippet children(array)}
{#each array.value as item, i (i)}
<input class='border rounded px-4 py-2' bind:value={array.value[i]} />
{/each}
<button
class='border px-2 py-2 bg-sky-500 hover:bg-sky-600 rounded text-white cursor-pointer'
onclick={() => array.value.push('')}
>
Add
</button>
{/snippet}
</I.Array>
<pre class='whitespace-pre-wrap'><code>{JSON.stringify(object.value, null, '\t')}</code></pre>
{/snippet}

</I.Object>
</div>
<button
class='border px-2 py-2 bg-gray-500 hover:bg-gray-600 w-72 mt-4 rounded text-white cursor-pointer'
onclick={() => value = { }}
>
Override value
</button>


<!-- ---------------------------------------------- -->
<style lang='postcss'>



</style>
5 changes: 4 additions & 1 deletion svelte-object/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"extends": "@refzlund/repo/tsconfig.base.json",
"extends": [
"@refzlund/repo/tsconfig.base.json",
"./.svelte-kit/tsconfig.json"
],
"exclude": ["_package", "svelte.config.js"],
"compilerOptions": {
"declaration": true,
Expand Down