Skip to content

Commit 2cd6d0f

Browse files
committed
feat(intersect): new package - @svelte-put/intersect
1 parent 4c19434 commit 2cd6d0f

33 files changed

Lines changed: 1378 additions & 109 deletions
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: intersect:release
2+
3+
on:
4+
workflow_dispatch:
5+
6+
jobs:
7+
Release:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- name: Checkout repository
11+
uses: actions/checkout@v3
12+
with:
13+
fetch-depth: 0
14+
- name: Setup pnpm
15+
uses: pnpm/action-setup@v2.2.1
16+
with:
17+
version: 7.0.0
18+
- name: Setup node
19+
uses: actions/setup-node@v3
20+
with:
21+
node-version: 16
22+
cache: pnpm
23+
- name: Install dependencies
24+
run: pnpm install --frozen-lockfile
25+
continue-on-error: false
26+
- name: Build package
27+
run: pnpm build --filter=@svelte-put/intersect
28+
continue-on-error: false
29+
- name: Release
30+
run: pnpm semantic-release --filter=@svelte-put/intersect
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
33+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

README.md

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Useful svelte stuff to put in your projects
1616
- [@svelte-put](#svelte-put)
1717
- [Table of Contents](#table-of-contents)
1818
- [Inspiration & Acknowledgement](#inspiration--acknowledgement)
19+
- [Playground](#playground)
1920
- [Packages](#packages)
2021
- [Svelte Actions](#svelte-actions)
2122
- [Contributing](#contributing)
@@ -31,10 +32,57 @@ There is already a great pool of [svelte actions collected by Shawn and other co
3132

3233
- Shawn's project aims to be a source for RFCs into `svelte`; I believe the stuff I am putting here should stay in user land.
3334
- I prefer having separate packages for their dedicated purposes (instead of one package that exports everything).
34-
- I want to include more than just actions in this collection.
35+
- I want to incrementally include more than just actions in this collection.
3536

3637
For those reasons, a monorepo seems like a good fit, hence this project.
3738

39+
<details>
40+
<summary>Why the name "svelte-put"?</summary>
41+
42+
Because I needed to come up quickly with a name short enough & easy to remember, and it was late at night as my creativity was running low. `use` was the first option but no longer available in the npm registry. `put` came up next in mind and I stuck with it...
43+
44+
</details>
45+
46+
## Playground
47+
48+
If you want to play around to see what's available before trying anything. Follow these steps:
49+
50+
1. Clone repo
51+
52+
```bash
53+
git clone https://github.com/vnphanquang/svelte-put.git
54+
```
55+
56+
or with ssh
57+
58+
```bash
59+
git clone git@github.com:vnphanquang/svelte-put.git
60+
```
61+
62+
2. Make sure you have [pnpm] and node compatible with what is specified in the `engines` section of the root [package.json](./package.json#engines)
63+
3. Install dependencies
64+
65+
```bash
66+
pnpm install
67+
```
68+
69+
4. Run playground (svelte-kit)
70+
71+
run at root:
72+
73+
```bash
74+
pnpm dev --filter=@svelte-put/svelte-kit
75+
```
76+
77+
or run at project directory
78+
79+
```bash
80+
cd apps/svelte-kit
81+
pnpm dev
82+
```
83+
84+
5. See playground at `localhost:3000`
85+
3886
## Packages
3987

4088
`@svelte-put` includes several packages that have self-managed release cycles, listed below. Check out their corresponding README for more details.
@@ -43,7 +91,8 @@ For those reasons, a monorepo seems like a good fit, hence this project.
4391

4492
| Package | Short Description | Version | Changelog |
4593
| --- | --- | --- | --- |
46-
| [svelte-movable][github.movable] | move node on mousedown | [![npm.movable.badge]][npm.movable] | [CHANGELOG][github.movable.changelog] |
94+
| [@svelte-put/movable][github.movable] | move node on mousedown | [![npm.movable.badge]][npm.movable] | [CHANGELOG][github.movable.changelog] |
95+
| [@svelte-put/intersect][github.intersect] | wrapper for IntersectionObserver | [![npm.intersect.badge]][npm.intersect] | [CHANGELOG][github.intersect.changelog] |
4796
## Contributing
4897

4998
[Read Contribution Guide][github.contributing]
@@ -76,6 +125,8 @@ For those reasons, a monorepo seems like a good fit, hence this project.
76125
[github.issues]: https://github.com/vnphanquang/svelte-action-movable/issues?q=
77126
[github.movable]: https://github.com/vnphanquang/svelte-put/tree/main/packages/actions/movable
78127
[github.movable.changelog]: https://github.com/vnphanquang/svelte-put/blob/main/packages/actions/movable/CHANGELOG.md
128+
[github.intersect]: https://github.com/vnphanquang/svelte-put/tree/main/packages/actions/intersect
129+
[github.intersect.changelog]: https://github.com/vnphanquang/svelte-put/blob/main/packages/actions/intersect/CHANGELOG.md
79130

80131
<!-- heading badge -->
81132
[semantic-release]: https://github.com/semantic-release/semantic-release
@@ -86,3 +137,7 @@ For those reasons, a monorepo seems like a good fit, hence this project.
86137
<!-- npm -->
87138
[npm.movable.badge]: https://img.shields.io/npm/v/@svelte-put/movable
88139
[npm.movable]: https://www.npmjs.com/package/@svelte-put/movable
140+
[npm.intersect.badge]: https://img.shields.io/npm/v/@svelte-put/intersect
141+
[npm.intersect]: https://www.npmjs.com/package/@svelte-put/intersect
142+
143+
[pnpm]: https://pnpm.io/

apps/svelte-kit/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"license": "MIT",
1414
"devDependencies": {
1515
"@svelte-put/eslint-config": "workspace:^",
16+
"@svelte-put/intersect": "workspace:^",
1617
"@svelte-put/movable": "workspace:^",
1718
"@svelte-put/prettierrc": "workspace:^",
1819
"@sveltejs/adapter-auto": "next",

apps/svelte-kit/src/app.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ declare namespace svelte.JSX {
3636
) => void;
3737
// on:movableend
3838
onmovableend?: (event: CustomEvent<import('@svelte-put/movable').MovableEventDetails>) => void;
39+
// on:intersect
40+
onintersect?: (event: CustomEvent<import('@svelte-put/intersect').IntersectDetail>) => void;
41+
// on:intersectonce
42+
onintersectonce?: (event: CustomEvent<import('@svelte-put/intersect').IntersectDetail>) => void;
3943
}
4044
}
4145

Lines changed: 12 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,104 +1,18 @@
11
<script lang="ts">
2-
import { movable, type MovableEventDetails } from '@svelte-put/movable';
3-
import Icon from 'svelte-awesome/components/Icon.svelte';
4-
import arrows from 'svelte-awesome/icons/arrows';
5-
import close from 'svelte-awesome/icons/close';
6-
import { fade } from 'svelte/transition';
72
8-
let modal = false;
9-
let containerNode: HTMLElement;
10-
let triggerNode: HTMLElement;
11-
12-
let lastKnownPosition: MovableEventDetails['position'] = { left: 0, top: 0 };
13-
let actionStatus: 'idle' | 'started' | 'stopped' = 'idle';
14-
15-
function updateLastKnownPosition(
16-
event: CustomEvent<MovableEventDetails>,
17-
status: 'started' | 'stopped',
18-
) {
19-
lastKnownPosition = event.detail.position;
20-
actionStatus = status;
21-
}
223
</script>
234

24-
<title>dev | @svelte-put</title>
5+
<title>@svelte-put</title>
256

26-
<main class="flex flex-1 flex-col p-4">
27-
<h1 class="mt-10 text-center text-4xl font-bold">Development Environment</h1>
28-
<div class="mt-10 grid flex-1 gap-y-10 md:grid-cols-2">
29-
<section
30-
class="flex h-[50vh] flex-col items-center justify-center md:h-auto"
31-
id="control-panel"
32-
>
33-
<fieldset class="grid h-full w-full place-items-center border-2 border-red-500">
34-
<legend>Boundary</legend>
35-
<fieldset class="container relative border-2 border-blue-500" bind:this={containerNode}>
36-
<legend>Container Node</legend>
37-
{#if modal}
38-
<div
39-
transition:fade={{ duration: 200 }}
40-
class="modal inset-center absolute overflow-y-auto border-2 border-border bg-bg p-8 drop-shadow-lg hover:shadow-xl"
41-
use:movable={{
42-
limit: {
43-
delta: '50px',
44-
parent: containerNode,
45-
},
46-
trigger: triggerNode,
47-
}}
48-
on:movablestart={(e) => updateLastKnownPosition(e, 'started')}
49-
on:movableend={(e) => updateLastKnownPosition(e, 'stopped')}
50-
>
51-
<button class="c-btn-icon absolute top-4 right-4" on:click={() => (modal = false)}>
52-
<Icon data={close} />
53-
</button>
54-
<button
55-
bind:this={triggerNode}
56-
class="c-btn-icon absolute top-4 right-10 hover:cursor-move"
57-
>
58-
<Icon data={arrows} />
59-
</button>
60-
<p class="text-xl">Modal content goes here</p>
61-
<p class="mt-10">
62-
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Exercitationem, quasi
63-
repellendus voluptatem consequatur sed quia blanditiis, iure nam, incidunt quibusdam
64-
velit quo soluta corrupti? Explicabo voluptas voluptate adipisci incidunt
65-
perspiciatis!
66-
</p>
67-
</div>
68-
{/if}
69-
</fieldset>
70-
</fieldset>
71-
</section>
72-
<section class="px-10" id="demo">
73-
<h2 class="text-center text-2xl">Control Panel</h2>
74-
<div class="mt-10 md:p-20">
75-
<p class="mt-10">
76-
Last Known Position: <span class="font-bold"
77-
>{JSON.stringify(lastKnownPosition, null, 2)}</span
78-
>
79-
</p>
80-
<p class="mt-10">Action status: <span class="font-bold">{actionStatus}</span></p>
81-
</div>
82-
<div class="flex items-center justify-center">
83-
<button
84-
type="button"
85-
class="mt-10 bg-primary p-6 drop-shadow-lg hover:bg-orange-700"
86-
on:click={() => (modal = true)}
87-
>
88-
Click to open modal
89-
</button>
90-
</div>
91-
</section>
92-
</div>
7+
<main class="flex-1 w-full grid place-items-center">
8+
<ul>
9+
<h1 class="text-2xl font-bold">Packages</h1>
10+
<p class="italic mb-4 mt-2">Click to navigate</p>
11+
<li>
12+
<a href="/movable" class="hover:text-primary">@svelte-put/movable</a>
13+
</li>
14+
<li>
15+
<a href="/intersect" class="hover:text-primary">@svelte-put/intersect</a>
16+
</li>
17+
</ul>
9318
</main>
94-
95-
<style>
96-
.container {
97-
width: calc(100% - 100px);
98-
height: calc(100% - 100px);
99-
}
100-
.modal {
101-
width: 75%;
102-
height: 75%;
103-
}
104-
</style>
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<script lang="ts">
2+
import { intersect, type IntersectDetail } from '@svelte-put/intersect';
3+
4+
let once = false;
5+
let onceEntry: IntersectionObserverEntry;
6+
let dynamic: boolean | undefined = undefined;
7+
let dynamicEntry: IntersectionObserverEntry;
8+
9+
function onOnce(event: CustomEvent<IntersectDetail>) {
10+
onceEntry = event.detail.entries[0];
11+
once = true;
12+
}
13+
14+
function onDynamic(event: CustomEvent<IntersectDetail>) {
15+
dynamicEntry = event.detail.entries[0];
16+
dynamic = dynamicEntry.isIntersecting;
17+
}
18+
19+
function entryObject(entry: IntersectionObserverEntry) {
20+
return {
21+
boundingClientRect: entry.boundingClientRect,
22+
intersectionRatio: entry.intersectionRatio,
23+
intersectionRect: entry.intersectionRect,
24+
isIntersecting: entry.isIntersecting,
25+
rootBounds: entry.rootBounds,
26+
target: {
27+
id: entry.target.id,
28+
className: entry.target.className,
29+
tagName: entry.target.tagName,
30+
},
31+
};
32+
}
33+
</script>
34+
35+
<title>intersect | @svelte-put</title>
36+
37+
<main class="flex-1 flex-col p-4 grid gap-y-10">
38+
<h1 class="t-10 text-center text-4xl font-bold">@svelte-put/intersect</h1>
39+
<div class="flex-1 grid gap-y-10 text-center">
40+
<section class="p-8 h-screen grid place-items-center bg-bg-accent">
41+
<p>A static section</p>
42+
</section>
43+
<section
44+
class="
45+
p-8 h-[800px] grid place-items-center bg-bg-accent
46+
{once ? 'animate-fade-in-up' : 'opacity-0'}
47+
"
48+
use:intersect={{ threshold: 0.4 }}
49+
on:intersectonce={onOnce}
50+
>
51+
<p>A section that will fade in once, when intersected with viewport by 40%, and stays static afterwards.</p>
52+
<div class='text-left px-10'>
53+
<p>First IntersectionObserverEntry:</p>
54+
{#if onceEntry}
55+
<ul>
56+
{#each Object.entries(entryObject(onceEntry)) as [key, value]}
57+
<li class="mt-2">{key}: {JSON.stringify(value)}</li>
58+
{/each}
59+
</ul>
60+
{/if}
61+
</div>
62+
</section>
63+
<section
64+
class="p-8 h-[800px] grid place-items-center bg-bg-accent"
65+
use:intersect={{ threshold: 0.4 }}
66+
on:intersect={onDynamic}
67+
>
68+
{#if dynamic !== undefined}
69+
<p class="self-start">Scrolling {dynamic ? 'into view' : 'out of view'}...</p>
70+
{/if}
71+
<p>A section that reacts to when scrolling in view (intersecting === true) and scrolling out of view (intersecting === false)</p>
72+
<div class='text-left px-10'>
73+
<p>Latest IntersectionObserverEntry:</p>
74+
{#if dynamicEntry}
75+
<ul>
76+
{#each Object.entries(entryObject(dynamicEntry)) as [key, value]}
77+
<li class="mt-2">{key}: {JSON.stringify(value)}</li>
78+
{/each}
79+
</ul>
80+
{/if}
81+
</div>
82+
{#if dynamic !== undefined}
83+
<p class="self-end">Scrolling {dynamic ? 'into view' : 'out of view'}...</p>
84+
{/if}
85+
</section>
86+
<section class="p-8 h-screen grid place-items-center bg-bg-accent">
87+
<p>Another static section</p>
88+
</section>
89+
</div>
90+
</main>

0 commit comments

Comments
 (0)