diff --git a/site/content/tutorial/15-context/01-context-api/app-a/App.svelte b/site/content/tutorial/15-context/01-context-api/app-a/App.svelte
new file mode 100644
index 0000000000..ea1ba4c7ae
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/app-a/App.svelte
@@ -0,0 +1,13 @@
+
+
+
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/01-context-api/app-a/Map.svelte b/site/content/tutorial/15-context/01-context-api/app-a/Map.svelte
new file mode 100644
index 0000000000..888f42da39
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/app-a/Map.svelte
@@ -0,0 +1,48 @@
+
+
+
+
+
+ {#if map}
+
+ {/if}
+
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/01-context-api/app-a/MapMarker.svelte b/site/content/tutorial/15-context/01-context-api/app-a/MapMarker.svelte
new file mode 100644
index 0000000000..9bebce66e4
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/app-a/MapMarker.svelte
@@ -0,0 +1,17 @@
+
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/01-context-api/app-a/mapbox.js b/site/content/tutorial/15-context/01-context-api/app-a/mapbox.js
new file mode 100644
index 0000000000..55b4200038
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/app-a/mapbox.js
@@ -0,0 +1,8 @@
+import mapbox from 'mapbox-gl';
+
+// https://docs.mapbox.com/help/glossary/access-token/
+mapbox.accessToken = MAPBOX_ACCESS_TOKEN;
+
+const key = {};
+
+export { mapbox, key };
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/01-context-api/app-b/App.svelte b/site/content/tutorial/15-context/01-context-api/app-b/App.svelte
new file mode 100644
index 0000000000..ea1ba4c7ae
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/app-b/App.svelte
@@ -0,0 +1,13 @@
+
+
+
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/01-context-api/app-b/Map.svelte b/site/content/tutorial/15-context/01-context-api/app-b/Map.svelte
new file mode 100644
index 0000000000..0282cbc311
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/app-b/Map.svelte
@@ -0,0 +1,50 @@
+
+
+
+
+
+ {#if map}
+
+ {/if}
+
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/01-context-api/app-b/MapMarker.svelte b/site/content/tutorial/15-context/01-context-api/app-b/MapMarker.svelte
new file mode 100644
index 0000000000..c936652507
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/app-b/MapMarker.svelte
@@ -0,0 +1,19 @@
+
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/01-context-api/app-b/mapbox.js b/site/content/tutorial/15-context/01-context-api/app-b/mapbox.js
new file mode 100644
index 0000000000..55b4200038
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/app-b/mapbox.js
@@ -0,0 +1,8 @@
+import mapbox from 'mapbox-gl';
+
+// https://docs.mapbox.com/help/glossary/access-token/
+mapbox.accessToken = MAPBOX_ACCESS_TOKEN;
+
+const key = {};
+
+export { mapbox, key };
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/01-context-api/text.md b/site/content/tutorial/15-context/01-context-api/text.md
new file mode 100644
index 0000000000..3d095dd679
--- /dev/null
+++ b/site/content/tutorial/15-context/01-context-api/text.md
@@ -0,0 +1,47 @@
+---
+title: setContext and getContext
+---
+
+The context API provides a mechanism for components to 'talk' to each other without passing around data and functions as props, or dispatching lots of events. It's an advanced feature, but a useful one.
+
+Take this example app using a [Mapbox GL](https://docs.mapbox.com/mapbox-gl-js/overview/) map. We'd like to display the markers, using the `` component, but we don't want to have to pass around a reference to the underlying Mapbox instance as a prop on each component.
+
+There are two halves to the context API — `setContext` and `getContext`. If a component calls `setContext(key, context)`, then any *child* component can retrieve the context with `const context = getContext(key)`.
+
+Let's set the context first. In `Map.svelte`, import `setContext` from `svelte` and `key` from `mapbox.js` and call `setContext`:
+
+```js
+import { onMount, setContext } from 'svelte';
+import { mapbox, key } from './mapbox.js';
+
+setContext(key, {
+ getMap: () => map
+});
+```
+
+The context object can be anything you like. Like [lifecycle functions](tutorial/onmount), `setContext` and `getContext` must be called during component initialisation; since `map` isn't created until the component has mounted, our context object contains a `getMap` function rather than `map` itself.
+
+On the other side of the equation, in `MapMarker.svelte`, we can now get a reference to the Mapbox instance:
+
+```js
+import { getContext } from 'svelte';
+import { mapbox, key } from './mapbox.js';
+
+const { getMap } = getContext(key);
+const map = getMap();
+```
+
+The markers can now add themselves to the map.
+
+> A more finished version of `` would also handle removal and prop changes, but we're only demonstrating context here.
+
+
+## Context keys
+
+In `mapbox.js` you'll see this line:
+
+```js
+const key = {};
+```
+
+We can use anything as a key — we could do `setContext('mapbox', ...)` for example. The downside of using a string is that different component libraries might accidentally use the same one; using an object literal means the keys are guaranteed not to conflict in any circumstance, even when you have multiple different contexts operating across many component layers.
\ No newline at end of file
diff --git a/site/content/tutorial/15-context/meta.json b/site/content/tutorial/15-context/meta.json
new file mode 100644
index 0000000000..d3bd862676
--- /dev/null
+++ b/site/content/tutorial/15-context/meta.json
@@ -0,0 +1,3 @@
+{
+ "title": "Context API"
+}
\ No newline at end of file
diff --git a/site/content/tutorial/99-todo/99-todo/text.md b/site/content/tutorial/99-todo/99-todo/text.md
index 8916aeeb00..683b4fa15b 100644
--- a/site/content/tutorial/99-todo/99-todo/text.md
+++ b/site/content/tutorial/99-todo/99-todo/text.md
@@ -113,6 +113,7 @@ Maybe lifecycle should go first, since we're using `onMount` in the `this` demo?
* [x] Custom JS transitions
* [x] Thunk(?) transitions
* [x] `on:introstart` etc
+* [ ] Local transitions
## Animations
diff --git a/site/now.json b/site/now.json
index 2840898344..aa1684a891 100644
--- a/site/now.json
+++ b/site/now.json
@@ -6,7 +6,8 @@
"NODE_ENV": "production",
"BASEURL": "https://v3.svelte.technology",
"GITHUB_CLIENT_ID": "@svelte-gist-client-id-v3",
- "GITHUB_CLIENT_SECRET": "@svelte-gist-client-secret-v3"
+ "GITHUB_CLIENT_SECRET": "@svelte-gist-client-secret-v3",
+ "MAPBOX_ACCESS_TOKEN": "@svelte-mapbox-access-token"
},
"files": [
"__sapper__/build",
diff --git a/site/rollup.config.js b/site/rollup.config.js
index 48f5559a8c..d39db86c0c 100644
--- a/site/rollup.config.js
+++ b/site/rollup.config.js
@@ -1,3 +1,4 @@
+import 'dotenv/config';
import resolve from 'rollup-plugin-node-resolve';
import replace from 'rollup-plugin-replace';
import commonjs from 'rollup-plugin-commonjs';
@@ -19,7 +20,8 @@ export default {
plugins: [
replace({
'process.browser': true,
- 'process.env.NODE_ENV': JSON.stringify(mode)
+ 'process.env.NODE_ENV': JSON.stringify(mode),
+ 'process.env.MAPBOX_ACCESS_TOKEN': JSON.stringify(process.env.MAPBOX_ACCESS_TOKEN)
}),
svelte({
dev,
diff --git a/site/src/components/Repl/Output/Viewer.svelte b/site/src/components/Repl/Output/Viewer.svelte
index 42f3e31326..eec904526f 100644
--- a/site/src/components/Repl/Output/Viewer.svelte
+++ b/site/src/components/Repl/Output/Viewer.svelte
@@ -63,9 +63,14 @@
const styles = document.querySelectorAll('style.svelte');
let i = styles.length;
while (i--) styles[i].parentNode.removeChild(styles[i]);
- `)
+ `);
+
+ await proxy.eval(`
+ // needed for context API tutorial
+ window.MAPBOX_ACCESS_TOKEN = process.env.MAPBOX_ACCESS_TOKEN;
+
+ ${$bundle.dom.code}
- await proxy.eval(`${$bundle.dom.code}
if (window.component) {
try {
window.component.$destroy();