Skip to content

Commit 30c531b

Browse files
committed
feat(utils): add English and Chinese README files for Skyroc Utils library, detailing features, installation instructions, and usage examples; include tsdown configuration for TypeScript project setup
1 parent 52f4922 commit 30c531b

File tree

3 files changed

+803
-0
lines changed

3 files changed

+803
-0
lines changed

primitives/utils/README.md

Lines changed: 396 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,396 @@
1+
# Skyroc Utils
2+
3+
English | [简体中文](./README.zh.md)
4+
5+
A lightweight utility library providing essential helper functions for TypeScript/JavaScript projects, including array manipulation, async operations, observer patterns, form input handling, keyboard events, and more. Built with TypeScript for complete type safety.
6+
7+
## ✨ Features
8+
9+
- 🎯 **Full TypeScript Support** - Built with TypeScript, providing complete type inference and type safety
10+
- 📦 **Lightweight & Modular** - Import only what you need
11+
- 🔄 **Observer Pattern** - Simplified RxJS-like Subject implementation
12+
- 🎹 **Keyboard Support** - Comprehensive keyboard code constants and utilities
13+
- 📝 **Form Utilities** - Helper functions for form input handling
14+
- 🧰 **Radash Integration** - Re-exports all utilities from the powerful [radash](https://radash-docs.vercel.app/) library
15+
-**Tree-shakeable** - Optimized for modern bundlers
16+
17+
## 📦 Installation
18+
19+
```bash
20+
npm install skyroc-utils
21+
# or
22+
pnpm add skyroc-utils
23+
# or
24+
yarn add skyroc-utils
25+
```
26+
27+
## 🚀 Quick Start
28+
29+
```typescript
30+
import { toArray, sleep, createSubject, isNil, KeyCode } from 'skyroc-utils';
31+
32+
// Convert value to array
33+
const arr = toArray('hello'); // ['hello']
34+
35+
// Async delay
36+
await sleep(1000);
37+
38+
// Observer pattern
39+
const subject = createSubject<string>();
40+
subject.subscribe(value => console.log(value));
41+
subject.next('Hello!');
42+
43+
// Type checking
44+
isNil(null); // true
45+
isNil(undefined); // true
46+
isNil(0); // false
47+
48+
// Keyboard codes
49+
console.log(KeyCode.ENTER); // 13
50+
```
51+
52+
## 📚 API Reference
53+
54+
### Array Utilities
55+
56+
#### `toArray<T>(value?: T | T[] | null): T[]`
57+
58+
Converts a value to an array. Returns an empty array for null/undefined values.
59+
60+
```typescript
61+
import { toArray } from 'skyroc-utils';
62+
63+
toArray('hello'); // ['hello']
64+
toArray(['a', 'b']); // ['a', 'b']
65+
toArray(null); // []
66+
toArray(undefined); // []
67+
```
68+
69+
### Async Utilities
70+
71+
#### `sleep(ms: number): Promise<void>`
72+
73+
Creates a promise that resolves after the specified delay in milliseconds.
74+
75+
```typescript
76+
import { sleep } from 'skyroc-utils';
77+
78+
async function example() {
79+
console.log('Start');
80+
await sleep(1000);
81+
console.log('After 1 second');
82+
}
83+
```
84+
85+
### Observer Pattern
86+
87+
#### `createSubject<T>(): Subject<T>`
88+
89+
Creates a Subject that can emit values to multiple observers. Implements a simplified RxJS Subject pattern.
90+
91+
**Returns:** `Subject<T>` with the following properties and methods:
92+
93+
- `next(value: T): void` - Emit a new value to all observers
94+
- `subscribe(observer: Observer<T> | ((v: T) => void)): Teardown` - Subscribe to value updates
95+
- `complete(): void` - Complete the subject and clear all observers
96+
- `unsubscribe(): void` - Remove all observers
97+
- `hasObservers(): boolean` - Check if there are active observers
98+
- `size: number` - Number of current observers (read-only)
99+
- `closed: boolean` - Whether the subject is closed (read-only)
100+
101+
**Example:**
102+
103+
```typescript
104+
import { createSubject } from 'skyroc-utils';
105+
106+
const subject = createSubject<string>();
107+
108+
// Subscribe with function
109+
const subscription1 = subject.subscribe(value => {
110+
console.log('Observer 1:', value);
111+
});
112+
113+
// Subscribe with observer object
114+
const subscription2 = subject.subscribe({
115+
next: value => console.log('Observer 2:', value)
116+
});
117+
118+
// Emit values
119+
subject.next('Hello'); // Both observers receive 'Hello'
120+
subject.next('World'); // Both observers receive 'World'
121+
122+
// Unsubscribe specific observer
123+
subscription1.unsubscribe();
124+
125+
subject.next('Goodbye'); // Only Observer 2 receives this
126+
127+
// Complete the subject
128+
subject.complete();
129+
```
130+
131+
### Form Input Utilities
132+
133+
#### `isCheckBoxInput(element: FieldElement): element is HTMLInputElement`
134+
135+
Checks if the element is a checkbox input.
136+
137+
#### `isRadioInput(element: FieldElement): element is HTMLInputElement`
138+
139+
Checks if the element is a radio input.
140+
141+
#### `isFileInput(element: FieldElement): element is HTMLInputElement`
142+
143+
Checks if the element is a file input.
144+
145+
#### `getEventValue(valuePropName?: string, ...args: any[]): any`
146+
147+
Extracts the value from an event object. Handles checkboxes (returns `checked`), regular inputs (returns `value`), and non-event values.
148+
149+
**Example:**
150+
151+
```typescript
152+
import { getEventValue, isCheckBoxInput } from 'skyroc-utils';
153+
154+
// In a form handler
155+
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
156+
const value = getEventValue('value', e);
157+
// For checkbox: returns e.target.checked
158+
// For other inputs: returns e.target.value
159+
}
160+
```
161+
162+
### Keyboard Utilities
163+
164+
#### `KeyCode`
165+
166+
Object containing keyboard key code constants and utility methods.
167+
168+
**Key Constants:**
169+
170+
```typescript
171+
import { KeyCode } from 'skyroc-utils';
172+
173+
KeyCode.ENTER // 13
174+
KeyCode.ESC // 27
175+
KeyCode.SPACE // 32
176+
KeyCode.BACKSPACE // 8
177+
KeyCode.DELETE // 46
178+
KeyCode.TAB // 9
179+
KeyCode.UP // 38
180+
KeyCode.DOWN // 40
181+
KeyCode.LEFT // 37
182+
KeyCode.RIGHT // 39
183+
KeyCode.A // 65
184+
KeyCode.Z // 90
185+
// ... and many more
186+
```
187+
188+
**Utility Methods:**
189+
190+
```typescript
191+
// Check if a key code represents a character key
192+
KeyCode.isCharacterKey(keyCode: number): boolean
193+
194+
// Check if a keyboard event is text-modifying
195+
KeyCode.isTextModifyingKeyEvent(e: KeyboardEvent): boolean
196+
```
197+
198+
**Example:**
199+
200+
```typescript
201+
import { KeyCode } from 'skyroc-utils';
202+
203+
function handleKeyDown(e: KeyboardEvent) {
204+
if (e.keyCode === KeyCode.ENTER) {
205+
console.log('Enter key pressed');
206+
}
207+
208+
if (KeyCode.isCharacterKey(e.keyCode)) {
209+
console.log('Character key pressed');
210+
}
211+
212+
if (KeyCode.isTextModifyingKeyEvent(e)) {
213+
console.log('Text modification key');
214+
}
215+
}
216+
```
217+
218+
### Object Utilities
219+
220+
#### `shallowEqual(a: any, b: any): boolean`
221+
222+
Performs shallow equality comparison between two values.
223+
224+
```typescript
225+
import { shallowEqual } from 'skyroc-utils';
226+
227+
shallowEqual({ a: 1 }, { a: 1 }); // true
228+
shallowEqual({ a: 1 }, { a: 2 }); // false
229+
shallowEqual({ a: { b: 1 } }, { a: { b: 1 } }); // false (different references)
230+
```
231+
232+
#### `isObjectType(value: unknown): value is object`
233+
234+
Checks if a value is an object type.
235+
236+
#### `isEventObject(event: unknown): event is Event`
237+
238+
Checks if a value is an event object.
239+
240+
### Type Utilities
241+
242+
#### `isNil(val: unknown): val is null | undefined`
243+
244+
Checks if a value is `null` or `undefined`.
245+
246+
```typescript
247+
import { isNil } from 'skyroc-utils';
248+
249+
isNil(null); // true
250+
isNil(undefined); // true
251+
isNil(0); // false
252+
isNil(''); // false
253+
isNil(false); // false
254+
```
255+
256+
### General Utilities
257+
258+
#### `noop(): void`
259+
260+
A no-operation function that does nothing. Useful as a default callback.
261+
262+
```typescript
263+
import { noop } from 'skyroc-utils';
264+
265+
function fetchData(onSuccess = noop) {
266+
// ... fetch logic
267+
onSuccess();
268+
}
269+
```
270+
271+
#### `omitUndefined<T extends object>(obj: T): Partial<T>`
272+
273+
Returns a new object with all `undefined` values removed.
274+
275+
```typescript
276+
import { omitUndefined } from 'skyroc-utils';
277+
278+
const obj = { a: 1, b: undefined, c: 3 };
279+
omitUndefined(obj); // { a: 1, c: 3 }
280+
```
281+
282+
### Radash Re-exports
283+
284+
This package re-exports all utilities from [radash](https://radash-docs.vercel.app/), a powerful functional utility library. You can use any radash function directly from this package:
285+
286+
```typescript
287+
import {
288+
unique, // Array unique values
289+
group, // Group array items
290+
debounce, // Debounce function
291+
throttle, // Throttle function
292+
retry, // Retry async function
293+
parallel, // Run promises in parallel
294+
// ... and 100+ more utilities
295+
} from 'skyroc-utils';
296+
297+
const numbers = [1, 2, 2, 3, 3, 3];
298+
unique(numbers); // [1, 2, 3]
299+
300+
const users = [
301+
{ name: 'John', role: 'admin' },
302+
{ name: 'Jane', role: 'user' },
303+
{ name: 'Bob', role: 'admin' }
304+
];
305+
group(users, u => u.role);
306+
// { admin: [...], user: [...] }
307+
```
308+
309+
For complete radash documentation, visit: [https://radash-docs.vercel.app/](https://radash-docs.vercel.app/)
310+
311+
## 🎯 Common Use Cases
312+
313+
### Debounced Search
314+
315+
```typescript
316+
import { debounce } from 'skyroc-utils';
317+
318+
const debouncedSearch = debounce({ delay: 300 }, (query: string) => {
319+
console.log('Searching for:', query);
320+
// Perform search...
321+
});
322+
323+
// Call multiple times quickly
324+
debouncedSearch('h');
325+
debouncedSearch('he');
326+
debouncedSearch('hel');
327+
debouncedSearch('hello'); // Only this will execute after 300ms
328+
```
329+
330+
### Event Bus Pattern
331+
332+
```typescript
333+
import { createSubject } from 'skyroc-utils';
334+
335+
interface AppEvent {
336+
type: 'userLogin' | 'userLogout' | 'dataUpdate';
337+
payload: any;
338+
}
339+
340+
const eventBus = createSubject<AppEvent>();
341+
342+
// Subscribe in component A
343+
eventBus.subscribe(event => {
344+
if (event.type === 'userLogin') {
345+
console.log('User logged in:', event.payload);
346+
}
347+
});
348+
349+
// Emit from component B
350+
eventBus.next({ type: 'userLogin', payload: { userId: 123 } });
351+
```
352+
353+
### Safe Value Normalization
354+
355+
```typescript
356+
import { toArray, isNil, omitUndefined } from 'skyroc-utils';
357+
358+
function normalizeConfig(config: any) {
359+
return omitUndefined({
360+
items: toArray(config.items),
361+
enabled: isNil(config.enabled) ? true : config.enabled,
362+
timeout: config.timeout
363+
});
364+
}
365+
```
366+
367+
## 📖 TypeScript Support
368+
369+
All functions and utilities are fully typed with TypeScript:
370+
371+
```typescript
372+
import { createSubject, toArray, sleep } from 'skyroc-utils';
373+
374+
// Generic type support
375+
const subject = createSubject<number>();
376+
subject.next(42); // ✅ OK
377+
subject.next('hello'); // ❌ Type error
378+
379+
// Array type inference
380+
const nums = toArray(123); // number[]
381+
const strs = toArray('abc'); // string[]
382+
383+
// Promise typing
384+
const delay: Promise<void> = sleep(1000);
385+
```
386+
387+
## 📄 License
388+
389+
MIT License
390+
391+
## 🔗 Links
392+
393+
- [GitHub Repository](https://github.com/Ohh-889/skyroc-ui)
394+
- [Issue Tracker](https://github.com/Ohh-889/skyroc-ui/issues)
395+
- [Radash Documentation](https://radash-docs.vercel.app/)
396+

0 commit comments

Comments
 (0)