mirror of https://github.com/sveltejs/svelte
commit
96c2eac523
@ -0,0 +1,224 @@
|
||||
---
|
||||
title: Introducing runes
|
||||
description: "Rethinking 'rethinking reactivity'"
|
||||
author: The Svelte team
|
||||
authorURL: /
|
||||
---
|
||||
|
||||
In 2019, Svelte 3 turned JavaScript into a [reactive language](/blog/svelte-3-rethinking-reactivity). Svelte is a web UI framework that uses a compiler to turn declarative component code like this...
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
let count = 0;
|
||||
|
||||
function increment() {
|
||||
count += 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={increment}>
|
||||
clicks: {count}
|
||||
</button>
|
||||
```
|
||||
|
||||
...into tightly optimized JavaScript that updates the document when state like `count` changes. Because the compiler can 'see' where `count` is referenced, the generated code is [highly efficient](/blog/virtual-dom-is-pure-overhead), and because we're hijacking syntax like `let` and `=` instead of using cumbersome APIs, you can [write less code](/blog/write-less-code).
|
||||
|
||||
A common piece of feedback we get is 'I wish I could write all my JavaScript like this'. When you're used to things inside components magically updating, going back to boring old procedural code feels like going from colour to black-and-white.
|
||||
|
||||
Svelte 5 changes all that with _runes_, which unlock _universal, fine-grained reactivity_.
|
||||
|
||||
<div class="max">
|
||||
<figure style="max-width: 960px; margin: 0 auto">
|
||||
<div style="aspect-ratio: 1.755; position: relative; margin: 0 auto;">
|
||||
<iframe style="position: absolute; width: 100%; height: 100%; left: 0; top: 0; margin: 0;" src="https://www.youtube-nocookie.com/embed/RVnxF3j3N8U" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<figcaption>Introducing runes</figcaption>
|
||||
</figure>
|
||||
</div>
|
||||
|
||||
## Before we begin
|
||||
|
||||
Even though we're changing how things work under the hood, Svelte 5 should be a drop-in replacement for almost everyone. The new features are opt-in — your existing components will continue to work.
|
||||
|
||||
We don't yet have a release date for Svelte 5. What we're showing you here is a work-in-progress that is likely to change!
|
||||
|
||||
## What are runes?
|
||||
|
||||
> **rune** /ro͞on/ _noun_
|
||||
>
|
||||
> A letter or mark used as a mystical or magic symbol.
|
||||
|
||||
Runes are symbols that influence the Svelte compiler. Whereas Svelte today uses `let`, `=`, the [`export`](https://learn.svelte.dev/tutorial/declaring-props) keyword and the [`$:`](https://learn.svelte.dev/tutorial/reactive-declarations) label to mean specific things, runes use _function syntax_ to achieve the same things and more.
|
||||
|
||||
For example, to declare a piece of reactive state, we can use the `$state` rune:
|
||||
|
||||
```diff
|
||||
<script>
|
||||
- let count = 0;
|
||||
+ let count = $state(0);
|
||||
|
||||
function increment() {
|
||||
count += 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<button on:click={increment}>
|
||||
clicks: {count}
|
||||
</button>
|
||||
```
|
||||
|
||||
At first glance, this might seem like a step back — perhaps even [un-Svelte-like](https://twitter.com/stolinski/status/1438173489479958536). Isn't it better if `let count` is reactive by default?
|
||||
|
||||
Well, no. The reality is that as applications grow in complexity, figuring out which values are reactive and which aren't can get tricky. And the heuristic only works for `let` declarations at the top level of a component, which can cause confusion. Having code behave one way inside `.svelte` files and another inside `.js` can make it hard to refactor code, for example if you need to turn something into a [store](https://learn.svelte.dev/tutorial/writable-stores) so that you can use it in multiple places.
|
||||
|
||||
## Beyond components
|
||||
|
||||
With runes, reactivity extends beyond the boundaries of your `.svelte` files. Suppose we wanted to encapsulate our counter logic in a way that could be reused between components. Today, you would use a [custom store](https://learn.svelte.dev/tutorial/custom-stores) in a `.js` or `.ts` file:
|
||||
|
||||
```js
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
export function createCounter() {
|
||||
const { subscribe, update } = writable(0);
|
||||
|
||||
return {
|
||||
subscribe,
|
||||
increment: () => update((n) => n + 1)
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Because this implements the _store contract_ — the returned value has a `subscribe` method — we can reference the store value by prefixing the store name with `$`:
|
||||
|
||||
```diff
|
||||
<script>
|
||||
+ import { createCounter } from './counter.js';
|
||||
+
|
||||
+ const counter = createCounter();
|
||||
- let count = 0;
|
||||
-
|
||||
- function increment() {
|
||||
- count += 1;
|
||||
- }
|
||||
</script>
|
||||
|
||||
-<button on:click={increment}>
|
||||
- clicks: {count}
|
||||
+<button on:click={counter.increment}>
|
||||
+ clicks: {$counter}
|
||||
</button>
|
||||
```
|
||||
|
||||
This works, but it's pretty weird! We've found that the store API can get rather unwieldy when you start doing more complex things.
|
||||
|
||||
With runes, things get much simpler:
|
||||
|
||||
```diff
|
||||
-import { writable } from 'svelte/store';
|
||||
|
||||
export function createCounter() {
|
||||
- const { subscribe, update } = writable(0);
|
||||
+ let count = $state(0);
|
||||
|
||||
return {
|
||||
- subscribe,
|
||||
- increment: () => update((n) => n + 1)
|
||||
+ get count() { return count },
|
||||
+ increment: () => count += 1
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
```diff
|
||||
<script>
|
||||
import { createCounter } from './counter.js';
|
||||
|
||||
const counter = createCounter();
|
||||
</script>
|
||||
|
||||
<button on:click={counter.increment}>
|
||||
- clicks: {$counter}
|
||||
+ clicks: {counter.count}
|
||||
</button>
|
||||
```
|
||||
|
||||
Note that we're using a [get property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) in the returned object, so that `counter.count` always refers to the current value rather than the value at the time the function was called.
|
||||
|
||||
## Runtime reactivity
|
||||
|
||||
Today, Svelte uses _compile-time reactivity_. This means that if you have some code that uses the `$:` label to re-run automatically when dependencies change, those dependencies are determined when Svelte compiles your component:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
export let width;
|
||||
export let height;
|
||||
|
||||
// the compiler knows it should recalculate `area`
|
||||
// when either `width` or `height` change...
|
||||
$: area = width * height;
|
||||
|
||||
// ...and that it should log the value of `area`
|
||||
// when _it_ changes
|
||||
$: console.log(area);
|
||||
</script>
|
||||
```
|
||||
|
||||
This works well... until it doesn't. Suppose we refactored the code above:
|
||||
|
||||
```js
|
||||
// @errors: 7006 2304
|
||||
const multiplyByHeight = (width) => width * height;
|
||||
$: area = multiplyByHeight(width);
|
||||
```
|
||||
|
||||
Because the `$: area = ...` declaration can only 'see' `width`, it won't be recalculated when `height` changes. As a result, code is hard to refactor, and understanding the intricacies of when Svelte chooses to update which values can become rather tricky beyond a certain level of complexity.
|
||||
|
||||
Svelte 5 introduces the `$derived` and `$effect` runes, which instead determine the dependencies of their expressions when they are evaluated:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
let { width, height } = $props(); // instead of `export let`
|
||||
|
||||
const area = $derived(width * height);
|
||||
|
||||
$effect(() => {
|
||||
console.log(area);
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
As with `$state`, `$derived` and `$effect` can also be used in your `.js` and `.ts` files.
|
||||
|
||||
## Signal boost
|
||||
|
||||
Like every other framework, we've come to the realisation that [Knockout](https://knockoutjs.com/) was right all along.
|
||||
|
||||
Svelte 5's reactivity is powered by _signals_, which are essentially [what Knockout was doing in 2010](https://dev.to/this-is-learning/the-evolution-of-signals-in-javascript-8ob). More recently, signals have been popularised by [Solid](https://www.solidjs.com/) and adopted by a multitude of other frameworks.
|
||||
|
||||
We're doing things a bit differently though. In Svelte 5, signals are an under-the-hood implementation detail rather than something you interact with directly. As such, we don't have the same API design constraints, and can maximise both efficiency _and_ ergonomics. For example, we avoid the type narrowing issues that arise when values are accessed by function call, and when compiling in server-side rendering mode we can ditch the signals altogether, since on the server they're nothing but overhead.
|
||||
|
||||
Signals unlock _fine-grained reactivity_, meaning that (for example) changes to a value inside a large list needn't invalidate all the _other_ members of the list. As such, Svelte 5 is ridonkulously fast.
|
||||
|
||||
## Simpler times ahead
|
||||
|
||||
Runes are an additive feature, but they make a whole bunch of existing concepts obsolete:
|
||||
|
||||
- the difference between `let` at the top level of a component and everywhere else
|
||||
- `export let`
|
||||
- `$:`, with all its attendant quirks
|
||||
- different behaviour between `<script>` and `<script context="module">`
|
||||
- the store API, parts of which are genuinely quite complicated
|
||||
- the `$` store prefix
|
||||
- `$$props` and `$$restProps`
|
||||
- lifecycle functions (things like `onMount` can just be `$effect` functions)
|
||||
|
||||
For those of you who already use Svelte, it's new stuff to learn, albeit hopefully stuff that makes your Svelte apps easier to build and maintain. But newcomers won't need to learn all those things — it'll just be in a section of the docs titled 'old stuff'.
|
||||
|
||||
This is just the beginning though. We have a long list of ideas for subsequent releases that will make Svelte simpler and more capable.
|
||||
|
||||
## Try it!
|
||||
|
||||
You can't use Svelte 5 in production yet. We're in the thick of it at the moment and can't tell you when it'll be ready to use in your apps.
|
||||
|
||||
But we didn't want to leave you hanging. We've created a [preview site](https://svelte-5-preview.vercel.app) with detailed explanations of the new features and an interactive playground. You can also visit the `#svelte-5-runes` channel of the [Svelte Discord](/chat) to learn more. We'd love to have your feedback!
|
||||
@ -0,0 +1,24 @@
|
||||
---
|
||||
title: "Hacktoberfest 2023 with SvelteKit"
|
||||
description: "SvelteKit joins in the Hacktoberfest event in 2023"
|
||||
author: Willow (GHOST) & Braden Wiggins
|
||||
authorURL: https://ghostdev.xyz
|
||||
---
|
||||
|
||||
# Sveltekit 🧡 Hacktoberfest
|
||||
|
||||
We're excited to announce SvelteKit's participation in this year's Hacktoberfest! Hacktoberfest is a global event that takes place every October, during which developers are encouraged to contribute to open-source projects like SvelteKit. The goal is to foster a vibrant open-source community, celebrate shared knowledge, and make the world of coding more accessible to all. You can find other participating repositories by searching the [`hacktoberfest` topic](https://github.com/topics/hacktoberfest) on github.
|
||||
|
||||
## Getting Started
|
||||
|
||||
The first step is to [register for Hacktoberfest](https://hacktoberfest.com/register). Once you've registered, any PRs submitted to Sveltekit will count towards your participation in the event!
|
||||
|
||||
## Contributing
|
||||
|
||||
If you need inspiration when looking for an issue to fix, check out the [low hanging fruit](https://github.com/sveltejs/kit/labels/low%20hanging%20fruit), [contributions-welcome](https://github.com/sveltejs/kit/labels/contributions-welcome), [ready to implement](https://github.com/sveltejs/kit/labels/ready%20to%20implement), or [documentation](https://github.com/sveltejs/kit/labels/documentation) tags.
|
||||
|
||||
It's a good idea to communicate clearly and often about what you're trying to solve or take on. You can do this by commenting on the issues you intend to take on. This helps avoid duplicate work and ensures that your contribution is in line with the project's goals. Nobody likes to have their work rejected, so it's best to ask questions early and often!
|
||||
|
||||
Join our [Discord](https://svelte.dev/chat) and ask questions in the dedicated `#hacktoberfest` channel. We're happy to help you get started!
|
||||
|
||||
We're excited to see what you've got in store for SvelteKit! Happy hacking! 🎃
|
||||
@ -0,0 +1,83 @@
|
||||
---
|
||||
title: "What's new in Svelte: October 2023"
|
||||
description: "Reactions to Runes and SvelteKit +server fallbacks"
|
||||
author: Dani Sandoval
|
||||
authorURL: https://dreamindani.com
|
||||
---
|
||||
|
||||
Svelte 5 isn't out yet (you can, however, [preview it now](https://svelte-5-preview.vercel.app/)), but that doesn't mean we don't get a sneak peek! Most notably are [Runes](https://svelte.dev/blog/runes) - a simpler way to manage reactive variables in Svelte code. There's lots of links the showcase section for deeper dives on all things Runes, but let's talk about what else been released this month...
|
||||
|
||||
## What's new in Svelte & Language Tools
|
||||
- [Svelte 4.2.1](https://github.com/sveltejs/svelte/blob/master/packages/svelte/CHANGELOG.md#421) was released with a bunch of fixes to HTML, CSS and sourcemap compilation
|
||||
- [The latest version of the Svelte language tools](https://github.com/sveltejs/language-tools/releases/tag/extensions-107.11.0) [enhances component references](https://github.com/sveltejs/language-tools/pull/2157) in the "Find All References" command, [fixes a persistent issue with automated types going missing](https://github.com/sveltejs/language-tools/pull/2160) after restarting a project and [adds fallback handling to auto-types](https://github.com/sveltejs/language-tools/issues/2156) (like those found in SvelteKit's `+server.js` files)
|
||||
|
||||
## What's new in SvelteKit
|
||||
- `+server.js` now has a catch-all handler that handles all unimplemented valid server requests. Just export a `fallback` function! (**1.25.0**, [Docs](https://kit.svelte.dev/docs/routing#server-fallback-method-handler), [#9755](https://github.com/sveltejs/kit/pull/9755))
|
||||
|
||||
That's all for the new features! If you're looking for other patches and performance updates, check out the [SvelteKit CHANGELOG](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md). You can also find adapter-specific CHANGELOGs in each of [the `adapter` directories](https://github.com/sveltejs/kit/tree/master/packages).
|
||||
|
||||
---
|
||||
|
||||
## Community Showcase
|
||||
|
||||
[Svelte Summit Fall](https://www.sveltesummit.com/) is happening on Nov 11, 2023. The 7th Virtual Svelte Conference is [open for proposals until October 15](https://sessionize.com/svelte-summit-fall-2023/) - anyone can submit!
|
||||
|
||||
Threlte [is throwing a hackathon](https://threlte.xyz/hackathon) (**motion warning for the landing page** - it will respect Reduce Motion settings). The kickoff event is on Sunday, 15 October 2023 16:00 UTC.
|
||||
|
||||
**Apps & Sites built with Svelte**
|
||||
- [game-of-life-svelte](https://github.com/StephenGunn/game-of-life-svelte) is a Conway's Game of Life implementation using SvelteKit tech
|
||||
- [Limey](https://limey.io/) is an easy-to-use website builder for simple sites and landing pages
|
||||
- [Appwrite's new landing page](https://appwrite.io/) is now written with SvelteKit (previously covered was their [console UI](https://github.com/appwrite/console) in Svelte)
|
||||
- [PlaceIt](https://github.com/Dae314/placeit-game) is a game about numbers and places
|
||||
- [Sveltroid](https://sveltroid.vercel.app/) is a fan-made recreation of Metroid Prime: Remastered ([code](https://github.com/TylerTonyJohnson/Metroid))
|
||||
- [Bolighub](https://www.bolighub.dk/) is a Denmark housing search portal
|
||||
- [Dithering](https://www.sigrist.dev/dithering) is a tool to dither photos with plenty of options
|
||||
- [Rocky Mountain Slam](https://www.rockymountainslam.com/) is an interactive map to follow Jason Heyn as he attempts to complete the first ever Rocky Mountain Slam ([code](https://github.com/martyheyn/rocky-mnt-slam))
|
||||
|
||||
|
||||
**Learning Resources**
|
||||
|
||||
_Featuring Svelte Contributors and Ambassadors_
|
||||
- [Svelte 5: Introducing Runes... with Rich Harris](https://www.youtube.com/watch?v=RVnxF3j3N8U) and its follow-up: [Svelte 5 runes: what's the deal with getters and setters?](https://www.youtube.com/watch?v=NR8L5m73dtE)
|
||||
- [Conditionally stream data in SvelteKit](https://geoffrich.net/posts/conditionally-stream-data/) by Geoff Rich
|
||||
- [Svelte Runes Change How Reactivity Works In Svelte](https://www.youtube.com/watch?v=TOTUXiYZhf4), [Make A 3D GitHub Skyline With Svelte To Flex On Your Peers](https://www.youtube.com/watch?v=f9fd1L1FEts), [Simple Page Transitions Using The View Transitions API With SvelteKit](https://www.youtube.com/watch?v=q_2irZO4SS8) and [Using JavaScript Libraries With Svelte Is Easy](https://www.youtube.com/watch?v=N9OjaQ0XtKQ) by Joy of Code
|
||||
- [Modern Web Podcast S11E2](https://modernweb.podbean.com/e/modern-web-podcast-s11e2-exploring-svelte-open-source-and-discord-bots-with-willow-ghost/) - Exploring Svelte, Open Source, and Discord Bots with Willow (GHOST)
|
||||
- [We are back! Svelte 5, Transitions, What's New?!](https://www.svelteradio.com/episodes/we-are-back-svelte-5-transitions-whats-new) by Svelte Radio
|
||||
- This Week in Svelte:
|
||||
- [2023 September 1](https://www.youtube.com/watch?v=fonBnVCIrjE) - SvelteKit 1.24.0, View Transitions API, AbortController
|
||||
- [2023 September 8](https://www.youtube.com/watch?v=jfBjmczZwRc) - SvelteKit 1.24.1, Capacitor walkthrough, reusing prop types
|
||||
- [2023 September 15](https://www.youtube.com/watch?v=qH2FavwhU88) - SvelteKit 1.25.0, deserialize form data, magic is coming
|
||||
- [2023 September 22](https://www.youtube.com/watch?v=ek7KE1EDu2w) - Svelte 5 Runes!
|
||||
|
||||
|
||||
_To Watch_
|
||||
- [RUNES - Coming in Svelte v5 | My Take](https://www.youtube.com/watch?v=iCK1coch1wA) by Coding Garden
|
||||
- [Don't Sleep on Svelte 5](https://www.youtube.com/watch?v=DgNWssn2vpc) and [Level Up Your Svelte Stores](https://www.youtube.com/watch?v=-vjNAyL2JCQ) by Huntabyte
|
||||
- [Introduction To Svelte Runes (Every Svelte Rune Explained)](https://www.youtube.com/watch?v=gihSBVfyFbI) by Cooper Codes
|
||||
- [Svelte Runes: Awesome or Awful?](https://www.youtube.com/watch?v=JRZCqUOmFwY) by Jack Herrington
|
||||
- [Let Build A Youtube Clone With SvelteKit (Svelte, Tailwind Css, RapidApi, Shadcn Svelte, Axios, etc)](https://www.youtube.com/watch?v=65yMfpsoH4o) by Lawal Adebola
|
||||
|
||||
|
||||
_To Read_
|
||||
- [Create the Perfect Sharable Rune in Svelte](https://dev.to/jdgamble555/create-the-perfect-sharable-rune-in-svelte-ij8) by Jonathan Gamble
|
||||
- [You Don't Need to "Learn" Svelte](https://kaviisuri.com/you-dont-need-to-learn-svelte) by KaviiSuri
|
||||
- [Build Websites with Prismic and SvelteKit](https://prismic.io/blog/sveltekit-prismic-integration) by Angelo Ashmore
|
||||
- [How to embed Svelte apps inside PHP?](https://www.okupter.com/blog/php-embed-svelte) by Justin Ahinon
|
||||
- [Using Web Browser's Indexed DB in SvelteKit](https://dev.to/theether0/using-web-browsers-indexed-db-in-sveltekit-3oo3) by Shivam Meena
|
||||
- [Integrate Storybook in Svelte: Doing it the Svelte-way](https://mainmatter.com/blog/2023/09/18/integrate-storybook-in-svelte-doing-it-the-svelte-way/) by Oscar Dominguez
|
||||
- [The Sveltekit tutorial: Part 1 | What, why, and how?](https://tntman.tech/posts/sveltekit-guide-part-1) by Suyashtnt
|
||||
|
||||
|
||||
**Libraries, Tools & Components**
|
||||
- [KitForStartups](https://github.com/okupter/kitforstartups) is an Open Source SvelteKit SaaS boilerplate
|
||||
- [SuperNavigation](https://github.com/0xDjole/super-navigation) is a mobile-like navigation UX for the web
|
||||
- [skeleton-material-theme](https://github.com/plasmatech8/skeleton-material-theme) is a Material theme for the Skeleton UI library
|
||||
- [better-i18n-for-svelte](https://github.com/versiobit/better-i18n-for-svelte) is a SEO focused library for multi-language SvelteKit sites
|
||||
- [uico](https://github.com/rossrobino/uico) is a Tailwind plugin that provides utility classes for basic UI elements
|
||||
- [svelte-maskify](https://www.npmjs.com/package/svelte-maskify) is a action wrapper for AlpineJS masks
|
||||
- [sveltekit-capacitor](https://github.com/Hugos68/sveltekit-capacitor) is a template for building a SvelteKit SPA with Capacitor
|
||||
- [router-gen.ts](https://gist.github.com/HugeLetters/7a2813897dfe08fa948a13cac8a359c7) is a type-safe router for SvelteKit
|
||||
|
||||
That's it for this month! Feel free to let us know if we missed anything on [Reddit](https://www.reddit.com/r/sveltejs/) or [Discord](https://discord.gg/svelte).
|
||||
|
||||
Until next time 👋
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": ["lube"],
|
||||
"rules": {
|
||||
"lube/svelte-naming-convention": ["error", { "fixSameNames": true }]
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": ["lube"],
|
||||
"rules": {
|
||||
"lube/svelte-naming-convention": ["error", { "fixSameNames": true }]
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,252 @@
|
||||
/// <reference lib="dom" />
|
||||
// This file is deliberately not exposed through the exports map.
|
||||
// It's meant to be loaded directly by the Svelte language server
|
||||
/* eslint-disable @typescript-eslint/no-empty-interface */
|
||||
|
||||
import * as svelteElements from './elements.js';
|
||||
|
||||
/**
|
||||
* @internal do not use
|
||||
*/
|
||||
type HTMLProps<Property extends string, Override> = Omit<
|
||||
import('./elements.js').SvelteHTMLElements[Property],
|
||||
keyof Override
|
||||
> &
|
||||
Override;
|
||||
|
||||
declare global {
|
||||
/**
|
||||
* This namespace does not exist in the runtime, it is only used for typings
|
||||
*/
|
||||
namespace svelteHTML {
|
||||
// Every namespace eligible for use needs to implement the following two functions
|
||||
/**
|
||||
* @internal do not use
|
||||
*/
|
||||
function mapElementTag<K extends keyof ElementTagNameMap>(tag: K): ElementTagNameMap[K];
|
||||
function mapElementTag<K extends keyof SVGElementTagNameMap>(tag: K): SVGElementTagNameMap[K];
|
||||
function mapElementTag(tag: any): any; // needs to be any because used in context of <svelte:element>
|
||||
|
||||
/**
|
||||
* @internal do not use
|
||||
*/
|
||||
function createElement<Elements extends IntrinsicElements, Key extends keyof Elements>(
|
||||
// "undefined | null" because of <svelte:element>
|
||||
element: Key | undefined | null,
|
||||
attrs: string extends Key ? svelteElements.HTMLAttributes<any> : Elements[Key]
|
||||
): Key extends keyof ElementTagNameMap
|
||||
? ElementTagNameMap[Key]
|
||||
: Key extends keyof SVGElementTagNameMap
|
||||
? SVGElementTagNameMap[Key]
|
||||
: any;
|
||||
function createElement<Elements extends IntrinsicElements, Key extends keyof Elements, T>(
|
||||
// "undefined | null" because of <svelte:element>
|
||||
element: Key | undefined | null,
|
||||
attrsEnhancers: T,
|
||||
attrs: (string extends Key ? svelteElements.HTMLAttributes<any> : Elements[Key]) & T
|
||||
): Key extends keyof ElementTagNameMap
|
||||
? ElementTagNameMap[Key]
|
||||
: Key extends keyof SVGElementTagNameMap
|
||||
? SVGElementTagNameMap[Key]
|
||||
: any;
|
||||
|
||||
// For backwards-compatibility and ease-of-use, in case someone enhanced the typings from import('svelte/elements').HTMLAttributes/SVGAttributes
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface HTMLAttributes<T extends EventTarget = any> {}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
interface SVGAttributes<T extends EventTarget = any> {}
|
||||
|
||||
/**
|
||||
* Avoid using this interface directly. Instead use the `SvelteHTMLElements` interface exported by `svelte/elements`
|
||||
* This should only be used if you need to extend the interface with custom elements
|
||||
*/
|
||||
interface IntrinsicElements extends svelteElements.SvelteHTMLElements {
|
||||
a: HTMLProps<'a', HTMLAttributes>;
|
||||
abbr: HTMLProps<'abbr', HTMLAttributes>;
|
||||
address: HTMLProps<'address', HTMLAttributes>;
|
||||
area: HTMLProps<'area', HTMLAttributes>;
|
||||
article: HTMLProps<'article', HTMLAttributes>;
|
||||
aside: HTMLProps<'aside', HTMLAttributes>;
|
||||
audio: HTMLProps<'audio', HTMLAttributes>;
|
||||
b: HTMLProps<'b', HTMLAttributes>;
|
||||
base: HTMLProps<'base', HTMLAttributes>;
|
||||
bdi: HTMLProps<'bdi', HTMLAttributes>;
|
||||
bdo: HTMLProps<'bdo', HTMLAttributes>;
|
||||
big: HTMLProps<'big', HTMLAttributes>;
|
||||
blockquote: HTMLProps<'blockquote', HTMLAttributes>;
|
||||
body: HTMLProps<'body', HTMLAttributes>;
|
||||
br: HTMLProps<'br', HTMLAttributes>;
|
||||
button: HTMLProps<'button', HTMLAttributes>;
|
||||
canvas: HTMLProps<'canvas', HTMLAttributes>;
|
||||
caption: HTMLProps<'caption', HTMLAttributes>;
|
||||
cite: HTMLProps<'cite', HTMLAttributes>;
|
||||
code: HTMLProps<'code', HTMLAttributes>;
|
||||
col: HTMLProps<'col', HTMLAttributes>;
|
||||
colgroup: HTMLProps<'colgroup', HTMLAttributes>;
|
||||
data: HTMLProps<'data', HTMLAttributes>;
|
||||
datalist: HTMLProps<'datalist', HTMLAttributes>;
|
||||
dd: HTMLProps<'dd', HTMLAttributes>;
|
||||
del: HTMLProps<'del', HTMLAttributes>;
|
||||
details: HTMLProps<'details', HTMLAttributes>;
|
||||
dfn: HTMLProps<'dfn', HTMLAttributes>;
|
||||
dialog: HTMLProps<'dialog', HTMLAttributes>;
|
||||
div: HTMLProps<'div', HTMLAttributes>;
|
||||
dl: HTMLProps<'dl', HTMLAttributes>;
|
||||
dt: HTMLProps<'dt', HTMLAttributes>;
|
||||
em: HTMLProps<'em', HTMLAttributes>;
|
||||
embed: HTMLProps<'embed', HTMLAttributes>;
|
||||
fieldset: HTMLProps<'fieldset', HTMLAttributes>;
|
||||
figcaption: HTMLProps<'figcaption', HTMLAttributes>;
|
||||
figure: HTMLProps<'figure', HTMLAttributes>;
|
||||
footer: HTMLProps<'footer', HTMLAttributes>;
|
||||
form: HTMLProps<'form', HTMLAttributes>;
|
||||
h1: HTMLProps<'h1', HTMLAttributes>;
|
||||
h2: HTMLProps<'h2', HTMLAttributes>;
|
||||
h3: HTMLProps<'h3', HTMLAttributes>;
|
||||
h4: HTMLProps<'h4', HTMLAttributes>;
|
||||
h5: HTMLProps<'h5', HTMLAttributes>;
|
||||
h6: HTMLProps<'h6', HTMLAttributes>;
|
||||
head: HTMLProps<'head', HTMLAttributes>;
|
||||
header: HTMLProps<'header', HTMLAttributes>;
|
||||
hgroup: HTMLProps<'hgroup', HTMLAttributes>;
|
||||
hr: HTMLProps<'hr', HTMLAttributes>;
|
||||
html: HTMLProps<'html', HTMLAttributes>;
|
||||
i: HTMLProps<'i', HTMLAttributes>;
|
||||
iframe: HTMLProps<'iframe', HTMLAttributes>;
|
||||
img: HTMLProps<'img', HTMLAttributes>;
|
||||
input: HTMLProps<'input', HTMLAttributes>;
|
||||
ins: HTMLProps<'ins', HTMLAttributes>;
|
||||
kbd: HTMLProps<'kbd', HTMLAttributes>;
|
||||
keygen: HTMLProps<'keygen', HTMLAttributes>;
|
||||
label: HTMLProps<'label', HTMLAttributes>;
|
||||
legend: HTMLProps<'legend', HTMLAttributes>;
|
||||
li: HTMLProps<'li', HTMLAttributes>;
|
||||
link: HTMLProps<'link', HTMLAttributes>;
|
||||
main: HTMLProps<'main', HTMLAttributes>;
|
||||
map: HTMLProps<'map', HTMLAttributes>;
|
||||
mark: HTMLProps<'mark', HTMLAttributes>;
|
||||
menu: HTMLProps<'menu', HTMLAttributes>;
|
||||
menuitem: HTMLProps<'menuitem', HTMLAttributes>;
|
||||
meta: HTMLProps<'meta', HTMLAttributes>;
|
||||
meter: HTMLProps<'meter', HTMLAttributes>;
|
||||
nav: HTMLProps<'nav', HTMLAttributes>;
|
||||
noscript: HTMLProps<'noscript', HTMLAttributes>;
|
||||
object: HTMLProps<'object', HTMLAttributes>;
|
||||
ol: HTMLProps<'ol', HTMLAttributes>;
|
||||
optgroup: HTMLProps<'optgroup', HTMLAttributes>;
|
||||
option: HTMLProps<'option', HTMLAttributes>;
|
||||
output: HTMLProps<'output', HTMLAttributes>;
|
||||
p: HTMLProps<'p', HTMLAttributes>;
|
||||
param: HTMLProps<'param', HTMLAttributes>;
|
||||
picture: HTMLProps<'picture', HTMLAttributes>;
|
||||
pre: HTMLProps<'pre', HTMLAttributes>;
|
||||
progress: HTMLProps<'progress', HTMLAttributes>;
|
||||
q: HTMLProps<'q', HTMLAttributes>;
|
||||
rp: HTMLProps<'rp', HTMLAttributes>;
|
||||
rt: HTMLProps<'rt', HTMLAttributes>;
|
||||
ruby: HTMLProps<'ruby', HTMLAttributes>;
|
||||
s: HTMLProps<'s', HTMLAttributes>;
|
||||
samp: HTMLProps<'samp', HTMLAttributes>;
|
||||
slot: HTMLProps<'slot', HTMLAttributes>;
|
||||
script: HTMLProps<'script', HTMLAttributes>;
|
||||
section: HTMLProps<'section', HTMLAttributes>;
|
||||
select: HTMLProps<'select', HTMLAttributes>;
|
||||
small: HTMLProps<'small', HTMLAttributes>;
|
||||
source: HTMLProps<'source', HTMLAttributes>;
|
||||
span: HTMLProps<'span', HTMLAttributes>;
|
||||
strong: HTMLProps<'strong', HTMLAttributes>;
|
||||
style: HTMLProps<'style', HTMLAttributes>;
|
||||
sub: HTMLProps<'sub', HTMLAttributes>;
|
||||
summary: HTMLProps<'summary', HTMLAttributes>;
|
||||
sup: HTMLProps<'sup', HTMLAttributes>;
|
||||
table: HTMLProps<'table', HTMLAttributes>;
|
||||
template: HTMLProps<'template', HTMLAttributes>;
|
||||
tbody: HTMLProps<'tbody', HTMLAttributes>;
|
||||
td: HTMLProps<'td', HTMLAttributes>;
|
||||
textarea: HTMLProps<'textarea', HTMLAttributes>;
|
||||
tfoot: HTMLProps<'tfoot', HTMLAttributes>;
|
||||
th: HTMLProps<'th', HTMLAttributes>;
|
||||
thead: HTMLProps<'thead', HTMLAttributes>;
|
||||
time: HTMLProps<'time', HTMLAttributes>;
|
||||
title: HTMLProps<'title', HTMLAttributes>;
|
||||
tr: HTMLProps<'tr', HTMLAttributes>;
|
||||
track: HTMLProps<'track', HTMLAttributes>;
|
||||
u: HTMLProps<'u', HTMLAttributes>;
|
||||
ul: HTMLProps<'ul', HTMLAttributes>;
|
||||
var: HTMLProps<'var', HTMLAttributes>;
|
||||
video: HTMLProps<'video', HTMLAttributes>;
|
||||
wbr: HTMLProps<'wbr', HTMLAttributes>;
|
||||
webview: HTMLProps<'webview', HTMLAttributes>;
|
||||
// SVG
|
||||
svg: HTMLProps<'svg', SVGAttributes>;
|
||||
|
||||
animate: HTMLProps<'animate', SVGAttributes>;
|
||||
animateMotion: HTMLProps<'animateMotion', SVGAttributes>;
|
||||
animateTransform: HTMLProps<'animateTransform', SVGAttributes>;
|
||||
circle: HTMLProps<'circle', SVGAttributes>;
|
||||
clipPath: HTMLProps<'clipPath', SVGAttributes>;
|
||||
defs: HTMLProps<'defs', SVGAttributes>;
|
||||
desc: HTMLProps<'desc', SVGAttributes>;
|
||||
ellipse: HTMLProps<'ellipse', SVGAttributes>;
|
||||
feBlend: HTMLProps<'feBlend', SVGAttributes>;
|
||||
feColorMatrix: HTMLProps<'feColorMatrix', SVGAttributes>;
|
||||
feComponentTransfer: HTMLProps<'feComponentTransfer', SVGAttributes>;
|
||||
feComposite: HTMLProps<'feComposite', SVGAttributes>;
|
||||
feConvolveMatrix: HTMLProps<'feConvolveMatrix', SVGAttributes>;
|
||||
feDiffuseLighting: HTMLProps<'feDiffuseLighting', SVGAttributes>;
|
||||
feDisplacementMap: HTMLProps<'feDisplacementMap', SVGAttributes>;
|
||||
feDistantLight: HTMLProps<'feDistantLight', SVGAttributes>;
|
||||
feDropShadow: HTMLProps<'feDropShadow', SVGAttributes>;
|
||||
feFlood: HTMLProps<'feFlood', SVGAttributes>;
|
||||
feFuncA: HTMLProps<'feFuncA', SVGAttributes>;
|
||||
feFuncB: HTMLProps<'feFuncB', SVGAttributes>;
|
||||
feFuncG: HTMLProps<'feFuncG', SVGAttributes>;
|
||||
feFuncR: HTMLProps<'feFuncR', SVGAttributes>;
|
||||
feGaussianBlur: HTMLProps<'feGaussianBlur', SVGAttributes>;
|
||||
feImage: HTMLProps<'feImage', SVGAttributes>;
|
||||
feMerge: HTMLProps<'feMerge', SVGAttributes>;
|
||||
feMergeNode: HTMLProps<'feMergeNode', SVGAttributes>;
|
||||
feMorphology: HTMLProps<'feMorphology', SVGAttributes>;
|
||||
feOffset: HTMLProps<'feOffset', SVGAttributes>;
|
||||
fePointLight: HTMLProps<'fePointLight', SVGAttributes>;
|
||||
feSpecularLighting: HTMLProps<'feSpecularLighting', SVGAttributes>;
|
||||
feSpotLight: HTMLProps<'feSpotLight', SVGAttributes>;
|
||||
feTile: HTMLProps<'feTile', SVGAttributes>;
|
||||
feTurbulence: HTMLProps<'feTurbulence', SVGAttributes>;
|
||||
filter: HTMLProps<'filter', SVGAttributes>;
|
||||
foreignObject: HTMLProps<'foreignObject', SVGAttributes>;
|
||||
g: HTMLProps<'g', SVGAttributes>;
|
||||
image: HTMLProps<'image', SVGAttributes>;
|
||||
line: HTMLProps<'line', SVGAttributes>;
|
||||
linearGradient: HTMLProps<'linearGradient', SVGAttributes>;
|
||||
marker: HTMLProps<'marker', SVGAttributes>;
|
||||
mask: HTMLProps<'mask', SVGAttributes>;
|
||||
metadata: HTMLProps<'metadata', SVGAttributes>;
|
||||
mpath: HTMLProps<'mpath', SVGAttributes>;
|
||||
path: HTMLProps<'path', SVGAttributes>;
|
||||
pattern: HTMLProps<'pattern', SVGAttributes>;
|
||||
polygon: HTMLProps<'polygon', SVGAttributes>;
|
||||
polyline: HTMLProps<'polyline', SVGAttributes>;
|
||||
radialGradient: HTMLProps<'radialGradient', SVGAttributes>;
|
||||
rect: HTMLProps<'rect', SVGAttributes>;
|
||||
stop: HTMLProps<'stop', SVGAttributes>;
|
||||
switch: HTMLProps<'switch', SVGAttributes>;
|
||||
symbol: HTMLProps<'symbol', SVGAttributes>;
|
||||
text: HTMLProps<'text', SVGAttributes>;
|
||||
textPath: HTMLProps<'textPath', SVGAttributes>;
|
||||
tspan: HTMLProps<'tspan', SVGAttributes>;
|
||||
use: HTMLProps<'use', SVGAttributes>;
|
||||
view: HTMLProps<'view', SVGAttributes>;
|
||||
|
||||
// Svelte specific
|
||||
'svelte:window': HTMLProps<'svelte:window', HTMLAttributes>;
|
||||
'svelte:body': HTMLProps<'svelte:body', HTMLAttributes>;
|
||||
'svelte:document': HTMLProps<'svelte:document', HTMLAttributes>;
|
||||
'svelte:fragment': { slot?: string };
|
||||
'svelte:options': HTMLProps<'svelte:options', HTMLAttributes>;
|
||||
'svelte:head': { [name: string]: any };
|
||||
|
||||
[name: string]: { [name: string]: any };
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
{
|
||||
"plugins": ["lube"],
|
||||
"rules": {
|
||||
"no-console": "off",
|
||||
"@typescript-eslint/no-var-requires": "off"
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"lube/svelte-naming-convention": ["error", { "fixSameNames": true }]
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
<svelte:options
|
||||
customElement={{
|
||||
tag: 'custom-element',
|
||||
props: {
|
||||
expanded: { reflect: true, type: 'Boolean', attribute: 'aria-expanded' }
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
<script>
|
||||
export let expanded = false;
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<button on:click={() => (expanded = !expanded)}>Toggle</button>
|
||||
<div class:hidden={!expanded}>Hidden Text</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,19 @@
|
||||
import * as assert from 'assert.js';
|
||||
import { tick } from 'svelte';
|
||||
import './main.svelte';
|
||||
|
||||
export default async function (target) {
|
||||
const element = document.createElement('custom-element');
|
||||
target.appendChild(element);
|
||||
await tick();
|
||||
|
||||
const el = target.querySelector('custom-element');
|
||||
el.shadowRoot.querySelector('button').click();
|
||||
await tick();
|
||||
|
||||
assert.equal(el.getAttribute('aria-expanded'), '');
|
||||
el.shadowRoot.querySelector('button').click();
|
||||
await tick();
|
||||
|
||||
assert.equal(el.getAttribute('aria-expanded'), null);
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
export default {
|
||||
skip_if_ssr: true,
|
||||
skip_if_hydrate: true,
|
||||
html: `
|
||||
<my-custom-element>Hello World!</my-custom-element>
|
||||
`
|
||||
};
|
||||
@ -0,0 +1,25 @@
|
||||
<script>
|
||||
class MyCustomElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this._obj = null;
|
||||
}
|
||||
|
||||
set camelCase(obj) {
|
||||
this._obj = obj;
|
||||
this.render();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.render();
|
||||
}
|
||||
|
||||
render() {
|
||||
this.innerHTML = 'Hello ' + this._obj.text + '!';
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('my-custom-element', MyCustomElement);
|
||||
</script>
|
||||
|
||||
<my-custom-element camelCase={{ text: 'World' }} />
|
||||
@ -0,0 +1,7 @@
|
||||
export default {
|
||||
skip_if_ssr: true,
|
||||
skip_if_hydrate: true,
|
||||
html: `
|
||||
<my-custom-inheritance-element>Hello World!</my-custom-inheritance-element>
|
||||
`
|
||||
};
|
||||
@ -0,0 +1,33 @@
|
||||
<script>
|
||||
class MyCustomElement extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this._obj = null;
|
||||
this._text = null;
|
||||
}
|
||||
|
||||
set text(text) {
|
||||
this._text = text;
|
||||
this.render();
|
||||
}
|
||||
|
||||
set camelCase(obj) {
|
||||
this._obj = obj;
|
||||
this.render();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.render();
|
||||
}
|
||||
|
||||
render() {
|
||||
this.innerHTML = 'Hello ' + this._obj.text + this._text;
|
||||
}
|
||||
}
|
||||
|
||||
class Extended extends MyCustomElement {}
|
||||
|
||||
window.customElements.define('my-custom-inheritance-element', Extended);
|
||||
</script>
|
||||
|
||||
<my-custom-inheritance-element camelCase={{ text: 'World' }} text="!" />
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue