@dxtmisha/functional-basic 0.8.5 → 0.10.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/README.md +44 -790
- package/dist/library.d.ts +784 -2
- package/dist/library.js +1748 -917
- package/package.json +28 -11
package/README.md
CHANGED
|
@@ -1,829 +1,83 @@
|
|
|
1
1
|
# @dxtmisha/functional-basic
|
|
2
2
|
|
|
3
|
-
> Core functional utility library for modern web development without framework dependencies
|
|
4
|
-
|
|
5
3
|
[](https://www.npmjs.com/package/@dxtmisha/functional-basic)
|
|
6
4
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://nodejs.org/)
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
`@dxtmisha/functional-basic` is a foundational utility library for modern web development. It's framework-agnostic and can be used in any TypeScript project — whether Vue, React, Nuxt, or plain browser code.
|
|
10
8
|
|
|
11
|
-
##
|
|
9
|
+
## Why this library?
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
npm install @dxtmisha/functional-basic
|
|
15
|
-
```
|
|
11
|
+
Every web application inevitably faces the same set of challenges: HTTP requests, localization, dates, cookies, caching, loading states. Typically each project solves these in its own way, accumulating scattered utilities that are spread across folders, duplicated between projects, and grow stale over time.
|
|
16
12
|
|
|
17
|
-
|
|
18
|
-
yarn add @dxtmisha/functional-basic
|
|
19
|
-
```
|
|
13
|
+
`functional-basic` brings all these solutions together in one place — thoughtful, tested, and ready to use. It's not a mega-framework with strict conventions, but a library: pick only what you need and use it however works best for you.
|
|
20
14
|
|
|
21
|
-
|
|
22
|
-
pnpm add @dxtmisha/functional-basic
|
|
23
|
-
```
|
|
15
|
+
## What does it do?
|
|
24
16
|
|
|
25
|
-
|
|
17
|
+
For **networking** — a full-featured HTTP client with lifecycle hooks, response caching, header management, response mocking for development, and an integrated loading state. Requests can be cancelled, configured, and extended — without pulling in extra dependencies.
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
- 🔧 **90+ Helper Functions** — for arrays, objects, strings, DOM, validation, and math
|
|
29
|
-
- 📝 **TypeScript Types** — full type coverage for all utilities
|
|
30
|
-
- ⚡ **Tree-shakeable** — import only what you use
|
|
31
|
-
- 🌍 **Geolocation & i18n** — auto-detect country, language, and formatting
|
|
32
|
-
- 🎨 **Country Flags** — 200+ flags with localized country names
|
|
33
|
-
- 📞 **Phone Masks** — international codes and number formatting
|
|
34
|
-
- 💾 **Caching** — intelligent cache system with invalidation
|
|
35
|
-
- 🌐 **HTTP Client** — extended API class with caching and loading indicators
|
|
36
|
-
- 🚫 **No Framework Dependencies** — works with vanilla JS, React, Vue, or any framework
|
|
37
|
-
- 📦 **Zero Dependencies** — no external runtime dependencies
|
|
19
|
+
For **geolocation and internationalization** — automatic detection of the user's country and language, locale-aware formatting of numbers, dates, currencies, and units of measurement, pluralization rules, country flags (200+ countries), phone codes and input masks. Everything is built on top of the native `Intl` API, ensuring correctness in any market.
|
|
38
20
|
|
|
39
|
-
|
|
21
|
+
For **browser state management** — convenient wrappers over `localStorage`, `sessionStorage`, `cookie`, and URL hash. All with TypeScript types and change subscription support. Data persists across sessions without extra boilerplate on your end.
|
|
40
22
|
|
|
41
|
-
|
|
23
|
+
For **SEO and meta tags** — a unified class that synchronizes `<title>`, Open Graph, and Twitter Card simultaneously. A single `setTitle()` call updates the browser tab, social media previews, and Twitter card at once. Works in both browser and SSR environments.
|
|
42
24
|
|
|
43
|
-
|
|
44
|
-
import {
|
|
45
|
-
toArray,
|
|
46
|
-
forEach,
|
|
47
|
-
toCamelCase,
|
|
48
|
-
toKebabCase,
|
|
49
|
-
transformation,
|
|
50
|
-
copyObject,
|
|
51
|
-
isFilled
|
|
52
|
-
} from '@dxtmisha/functional-basic'
|
|
25
|
+
For **data manipulation** — a rich set of utilities: deep object copying, array operations, safe type conversion, value validation, string formatting, and template substitution. Written with real edge cases in mind, not just the happy path.
|
|
53
26
|
|
|
54
|
-
|
|
55
|
-
const items = toArray('single') // ['single']
|
|
56
|
-
forEach([1, 2, 3], (item) => console.log(item))
|
|
57
|
-
|
|
58
|
-
// String case transformations
|
|
59
|
-
const camel = toCamelCase('my-variable-name') // 'myVariableName'
|
|
60
|
-
const kebab = toKebabCase('myVariableName') // 'my-variable-name'
|
|
61
|
-
|
|
62
|
-
// Object operations
|
|
63
|
-
const data = transformation('{"name":"test"}') // { name: 'test' }
|
|
64
|
-
const copy = copyObject({ deep: { object: true } })
|
|
65
|
-
|
|
66
|
-
// Validation
|
|
67
|
-
if (isFilled(value)) {
|
|
68
|
-
// value is not empty
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Utility Classes
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
import {
|
|
76
|
-
Cache,
|
|
77
|
-
Datetime,
|
|
78
|
-
Geo,
|
|
79
|
-
Hash,
|
|
80
|
-
Api,
|
|
81
|
-
Cookie,
|
|
82
|
-
DataStorage
|
|
83
|
-
} from '@dxtmisha/functional-basic'
|
|
84
|
-
|
|
85
|
-
// Caching
|
|
86
|
-
const cache = new Cache()
|
|
87
|
-
const userData = cache.get('user', () => fetchUser())
|
|
88
|
-
|
|
89
|
-
// Date operations
|
|
90
|
-
const datetime = new Datetime('2024-10-15')
|
|
91
|
-
const formatted = datetime.format('YYYY-MM-DD HH:mm')
|
|
92
|
-
|
|
93
|
-
// Geolocation
|
|
94
|
-
const country = Geo.getCountry() // 'US'
|
|
95
|
-
const language = Geo.getLanguage() // 'en'
|
|
96
|
-
|
|
97
|
-
// URL Hash management
|
|
98
|
-
Hash.set('userId', '12345')
|
|
99
|
-
const userId = Hash.get('userId')
|
|
100
|
-
|
|
101
|
-
// HTTP requests
|
|
102
|
-
Api.setUrl('/api/')
|
|
103
|
-
const users = await Api.get({ path: 'users' })
|
|
104
|
-
|
|
105
|
-
// Cookie management
|
|
106
|
-
const theme = new Cookie('theme')
|
|
107
|
-
theme.set('dark')
|
|
108
|
-
|
|
109
|
-
// LocalStorage wrapper
|
|
110
|
-
const settings = new DataStorage('app-settings')
|
|
111
|
-
settings.set({ theme: 'dark' })
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## 📚 API Documentation
|
|
115
|
-
|
|
116
|
-
### 🏗️ Classes
|
|
117
|
-
|
|
118
|
-
#### API & Network
|
|
119
|
-
|
|
120
|
-
**Api** — Static HTTP client with caching, loading indicators, and locale support
|
|
121
|
-
```typescript
|
|
122
|
-
Api.setUrl('/api/v1')
|
|
123
|
-
Api.setHeaders({ Authorization: 'Bearer token' })
|
|
124
|
-
|
|
125
|
-
const data = await Api.get({ path: 'users' })
|
|
126
|
-
const result = await Api.post({ path: 'users', request: { name: 'John' } })
|
|
127
|
-
const updated = await Api.put({ path: 'users/123', request: { name: 'Jane' } })
|
|
128
|
-
await Api.delete({ path: 'users/123' })
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
**ApiDefault** — Manage default request data
|
|
132
|
-
```typescript
|
|
133
|
-
const apiDefault = new ApiDefault()
|
|
134
|
-
apiDefault.set({ apiKey: 'key-123', version: '1.0' })
|
|
135
|
-
const data = apiDefault.get({ userId: '456' }) // merges with defaults
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
**ApiHeaders** — HTTP headers management
|
|
139
|
-
```typescript
|
|
140
|
-
const headers = new ApiHeaders()
|
|
141
|
-
headers.set({ Authorization: 'Bearer token', 'X-Api-Key': 'key-123' })
|
|
142
|
-
const requestHeaders = headers.get({ 'Content-Type': 'application/json' })
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
**ApiPreparation** — Request lifecycle hooks
|
|
146
|
-
```typescript
|
|
147
|
-
const preparation = new ApiPreparation()
|
|
148
|
-
preparation.set(async () => {
|
|
149
|
-
// Called before request
|
|
150
|
-
await refreshToken()
|
|
151
|
-
})
|
|
152
|
-
preparation.setEnd(async (response) => {
|
|
153
|
-
// Called after request
|
|
154
|
-
return { reset: false, data: null }
|
|
155
|
-
})
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
**ApiResponse** — Response caching and management
|
|
159
|
-
```typescript
|
|
160
|
-
const response = new ApiResponse(apiDefault)
|
|
161
|
-
response.add({ path: '/users', method: 'GET', response: userData })
|
|
162
|
-
const cached = response.get('/users', 'GET')
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
**ApiStatus** — Track API request status
|
|
166
|
-
```typescript
|
|
167
|
-
const status = new ApiStatus()
|
|
168
|
-
status.setStatus(200, 'OK')
|
|
169
|
-
status.setError('Network error')
|
|
170
|
-
console.log(status.getStatus()) // 200
|
|
171
|
-
console.log(status.getError()) // 'Network error'
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
**Loading** — Global loading indicator management
|
|
175
|
-
```typescript
|
|
176
|
-
Loading.show() // show loading
|
|
177
|
-
Loading.hide() // hide loading
|
|
178
|
-
if (Loading.is()) { /* is loading */ }
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
#### Caching
|
|
182
|
-
|
|
183
|
-
**Cache** — Manage multiple caches with automatic invalidation
|
|
184
|
-
```typescript
|
|
185
|
-
const cache = new Cache()
|
|
186
|
-
const data = cache.get('key', () => expensiveOperation(), [dep1, dep2])
|
|
187
|
-
const asyncData = await cache.getAsync('key', async () => await fetch())
|
|
188
|
-
cache.clear() // clear all caches
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
**CacheItem** — Low-level single cache value management
|
|
192
|
-
```typescript
|
|
193
|
-
const item = new CacheItem(() => computeValue())
|
|
194
|
-
const value = item.getCache([dependencies])
|
|
195
|
-
item.clearCache()
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
**CacheStatic** — Static cache for global data
|
|
199
|
-
```typescript
|
|
200
|
-
CacheStatic.set('config', configuration)
|
|
201
|
-
const config = CacheStatic.get('config')
|
|
202
|
-
CacheStatic.clear('config')
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
#### Data Storage
|
|
206
|
-
|
|
207
|
-
**Cookie** — Cookie management with automatic serialization
|
|
208
|
-
```typescript
|
|
209
|
-
const theme = new Cookie('theme')
|
|
210
|
-
theme.set('dark', { age: 365 * 24 * 60 * 60 }) // 1 year
|
|
211
|
-
const value = theme.get('light') // with default
|
|
212
|
-
theme.remove()
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
**CookieBlock** — Cookie consent management
|
|
216
|
-
```typescript
|
|
217
|
-
CookieBlock.set(true) // allow cookies
|
|
218
|
-
if (CookieBlock.isBlock()) { /* cookies blocked */ }
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
**DataStorage** — LocalStorage/SessionStorage wrapper
|
|
222
|
-
```typescript
|
|
223
|
-
const storage = new DataStorage('settings')
|
|
224
|
-
storage.set({ theme: 'dark', lang: 'en' })
|
|
225
|
-
const settings = storage.get({ theme: 'light' }) // with default
|
|
226
|
-
storage.clear()
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
**Hash** — URL hash parameter management
|
|
230
|
-
```typescript
|
|
231
|
-
Hash.set('page', 'home')
|
|
232
|
-
Hash.set('userId', '123')
|
|
233
|
-
const page = Hash.get('page', 'home')
|
|
234
|
-
Hash.addWatch('theme', (theme) => applyTheme(theme))
|
|
235
|
-
Hash.go({ page: 'products', category: 'electronics' })
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
**Global** — Global configuration storage
|
|
239
|
-
```typescript
|
|
240
|
-
Global.add({ apiUrl: 'https://api.example.com', version: '1.0' })
|
|
241
|
-
const apiUrl = Global.get('apiUrl')
|
|
242
|
-
Global.set('apiUrl', 'https://new-api.example.com')
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
#### Geolocation & Internationalization
|
|
246
|
-
|
|
247
|
-
**Geo** — Location detection and geographic data
|
|
248
|
-
```typescript
|
|
249
|
-
const country = Geo.getCountry() // 'US'
|
|
250
|
-
const language = Geo.getLanguage() // 'en'
|
|
251
|
-
const standard = Geo.getStandard() // 'en-US'
|
|
252
|
-
Geo.set('en-US') // set locale
|
|
253
|
-
const info = Geo.get() // full geo information
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
**GeoIntl** — Locale-aware formatting (Intl API)
|
|
257
|
-
```typescript
|
|
258
|
-
const intl = new GeoIntl('en-US')
|
|
259
|
-
const formatted = intl.number(1234.56) // '1,234.56'
|
|
260
|
-
const currency = intl.currency(99.99, 'USD') // '$99.99'
|
|
261
|
-
const date = intl.date(new Date(), 'short') // '10/15/2024'
|
|
262
|
-
const relative = intl.relative(-2, 'day') // '2 days ago'
|
|
263
|
-
const percent = intl.percent(0.75) // '75%'
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
**GeoFlag** — Country flags management
|
|
267
|
-
```typescript
|
|
268
|
-
const flag = new GeoFlag('en-US')
|
|
269
|
-
const usa = flag.get('US')
|
|
270
|
-
// { country: 'United States', icon: '@flag-us', value: 'US', ... }
|
|
271
|
-
const list = flag.getList() // list of all countries
|
|
272
|
-
const filtered = flag.getListByFilter('united') // search countries
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
**GeoPhone** — Phone codes and masks
|
|
276
|
-
```typescript
|
|
277
|
-
const phone = GeoPhone.get('US')
|
|
278
|
-
// { phone: 1, within: 1, mask: ['+1 (***) ***-****'], value: 'US' }
|
|
279
|
-
const info = GeoPhone.getByPhone('+14155551234')
|
|
280
|
-
// detect country by phone number
|
|
281
|
-
const list = GeoPhone.getList() // all phone codes
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
#### Date & Time
|
|
285
|
-
|
|
286
|
-
**Datetime** — Date operations and formatting
|
|
287
|
-
```typescript
|
|
288
|
-
const dt = new Datetime('2024-10-15', 'full', 'en-US')
|
|
289
|
-
const formatted = dt.format('YYYY-MM-DD HH:mm:ss')
|
|
290
|
-
const iso = dt.toIso() // ISO 8601 format
|
|
291
|
-
dt.moveByDay(5) // +5 days
|
|
292
|
-
dt.moveByMonth(-1) // -1 month
|
|
293
|
-
const year = dt.getYear()
|
|
294
|
-
const month = dt.getMonth()
|
|
295
|
-
const day = dt.getDay()
|
|
296
|
-
const hour = dt.getHour()
|
|
297
|
-
```
|
|
298
|
-
|
|
299
|
-
#### Translations & Meta
|
|
300
|
-
|
|
301
|
-
**Translate** — Translation system with caching
|
|
302
|
-
```typescript
|
|
303
|
-
const text = await Translate.get('welcome.message')
|
|
304
|
-
const withVars = await Translate.get('hello.user', { name: 'John' })
|
|
305
|
-
const texts = await Translate.getList(['save', 'cancel', 'submit'])
|
|
306
|
-
const cached = Translate.getSync('button.save') // sync from cache
|
|
307
|
-
Translate.init(() => import('./translations.json'))
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
**Meta** — HTML meta tags management
|
|
311
|
-
```typescript
|
|
312
|
-
const meta = new Meta()
|
|
313
|
-
meta.set('title', 'Page Title')
|
|
314
|
-
meta.set('description', 'Page description')
|
|
315
|
-
meta.set('keywords', 'key1, key2, key3')
|
|
316
|
-
meta.render() // apply to DOM
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
**MetaManager** — Manage multiple meta instances
|
|
320
|
-
```typescript
|
|
321
|
-
MetaManager.add('page1', { title: 'Page 1', description: 'First page' })
|
|
322
|
-
MetaManager.add('page2', { title: 'Page 2', description: 'Second page' })
|
|
323
|
-
MetaManager.render() // render all
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
**MetaOg** — Open Graph meta tags
|
|
327
|
-
```typescript
|
|
328
|
-
const og = new MetaOg()
|
|
329
|
-
og.set('title', 'Share Title')
|
|
330
|
-
og.set('description', 'Share description')
|
|
331
|
-
og.set('image', 'https://example.com/image.jpg')
|
|
332
|
-
og.render()
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
**MetaTwitter** — Twitter Card meta tags
|
|
336
|
-
```typescript
|
|
337
|
-
const twitter = new MetaTwitter()
|
|
338
|
-
twitter.set('title', 'Tweet Title')
|
|
339
|
-
twitter.set('description', 'Tweet description')
|
|
340
|
-
twitter.set('image', 'https://example.com/image.jpg')
|
|
341
|
-
twitter.render()
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
#### Icons & Communication
|
|
345
|
-
|
|
346
|
-
**Icons** — SVG icon management
|
|
347
|
-
```typescript
|
|
348
|
-
Icons.add('user', '/icons/user.svg')
|
|
349
|
-
const icon = await Icons.get('user')
|
|
350
|
-
const autoPath = await Icons.get('@arrow-left') // auto path
|
|
351
|
-
if (Icons.is('settings')) { /* icon exists */ }
|
|
352
|
-
Icons.addPath('/assets/icons/')
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
**BroadcastMessage** — Cross-tab communication
|
|
356
|
-
```typescript
|
|
357
|
-
const broadcast = new BroadcastMessage('app-channel')
|
|
358
|
-
broadcast.on('update', (data) => console.log('Received:', data))
|
|
359
|
-
broadcast.send('update', { userId: 123, action: 'refresh' })
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
#### Events & DOM
|
|
363
|
-
|
|
364
|
-
**EventItem** — DOM event management
|
|
365
|
-
```typescript
|
|
366
|
-
const event = new EventItem(element, 'click', handler)
|
|
367
|
-
event.start() // start listening
|
|
368
|
-
event.stop() // stop listening
|
|
369
|
-
event.toggle(true) // enable/disable
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
**ScrollbarWidth** — Detect scrollbar width
|
|
373
|
-
```typescript
|
|
374
|
-
const width = await ScrollbarWidth.get() // width in px
|
|
375
|
-
const shouldHide = await ScrollbarWidth.is() // thin scrollbar?
|
|
376
|
-
```
|
|
27
|
+
For **DOM** — element creation, attribute handling, scrolling, querying, and image utilities. Small but essential tools that save time when working with the browser environment.
|
|
377
28
|
|
|
378
|
-
|
|
29
|
+
## Installation
|
|
379
30
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
```typescript
|
|
383
|
-
toArray(value) // convert to array
|
|
384
|
-
arrFill(value, count) // create array with repetitions
|
|
385
|
-
forEach(data, callback) // universal iteration
|
|
386
|
-
uniqueArray(array) // remove duplicates
|
|
387
|
-
inArray(array, value) // check presence
|
|
388
|
-
getColumn(array, column) // extract column
|
|
389
|
-
splice(array, start, count) // immutable splice
|
|
390
|
-
getLengthOfAllArray(...arrays) // total length of arrays
|
|
391
|
-
getMaxLengthAllArray(...arrays) // max length
|
|
392
|
-
getMinLengthAllArray(...arrays) // min length
|
|
393
|
-
```
|
|
394
|
-
|
|
395
|
-
#### Object Operations
|
|
396
|
-
|
|
397
|
-
```typescript
|
|
398
|
-
copyObject(obj) // deep copy
|
|
399
|
-
isObjectNotArray(value) // check object (not array)
|
|
400
|
-
getObjectByKeys(obj, keys) // extract by keys
|
|
401
|
-
getObjectNoUndefined(obj) // remove undefined
|
|
402
|
-
getObjectOrNone(obj) // get object or empty
|
|
403
|
-
replaceRecursive(data, search, replace) // recursive replace
|
|
404
|
-
setValues(obj, keys, value) // set values
|
|
405
|
-
intersectKey(data1, data2) // key intersection
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
#### String Operations
|
|
409
|
-
|
|
410
|
-
```typescript
|
|
411
|
-
toCamelCase(str) // to camelCase
|
|
412
|
-
toKebabCase(str) // to kebab-case
|
|
413
|
-
toCamelCaseFirst(str) // capitalize first
|
|
414
|
-
anyToString(value) // universal string conversion
|
|
415
|
-
strFill(value, length, fill) // fill string
|
|
416
|
-
replaceTemplate(str, replacements) // replace templates
|
|
417
|
-
applyTemplate(text, data) // apply template
|
|
418
|
-
getRandomText(min, max) // generate random text
|
|
419
|
-
encodeAttribute(value) // encode for HTML attribute
|
|
420
|
-
```
|
|
421
|
-
|
|
422
|
-
#### DOM Operations
|
|
423
|
-
|
|
424
|
-
```typescript
|
|
425
|
-
getElement(selector) // get element
|
|
426
|
-
createElement(parent, tag, options) // create element
|
|
427
|
-
getElementId(element) // get/generate ID
|
|
428
|
-
getAttributes(element) // get attributes
|
|
429
|
-
setElementItem(element, name, value) // set attribute
|
|
430
|
-
getElementItem(element, name) // get attribute
|
|
431
|
-
getElementOrWindow(element) // get element or window
|
|
432
|
-
domQuerySelector(selector) // safe querySelector
|
|
433
|
-
domQuerySelectorAll(selector) // safe querySelectorAll
|
|
434
|
-
goScroll(element, options) // smooth scroll
|
|
435
|
-
initScrollbarOffset() // scrollbar compensation
|
|
436
|
-
```
|
|
437
|
-
|
|
438
|
-
#### Events
|
|
439
|
-
|
|
440
|
-
```typescript
|
|
441
|
-
eventStopPropagation(event) // stop propagation
|
|
442
|
-
getKey(event) // get pressed key
|
|
443
|
-
getMouseClient(event) // mouse/touch coordinates
|
|
444
|
-
getMouseClientX(event) // X coordinate
|
|
445
|
-
getMouseClientY(event) // Y coordinate
|
|
446
|
-
getClipboardData(event) // clipboard data
|
|
447
|
-
writeClipboardData(text) // write to clipboard
|
|
448
|
-
```
|
|
449
|
-
|
|
450
|
-
#### Validation
|
|
451
|
-
|
|
452
|
-
```typescript
|
|
453
|
-
isFilled(value) // check if filled
|
|
454
|
-
isArray(value) // check array
|
|
455
|
-
isObject(value) // check object
|
|
456
|
-
isString(value) // check string
|
|
457
|
-
isNumber(value) // check number
|
|
458
|
-
isFunction(value) // check function
|
|
459
|
-
isFloat(value) // check float
|
|
460
|
-
isIntegerBetween(value, min, max) // check range
|
|
461
|
-
isDifferent(value1, value2) // check difference
|
|
462
|
-
isNull(value) // check null/undefined
|
|
463
|
-
isDomRuntime() // check browser environment
|
|
464
|
-
isWindow(element) // check window
|
|
465
|
-
isInDom(element) // check if in DOM
|
|
466
|
-
isSelected(value, check) // check selection
|
|
467
|
-
isSelectedByList(list, value) // check in list
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
#### Math Operations
|
|
471
|
-
|
|
472
|
-
```typescript
|
|
473
|
-
random(min, max) // random number
|
|
474
|
-
getStepPercent(value, min, max) // percent from range
|
|
475
|
-
getStepValue(percent, min, max) // value by percent
|
|
476
|
-
toNumber(value) // convert to number
|
|
477
|
-
toNumberByMax(value, max) // with limit
|
|
478
|
-
toPercent(value) // to percent
|
|
479
|
-
toPercentBy100(value) // to percent (divide by 100)
|
|
480
|
-
```
|
|
481
|
-
|
|
482
|
-
#### Conversions
|
|
483
|
-
|
|
484
|
-
```typescript
|
|
485
|
-
transformation(value) // universal conversion
|
|
486
|
-
toDate(value) // to Date object
|
|
487
|
-
secondToTime(seconds) // seconds to time format
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
#### Execution Utilities
|
|
491
|
-
|
|
492
|
-
```typescript
|
|
493
|
-
executeFunction(callback) // execute function or return value
|
|
494
|
-
executePromise(callback) // async execution
|
|
495
|
-
frame(callback, next, end) // requestAnimationFrame loop
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
#### Data Operations
|
|
499
|
-
|
|
500
|
-
```typescript
|
|
501
|
-
getItemByPath(obj, path) // get by path
|
|
502
|
-
getExp(value, flags) // create RegExp with escaping
|
|
503
|
-
getRequestString(data) // object to query string
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
### 📝 TypeScript Types
|
|
507
|
-
|
|
508
|
-
```typescript
|
|
509
|
-
// Basic types
|
|
510
|
-
Undefined // undefined | null
|
|
511
|
-
EmptyValue // all "empty" values
|
|
512
|
-
NumberOrString // number | string
|
|
513
|
-
NumberOrStringOrBoolean // number | string | boolean
|
|
514
|
-
NumberOrStringOrDate // number | string | Date
|
|
515
|
-
NormalOrArray<T> // T | T[]
|
|
516
|
-
FunctionArgs<Args, Return> // typed function
|
|
517
|
-
FunctionReturn<R> // () => R
|
|
518
|
-
ObjectOrArray<T> // Record | T[]
|
|
519
|
-
ItemList // Record<string, any>
|
|
520
|
-
ElementOrString<E> // E | string | Window
|
|
521
|
-
|
|
522
|
-
// API types
|
|
523
|
-
ApiMethodItem // enum: GET, POST, PUT, DELETE
|
|
524
|
-
ApiMethod // HTTP method type
|
|
525
|
-
ApiFetch // API request options
|
|
526
|
-
ApiPreparationEnd // preparation callback result
|
|
527
|
-
ApiDefaultValue // default request data
|
|
528
|
-
ApiStatusItem // status information
|
|
529
|
-
ApiResponseItem // response cache item
|
|
530
|
-
|
|
531
|
-
// Geo types
|
|
532
|
-
GeoItemFull // full country information
|
|
533
|
-
GeoFlagItem // flag information
|
|
534
|
-
GeoPhoneValue // phone data
|
|
535
|
-
GeoDate // date format types
|
|
536
|
-
|
|
537
|
-
// Meta types
|
|
538
|
-
MetaItemType // meta tag types
|
|
539
|
-
MetaManagerItemType // meta manager item
|
|
540
|
-
```
|
|
541
|
-
|
|
542
|
-
## 🎯 Usage Examples
|
|
543
|
-
|
|
544
|
-
### Caching Expensive Operations
|
|
545
|
-
|
|
546
|
-
```typescript
|
|
547
|
-
import { Cache } from '@dxtmisha/functional-basic'
|
|
548
|
-
|
|
549
|
-
const cache = new Cache()
|
|
550
|
-
let userId = 1
|
|
551
|
-
|
|
552
|
-
// Data is cached on first call
|
|
553
|
-
const userData = cache.get(
|
|
554
|
-
'user-data',
|
|
555
|
-
() => {
|
|
556
|
-
console.log('Loading user data...')
|
|
557
|
-
return fetchUserData(userId)
|
|
558
|
-
},
|
|
559
|
-
[userId] // dependencies for invalidation
|
|
560
|
-
)
|
|
561
|
-
|
|
562
|
-
// When userId changes, cache invalidates
|
|
563
|
-
userId = 2
|
|
564
|
-
const newUserData = cache.get('user-data', () => fetchUserData(userId), [userId])
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
### Locale-Aware Formatting
|
|
568
|
-
|
|
569
|
-
```typescript
|
|
570
|
-
import { GeoIntl } from '@dxtmisha/functional-basic'
|
|
571
|
-
|
|
572
|
-
const intl = new GeoIntl('en-US')
|
|
573
|
-
|
|
574
|
-
// Numbers
|
|
575
|
-
console.log(intl.number(1234567.89)) // '1,234,567.89'
|
|
576
|
-
|
|
577
|
-
// Currency
|
|
578
|
-
console.log(intl.currency(99.99, 'USD')) // '$99.99'
|
|
579
|
-
|
|
580
|
-
// Dates
|
|
581
|
-
console.log(intl.date(new Date(), 'long')) // 'October 15, 2024'
|
|
582
|
-
|
|
583
|
-
// Relative time
|
|
584
|
-
console.log(intl.relative(-2, 'day')) // '2 days ago'
|
|
585
|
-
|
|
586
|
-
// Plural forms
|
|
587
|
-
console.log(intl.plural(5, ['item', 'items'])) // '5 items'
|
|
31
|
+
```bash
|
|
32
|
+
npm install @dxtmisha/functional-basic
|
|
588
33
|
```
|
|
589
34
|
|
|
590
|
-
|
|
35
|
+
## Quick Start
|
|
591
36
|
|
|
592
37
|
```typescript
|
|
593
|
-
import { Api } from '@dxtmisha/functional-basic'
|
|
38
|
+
import { Api, GeoIntl, Meta, Cache, isFilled } from '@dxtmisha/functional-basic'
|
|
594
39
|
|
|
595
|
-
//
|
|
40
|
+
// HTTP client
|
|
596
41
|
Api.setUrl('/api/v1')
|
|
597
|
-
Api.setHeaders({
|
|
598
|
-
Authorization: 'Bearer token',
|
|
599
|
-
'Content-Type': 'application/json'
|
|
600
|
-
})
|
|
601
|
-
|
|
602
|
-
// GET request
|
|
603
42
|
const users = await Api.get({ path: 'users' })
|
|
604
43
|
|
|
605
|
-
//
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
// PUT
|
|
612
|
-
await Api.put({
|
|
613
|
-
path: 'users/123',
|
|
614
|
-
request: { name: 'Jane Doe' }
|
|
615
|
-
})
|
|
616
|
-
|
|
617
|
-
// DELETE
|
|
618
|
-
await Api.delete({ path: 'users/123' })
|
|
619
|
-
|
|
620
|
-
// With query parameters
|
|
621
|
-
const filtered = await Api.get({
|
|
622
|
-
path: 'users',
|
|
623
|
-
request: { role: 'admin', active: true }
|
|
624
|
-
})
|
|
625
|
-
// GET /api/v1/users?role=admin&active=true
|
|
626
|
-
```
|
|
627
|
-
|
|
628
|
-
### URL Hash Management
|
|
629
|
-
|
|
630
|
-
```typescript
|
|
631
|
-
import { Hash } from '@dxtmisha/functional-basic'
|
|
632
|
-
|
|
633
|
-
// Set parameters
|
|
634
|
-
Hash.set('page', 'products')
|
|
635
|
-
Hash.set('category', 'electronics')
|
|
636
|
-
Hash.set('sort', 'price')
|
|
637
|
-
|
|
638
|
-
// URL becomes: #page:products/category:electronics/sort:price
|
|
639
|
-
|
|
640
|
-
// Get parameters
|
|
641
|
-
const page = Hash.get('page', 'home')
|
|
642
|
-
const category = Hash.get('category')
|
|
643
|
-
|
|
644
|
-
// Watch for changes
|
|
645
|
-
Hash.addWatch('page', (newPage) => {
|
|
646
|
-
console.log(`Page changed to: ${newPage}`)
|
|
647
|
-
loadPageContent(newPage)
|
|
648
|
-
})
|
|
649
|
-
|
|
650
|
-
// Bulk update
|
|
651
|
-
Hash.go({ page: 'checkout', step: '1' })
|
|
652
|
-
```
|
|
653
|
-
|
|
654
|
-
### Meta Tags Management
|
|
44
|
+
// Locale-aware formatting
|
|
45
|
+
const intl = new GeoIntl()
|
|
46
|
+
intl.number(1234567.89) // '1,234,567.89'
|
|
47
|
+
intl.currency(99.99, 'USD') // '$99.99'
|
|
48
|
+
intl.date(new Date(), 'date')
|
|
655
49
|
|
|
656
|
-
|
|
657
|
-
|
|
50
|
+
// Caching
|
|
51
|
+
const cache = new Cache()
|
|
52
|
+
const data = cache.get('key', () => expensiveOperation(), [dep])
|
|
658
53
|
|
|
659
|
-
//
|
|
54
|
+
// Unified SEO — one call updates title, og:title and twitter:title
|
|
660
55
|
const meta = new Meta()
|
|
661
|
-
meta.
|
|
662
|
-
meta.
|
|
663
|
-
meta.set('keywords', 'awesome, page, example')
|
|
664
|
-
meta.render()
|
|
665
|
-
|
|
666
|
-
// Open Graph
|
|
667
|
-
const og = new MetaOg()
|
|
668
|
-
og.set('title', 'Share Title')
|
|
669
|
-
og.set('description', 'Share description for social media')
|
|
670
|
-
og.set('image', 'https://example.com/share-image.jpg')
|
|
671
|
-
og.set('url', 'https://example.com/page')
|
|
672
|
-
og.render()
|
|
673
|
-
|
|
674
|
-
// Twitter Card
|
|
675
|
-
const twitter = new MetaTwitter()
|
|
676
|
-
twitter.set('title', 'Tweet Title')
|
|
677
|
-
twitter.set('description', 'Tweet description')
|
|
678
|
-
twitter.set('image', 'https://example.com/twitter-image.jpg')
|
|
679
|
-
twitter.render()
|
|
680
|
-
```
|
|
681
|
-
|
|
682
|
-
### Cross-Tab Communication
|
|
683
|
-
|
|
684
|
-
```typescript
|
|
685
|
-
import { BroadcastMessage } from '@dxtmisha/functional-basic'
|
|
686
|
-
|
|
687
|
-
const channel = new BroadcastMessage('app-sync')
|
|
688
|
-
|
|
689
|
-
// Listen for messages
|
|
690
|
-
channel.on('user-updated', (data) => {
|
|
691
|
-
console.log('User updated in another tab:', data)
|
|
692
|
-
updateUI(data)
|
|
693
|
-
})
|
|
694
|
-
|
|
695
|
-
// Send message to all tabs
|
|
696
|
-
channel.send('user-updated', {
|
|
697
|
-
userId: 123,
|
|
698
|
-
name: 'John Doe',
|
|
699
|
-
timestamp: Date.now()
|
|
700
|
-
})
|
|
701
|
-
```
|
|
702
|
-
|
|
703
|
-
### Date Operations
|
|
704
|
-
|
|
705
|
-
```typescript
|
|
706
|
-
import { Datetime } from '@dxtmisha/functional-basic'
|
|
707
|
-
|
|
708
|
-
const dt = new Datetime('2024-10-15 14:30:00', 'full', 'en-US')
|
|
709
|
-
|
|
710
|
-
// Formatting
|
|
711
|
-
console.log(dt.format('YYYY-MM-DD')) // '2024-10-15'
|
|
712
|
-
console.log(dt.format('DD/MM/YYYY HH:mm')) // '15/10/2024 14:30'
|
|
713
|
-
console.log(dt.toIso()) // '2024-10-15T14:30:00.000Z'
|
|
714
|
-
|
|
715
|
-
// Manipulation
|
|
716
|
-
dt.moveByDay(7) // +7 days
|
|
717
|
-
dt.moveByMonth(-1) // -1 month
|
|
718
|
-
dt.moveByHour(3) // +3 hours
|
|
719
|
-
|
|
720
|
-
// Getters
|
|
721
|
-
console.log(dt.getYear()) // 2024
|
|
722
|
-
console.log(dt.getMonth()) // 10
|
|
723
|
-
console.log(dt.getDay()) // 15
|
|
724
|
-
console.log(dt.getDayWeek()) // 2 (Tuesday)
|
|
725
|
-
```
|
|
726
|
-
|
|
727
|
-
## 📁 Export Structure
|
|
728
|
-
|
|
729
|
-
```
|
|
730
|
-
@dxtmisha/functional-basic
|
|
731
|
-
├── / # All utilities (recommended)
|
|
732
|
-
└── /types/* # TypeScript types
|
|
733
|
-
```
|
|
734
|
-
|
|
735
|
-
## 🔧 Requirements
|
|
736
|
-
|
|
737
|
-
- **Node.js**: ≥18.0.0
|
|
738
|
-
- **TypeScript**: 4.0+ (optional)
|
|
739
|
-
- **No Framework Required**: Works with vanilla JS or any framework
|
|
740
|
-
|
|
741
|
-
## 🤝 Compatibility
|
|
742
|
-
|
|
743
|
-
| Environment | Support |
|
|
744
|
-
|-------------|---------|
|
|
745
|
-
| **Browsers** | ✅ ES2020+ (Chrome 80+, Firefox 72+, Safari 13.1+, Edge 80+) |
|
|
746
|
-
| **Node.js** | ✅ 18+ |
|
|
747
|
-
| **TypeScript** | ✅ 4+ |
|
|
748
|
-
| **Vanilla JS** | ✅ Full support |
|
|
749
|
-
| **React** | ✅ Full support |
|
|
750
|
-
| **Vue** | ✅ Full support |
|
|
751
|
-
| **Angular** | ✅ Full support |
|
|
752
|
-
| **SSR** | ✅ With environment checks |
|
|
753
|
-
|
|
754
|
-
## 📊 Bundle Size
|
|
755
|
-
|
|
756
|
-
- **Full library**: ~90KB (minified)
|
|
757
|
-
- **With tree-shaking**: only used functions are imported
|
|
758
|
-
- **Minimal import**: ~1KB (single function)
|
|
759
|
-
- **Dependencies**: zero runtime dependencies
|
|
56
|
+
meta.setSuffix('My Site')
|
|
57
|
+
meta.setTitle('Article').setDescription('...').setImage('https://...')
|
|
760
58
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
The library fully supports tree-shaking:
|
|
764
|
-
|
|
765
|
-
```typescript
|
|
766
|
-
// ❌ Bad - imports entire library
|
|
767
|
-
import * as functional from '@dxtmisha/functional-basic'
|
|
768
|
-
|
|
769
|
-
// ✅ Good - imports only what's needed
|
|
770
|
-
import { toArray, forEach, Cache } from '@dxtmisha/functional-basic'
|
|
59
|
+
// Validation
|
|
60
|
+
if (isFilled(value)) { /* ... */ }
|
|
771
61
|
```
|
|
772
62
|
|
|
773
|
-
##
|
|
774
|
-
|
|
775
|
-
- ✅ **Full TypeScript support** — TypeScript out of the box
|
|
776
|
-
- ✅ **Zero dependencies** — no external runtime dependencies
|
|
777
|
-
- ✅ **Framework agnostic** — works with any framework or vanilla JS
|
|
778
|
-
- ✅ **Tree-shakeable** — optimal bundle size
|
|
779
|
-
- ✅ **SSR friendly** — safe for server-side rendering
|
|
780
|
-
- ✅ **Comprehensive** — everything you need in one library
|
|
781
|
-
- ✅ **Well tested** — comprehensive test coverage
|
|
782
|
-
- ✅ **Well documented** — complete API documentation
|
|
783
|
-
- ✅ **Production ready** — used in production projects
|
|
784
|
-
- ✅ **Regular updates** — active development and support
|
|
785
|
-
|
|
786
|
-
## 📖 Difference from @dxtmisha/functional
|
|
787
|
-
|
|
788
|
-
- **@dxtmisha/functional-basic**: Core utilities without Vue dependencies
|
|
789
|
-
- **@dxtmisha/functional**: Includes Vue composables and reactive utilities
|
|
790
|
-
|
|
791
|
-
Use `functional-basic` if:
|
|
792
|
-
- You're not using Vue.js
|
|
793
|
-
- You want minimal dependencies
|
|
794
|
-
- You're building a library
|
|
795
|
-
- You need maximum compatibility
|
|
796
|
-
|
|
797
|
-
Use `functional` if:
|
|
798
|
-
- You're building a Vue.js application
|
|
799
|
-
- You want reactive composables
|
|
800
|
-
- You need Vue-specific utilities
|
|
801
|
-
|
|
802
|
-
## 📖 Additional Documentation
|
|
803
|
-
|
|
804
|
-
- [GitHub Repository](https://github.com/dxtmisha/dxt-ui)
|
|
805
|
-
- [Full API Documentation](https://github.com/dxtmisha/dxt-ui/tree/main/packages/wiki/src/media/functional-basic)
|
|
806
|
-
- [DXT UI Documentation](https://dxtmisha.github.io/dxt-ui/)
|
|
807
|
-
|
|
808
|
-
## 🐛 Report Issues
|
|
809
|
-
|
|
810
|
-
If you found a bug or want to suggest an improvement:
|
|
811
|
-
|
|
812
|
-
- [GitHub Issues](https://github.com/dxtmisha/dxt-ui/issues)
|
|
813
|
-
|
|
814
|
-
## 📄 License
|
|
63
|
+
## Principles
|
|
815
64
|
|
|
816
|
-
|
|
65
|
+
- **Zero external dependencies** — no third-party packages are pulled in. Fewer conflicts, fewer vulnerabilities, fewer surprises during updates.
|
|
66
|
+
- **TypeScript-first** — strict typing and autocomplete out of the box. Types aren't an "add-on" — they're an integral part of the API.
|
|
67
|
+
- **Clean API** — method chaining, predictable behavior, clear naming. You don't need to read the docs to understand what `isFilled` or `setTitle` does.
|
|
68
|
+
- **Test coverage** — every class and function ships with tests. Library changes won't silently break your project.
|
|
817
69
|
|
|
818
|
-
##
|
|
70
|
+
## Documentation
|
|
819
71
|
|
|
820
|
-
|
|
72
|
+
Full API reference, examples, and guides:
|
|
821
73
|
|
|
822
|
-
|
|
74
|
+
**[📖 https://dxtmisha.github.io/dxt-ui/](https://dxtmisha.github.io/dxt-ui/)**
|
|
823
75
|
|
|
824
|
-
|
|
76
|
+
## Difference from @dxtmisha/functional
|
|
825
77
|
|
|
826
|
-
|
|
78
|
+
- **`@dxtmisha/functional-basic`** — core utilities, no framework dependencies. Use this with vanilla JS, React, or any non-Vue stack, or when building a library.
|
|
79
|
+
- **`@dxtmisha/functional`** — extends `functional-basic` with Vue 3 composables and reactive utilities. Use this in Vue / Nuxt applications.
|
|
827
80
|
|
|
828
|
-
|
|
81
|
+
## License
|
|
829
82
|
|
|
83
|
+
[MIT](LICENSE)
|