@useless-engineer/utils 0.1.0 β†’ 0.1.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.
Files changed (2) hide show
  1. package/README.md +203 -4
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,11 +1,210 @@
1
- # @useless-engineer/utils
1
+ <div align="center">
2
2
 
3
- Small, typed utilities from [@useless_engineer.dev](https://www.instagram.com/useless_engineer.dev/).
4
- One package, multiple entry points, so React Native code never pulls in what it doesn't use.
3
+ # πŸ› οΈ @useless-engineer/utils
4
+
5
+ **Small, typed utilities distilled from real production bugs.**
6
+ One package. Multiple entry points. Only pay for what you import.
7
+
8
+ [![npm version](https://img.shields.io/npm/v/@useless-engineer/utils?style=for-the-badge&logo=npm&color=CB3837&labelColor=1a1a1a)](https://www.npmjs.com/package/@useless-engineer/utils)
9
+ [![npm downloads](https://img.shields.io/npm/dm/@useless-engineer/utils?style=for-the-badge&color=7c3aed&labelColor=1a1a1a)](https://www.npmjs.com/package/@useless-engineer/utils)
10
+ [![license](https://img.shields.io/npm/l/@useless-engineer/utils?style=for-the-badge&color=22c55e&labelColor=1a1a1a)](./LICENSE)
11
+
12
+ ![TypeScript](https://img.shields.io/badge/TypeScript-ready-3178C6?style=flat-square&logo=typescript&logoColor=white)
13
+ ![Tree-shakeable](https://img.shields.io/badge/tree--shakeable-yes-10b981?style=flat-square)
14
+ ![Zero deps](https://img.shields.io/badge/dependencies-0-f59e0b?style=flat-square)
15
+ ![ESM + CJS](https://img.shields.io/badge/ESM%20%2B%20CJS-both-0ea5e9?style=flat-square)
16
+ ![React Native](https://img.shields.io/badge/React%20Native-supported-61DAFB?style=flat-square&logo=react&logoColor=black)
17
+
18
+ [**πŸ“¦ Install**](#-install) Β·
19
+ [**⚑ Quick start**](#-quick-start) ·
20
+ [**πŸ“š API**](#-api) Β·
21
+ [**πŸ—ΊοΈ Roadmap**](#️-roadmap) Β·
22
+ [**πŸ“Έ Follow**](https://www.instagram.com/useless_engineer.dev/)
23
+
24
+ </div>
25
+
26
+ ---
27
+
28
+ ## ✨ Why this exists
29
+
30
+ Every utility here started as an [Instagram post](https://www.instagram.com/useless_engineer.dev/) about a bug that actually shipped. The post explains the problem; this package is the fix, typed and tested, so you never copy-paste it again.
31
+
32
+ | | |
33
+ | ------------------------ | ------------------------------------------------------ |
34
+ | 🎯 **Focused** | Each function does one thing and has tests |
35
+ | 🌲 **Tree-shakeable** | `sideEffects: false`, import only what you use |
36
+ | 🧩 **Split by platform** | Core, React Native, and more, each its own import path |
37
+ | πŸ”’ **Strictly typed** | Written in TypeScript with strict mode on |
38
+
39
+ ---
40
+
41
+ ## πŸ“¦ Install
42
+
43
+ ```bash
44
+ npm install @useless-engineer/utils
45
+ ```
46
+
47
+ <details>
48
+ <summary><b>pnpm / yarn / bun</b></summary>
49
+
50
+ ```bash
51
+ pnpm add @useless-engineer/utils
52
+ yarn add @useless-engineer/utils
53
+ bun add @useless-engineer/utils
54
+ ```
55
+
56
+ </details>
57
+
58
+ ---
59
+
60
+ ## ⚑ Quick start
5
61
 
6
62
  ```ts
7
63
  import { debounce, throttle } from "@useless-engineer/utils";
64
+
65
+ const onSearch = debounce((query: string) => fetchResults(query), 300);
66
+ const onScroll = throttle(() => updateHeader(), 100);
67
+ ```
68
+
69
+ ```ts
70
+ import { isIOS, isAndroid } from "@useless-engineer/utils/react-native";
71
+
72
+ const padding = isIOS ? 20 : 16;
73
+ ```
74
+
75
+ > πŸ’‘ `react` and `react-native` are **optional** peer dependencies. If you only use the core entry, you never need to install either.
76
+
77
+ ---
78
+
79
+ ## 🧭 Entry points
80
+
81
+ | Import path | For | Status |
82
+ | -------------------------------------- | ------------------------- | ----------------------------------------------------------------------------- |
83
+ | `@useless-engineer/utils` | Platform-agnostic helpers | ![live](https://img.shields.io/badge/-live-22c55e?style=flat-square) |
84
+ | `@useless-engineer/utils/react-native` | React Native helpers | ![live](https://img.shields.io/badge/-live-22c55e?style=flat-square) |
85
+ | `@useless-engineer/utils/react` | React hooks | ![soon](https://img.shields.io/badge/-coming%20soon-f59e0b?style=flat-square) |
86
+
87
+ ---
88
+
89
+ ## πŸ“š API
90
+
91
+ ### Core
92
+
93
+ <details>
94
+ <summary><code>debounce(fn, delay)</code> &nbsp; ![live](https://img.shields.io/badge/-live-22c55e?style=flat-square) ![async](https://img.shields.io/badge/-async-6366f1?style=flat-square)</summary>
95
+
96
+ <br>
97
+
98
+ Waits for quiet. Every call resets the timer, and only the last call fires. Good for search inputs and autosave.
99
+
100
+ ```ts
101
+ const save = debounce((text: string) => api.save(text), 500);
102
+
103
+ save("h");
104
+ save("he");
105
+ save("hello"); // only this one runs, 500ms after the last call
106
+
107
+ // In a React effect cleanup, so nothing fires after unmount:
108
+ save.cancel();
109
+ ```
110
+
111
+ | Param | Type | Description |
112
+ | ----------- | ------------------- | ----------------------------------- |
113
+ | `fn` | `(...args) => void` | Function to debounce |
114
+ | `delay` | `number` | Milliseconds of quiet before firing |
115
+ | **returns** | `Debounced` | Callable with a `.cancel()` method |
116
+
117
+ </details>
118
+
119
+ <details>
120
+ <summary><code>throttle(fn, interval, options?)</code> &nbsp; ![live](https://img.shields.io/badge/-live-22c55e?style=flat-square) ![async](https://img.shields.io/badge/-async-6366f1?style=flat-square)</summary>
121
+
122
+ <br>
123
+
124
+ Keeps a steady beat. Runs at most once per interval, however often it's called. Good for scroll, drag, and resize.
125
+
126
+ ```ts
127
+ const onScroll = throttle(() => updateHeader(), 100);
128
+
129
+ // Skip the immediate first call:
130
+ throttle(fn, 100, { leading: false });
131
+
132
+ // Skip the final catch-up call:
133
+ throttle(fn, 100, { trailing: false });
134
+ ```
135
+
136
+ | Option | Default | Description |
137
+ | ---------- | ------- | --------------------------------------------------- |
138
+ | `leading` | `true` | Fire right away on the first call of a burst |
139
+ | `trailing` | `true` | Fire once more at the end with the latest arguments |
140
+
141
+ Returns a function with `.cancel()`.
142
+
143
+ </details>
144
+
145
+ <details>
146
+ <summary><b>debounce or throttle?</b></summary>
147
+
148
+ <br>
149
+
150
+ | | `debounce` | `throttle` |
151
+ | ------------ | --------------------------------- | -------------------------------- |
152
+ | Fires | Once, after calls **stop** | On a fixed beat **during** calls |
153
+ | Use for | Search box, autosave, validation | Scroll, drag, resize |
154
+ | Ask yourself | "Do I only need the final state?" | "Does it need to stay live?" |
155
+
156
+ </details>
157
+
158
+ ### React Native
159
+
160
+ <details>
161
+ <summary><code>isIOS</code> / <code>isAndroid</code> &nbsp; ![live](https://img.shields.io/badge/-live-22c55e?style=flat-square) ![react native](https://img.shields.io/badge/-react%20native-61DAFB?style=flat-square&logoColor=black)</summary>
162
+
163
+ <br>
164
+
165
+ Plain booleans derived from `Platform.OS`.
166
+
167
+ ```ts
8
168
  import { isIOS, isAndroid } from "@useless-engineer/utils/react-native";
169
+
170
+ const behavior = isIOS ? "padding" : "height";
171
+ ```
172
+
173
+ </details>
174
+
175
+ ---
176
+
177
+ ## πŸ—ΊοΈ Roadmap
178
+
179
+ Released one or two at a time, each matching a post that's already live.
180
+
181
+ | Next up | Entry | Origin |
182
+ | ------------------------------------------------------------------------------------------------------------------------ | ------------ | ----------------------------------------- |
183
+ | ![next](https://img.shields.io/badge/-next-f59e0b?style=flat-square) `delay`, `withTimeout` | core | Validated timers, `Promise.race` timeouts |
184
+ | ![planned](https://img.shields.io/badge/-planned-64748b?style=flat-square) `safeParseJSON`, `safeStringify`, `deepClone` | core | JSON and shallow-copy gotchas |
185
+ | ![planned](https://img.shields.io/badge/-planned-64748b?style=flat-square) `getAccessibilityProps`, `createShadow` | react-native | Accessibility and iOS-only shadows |
186
+ | ![planned](https://img.shields.io/badge/-planned-64748b?style=flat-square) `useInterval`, `useCountdown`, `useIsMounted` | react | Stale closures and unmounted updates |
187
+
188
+ ---
189
+
190
+ ## 🀝 Contributing
191
+
192
+ Found a bug or have a post idea that deserves a utility? [Open an issue](https://github.com/<your-username>/useless-engineer/issues).
193
+
194
+ ```bash
195
+ npm install
196
+ npm test
197
+ npm run build
9
198
  ```
10
199
 
11
- `react` and `react-native` are optional peer dependencies.
200
+ ---
201
+
202
+ <div align="center">
203
+
204
+ **Built from real bugs, one post at a time.**
205
+
206
+ [![Instagram](https://img.shields.io/badge/Follow-@useless__engineer.dev-E4405F?style=for-the-badge&logo=instagram&logoColor=white)](https://www.instagram.com/useless_engineer.dev/)
207
+
208
+ MIT Β© Saurabh Bandkar
209
+
210
+ </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@useless-engineer/utils",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "repo for small, utility functions by useless engineer",
5
5
  "author": "Useless Engineer",
6
6
  "keywords": [