diff --git a/CHANGELOG.md b/CHANGELOG.md index 8af9c096de..a3fb361e5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Svelte changelog +## Unreleased + +* Fix `$$props` and `$$restProps` when compiling to a custom element ([#5482](https://github.com/sveltejs/svelte/issues/5482)) +* Fix function calls in `` props that use contextual values ([#5565](https://github.com/sveltejs/svelte/issues/5565)) +* Fix handling aborted transitions in `{:else}` blocks ([#5573](https://github.com/sveltejs/svelte/issues/5573)) +* Add `Element` and `Node` to known globals ([#5586](https://github.com/sveltejs/svelte/issues/5586)) + ## 3.29.4 * Fix code generation error with `??` alongside logical operators ([#5558](https://github.com/sveltejs/svelte/issues/5558)) diff --git a/README.md b/README.md index 9fbada7aa3..d1befaf1ce 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ license - Chat + Chat

diff --git a/package-lock.json b/package-lock.json index 9da1189dcc..e04cc22175 100644 --- a/package-lock.json +++ b/package-lock.json @@ -144,8 +144,8 @@ } }, "@sveltejs/eslint-config": { - "version": "github:sveltejs/eslint-config#5d1ba28f99568e42f26d9b7484ab57720f6ec9b4", - "from": "github:sveltejs/eslint-config#v5.4.0", + "version": "github:sveltejs/eslint-config#54081d752d199dba97db9f578665c87f18469da3", + "from": "github:sveltejs/eslint-config#v5.5.0", "dev": true }, "@tootallnate/once": { diff --git a/package.json b/package.json index c2b15d50d0..a0f0b9e455 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@rollup/plugin-sucrase": "^3.0.0", "@rollup/plugin-typescript": "^2.0.1", "@rollup/plugin-virtual": "^2.0.0", - "@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.4.0", + "@sveltejs/eslint-config": "github:sveltejs/eslint-config#v5.5.0", "@types/mocha": "^7.0.0", "@types/node": "^8.10.53", "@typescript-eslint/eslint-plugin": "^3.0.2", diff --git a/site/content/blog/2020-11-01-whats-new-in-svelte-november-2020.md b/site/content/blog/2020-11-01-whats-new-in-svelte-november-2020.md new file mode 100644 index 0000000000..433bafaa29 --- /dev/null +++ b/site/content/blog/2020-11-01-whats-new-in-svelte-november-2020.md @@ -0,0 +1,46 @@ +--- +title: What's new in Svelte: November 2020 +description: Slot forwarding fixes, SvelteKit for faster local development, and more from Svelte Summit +author: Daniel Sandoval +authorURL: https://desandoval.net +--- + +Welcome back to the "What's new in Svelte" series! This month, we're covering new features & bug fixes, last month's Svelte Summit and some stand-out sites and libraries... + +## New features & impactful bug fixes + +1. Destructuring Promises now works as expected by using the `{#await}` syntax + (**3.29.3**, [Example](https://svelte.dev/repl/3fd4e2cecfa14d629961478f1dac2445?version=3.29.3)) +2. Slot forwarding (released in 3.29.0) should no longer hang during compilation (**3.29.3**, [Example](https://svelte.dev/repl/29959e70103f4868a6525c0734934936?version=3.29.3)) +3. Better typings for the `get` function in `svelte/store` and on lifecycle hooks (**3.29.1**) + +**What's going on in Sapper?** + +Sapper got some new types in its `preload` function, which will make typing easier if you are using TypeScript. See the [Sapper docs](https://sapper.svelte.dev/docs#Typing_the_function) on how to use them. There also were fixes to `preload` links in exported sites. Route layouts got a few fixes too - including ensuring CSS is applied to nested route layouts. You can also better organize your files now that extensions with multiple dots are supported. (**0.28.10**) + + +For all the features and bugfixes see the CHANGELOGs for [Svelte](https://github.com/sveltejs/svelte/blob/master/CHANGELOG.md) and [Sapper](https://github.com/sveltejs/sapper/blob/master/CHANGELOG.md). + + +## [Svelte Summit](https://sveltesummit.com/) was Svelte-tacular! +- Rich Harris demoed the possible future of Svelte development in a talk titled "Futuristic Web Development". The not-yet-public project is called SvelteKit (name may change) and will bring a first-class developer experience and more flexibility for build outputs. If you want to get the full sneak-peek, [check out the video](https://www.youtube.com/watch?v=qSfdtmcZ4d0). +- 17 speakers made the best of the conference's virtual format... From floating heads to seamless demos, Svelte developers from every skill level will find something of interest in this year's [YouTube playlist](https://www.youtube.com/playlist?list=PL8bMgX1kyZThM1sbYCoWdTcpiYysJsSeu) + +--- + +## Community Showcase +- [Svelte Lab](https://sveltelab.app/) showcases a variety of components, visualizations and interactions that can be achieved in Svelte. You can click into any component to see its source or edit it, using the site's built-in REPL +- [svelte-electron-boilerplate](https://github.com/hjalmar/svelte-electron-boilerplate) is a fast way to get up and running with a Svelte app built in the desktop javascript framework, Electron +- [React Hooks in Svelte](https://github.com/joshnuss/react-hooks-in-svelte) showcases examples of common React Hooks ported to Svelte. +- [gurlic](https://gurlic.com/) is a social network and internet experiment that is super snappy thanks to Svelte +- [Interference 2020](https://interference2020.org/) visualizes reported foreign interference in the 2020 U.S. elections. You can learn more about how it was built in [YYY's talk at Svelte Summit]() +- [jitsi-svelte](https://github.com/relm-us/jitsi-svelte) lets you easily create your own custom Jitsi client by providing out-of-the-box components built with Svelte +- [Ellx](https://ellx.io/) is part spreadsheet, part notebook and part IDE. It's super smooth thanks to Svelte 😎 +- [This New Zealand news site](https://www.nzherald.co.nz/nz/election-2020-latest-results-party-vote-electorate-vote-and-full-data/5CFVO4ENKNQDE3SICRRNPU5GZM/) breaks down the results of the 2020 Parliamentary elections using Svelte +- [Budibase](https://github.com/Budibase/budibase) is a no-code app builder, powered by Svelte +- [Svelt-yjs](https://github.com/relm-us/svelt-yjs) combines the collaborative, local-first technology of Yjs with the power of Svelte to enable multiple users across the internet to stay in sync. +- [tabler-icons-svelte](https://github.com/benflap/tabler-icons-svelte) is a Svelte wrapper for over 850 free MIT-licensed high-quality SVG icons for you to use in your web projects. + +## See you next month! + +Got an idea for something to add to the Showcase? Want to get involved more with Svelte? We're always looking for maintainers, contributors and fanatics... Check out the [Svelte Society](https://sveltesociety.dev/), [Reddit](https://www.reddit.com/r/sveltejs/) and [Discord](https://discord.com/invite/yy75DKs) to get involved! diff --git a/site/content/docs/02-template-syntax.md b/site/content/docs/02-template-syntax.md index d955f650e2..119488aacc 100644 --- a/site/content/docs/02-template-syntax.md +++ b/site/content/docs/02-template-syntax.md @@ -1317,6 +1317,31 @@ Named slots allow consumers to target specific areas. They can also have fallbac ``` +#### [`$$slots`](slots_object) + +--- + +`$$slots` is an object whose keys are the names of the slots passed into the component by the parent. If the parent does not pass in a slot with a particular name, that name will not be a present in `$$slots`. This allows components to render a slot (and other elements, like wrappers for styling) only if the parent provides it. + +Note that explicitly passing in an empty named slot will add that slot's name to `$$slots`. For example, if a parent passes `
` to a child component, `$$slots.title` will be truthy within the child. + +```sv + + +

Blog Post Title

+
+ + +
+ + {#if $$slots.description} + +
+ + {/if} +
+``` + #### [``](slot_let) --- diff --git a/site/content/examples/05-bindings/09-media-elements/App.svelte b/site/content/examples/05-bindings/09-media-elements/App.svelte index 7a071dbe49..45345a39ff 100644 --- a/site/content/examples/05-bindings/09-media-elements/App.svelte +++ b/site/content/examples/05-bindings/09-media-elements/App.svelte @@ -115,8 +115,9 @@ on:mousedown={handleMousedown} bind:currentTime={time} bind:duration - bind:paused - > + bind:paused> + +
diff --git a/site/content/tutorial/14-composition/04-optional-slots/app-a/App.svelte b/site/content/tutorial/14-composition/04-optional-slots/app-a/App.svelte new file mode 100755 index 0000000000..80a4df59f8 --- /dev/null +++ b/site/content/tutorial/14-composition/04-optional-slots/app-a/App.svelte @@ -0,0 +1,57 @@ + + + + +

+ Projects +

+ +
    +
  • + +
    + +

    Those interface tests are now passing.

    +
    +
    +
    +
  • +
  • + +
  • +
diff --git a/site/content/tutorial/14-composition/04-optional-slots/app-a/Comment.svelte b/site/content/tutorial/14-composition/04-optional-slots/app-a/Comment.svelte new file mode 100755 index 0000000000..8d15ffa882 --- /dev/null +++ b/site/content/tutorial/14-composition/04-optional-slots/app-a/Comment.svelte @@ -0,0 +1,56 @@ + + + + +
+
+ +
+

{name}

+ +
+
+
+ +
+
diff --git a/site/content/tutorial/14-composition/04-optional-slots/app-a/Project.svelte b/site/content/tutorial/14-composition/04-optional-slots/app-a/Project.svelte new file mode 100755 index 0000000000..38d19fc638 --- /dev/null +++ b/site/content/tutorial/14-composition/04-optional-slots/app-a/Project.svelte @@ -0,0 +1,62 @@ + + + + +
+
+

{title}

+

{tasksCompleted}/{totalTasks} tasks completed

+
+
+

Comments

+ +
+
diff --git a/site/content/tutorial/14-composition/04-optional-slots/app-b/App.svelte b/site/content/tutorial/14-composition/04-optional-slots/app-b/App.svelte new file mode 100755 index 0000000000..80a4df59f8 --- /dev/null +++ b/site/content/tutorial/14-composition/04-optional-slots/app-b/App.svelte @@ -0,0 +1,57 @@ + + + + +

+ Projects +

+ +
    +
  • + +
    + +

    Those interface tests are now passing.

    +
    +
    +
    +
  • +
  • + +
  • +
diff --git a/site/content/tutorial/14-composition/04-optional-slots/app-b/Comment.svelte b/site/content/tutorial/14-composition/04-optional-slots/app-b/Comment.svelte new file mode 100755 index 0000000000..8d15ffa882 --- /dev/null +++ b/site/content/tutorial/14-composition/04-optional-slots/app-b/Comment.svelte @@ -0,0 +1,56 @@ + + + + +
+
+ +
+

{name}

+ +
+
+
+ +
+
diff --git a/site/content/tutorial/14-composition/04-optional-slots/app-b/Project.svelte b/site/content/tutorial/14-composition/04-optional-slots/app-b/Project.svelte new file mode 100755 index 0000000000..87a1d0c3ac --- /dev/null +++ b/site/content/tutorial/14-composition/04-optional-slots/app-b/Project.svelte @@ -0,0 +1,64 @@ + + + + +
+
+

{title}

+

{tasksCompleted}/{totalTasks} tasks completed

+
+ {#if $$slots.comments} +
+

Comments

+ +
+ {/if} +
diff --git a/site/content/tutorial/14-composition/04-optional-slots/text.md b/site/content/tutorial/14-composition/04-optional-slots/text.md new file mode 100644 index 0000000000..b875f4c87d --- /dev/null +++ b/site/content/tutorial/14-composition/04-optional-slots/text.md @@ -0,0 +1,28 @@ +--- +title: Checking for slot content +--- + +In some cases, you may want to control parts of your component based on whether the parent passes in content for a certain slot. Perhaps you have a wrapper around that slot, and you don't want to render it if the slot is empty. Or perhaps you'd like to apply a class only if the slot is present. You can do this by checking the properties of the special `$$slots` variable. + +`$$slots` is an object whose keys are the names of the slots passed in by the parent component. If the parent leaves a slot empty, then `$$slots` will not have an entry for that slot. + +Notice that both instances of `` in this example render a container for comments and a notification dot, even though only one has comments. We want to use `$$slots` to make sure we only render these elements when the parent `` passes in content for the `comments` slot. + +In `Project.svelte`, update the `class:has-discussion` directive on the `
`: + +```html +
+``` + +Next, wrap the `comments` slot and its wrapping `
` in an `if` block that checks `$$slots`: + +```html +{#if $$slots.comments} +
+

Comments

+ +
+{/if} +``` + +Now the comments container and the notification dot won't render when `` leaves the `comments` slot empty. diff --git a/site/content/tutorial/14-composition/04-slot-props/app-a/App.svelte b/site/content/tutorial/14-composition/05-slot-props/app-a/App.svelte similarity index 100% rename from site/content/tutorial/14-composition/04-slot-props/app-a/App.svelte rename to site/content/tutorial/14-composition/05-slot-props/app-a/App.svelte diff --git a/site/content/tutorial/14-composition/04-slot-props/app-a/Hoverable.svelte b/site/content/tutorial/14-composition/05-slot-props/app-a/Hoverable.svelte similarity index 100% rename from site/content/tutorial/14-composition/04-slot-props/app-a/Hoverable.svelte rename to site/content/tutorial/14-composition/05-slot-props/app-a/Hoverable.svelte diff --git a/site/content/tutorial/14-composition/04-slot-props/app-b/App.svelte b/site/content/tutorial/14-composition/05-slot-props/app-b/App.svelte similarity index 100% rename from site/content/tutorial/14-composition/04-slot-props/app-b/App.svelte rename to site/content/tutorial/14-composition/05-slot-props/app-b/App.svelte diff --git a/site/content/tutorial/14-composition/04-slot-props/app-b/Hoverable.svelte b/site/content/tutorial/14-composition/05-slot-props/app-b/Hoverable.svelte similarity index 100% rename from site/content/tutorial/14-composition/04-slot-props/app-b/Hoverable.svelte rename to site/content/tutorial/14-composition/05-slot-props/app-b/Hoverable.svelte diff --git a/site/content/tutorial/14-composition/04-slot-props/text.md b/site/content/tutorial/14-composition/05-slot-props/text.md similarity index 100% rename from site/content/tutorial/14-composition/04-slot-props/text.md rename to site/content/tutorial/14-composition/05-slot-props/text.md diff --git a/src/compiler/compile/Component.ts b/src/compiler/compile/Component.ts index c16862165c..d2542c9830 100644 --- a/src/compiler/compile/Component.ts +++ b/src/compiler/compile/Component.ts @@ -521,8 +521,7 @@ export default class Component { if (this.hoistable_nodes.has(node)) return false; if (this.reactive_declaration_nodes.has(node)) return false; if (node.type === 'ImportDeclaration') return false; - if (node.type === 'ExportDeclaration' && node.specifiers.length > 0) - return false; + if (node.type === 'ExportDeclaration' && node.specifiers.length > 0) return false; return true; }); } @@ -1038,8 +1037,9 @@ export default class Component { this.vars.find( variable => variable.name === name && variable.module ) - ) + ) { return false; + } return true; }); @@ -1288,8 +1288,9 @@ export default class Component { declaration.dependencies.forEach(name => { if (declaration.assignees.has(name)) return; const earlier_declarations = lookup.get(name); - if (earlier_declarations) + if (earlier_declarations) { earlier_declarations.forEach(add_declaration); + } }); this.reactive_declarations.push(declaration); @@ -1319,8 +1320,9 @@ export default class Component { if (globals.has(name) && node.type !== 'InlineComponent') return; let message = `'${name}' is not defined`; - if (!this.ast.instance) + if (!this.ast.instance) { message += `. Consider adding a + +

name: {name}

+

$$props: {JSON.stringify($$props)}

+

$$restProps: {JSON.stringify($$restProps)}

+ diff --git a/test/custom-elements/samples/$$props/test.js b/test/custom-elements/samples/$$props/test.js new file mode 100644 index 0000000000..94cad86577 --- /dev/null +++ b/test/custom-elements/samples/$$props/test.js @@ -0,0 +1,13 @@ +import * as assert from 'assert'; +import './main.svelte'; + +export default function (target) { + target.innerHTML = ''; + const el = target.querySelector('custom-element'); + + assert.htmlEqual(el.shadowRoot.innerHTML, ` +

name: world

+

$$props: {"name":"world","answer":"42","test":"svelte"}

+

$$restProps: {"answer":"42","test":"svelte"}

+ `); +} diff --git a/test/hydration/index.ts b/test/hydration/index.ts index e50351c56e..2eefee3fac 100644 --- a/test/hydration/index.ts +++ b/test/hydration/index.ts @@ -118,9 +118,11 @@ describe('hydration', () => { throw err; } - if (config.show) showOutput(cwd, { - hydratable: true - }); + if (config.show) { + showOutput(cwd, { + hydratable: true + }); + } }); } diff --git a/test/js/samples/css-shadow-dom-keyframes/expected.js b/test/js/samples/css-shadow-dom-keyframes/expected.js index a0a0ebe021..82a39e5924 100644 --- a/test/js/samples/css-shadow-dom-keyframes/expected.js +++ b/test/js/samples/css-shadow-dom-keyframes/expected.js @@ -1,6 +1,7 @@ /* generated by Svelte vX.Y.Z */ import { SvelteElement, + attribute_to_object, detach, element, init, @@ -34,7 +35,18 @@ class Component extends SvelteElement { constructor(options) { super(); this.shadowRoot.innerHTML = ``; - init(this, { target: this.shadowRoot }, null, create_fragment, safe_not_equal, {}); + + init( + this, + { + target: this.shadowRoot, + props: attribute_to_object(this.attributes) + }, + null, + create_fragment, + safe_not_equal, + {} + ); if (options) { if (options.target) { diff --git a/test/runtime/samples/component-slot-context-props-each-nested/Nested.svelte b/test/runtime/samples/component-slot-context-props-each-nested/Nested.svelte new file mode 100644 index 0000000000..fab3ae1890 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-each-nested/Nested.svelte @@ -0,0 +1,14 @@ + + +{#each items as item (item)} + {#each keys as key (key)} + setKey(key, value, item)} /> + {/each} +{/each} \ No newline at end of file diff --git a/test/runtime/samples/component-slot-context-props-each-nested/_config.js b/test/runtime/samples/component-slot-context-props-each-nested/_config.js new file mode 100644 index 0000000000..869cc555b1 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-each-nested/_config.js @@ -0,0 +1,36 @@ +export default { + html: ` + + + + + `, + async test({ assert, target, window, component }) { + const [btn1, btn2, btn3, btn4] = target.querySelectorAll('button'); + const click = new window.MouseEvent('click'); + + await btn1.dispatchEvent(click); + assert.deepEqual(component.log, ['setKey(a, value-a-c, c)']); + + await btn2.dispatchEvent(click); + assert.deepEqual(component.log, [ + 'setKey(a, value-a-c, c)', + 'setKey(b, value-b-c, c)' + ]); + + await btn3.dispatchEvent(click); + assert.deepEqual(component.log, [ + 'setKey(a, value-a-c, c)', + 'setKey(b, value-b-c, c)', + 'setKey(a, value-a-d, d)' + ]); + + await btn4.dispatchEvent(click); + assert.deepEqual(component.log, [ + 'setKey(a, value-a-c, c)', + 'setKey(b, value-b-c, c)', + 'setKey(a, value-a-d, d)', + 'setKey(b, value-b-d, d)' + ]); + } +}; diff --git a/test/runtime/samples/component-slot-context-props-each-nested/main.svelte b/test/runtime/samples/component-slot-context-props-each-nested/main.svelte new file mode 100644 index 0000000000..7feb55aaf6 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-each-nested/main.svelte @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-context-props-each/Nested.svelte b/test/runtime/samples/component-slot-context-props-each/Nested.svelte new file mode 100644 index 0000000000..a29ffe0376 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-each/Nested.svelte @@ -0,0 +1,11 @@ + + +{#each keys as key (key)} + setKey(key, value)} /> +{/each} \ No newline at end of file diff --git a/test/runtime/samples/component-slot-context-props-each/_config.js b/test/runtime/samples/component-slot-context-props-each/_config.js new file mode 100644 index 0000000000..f374e7f827 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-each/_config.js @@ -0,0 +1,19 @@ +export default { + html: ` + + + `, + async test({ assert, target, window, component }) { + const [btn1, btn2] = target.querySelectorAll('button'); + const click = new window.MouseEvent('click'); + + await btn1.dispatchEvent(click); + assert.deepEqual(component.log, ['setKey(a, value-a)']); + + await btn2.dispatchEvent(click); + assert.deepEqual(component.log, [ + 'setKey(a, value-a)', + 'setKey(b, value-b)' + ]); + } +}; diff --git a/test/runtime/samples/component-slot-context-props-each/main.svelte b/test/runtime/samples/component-slot-context-props-each/main.svelte new file mode 100644 index 0000000000..7dc17b4c95 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-each/main.svelte @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-context-props-let/Inner.svelte b/test/runtime/samples/component-slot-context-props-let/Inner.svelte new file mode 100644 index 0000000000..6beaabbb68 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-let/Inner.svelte @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-context-props-let/Nested.svelte b/test/runtime/samples/component-slot-context-props-let/Nested.svelte new file mode 100644 index 0000000000..97c44c5145 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-let/Nested.svelte @@ -0,0 +1,8 @@ + + + + set(key, value)} /> + \ No newline at end of file diff --git a/test/runtime/samples/component-slot-context-props-let/_config.js b/test/runtime/samples/component-slot-context-props-let/_config.js new file mode 100644 index 0000000000..f374e7f827 --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-let/_config.js @@ -0,0 +1,19 @@ +export default { + html: ` + + + `, + async test({ assert, target, window, component }) { + const [btn1, btn2] = target.querySelectorAll('button'); + const click = new window.MouseEvent('click'); + + await btn1.dispatchEvent(click); + assert.deepEqual(component.log, ['setKey(a, value-a)']); + + await btn2.dispatchEvent(click); + assert.deepEqual(component.log, [ + 'setKey(a, value-a)', + 'setKey(b, value-b)' + ]); + } +}; diff --git a/test/runtime/samples/component-slot-context-props-let/main.svelte b/test/runtime/samples/component-slot-context-props-let/main.svelte new file mode 100644 index 0000000000..a061f73b3a --- /dev/null +++ b/test/runtime/samples/component-slot-context-props-let/main.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/test/runtime/samples/transition-abort/_config.js b/test/runtime/samples/transition-abort/_config.js new file mode 100644 index 0000000000..4f31c44a4d --- /dev/null +++ b/test/runtime/samples/transition-abort/_config.js @@ -0,0 +1,31 @@ +// expect aborting halfway through outro transition +// to behave the same in `{#if}` block as in `{:else}` block +export default { + html: ` +
a
+ +
a
+ `, + + async test({ assert, component, target, window, raf }) { + component.visible = false; + + // abort halfway through the outro transition + raf.tick(50); + + await component.$set({ + visible: true, + array: ['a', 'b', 'c'] + }); + + assert.htmlEqual(target.innerHTML, ` +
a
+
b
+
c
+ +
a
+
b
+
c
+ `); + } +}; diff --git a/test/runtime/samples/transition-abort/main.svelte b/test/runtime/samples/transition-abort/main.svelte new file mode 100644 index 0000000000..b574229712 --- /dev/null +++ b/test/runtime/samples/transition-abort/main.svelte @@ -0,0 +1,21 @@ + + +{#if visible} + {#each array as item} +
{item}
+ {/each} +{/if} + +{#if !visible} +{:else} + {#each array as item} +
{item}
+ {/each} +{/if} \ No newline at end of file