situs-kit 0.2.0 → 0.2.1

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/README.md CHANGED
@@ -1,19 +1,307 @@
1
1
  # situs-kit
2
2
 
3
- A zero-dependency creative developer toolkit
3
+ - [SplitText](#splittext)
4
+ - [SmoothScroll](#smoothscroll)
5
+ - [Ticker](#ticker)
4
6
 
5
- ## Install
7
+ ---
6
8
 
7
- ```bash
8
- npm install situs-kit
9
+ # SplitText
10
+
11
+ Split text into characters, words, and lines while preserving inline HTML elements like `<a>`, `<em>`, `<strong>`, and `<u>`.
12
+
13
+ ## Basic Usage
14
+
15
+ ```ts
16
+ import { SplitText } from "situs-kit/split-text";
17
+
18
+ const split = new SplitText("#my-text", {
19
+ type: ["chars", "words", "lines"],
20
+ });
21
+
22
+ split.chars; // HTMLElement[]
23
+ split.words; // HTMLElement[]
24
+ split.lines; // HTMLElement[]
25
+ ```
26
+
27
+ ## Constructor
28
+
29
+ ```ts
30
+ new SplitText(
31
+ element: HTMLElement | HTMLElement[] | ArrayLike<HTMLElement> | string,
32
+ options?: SplitTextOptions
33
+ )
34
+ ```
35
+
36
+ The `element` parameter accepts:
37
+
38
+ - A CSS selector string (e.g. `"#my-text"`, `".my-class"`)
39
+ - A single `HTMLElement`
40
+ - An array or array-like collection of `HTMLElement`s (creates sub-instances, aggregating results)
41
+
42
+ ## Options
43
+
44
+ ```ts
45
+ new SplitText(element, {
46
+ type: ["chars", "words", "lines"], // which levels to split
47
+ tag: "span", // wrapper element tag
48
+ mask: ["chars", "lines"], // which levels to mask
49
+ resize: true, // auto-reflow lines on resize
50
+ style: {
51
+ chars: { color: "red" },
52
+ words: {},
53
+ lines: {},
54
+ mask: {},
55
+ },
56
+ class: {
57
+ chars: "my-char",
58
+ words: "my-word",
59
+ lines: "my-line",
60
+ mask: "my-mask",
61
+ },
62
+ });
63
+ ```
64
+
65
+ | Option | Type | Default | Description |
66
+ |--------|------|---------|-------------|
67
+ | `type` | `SplitType \| SplitType[]` | `["chars", "words", "lines"]` | Split granularity |
68
+ | `tag` | `string` | `"span"` | Wrapper element tag |
69
+ | `mask` | `boolean \| SplitType[]` | `false` | Create overflow-hidden wrappers. `true` masks all requested types; array masks only specified types |
70
+ | `resize` | `boolean` | `true` | Auto-reflow lines on window resize (only applies when lines are split) |
71
+ | `style` | `object` | — | Inline styles per split type (`chars`, `words`, `lines`, `mask`) |
72
+ | `class` | `object` | — | CSS classes per split type (`chars`, `words`, `lines`, `mask`) |
73
+
74
+ ### Types
75
+
76
+ ```ts
77
+ type SplitType = "chars" | "words" | "lines"
78
+
79
+ type SplitTypeOption =
80
+ | SplitType
81
+ | ["chars"]
82
+ | ["words"]
83
+ | ["lines"]
84
+ | ["chars", "words"]
85
+ | ["chars", "lines"]
86
+ | ["words", "lines"]
87
+ | ["chars", "words", "lines"]
88
+ ```
89
+
90
+ ## Properties
91
+
92
+ | Property | Type | Description |
93
+ |----------|------|-------------|
94
+ | `dom` | `HTMLElement \| HTMLElement[]` | The original element(s) |
95
+ | `chars` | `HTMLElement[]` | Character wrapper elements |
96
+ | `words` | `HTMLElement[]` | Word wrapper elements |
97
+ | `lines` | `HTMLElement[]` | Line wrapper elements |
98
+ | `masks` | `{ chars: HTMLElement[], words: HTMLElement[], lines: HTMLElement[] }` | Mask wrapper elements per split type |
99
+
100
+ ## Methods
101
+
102
+ ### `reflow()`
103
+
104
+ Recalculate line groupings without re-splitting characters or words. Called automatically on resize when `resize: true`. Does nothing if lines weren't requested in `type`.
105
+
106
+ ```ts
107
+ split.reflow();
108
+ ```
109
+
110
+ ### `revert()`
111
+
112
+ Restore the element to its original HTML. Clears all `chars`, `words`, `lines`, and `masks` arrays. Calls `destroy()` internally.
113
+
114
+ ```ts
115
+ split.revert();
116
+ ```
117
+
118
+ ### `destroy()`
119
+
120
+ Remove resize observers and cancel pending animation frames. Called automatically by `revert()`. Safe to call multiple times.
121
+
122
+ ```ts
123
+ split.destroy();
124
+ ```
125
+
126
+ ## Data Attributes
127
+
128
+ Split elements include data attributes for CSS targeting:
129
+
130
+ ```css
131
+ [data-char] { display: inline-block; }
132
+ [data-word] { display: inline-block; }
133
+ [data-line] { display: block; }
134
+ ```
135
+
136
+ Mask elements use:
137
+
138
+ - `data-maskChar`
139
+ - `data-maskWord`
140
+ - `data-maskLine`
141
+
142
+ ## HTML Preservation
143
+
144
+ Inline elements like `<a>`, `<em>`, `<strong>`, `<u>`, `<i>`, `<b>`, `<ins>`, `<s>`, `<strike>`, and `<del>` are preserved and cloned around split elements.
145
+
146
+ Opaque elements like `<div>`, `<span>`, `<svg>`, `<img>`, `<br>`, `<canvas>`, `<video>`, `<audio>`, `<iframe>`, `<input>`, `<textarea>`, `<select>`, `<button>`, `<picture>`, and `<figure>` are treated as atomic units.
147
+
148
+ ```html
149
+ <!-- Input -->
150
+ <p id="text">Hello <strong>world</strong></p>
151
+
152
+ <!-- After split, <strong> wraps are preserved -->
153
+ ```
154
+
155
+ ## Masking
156
+
157
+ Masks wrap split elements in `overflow: hidden` containers, useful for reveal animations. You can specify which split levels to mask:
158
+
159
+ ```ts
160
+ // mask only lines
161
+ const split = new SplitText("#text", {
162
+ type: ["words", "lines"],
163
+ mask: ["lines"],
164
+ });
165
+
166
+ split.masks.lines; // HTMLElement[] - overflow:hidden wrappers
167
+
168
+ // mask all split types
169
+ const split2 = new SplitText("#text", {
170
+ type: ["chars", "words", "lines"],
171
+ mask: true,
172
+ });
173
+ ```
174
+
175
+ ## Multi-Element Support
176
+
177
+ When passing multiple elements (via selector, array, or array-like), SplitText creates sub-instances and aggregates all results into the top-level `chars`, `words`, `lines`, and `masks` arrays.
178
+
179
+ ```ts
180
+ const split = new SplitText(".my-text");
181
+
182
+ // chars/words/lines contain elements from all matched elements
183
+ split.chars; // HTMLElement[] from all .my-text elements
184
+ ```
185
+
186
+ ## Additional Behaviors
187
+
188
+ - **Letter spacing**: Automatically applied to character elements when the parent has `letter-spacing` set
189
+ - **Text indent**: Preserved on the first line
190
+
191
+ ---
192
+
193
+ # SmoothScroll
194
+
195
+ Smooth scroll with frame-rate independent damping. Intercepts wheel for smooth interpolation, uses native scroll for touch/mobile.
196
+
197
+ ## Usage
198
+
199
+ ```ts
200
+ import { SmoothScroll } from "situs-kit/smooth-scroll";
201
+
202
+ const scroll = new SmoothScroll();
203
+ ```
204
+
205
+ ### Options
206
+
207
+ ```ts
208
+ const scroll = new SmoothScroll({
209
+ wrapper: "#scroll-box", // window | HTMLElement | string (default: window)
210
+ direction: "vertical", // "vertical" | "horizontal"
211
+ duration: 800, // global to() duration in ms (0 = use damp)
212
+ ease: 0.09, // number → damp factor, function → tween ease (default: 0.09)
213
+ prevent: true, // stop wheel propagation (default: true for elements, false for window)
214
+ });
215
+ ```
216
+
217
+ ## Scroll State
218
+
219
+ ```ts
220
+ const { current, target, velocity, direction, max, scrolling } = scroll.scroll;
221
+ ```
222
+
223
+ > **Note:** `scroll` returns a shared object that is mutated each frame. Destructure or copy the values if you need to compare across frames.
224
+
225
+ | Property | Type | Description |
226
+ |----------|------|-------------|
227
+ | `current` | `number` | Current interpolated position |
228
+ | `target` | `number` | Target position |
229
+ | `velocity` | `number` | Pixels moved since last frame |
230
+ | `direction` | `1 \| -1` | 1 = forward, -1 = backward |
231
+ | `max` | `number` | Maximum scroll value |
232
+ | `scrolling` | `boolean` | Whether currently scrolling |
233
+
234
+ ## Methods
235
+
236
+ ### `to(target, options?)`
237
+
238
+ ```ts
239
+ scroll.to(500);
240
+ scroll.to("#section-2", { offset: -100 });
241
+ scroll.to(element, { duration: 1000 });
242
+ scroll.to(0, { immediate: true });
9
243
  ```
10
244
 
11
- ## Modules
245
+ | Option | Type | Description |
246
+ |--------|------|-------------|
247
+ | `offset` | `number` | Pixel offset added to target |
248
+ | `duration` | `number` | Animation duration in ms (defaults to constructor `duration`) |
249
+ | `ease` | `number \| (t: number) => number` | Number → damp factor, function → tween ease curve |
250
+ | `immediate` | `boolean` | Jump instantly |
251
+ | `onComplete` | `() => void` | Callback when scroll completes |
252
+
253
+ ### `start()` / `stop()`
254
+
255
+ Resume or pause scroll listening and the animation loop.
256
+
257
+ ### `destroy()`
258
+
259
+ Full cleanup — removes listeners, stops the ticker, clears events.
260
+
261
+ ## Events
262
+
263
+ ```ts
264
+ scroll.on("scroll", ({ current, target, velocity, direction, max }) => {});
265
+ scroll.off("scroll", callback);
266
+ ```
267
+
268
+ ## Window vs Element Mode
269
+
270
+ Both modes use the same scroll-jacking approach: wheel is intercepted for smooth damping, touch and programmatic scrolls sync via native `scroll` events.
271
+
272
+ **Window** (default) — drives scroll via `window.scrollTo()`.
273
+
274
+ **Element** — pass a `wrapper` to enable. Drives scroll via `scrollTop`/`scrollLeft`. The wrapper element should have `overflow: auto` or `overflow: scroll`.
275
+
276
+ ---
277
+
278
+ # Ticker
279
+
280
+ Shared singleton RAF loop. Used internally by SmoothScroll.
281
+
282
+ ## Usage
283
+
284
+ ```ts
285
+ import { Ticker, getDeltaFrame } from "situs-kit/ticker";
286
+
287
+ const off = Ticker.add((elapsed) => {
288
+ const df = getDeltaFrame(); // 1.0 = 60fps frame
289
+ object.x += speed * df;
290
+ });
291
+
292
+ off(); // unsubscribe
293
+ ```
294
+
295
+ ## API
296
+
297
+ ### `Ticker.add(callback): () => void`
298
+
299
+ Add a callback to the loop. Returns an unsubscribe function. The callback receives `elapsed` (ms since added).
300
+
301
+ ### `Ticker.remove(callback): void`
12
302
 
13
- - [SplitText](./docs/split-text.md) Split text into characters, words, and lines with HTML preservation
14
- - [SmoothScroll](./docs/smooth-scroll.md) — Lerp-based smooth scroll with native touch/mobile support
15
- - [Ticker](./docs/ticker.md) — Shared RAF loop manager for frame-synced animations
303
+ Remove a callback by reference.
16
304
 
17
- ## License
305
+ ### `getDeltaFrame(): number`
18
306
 
19
- MIT
307
+ Normalized delta frame. `1.0` at 60fps, `2.0` at 30fps, `0.5` at 120fps.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "situs-kit",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "A creative developer helper library",
5
5
  "license": "MIT",
6
6
  "module": "./dist/index.js",
@@ -26,8 +26,7 @@
26
26
  }
27
27
  },
28
28
  "files": [
29
- "dist",
30
- "docs"
29
+ "dist"
31
30
  ],
32
31
  "scripts": {
33
32
  "build": "bun build.ts && bunx tsc -p tsconfig.build.json",
@@ -1,82 +0,0 @@
1
- # SmoothScroll
2
-
3
- Smooth scroll with frame-rate independent damping. Intercepts wheel for smooth interpolation, uses native scroll for touch/mobile.
4
-
5
- ## Usage
6
-
7
- ```ts
8
- import { SmoothScroll } from "situs-kit/smooth-scroll";
9
-
10
- const scroll = new SmoothScroll();
11
- ```
12
-
13
- ### Options
14
-
15
- ```ts
16
- const scroll = new SmoothScroll({
17
- wrapper: "#scroll-box", // window | HTMLElement | string (default: window)
18
- direction: "vertical", // "vertical" | "horizontal"
19
- duration: 800, // global to() duration in ms (0 = use damp)
20
- ease: 0.09, // number → damp factor, function → tween ease (default: 0.09)
21
- prevent: true, // stop wheel propagation (default: true for elements, false for window)
22
- });
23
- ```
24
-
25
- ## Scroll State
26
-
27
- ```ts
28
- const { current, target, velocity, direction, max, scrolling } = scroll.scroll;
29
- ```
30
-
31
- > **Note:** `scroll` returns a shared object that is mutated each frame. Destructure or copy the values if you need to compare across frames.
32
-
33
- | Property | Type | Description |
34
- |----------|------|-------------|
35
- | `current` | `number` | Current interpolated position |
36
- | `target` | `number` | Target position |
37
- | `velocity` | `number` | Pixels moved since last frame |
38
- | `direction` | `1 \| -1` | 1 = forward, -1 = backward |
39
- | `max` | `number` | Maximum scroll value |
40
- | `scrolling` | `boolean` | Whether currently scrolling |
41
-
42
- ## Methods
43
-
44
- ### `to(target, options?)`
45
-
46
- ```ts
47
- scroll.to(500);
48
- scroll.to("#section-2", { offset: -100 });
49
- scroll.to(element, { duration: 1000 });
50
- scroll.to(0, { immediate: true });
51
- ```
52
-
53
- | Option | Type | Description |
54
- |--------|------|-------------|
55
- | `offset` | `number` | Pixel offset added to target |
56
- | `duration` | `number` | Animation duration in ms (defaults to constructor `duration`) |
57
- | `ease` | `number \| (t: number) => number` | Number → damp factor, function → tween ease curve |
58
- | `immediate` | `boolean` | Jump instantly |
59
- | `onComplete` | `() => void` | Callback when scroll completes |
60
-
61
- ### `start()` / `stop()`
62
-
63
- Resume or pause scroll listening and the animation loop.
64
-
65
- ### `destroy()`
66
-
67
- Full cleanup — removes listeners, stops the ticker, clears events.
68
-
69
- ## Events
70
-
71
- ```ts
72
- scroll.on("scroll", ({ current, target, velocity, direction, max }) => {});
73
- scroll.off("scroll", callback);
74
- ```
75
-
76
- ## Window vs Element Mode
77
-
78
- Both modes use the same scroll-jacking approach: wheel is intercepted for smooth damping, touch and programmatic scrolls sync via native `scroll` events.
79
-
80
- **Window** (default) — drives scroll via `window.scrollTo()`.
81
-
82
- **Element** — pass a `wrapper` to enable. Drives scroll via `scrollTop`/`scrollLeft`. The wrapper element should have `overflow: auto` or `overflow: scroll`.
@@ -1,181 +0,0 @@
1
- # SplitText
2
-
3
- Split text into characters, words, and lines while preserving inline HTML elements like `<a>`, `<em>`, `<strong>`, and `<u>`.
4
-
5
- ## Basic Usage
6
-
7
- ```ts
8
- import { SplitText } from "situs-kit/split-text";
9
-
10
- const split = new SplitText("#my-text", {
11
- type: ["chars", "words", "lines"],
12
- });
13
-
14
- split.chars; // HTMLElement[]
15
- split.words; // HTMLElement[]
16
- split.lines; // HTMLElement[]
17
- ```
18
-
19
- ## Constructor
20
-
21
- ```ts
22
- new SplitText(
23
- element: HTMLElement | HTMLElement[] | ArrayLike<HTMLElement> | string,
24
- options?: SplitTextOptions
25
- )
26
- ```
27
-
28
- The `element` parameter accepts:
29
-
30
- - A CSS selector string (e.g. `"#my-text"`, `".my-class"`)
31
- - A single `HTMLElement`
32
- - An array or array-like collection of `HTMLElement`s (creates sub-instances, aggregating results)
33
-
34
- ## Options
35
-
36
- ```ts
37
- new SplitText(element, {
38
- type: ["chars", "words", "lines"], // which levels to split
39
- tag: "span", // wrapper element tag
40
- mask: ["chars", "lines"], // which levels to mask
41
- resize: true, // auto-reflow lines on resize
42
- style: {
43
- chars: { color: "red" },
44
- words: {},
45
- lines: {},
46
- mask: {},
47
- },
48
- class: {
49
- chars: "my-char",
50
- words: "my-word",
51
- lines: "my-line",
52
- mask: "my-mask",
53
- },
54
- });
55
- ```
56
-
57
- | Option | Type | Default | Description |
58
- |--------|------|---------|-------------|
59
- | `type` | `SplitType \| SplitType[]` | `["chars", "words", "lines"]` | Split granularity |
60
- | `tag` | `string` | `"span"` | Wrapper element tag |
61
- | `mask` | `boolean \| SplitType[]` | `false` | Create overflow-hidden wrappers. `true` masks all requested types; array masks only specified types |
62
- | `resize` | `boolean` | `true` | Auto-reflow lines on window resize (only applies when lines are split) |
63
- | `style` | `object` | — | Inline styles per split type (`chars`, `words`, `lines`, `mask`) |
64
- | `class` | `object` | — | CSS classes per split type (`chars`, `words`, `lines`, `mask`) |
65
-
66
- ### Types
67
-
68
- ```ts
69
- type SplitType = "chars" | "words" | "lines"
70
-
71
- type SplitTypeOption =
72
- | SplitType
73
- | ["chars"]
74
- | ["words"]
75
- | ["lines"]
76
- | ["chars", "words"]
77
- | ["chars", "lines"]
78
- | ["words", "lines"]
79
- | ["chars", "words", "lines"]
80
- ```
81
-
82
- ## Properties
83
-
84
- | Property | Type | Description |
85
- |----------|------|-------------|
86
- | `dom` | `HTMLElement \| HTMLElement[]` | The original element(s) |
87
- | `chars` | `HTMLElement[]` | Character wrapper elements |
88
- | `words` | `HTMLElement[]` | Word wrapper elements |
89
- | `lines` | `HTMLElement[]` | Line wrapper elements |
90
- | `masks` | `{ chars: HTMLElement[], words: HTMLElement[], lines: HTMLElement[] }` | Mask wrapper elements per split type |
91
-
92
- ## Methods
93
-
94
- ### `reflow()`
95
-
96
- Recalculate line groupings without re-splitting characters or words. Called automatically on resize when `resize: true`. Does nothing if lines weren't requested in `type`.
97
-
98
- ```ts
99
- split.reflow();
100
- ```
101
-
102
- ### `revert()`
103
-
104
- Restore the element to its original HTML. Clears all `chars`, `words`, `lines`, and `masks` arrays. Calls `destroy()` internally.
105
-
106
- ```ts
107
- split.revert();
108
- ```
109
-
110
- ### `destroy()`
111
-
112
- Remove resize observers and cancel pending animation frames. Called automatically by `revert()`. Safe to call multiple times.
113
-
114
- ```ts
115
- split.destroy();
116
- ```
117
-
118
- ## Data Attributes
119
-
120
- Split elements include data attributes for CSS targeting:
121
-
122
- ```css
123
- [data-char] { display: inline-block; }
124
- [data-word] { display: inline-block; }
125
- [data-line] { display: block; }
126
- ```
127
-
128
- Mask elements use:
129
-
130
- - `data-maskChar`
131
- - `data-maskWord`
132
- - `data-maskLine`
133
-
134
- ## HTML Preservation
135
-
136
- Inline elements like `<a>`, `<em>`, `<strong>`, `<u>`, `<i>`, `<b>`, `<ins>`, `<s>`, `<strike>`, and `<del>` are preserved and cloned around split elements.
137
-
138
- Opaque elements like `<div>`, `<span>`, `<svg>`, `<img>`, `<br>`, `<canvas>`, `<video>`, `<audio>`, `<iframe>`, `<input>`, `<textarea>`, `<select>`, `<button>`, `<picture>`, and `<figure>` are treated as atomic units.
139
-
140
- ```html
141
- <!-- Input -->
142
- <p id="text">Hello <strong>world</strong></p>
143
-
144
- <!-- After split, <strong> wraps are preserved -->
145
- ```
146
-
147
- ## Masking
148
-
149
- Masks wrap split elements in `overflow: hidden` containers, useful for reveal animations. You can specify which split levels to mask:
150
-
151
- ```ts
152
- // mask only lines
153
- const split = new SplitText("#text", {
154
- type: ["words", "lines"],
155
- mask: ["lines"],
156
- });
157
-
158
- split.masks.lines; // HTMLElement[] - overflow:hidden wrappers
159
-
160
- // mask all split types
161
- const split2 = new SplitText("#text", {
162
- type: ["chars", "words", "lines"],
163
- mask: true,
164
- });
165
- ```
166
-
167
- ## Multi-Element Support
168
-
169
- When passing multiple elements (via selector, array, or array-like), SplitText creates sub-instances and aggregates all results into the top-level `chars`, `words`, `lines`, and `masks` arrays.
170
-
171
- ```ts
172
- const split = new SplitText(".my-text");
173
-
174
- // chars/words/lines contain elements from all matched elements
175
- split.chars; // HTMLElement[] from all .my-text elements
176
- ```
177
-
178
- ## Additional Behaviors
179
-
180
- - **Letter spacing**: Automatically applied to character elements when the parent has `letter-spacing` set
181
- - **Text indent**: Preserved on the first line
package/docs/ticker.md DELETED
@@ -1,30 +0,0 @@
1
- # Ticker
2
-
3
- Shared singleton RAF loop. Used internally by SmoothScroll.
4
-
5
- ## Usage
6
-
7
- ```ts
8
- import { Ticker, getDeltaFrame } from "situs-kit/ticker";
9
-
10
- const off = Ticker.add((elapsed) => {
11
- const df = getDeltaFrame(); // 1.0 = 60fps frame
12
- object.x += speed * df;
13
- });
14
-
15
- off(); // unsubscribe
16
- ```
17
-
18
- ## API
19
-
20
- ### `Ticker.add(callback): () => void`
21
-
22
- Add a callback to the loop. Returns an unsubscribe function. The callback receives `elapsed` (ms since added).
23
-
24
- ### `Ticker.remove(callback): void`
25
-
26
- Remove a callback by reference.
27
-
28
- ### `getDeltaFrame(): number`
29
-
30
- Normalized delta frame. `1.0` at 60fps, `2.0` at 30fps, `0.5` at 120fps.