scroll-arrows 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +155 -0
- package/dist/chunk-HLZXSGP5.js +557 -0
- package/dist/index.cjs +572 -0
- package/dist/index.d.cts +57 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.js +11 -0
- package/dist/react.cjs +593 -0
- package/dist/react.d.cts +21 -0
- package/dist/react.d.ts +21 -0
- package/dist/react.js +31 -0
- package/dist/types-DehQP2Hx.d.cts +104 -0
- package/dist/types-DehQP2Hx.d.ts +104 -0
- package/package.json +84 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
# scroll-arrows
|
|
2
|
+
|
|
3
|
+
[](https://github.com/dancj/scroll-arrows/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/scroll-arrows)
|
|
5
|
+
[](https://bundlephobia.com/package/scroll-arrows)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+
Hand-drawn arrows that **draw themselves between two elements as you scroll**.
|
|
9
|
+
A single `roughness` knob slides from clean straight lines (0) to scratchy,
|
|
10
|
+
curvy scribbles (1) — same sketchy engine as Excalidraw ([rough.js]).
|
|
11
|
+
|
|
12
|
+
Framework-agnostic core + a thin React wrapper. Arrows live in a click-through
|
|
13
|
+
overlay `<svg>`, auto-track their endpoints with `ResizeObserver`, and draw on
|
|
14
|
+
scroll progress.
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install scroll-arrows
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Vanilla
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { scrollArrow } from "scroll-arrows";
|
|
24
|
+
|
|
25
|
+
const arrow = scrollArrow({
|
|
26
|
+
start: "#box-a", // Element or CSS selector
|
|
27
|
+
end: "#box-b",
|
|
28
|
+
roughness: 0.7, // 0 clean → 1 scratchy
|
|
29
|
+
stroke: "#e7e9ee",
|
|
30
|
+
strokeWidth: 2.5,
|
|
31
|
+
head: "end", // "start" | "end" | "both" | "none"
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// later
|
|
35
|
+
arrow.destroy();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## How it works
|
|
39
|
+
|
|
40
|
+
- **Anchoring** — pass two elements; the arrow picks the best edges (`auto`
|
|
41
|
+
sockets) and recomputes when they move or resize. Override with
|
|
42
|
+
`startSocket` / `endSocket`.
|
|
43
|
+
- **Scroll draw** — progress is driven by a target's travel through the
|
|
44
|
+
viewport (`scroll.range`, fractions of viewport height, default `[0.85, 0.35]`).
|
|
45
|
+
`speed` finishes the stroke earlier/later; `easing` shapes the curve.
|
|
46
|
+
- **Roughness** — one knob mapped onto rough.js `roughness`/`bowing` plus path
|
|
47
|
+
curvature. `seed` keeps a given arrow's scribble stable across renders.
|
|
48
|
+
Endpoints stay pinned to the anchors at any roughness (`anchorEnds`, default
|
|
49
|
+
true); set it false to let scratchy ends wander off the targets.
|
|
50
|
+
- **Obstacle routing** — pass `avoid` (an element or array) and the curve bows
|
|
51
|
+
around them with an `avoidPadding` gap instead of cutting through. Single-bend
|
|
52
|
+
router: it clears the worst blocker, not a full path-finder.
|
|
53
|
+
- **Manual mode** — `scroll: false` + `setProgress(0..1)` to drive it yourself
|
|
54
|
+
(e.g. from GSAP/Motion).
|
|
55
|
+
- **Labels** — `label` rides along the line at `labelAt` (0..1, default mid)
|
|
56
|
+
and can sit off the line via `labelOffset` (perpendicular px; + = left of the
|
|
57
|
+
draw direction, − = right). Fades in as the pen draws through it.
|
|
58
|
+
`labelBackground` masks a gap in the line behind the text (the excalidraw
|
|
59
|
+
look); style via `labelColor` / `font`.
|
|
60
|
+
|
|
61
|
+
## React
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
import { useRef } from "react";
|
|
65
|
+
import { ScrollArrowLine } from "scroll-arrows/react";
|
|
66
|
+
|
|
67
|
+
function Diagram() {
|
|
68
|
+
const a = useRef<HTMLDivElement>(null);
|
|
69
|
+
const b = useRef<HTMLDivElement>(null);
|
|
70
|
+
return (
|
|
71
|
+
<>
|
|
72
|
+
<div ref={a}>A</div>
|
|
73
|
+
<div ref={b}>B</div>
|
|
74
|
+
<ScrollArrowLine start={a} end={b} roughness={0.6} />
|
|
75
|
+
</>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`ScrollArrowLine` renders nothing into the React tree — it manages the overlay
|
|
81
|
+
arrow via effect and cleans up on unmount. `useScrollArrow(opts)` is the hook
|
|
82
|
+
form. Pass `deps={[...]}` to re-create when inputs change.
|
|
83
|
+
|
|
84
|
+
## Astro
|
|
85
|
+
|
|
86
|
+
The core is DOM-only, so run it in a client script (it must execute in the
|
|
87
|
+
browser, not at build time):
|
|
88
|
+
|
|
89
|
+
```astro
|
|
90
|
+
---
|
|
91
|
+
// Diagram.astro
|
|
92
|
+
---
|
|
93
|
+
<div id="a">A</div>
|
|
94
|
+
<div id="b">B</div>
|
|
95
|
+
|
|
96
|
+
<script>
|
|
97
|
+
import { scrollArrow } from "scroll-arrows";
|
|
98
|
+
scrollArrow({ start: "#a", end: "#b", roughness: 0.6 });
|
|
99
|
+
</script>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
For an Astro React island, use the React API and hydrate with `client:visible`:
|
|
103
|
+
|
|
104
|
+
```astro
|
|
105
|
+
<Diagram client:visible />
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## API
|
|
109
|
+
|
|
110
|
+
`scrollArrow(options)` / `new ScrollArrow(options)` → instance with
|
|
111
|
+
`setProgress(p)`, `refresh()`, `destroy()`.
|
|
112
|
+
|
|
113
|
+
Key options: `start`, `end`, `container`, `roughness`, `stroke`, `strokeWidth`,
|
|
114
|
+
`seed`, `startSocket`, `endSocket`, `curvature`, `head`, `headSize`, `scroll`,
|
|
115
|
+
`speed`, `easing`, `progress`. Full types ship with the package.
|
|
116
|
+
|
|
117
|
+
## Develop
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npm run demo # vite playground at /demo
|
|
121
|
+
npm test # vitest (library + release tooling)
|
|
122
|
+
npm run coverage # vitest + v8 coverage (pure logic gated at 90%)
|
|
123
|
+
npm run build # tsup → dist (ESM + CJS + d.ts)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Releasing
|
|
127
|
+
|
|
128
|
+
Automated **staging → main** flow (semver, derived from conventional-commit PR
|
|
129
|
+
titles):
|
|
130
|
+
|
|
131
|
+
1. Feature PRs merge into `staging`.
|
|
132
|
+
2. `auto-release-pr.yml` keeps a single **"Release: staging to main"** PR open,
|
|
133
|
+
its body a categorized summary (Features / Fixes / Docs / Maintenance) plus
|
|
134
|
+
the proposed next version (`feat:` → minor, `fix:`/other → patch, `!` or
|
|
135
|
+
`BREAKING CHANGE` → major).
|
|
136
|
+
3. Merging that PR to `main` triggers `release-changelog.yml`: it computes the
|
|
137
|
+
version from the newest `v*` tag, bumps `package.json` + prepends a
|
|
138
|
+
`CHANGELOG.md` entry on a `release-<version>` branch, tags `v<version>`, and
|
|
139
|
+
opens a sync PR back to `staging`.
|
|
140
|
+
4. The pushed `v*` tag triggers `release.yml`, publishing to npm via
|
|
141
|
+
**trusted publishing (OIDC)** with provenance (version pinned to the tag).
|
|
142
|
+
|
|
143
|
+
Release logic lives in `scripts/*.mjs` (pure helpers + injectable-deps
|
|
144
|
+
orchestrators), unit-tested under vitest.
|
|
145
|
+
|
|
146
|
+
Publishing uses OIDC — no `NPM_TOKEN` secret. One-time bootstrap (npm requires
|
|
147
|
+
the package to exist before a trusted publisher can be configured):
|
|
148
|
+
|
|
149
|
+
1. `npm login` then `npm publish --access public` once from your machine.
|
|
150
|
+
2. On npmjs.com → the package → Settings → **Trusted Publishing**, add the
|
|
151
|
+
GitHub Actions publisher (`dancj/scroll-arrows`, workflow `release.yml`).
|
|
152
|
+
|
|
153
|
+
After that, every `v*` tag publishes from CI with no stored credentials.
|
|
154
|
+
|
|
155
|
+
[rough.js]: https://roughjs.com
|