diff --git a/site/content/examples/13-actions/00-actions/App.svelte b/site/content/examples/13-actions/00-actions/App.svelte index 4548a5cbb6..bd990a5360 100644 --- a/site/content/examples/13-actions/00-actions/App.svelte +++ b/site/content/examples/13-actions/00-actions/App.svelte @@ -1,39 +1,15 @@ -
+ +{#if showModal} +
(showModal = false)}> + Click outside me! +
+{/if} \ No newline at end of file + diff --git a/site/content/examples/13-actions/00-actions/click_outside.js b/site/content/examples/13-actions/00-actions/click_outside.js new file mode 100644 index 0000000000..e8983c1457 --- /dev/null +++ b/site/content/examples/13-actions/00-actions/click_outside.js @@ -0,0 +1,15 @@ +export function clickOutside(node) { + const handleClick = (event) => { + if (!node.contains(event.target)) { + node.dispatchEvent(new CustomEvent("outclick")); + } + }; + + document.addEventListener("click", handleClick, true); + + return { + destroy() { + document.removeEventListener("click", handleClick, true); + } + }; +} diff --git a/site/content/examples/13-actions/03-actions-pannable/App.svelte b/site/content/examples/13-actions/03-actions-pannable/App.svelte new file mode 100644 index 0000000000..4548a5cbb6 --- /dev/null +++ b/site/content/examples/13-actions/03-actions-pannable/App.svelte @@ -0,0 +1,51 @@ + + +
+ + \ No newline at end of file diff --git a/site/content/examples/13-actions/03-actions-pannable/meta.json b/site/content/examples/13-actions/03-actions-pannable/meta.json new file mode 100644 index 0000000000..b97be8071f --- /dev/null +++ b/site/content/examples/13-actions/03-actions-pannable/meta.json @@ -0,0 +1,3 @@ +{ + "title": "A more complex action" +} \ No newline at end of file diff --git a/site/content/examples/13-actions/00-actions/pannable.js b/site/content/examples/13-actions/03-actions-pannable/pannable.js similarity index 100% rename from site/content/examples/13-actions/00-actions/pannable.js rename to site/content/examples/13-actions/03-actions-pannable/pannable.js diff --git a/site/content/tutorial/12-actions/01-actions/app-a/App.svelte b/site/content/tutorial/12-actions/01-actions/app-a/App.svelte index feacc44c52..40b4ea2673 100644 --- a/site/content/tutorial/12-actions/01-actions/app-a/App.svelte +++ b/site/content/tutorial/12-actions/01-actions/app-a/App.svelte @@ -1,29 +1,16 @@ + +{#if showModal} +
(showModal = false)}> + Click outside me! +
+{/if} + - -
\ No newline at end of file diff --git a/site/content/tutorial/12-actions/01-actions/app-a/pannable.js b/site/content/tutorial/12-actions/01-actions/app-a/click_outside.js similarity index 69% rename from site/content/tutorial/12-actions/01-actions/app-a/pannable.js rename to site/content/tutorial/12-actions/01-actions/app-a/click_outside.js index 332cd3e147..c406f6e95c 100644 --- a/site/content/tutorial/12-actions/01-actions/app-a/pannable.js +++ b/site/content/tutorial/12-actions/01-actions/app-a/click_outside.js @@ -1,4 +1,4 @@ -export function pannable(node) { +export function clickOutside(node) { // setup work goes here... return { @@ -6,4 +6,4 @@ export function pannable(node) { // ...cleanup goes here } }; -} \ No newline at end of file +} diff --git a/site/content/tutorial/12-actions/01-actions/app-b/App.svelte b/site/content/tutorial/12-actions/01-actions/app-b/App.svelte index 171f82762c..bd990a5360 100644 --- a/site/content/tutorial/12-actions/01-actions/app-b/App.svelte +++ b/site/content/tutorial/12-actions/01-actions/app-b/App.svelte @@ -1,30 +1,16 @@ + +{#if showModal} +
(showModal = false)}> + Click outside me! +
+{/if} + - -
\ No newline at end of file diff --git a/site/content/tutorial/12-actions/01-actions/app-b/click_outside.js b/site/content/tutorial/12-actions/01-actions/app-b/click_outside.js new file mode 100644 index 0000000000..e8983c1457 --- /dev/null +++ b/site/content/tutorial/12-actions/01-actions/app-b/click_outside.js @@ -0,0 +1,15 @@ +export function clickOutside(node) { + const handleClick = (event) => { + if (!node.contains(event.target)) { + node.dispatchEvent(new CustomEvent("outclick")); + } + }; + + document.addEventListener("click", handleClick, true); + + return { + destroy() { + document.removeEventListener("click", handleClick, true); + } + }; +} diff --git a/site/content/tutorial/12-actions/01-actions/app-b/pannable.js b/site/content/tutorial/12-actions/01-actions/app-b/pannable.js deleted file mode 100644 index f7d15328be..0000000000 --- a/site/content/tutorial/12-actions/01-actions/app-b/pannable.js +++ /dev/null @@ -1,47 +0,0 @@ -export function pannable(node) { - let x; - let y; - - function handleMousedown(event) { - x = event.clientX; - y = event.clientY; - - node.dispatchEvent(new CustomEvent('panstart', { - detail: { x, y } - })); - - window.addEventListener('mousemove', handleMousemove); - window.addEventListener('mouseup', handleMouseup); - } - - function handleMousemove(event) { - const dx = event.clientX - x; - const dy = event.clientY - y; - x = event.clientX; - y = event.clientY; - - node.dispatchEvent(new CustomEvent('panmove', { - detail: { x, y, dx, dy } - })); - } - - function handleMouseup(event) { - x = event.clientX; - y = event.clientY; - - node.dispatchEvent(new CustomEvent('panend', { - detail: { x, y } - })); - - window.removeEventListener('mousemove', handleMousemove); - window.removeEventListener('mouseup', handleMouseup); - } - - node.addEventListener('mousedown', handleMousedown); - - return { - destroy() { - node.removeEventListener('mousedown', handleMousedown); - } - }; -} \ No newline at end of file diff --git a/site/content/tutorial/12-actions/01-actions/text.md b/site/content/tutorial/12-actions/01-actions/text.md index 3706b31e7c..dfe75c192f 100644 --- a/site/content/tutorial/12-actions/01-actions/text.md +++ b/site/content/tutorial/12-actions/01-actions/text.md @@ -4,85 +4,45 @@ title: The use directive Actions are essentially element-level lifecycle functions. They're useful for things like: -* interfacing with third-party libraries -* lazy-loaded images -* tooltips -* adding custom event handlers +- interfacing with third-party libraries +- lazy-loaded images +- tooltips +- adding custom event handlers -In this app, we want to make the orange box 'pannable'. It has event handlers for the `panstart`, `panmove` and `panend` events, but these aren't native DOM events. We have to dispatch them ourselves. First, import the `pannable` function... +In this app, we want to make the orange modal close when the user clicks outside it. It has an event handler for the `outclick` event, but it isn't a native DOM event. We have to dispatch it ourselves. First, import the `clickOutside` function... ```js -import { pannable } from './pannable.js'; +import { clickOutside } from "./click_outside.js"; ``` ...then use it with the element: ```html -
+
+ Click outside me! +
``` -Open the `pannable.js` file. Like transition functions, an action function receives a `node` and some optional parameters, and returns an action object. That object can have a `destroy` function, which is called when the element is unmounted. +Open the `click_outside.js` file. Like transition functions, an action function receives a `node` (which is the element that the action is applied to) and some optional parameters, and returns an action object. That object can have a `destroy` function, which is called when the element is unmounted. -We want to fire `panstart` event when the user mouses down on the element, `panmove` events (with `dx` and `dy` properties showing how far the mouse moved) when they drag it, and `panend` events when they mouse up. One possible implementation looks like this: +We want to fire the `outclick` event when the user clicks outside the orange box. One possible implementation looks like this: ```js -export function pannable(node) { - let x; - let y; - - function handleMousedown(event) { - x = event.clientX; - y = event.clientY; - - node.dispatchEvent(new CustomEvent('panstart', { - detail: { x, y } - })); - - window.addEventListener('mousemove', handleMousemove); - window.addEventListener('mouseup', handleMouseup); - } - - function handleMousemove(event) { - const dx = event.clientX - x; - const dy = event.clientY - y; - x = event.clientX; - y = event.clientY; - - node.dispatchEvent(new CustomEvent('panmove', { - detail: { x, y, dx, dy } - })); - } - - function handleMouseup(event) { - x = event.clientX; - y = event.clientY; - - node.dispatchEvent(new CustomEvent('panend', { - detail: { x, y } - })); - - window.removeEventListener('mousemove', handleMousemove); - window.removeEventListener('mouseup', handleMouseup); - } +export function clickOutside(node) { + const handleClick = (event) => { + if (!node.contains(event.target)) { + node.dispatchEvent(new CustomEvent("outclick")); + } + }; - node.addEventListener('mousedown', handleMousedown); + document.addEventListener("click", handleClick, true); return { destroy() { - node.removeEventListener('mousedown', handleMousedown); - } + document.removeEventListener("click", handleClick, true); + }, }; } ``` -Update the `pannable` function and try moving the box around. - -> This implementation is for demonstration purposes — a more complete one would also consider touch events. +Update the `clickOutside` function, click the button to show the modal and then click outside it to close it. diff --git a/site/static/examples/thumbnails/actions-pannable.jpg b/site/static/examples/thumbnails/actions-pannable.jpg new file mode 100644 index 0000000000..3c152ab570 Binary files /dev/null and b/site/static/examples/thumbnails/actions-pannable.jpg differ