@dxtmisha/functional 1.6.8 → 1.9.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 +36 -727
- package/dist/library.d.ts +732 -82
- package/dist/library.js +1112 -434
- package/package.json +12 -7
package/README.md
CHANGED
|
@@ -1,767 +1,76 @@
|
|
|
1
1
|
# @dxtmisha/functional
|
|
2
2
|
|
|
3
|
-
> Comprehensive functional utility library for modern web development
|
|
4
|
-
|
|
5
3
|
[](https://www.npmjs.com/package/@dxtmisha/functional)
|
|
6
4
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[](https://nodejs.org/)
|
|
40
6
|
|
|
41
|
-
|
|
7
|
+
`@dxtmisha/functional` is a library of utilities, base classes, and composables for complex web development in Vue 3. The package operates on the foundation of `@dxtmisha/functional-basic`, providing reactive wrappers and architectural solutions designed specifically for the Vue ecosystem (Composition API).
|
|
42
8
|
|
|
43
|
-
|
|
44
|
-
import {
|
|
45
|
-
toArray,
|
|
46
|
-
forEach,
|
|
47
|
-
toCamelCase,
|
|
48
|
-
toKebabCase,
|
|
49
|
-
transformation,
|
|
50
|
-
copyObject,
|
|
51
|
-
isFilled
|
|
52
|
-
} from '@dxtmisha/functional'
|
|
53
|
-
|
|
54
|
-
// Array operations
|
|
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 } })
|
|
9
|
+
## Why this library?
|
|
65
10
|
|
|
66
|
-
|
|
67
|
-
if (isFilled(value)) {
|
|
68
|
-
// value is not empty
|
|
69
|
-
}
|
|
70
|
-
```
|
|
11
|
+
Every modern frontend application inevitably faces the same set of challenges: managing HTTP requests, localization, dates, cookies, caching, loading states, and side effects.
|
|
71
12
|
|
|
72
|
-
|
|
13
|
+
When developers solve these tasks locally within components, it often leads to code duplication, bloated `.vue` files, and memory leaks from forgotten subscriptions. `functional` solves this by moving business logic into ready-made reactive abstractions. You simply call the necessary composable or class, and under the hood, the library manages `ref` dependencies, monitors the Vue lifecycle, and maintains strict TypeScript typing.
|
|
73
14
|
|
|
74
|
-
|
|
75
|
-
import {
|
|
76
|
-
Cache,
|
|
77
|
-
Datetime,
|
|
78
|
-
Geo,
|
|
79
|
-
Hash,
|
|
80
|
-
Api,
|
|
81
|
-
Cookie,
|
|
82
|
-
DataStorage
|
|
83
|
-
} from '@dxtmisha/functional'
|
|
15
|
+
## What does it do?
|
|
84
16
|
|
|
85
|
-
|
|
86
|
-
const cache = new Cache()
|
|
87
|
-
const userData = cache.get('user', () => fetchUser())
|
|
17
|
+
For **network requests (API)** — a set of composables (`useApiGet`, `useApiPost`, `useApiRequest`, etc.) that encapsulate server interactions. They return a fully reactive object with loading states, errors, and fetched data. They intelligently handle response caching, headers, and automatic cancellation of outdated requests.
|
|
88
18
|
|
|
89
|
-
|
|
90
|
-
const datetime = new Datetime('2024-10-15')
|
|
91
|
-
const formatted = datetime.format('YYYY-MM-DD HH:mm')
|
|
19
|
+
For **browser state management** — convenient reactive hooks (`useStorageRef`, `useSessionRef`, `useCookieRef`, `useHashRef`) that seamlessly bind a Vue variable to LocalStorage, URL hash, or a cookie. It automatically synchronizes with browser storage and reacts across tabs.
|
|
92
20
|
|
|
93
|
-
|
|
94
|
-
const country = Geo.getCountry() // 'US'
|
|
95
|
-
const language = Geo.getLanguage() // 'en'
|
|
21
|
+
For **geolocation and internationalization** — utilities like `useTranslateRef`, `useGeoIntlRef`, and `DatetimeRef` that automatically respond strictly to changes in global environment settings (language, currency, region) and dynamically rebuild forms, dates, and translations without custom event listeners.
|
|
96
22
|
|
|
97
|
-
|
|
98
|
-
Hash.set('userId', '12345')
|
|
99
|
-
const userId = Hash.get('userId')
|
|
23
|
+
For **UI component architecture** — a powerful system of base classes (`DesignAbstract`, `DesignComp`, `DesignAsyncAbstract`) that allows extracting complex internal component logic into separate, testable files. This makes `.vue` templates beautifully clean and business features highly reusable.
|
|
100
24
|
|
|
101
|
-
|
|
102
|
-
const api = new Api('/api')
|
|
103
|
-
const users = await api.get('/users')
|
|
25
|
+
For **auxiliary utilities** — specialized reactive modules for SEO tags (`useMeta`), inter-tab real-time communication (`useBroadcastValueRef`), robust loading indicators (`useLoadingRef`), and executing asynchronous operations cleanly in the Vue render cycle (`computedAsync`, `toComputed`).
|
|
104
26
|
|
|
105
|
-
|
|
106
|
-
const theme = new Cookie('theme')
|
|
107
|
-
theme.set('dark')
|
|
27
|
+
## Installation
|
|
108
28
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
settings.set({ theme: 'dark' })
|
|
29
|
+
```bash
|
|
30
|
+
npm install @dxtmisha/functional
|
|
112
31
|
```
|
|
113
32
|
|
|
114
|
-
|
|
33
|
+
## Quick Start
|
|
115
34
|
|
|
116
35
|
```typescript
|
|
117
|
-
import {
|
|
118
|
-
useGeoIntlRef,
|
|
119
|
-
useStorageRef,
|
|
120
|
-
useApiRef,
|
|
121
|
-
useHashRef,
|
|
122
|
-
useTranslateRef
|
|
123
|
-
} from '@dxtmisha/functional'
|
|
36
|
+
import { useGeoIntlRef, useStorageRef, useApiRef } from '@dxtmisha/functional'
|
|
124
37
|
|
|
125
38
|
export default {
|
|
126
39
|
setup() {
|
|
127
|
-
// Reactive geolocation
|
|
128
|
-
const { country, language } = useGeoIntlRef()
|
|
129
|
-
|
|
130
|
-
// Reactive storage
|
|
131
|
-
const { value: theme, set: setTheme } = useStorageRef('theme', 'light')
|
|
132
|
-
|
|
133
|
-
// Reactive API requests
|
|
134
|
-
const { data, loading, error } = useApiRef('/api/users')
|
|
135
|
-
|
|
136
|
-
// Reactive URL hash
|
|
137
|
-
const { hash, setHash } = useHashRef()
|
|
138
|
-
|
|
139
|
-
// Reactive translations
|
|
140
|
-
const { t } = useTranslateRef()
|
|
141
|
-
|
|
142
|
-
return { country, language, theme, setTheme, data, loading }
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## 📚 API Documentation
|
|
148
|
-
|
|
149
|
-
### 🏗️ Classes
|
|
150
|
-
|
|
151
|
-
#### API & Network
|
|
152
|
-
|
|
153
|
-
**Api** — HTTP client with caching, loading indicators, and locale support
|
|
154
|
-
```typescript
|
|
155
|
-
Api.setUrl('/api/v1')
|
|
156
|
-
Api.setHeaders({ 'Authorization': 'Bearer token' })
|
|
157
|
-
const api = new Api()
|
|
158
|
-
const data = await api.get('/users')
|
|
159
|
-
const result = await api.post('/users', { name: 'John' })
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
**Loading** — Global loading indicator management
|
|
163
|
-
```typescript
|
|
164
|
-
Loading.show() // show loading
|
|
165
|
-
Loading.hide() // hide loading
|
|
166
|
-
if (Loading.is()) { /* is loading */ }
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
#### Caching
|
|
170
|
-
|
|
171
|
-
**Cache** — Manage multiple caches with automatic invalidation
|
|
172
|
-
```typescript
|
|
173
|
-
const cache = new Cache()
|
|
174
|
-
const data = cache.get('key', () => expensiveOperation(), [dep1, dep2])
|
|
175
|
-
const asyncData = await cache.getAsync('key', async () => await fetch())
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
**CacheItem** — Low-level single cache value management
|
|
179
|
-
```typescript
|
|
180
|
-
const item = new CacheItem(() => computeValue())
|
|
181
|
-
const value = item.getCache([dependencies])
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
**CacheStatic** — Static cache for global data
|
|
185
|
-
```typescript
|
|
186
|
-
CacheStatic.set('config', configuration)
|
|
187
|
-
const config = CacheStatic.get('config')
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
#### Data Storage
|
|
191
|
-
|
|
192
|
-
**Cookie** — Cookie management with automatic serialization
|
|
193
|
-
```typescript
|
|
194
|
-
const theme = new Cookie('theme')
|
|
195
|
-
theme.set('dark', { age: 365 * 24 * 60 * 60 }) // 1 year
|
|
196
|
-
const value = theme.get('light') // with default
|
|
197
|
-
theme.remove()
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
**CookieBlock** — Cookie consent management
|
|
201
|
-
```typescript
|
|
202
|
-
CookieBlock.set(true) // allow cookies
|
|
203
|
-
if (CookieBlock.isBlock()) { /* cookies blocked */ }
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
**DataStorage** — LocalStorage/SessionStorage wrapper
|
|
207
|
-
```typescript
|
|
208
|
-
const storage = new DataStorage('settings')
|
|
209
|
-
storage.set({ theme: 'dark', lang: 'en' })
|
|
210
|
-
const settings = storage.get({ theme: 'light' }) // with default
|
|
211
|
-
storage.clear()
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
**Hash** — URL hash parameter management
|
|
215
|
-
```typescript
|
|
216
|
-
Hash.set('page', 'home')
|
|
217
|
-
Hash.set('userId', '123')
|
|
218
|
-
const page = Hash.get('page', 'home')
|
|
219
|
-
Hash.addWatch('theme', (theme) => applyTheme(theme))
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
**Global** — Global configuration storage
|
|
223
|
-
```typescript
|
|
224
|
-
Global.add({ apiUrl: 'https://api.example.com', version: '1.0' })
|
|
225
|
-
const apiUrl = Global.get('apiUrl')
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
#### Geolocation & Internationalization
|
|
229
|
-
|
|
230
|
-
**Geo** — Location detection and geographic data
|
|
231
|
-
```typescript
|
|
232
|
-
const country = Geo.getCountry() // 'US'
|
|
233
|
-
const language = Geo.getLanguage() // 'en'
|
|
234
|
-
const standard = Geo.getStandard() // 'en-US'
|
|
235
|
-
Geo.set('en-US') // set locale
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
**GeoIntl** — Locale-aware formatting (Intl API)
|
|
239
|
-
```typescript
|
|
240
|
-
const intl = new GeoIntl('en-US')
|
|
241
|
-
const formatted = intl.number(1234.56) // '1,234.56'
|
|
242
|
-
const currency = intl.currency(99.99, 'USD') // '$99.99'
|
|
243
|
-
const date = intl.date(new Date(), 'short') // '10/15/2024'
|
|
244
|
-
const relative = intl.relative(-2, 'day') // '2 days ago'
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
**GeoFlag** — Country flags management
|
|
248
|
-
```typescript
|
|
249
|
-
const flag = new GeoFlag('en-US')
|
|
250
|
-
const usa = flag.get('US')
|
|
251
|
-
// { country: 'United States', icon: '@flag-us', value: 'US', ... }
|
|
252
|
-
const list = flag.getList() // list of all countries
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
**GeoPhone** — Phone codes and masks
|
|
256
|
-
```typescript
|
|
257
|
-
const phone = GeoPhone.get('US')
|
|
258
|
-
// { phone: 1, within: 1, mask: ['+1 (***) ***-****'], value: 'US' }
|
|
259
|
-
const info = GeoPhone.getByPhone('+14155551234')
|
|
260
|
-
// detect country by phone number
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
#### Date & Time
|
|
264
|
-
|
|
265
|
-
**Datetime** — Date operations and formatting
|
|
266
|
-
```typescript
|
|
267
|
-
const dt = new Datetime('2024-10-15', 'full', 'en-US')
|
|
268
|
-
const formatted = dt.format('YYYY-MM-DD HH:mm:ss')
|
|
269
|
-
const iso = dt.toIso() // ISO 8601 format
|
|
270
|
-
dt.moveByDay(5) // +5 days
|
|
271
|
-
dt.moveByMonth(-1) // -1 month
|
|
272
|
-
const year = dt.getYear()
|
|
273
|
-
const month = dt.getMonth()
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
#### Translations
|
|
277
|
-
|
|
278
|
-
**Translate** — Translation system with caching
|
|
279
|
-
```typescript
|
|
280
|
-
const text = await Translate.get('welcome.message')
|
|
281
|
-
const withVars = await Translate.get('hello.user', { name: 'John' })
|
|
282
|
-
const texts = await Translate.getList(['save', 'cancel', 'submit'])
|
|
283
|
-
const cached = Translate.getSync('button.save') // sync from cache
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
#### Icons
|
|
287
|
-
|
|
288
|
-
**Icons** — SVG icon management
|
|
289
|
-
```typescript
|
|
290
|
-
Icons.add('user', '/icons/user.svg')
|
|
291
|
-
const icon = await Icons.get('user')
|
|
292
|
-
const autoPath = await Icons.get('@arrow-left') // auto path
|
|
293
|
-
if (Icons.is('settings')) { /* icon exists */ }
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
#### Events
|
|
297
|
-
|
|
298
|
-
**EventItem** — DOM event management
|
|
299
|
-
```typescript
|
|
300
|
-
const event = new EventItem(element, 'click', handler)
|
|
301
|
-
event.start() // start listening
|
|
302
|
-
event.stop() // stop listening
|
|
303
|
-
event.toggle(true) // enable/disable
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
#### Utilities
|
|
307
|
-
|
|
308
|
-
**ScrollbarWidth** — Detect scrollbar width
|
|
309
|
-
```typescript
|
|
310
|
-
const width = await ScrollbarWidth.get() // width in px
|
|
311
|
-
const shouldHide = await ScrollbarWidth.is() // thin scrollbar?
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### 🎯 Vue Composables
|
|
315
|
-
|
|
316
|
-
**useApiRef** — Reactive HTTP requests
|
|
317
|
-
```typescript
|
|
318
|
-
const { data, loading, error, reload } = useApiRef('/api/users')
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
**useCookieRef** — Reactive cookies
|
|
322
|
-
```typescript
|
|
323
|
-
const { value, set } = useCookieRef('theme', 'light')
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
**useGeoIntlRef** — Reactive geolocation
|
|
327
|
-
```typescript
|
|
328
|
-
const { country, language, intl } = useGeoIntlRef()
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
**useHashRef** — Reactive URL hash
|
|
332
|
-
```typescript
|
|
333
|
-
const { hash, setHash } = useHashRef()
|
|
334
|
-
const userId = useHashRef('userId', '0')
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
**useLazyRef** — Lazy data loading
|
|
338
|
-
```typescript
|
|
339
|
-
const { value, load, loading } = useLazyRef(async () => await fetchData())
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
**useLoadingRef** — Reactive loading state
|
|
343
|
-
```typescript
|
|
344
|
-
const { loading, is, show, hide } = useLoadingRef()
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
**useSessionRef** — Reactive sessionStorage
|
|
348
|
-
```typescript
|
|
349
|
-
const { value, set } = useSessionRef('tempData', {})
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
**useStorageRef** — Reactive localStorage
|
|
353
|
-
```typescript
|
|
354
|
-
const { value, set, clear } = useStorageRef('settings', { theme: 'dark' })
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
**useTranslateRef** — Reactive translations
|
|
358
|
-
```typescript
|
|
359
|
-
const { t, locale, setLocale } = useTranslateRef()
|
|
360
|
-
const text = t('welcome.message')
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
### 🔧 Functions
|
|
364
|
-
|
|
365
|
-
#### Array Operations
|
|
366
|
-
|
|
367
|
-
```typescript
|
|
368
|
-
toArray(value) // convert to array
|
|
369
|
-
arrFill(value, count) // create array with repetitions
|
|
370
|
-
forEach(data, callback) // universal iteration
|
|
371
|
-
uniqueArray(array) // remove duplicates
|
|
372
|
-
inArray(array, value) // check presence
|
|
373
|
-
getColumn(array, column) // extract column
|
|
374
|
-
splice(array, start, count) // immutable splice
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
#### Object Operations
|
|
378
|
-
|
|
379
|
-
```typescript
|
|
380
|
-
copyObject(obj) // deep copy
|
|
381
|
-
isObjectNotArray(value) // check object (not array)
|
|
382
|
-
getObjectByKeys(obj, keys) // extract by keys
|
|
383
|
-
getObjectNoUndefined(obj) // remove undefined
|
|
384
|
-
replaceRecursive(data, search, replace) // recursive replace
|
|
385
|
-
setValues(obj, keys, value) // set values
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
#### String Operations
|
|
389
|
-
|
|
390
|
-
```typescript
|
|
391
|
-
toCamelCase(str) // to camelCase
|
|
392
|
-
toKebabCase(str) // to kebab-case
|
|
393
|
-
toCamelCaseFirst(str) // capitalize first
|
|
394
|
-
anyToString(value) // universal string conversion
|
|
395
|
-
strFill(value, length, fill) // fill string
|
|
396
|
-
replaceTemplate(str, replacements) // replace templates
|
|
397
|
-
applyTemplate(text, data) // apply template
|
|
398
|
-
getRandomText(min, max) // generate random text
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
#### DOM Operations
|
|
402
|
-
|
|
403
|
-
```typescript
|
|
404
|
-
getElement(selector) // get element
|
|
405
|
-
createElement(parent, tag, options) // create element
|
|
406
|
-
getElementId(element) // get/generate ID
|
|
407
|
-
getAttributes(element) // get attributes
|
|
408
|
-
setElementItem(element, name, value) // set attribute
|
|
409
|
-
domQuerySelector(selector) // safe querySelector
|
|
410
|
-
domQuerySelectorAll(selector) // safe querySelectorAll
|
|
411
|
-
goScroll(element, options) // smooth scroll
|
|
412
|
-
initScrollbarOffset() // scrollbar compensation
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
#### Events
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
eventStopPropagation(event) // stop propagation
|
|
419
|
-
getKey(event) // get pressed key
|
|
420
|
-
getMouseClient(event) // mouse/touch coordinates
|
|
421
|
-
getMouseClientX(event) // X coordinate
|
|
422
|
-
getMouseClientY(event) // Y coordinate
|
|
423
|
-
getClipboardData(event) // clipboard data
|
|
424
|
-
writeClipboardData(text) // write to clipboard
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
#### Validation
|
|
428
|
-
|
|
429
|
-
```typescript
|
|
430
|
-
isFilled(value) // check if filled
|
|
431
|
-
isArray(value) // check array
|
|
432
|
-
isObject(value) // check object
|
|
433
|
-
isString(value) // check string
|
|
434
|
-
isNumber(value) // check number
|
|
435
|
-
isFunction(value) // check function
|
|
436
|
-
isFloat(value) // check float
|
|
437
|
-
isIntegerBetween(value, min, max) // check range
|
|
438
|
-
isDifferent(value1, value2) // check difference
|
|
439
|
-
isNull(value) // check null/undefined
|
|
440
|
-
isDomRuntime() // check browser environment
|
|
441
|
-
isWindow(element) // check window
|
|
442
|
-
isInDom(element) // check if in DOM
|
|
443
|
-
isSelected(value, check) // check selection
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
#### Math Operations
|
|
447
|
-
|
|
448
|
-
```typescript
|
|
449
|
-
random(min, max) // random number
|
|
450
|
-
getStepPercent(value, min, max) // percent from range
|
|
451
|
-
getStepValue(percent, min, max) // value by percent
|
|
452
|
-
toNumber(value) // convert to number
|
|
453
|
-
toNumberByMax(value, max) // with limit
|
|
454
|
-
toPercent(value) // to percent
|
|
455
|
-
toPercentBy100(value) // to percent (divide by 100)
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
#### Conversions
|
|
459
|
-
|
|
460
|
-
```typescript
|
|
461
|
-
transformation(value) // universal conversion
|
|
462
|
-
toDate(value) // to Date object
|
|
463
|
-
toBind(extra, value) // merge props
|
|
464
|
-
toBinds(list) // merge props list
|
|
465
|
-
secondToTime(seconds) // seconds to time format
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
#### Execution Utilities
|
|
469
|
-
|
|
470
|
-
```typescript
|
|
471
|
-
executeFunction(callback) // execute function or return value
|
|
472
|
-
executePromise(callback) // async execution
|
|
473
|
-
executeUse(callback, options) // caching for Vue composables
|
|
474
|
-
frame(callback, next, end) // requestAnimationFrame loop
|
|
475
|
-
```
|
|
476
|
-
|
|
477
|
-
#### Data Operations
|
|
478
|
-
|
|
479
|
-
```typescript
|
|
480
|
-
getItemByPath(obj, path) // get by path
|
|
481
|
-
getExp(value, flags) // create RegExp with escaping
|
|
482
|
-
getRequestString(data) // object to query string
|
|
483
|
-
getLengthOfAllArray(arrays) // total length of arrays
|
|
484
|
-
getMaxLengthAllArray(arrays) // max length
|
|
485
|
-
getMinLengthAllArray(arrays) // min length
|
|
486
|
-
intersectKey(data1, data2) // key intersection
|
|
487
|
-
```
|
|
488
|
-
|
|
489
|
-
#### Vue Utilities
|
|
490
|
-
|
|
491
|
-
```typescript
|
|
492
|
-
getRef(value) // get ref value
|
|
493
|
-
setRef(target, value) // set ref value
|
|
494
|
-
toRefItem(callback) // convert to ref
|
|
495
|
-
toComputed(callback) // create computed
|
|
496
|
-
getComputedAsync(callback) // async computed
|
|
497
|
-
getBindRef(extra, value) // reactive props merge
|
|
498
|
-
render(callback) // render with tracking
|
|
499
|
-
getBind(props, options) // get bind attributes
|
|
500
|
-
getClassName(classes) // merge classes
|
|
501
|
-
getIndexForRender(array) // indexes for render
|
|
502
|
-
```
|
|
503
|
-
|
|
504
|
-
### 📝 TypeScript Types
|
|
505
|
-
|
|
506
|
-
```typescript
|
|
507
|
-
// Basic types
|
|
508
|
-
Undefined // undefined | null
|
|
509
|
-
EmptyValue // all "empty" values
|
|
510
|
-
NumberOrString // number | string
|
|
511
|
-
NumberOrStringOrBoolean // number | string | boolean
|
|
512
|
-
NumberOrStringOrDate // number | string | Date
|
|
513
|
-
NormalOrArray<T> // T | T[]
|
|
514
|
-
NormalOrPromise<T> // T | Promise<T>
|
|
515
|
-
FunctionArgs<Args, Return> // typed function
|
|
516
|
-
FunctionReturn<R> // () => R
|
|
517
|
-
ObjectOrArray<T> // Record | T[]
|
|
518
|
-
ItemList // Record<string, any>
|
|
519
|
-
ElementOrString<E> // E | string | Window
|
|
520
|
-
|
|
521
|
-
// Geo types
|
|
522
|
-
GeoItemFull // full country information
|
|
523
|
-
GeoFlagItem // flag information
|
|
524
|
-
GeoPhoneValue // phone data
|
|
525
|
-
GeoDate // date format types
|
|
526
|
-
|
|
527
|
-
// List types
|
|
528
|
-
ConversionType // conversion types
|
|
529
|
-
DataOrCallbackType<T> // data or callback
|
|
530
|
-
|
|
531
|
-
// Ref types (Vue)
|
|
532
|
-
RefOrNormal<T> // Ref<T> | T
|
|
533
|
-
RefOrNormalOrCallback<T> // Ref<T> | T | (() => T)
|
|
534
|
-
ConversionRefType<T> // ref conversion type
|
|
535
|
-
|
|
536
|
-
// Constructor types
|
|
537
|
-
ClassesItemType // class element types
|
|
538
|
-
PropsValueType // props value types
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
## 🎯 Usage Examples
|
|
542
|
-
|
|
543
|
-
### Caching Expensive Operations
|
|
544
|
-
|
|
545
|
-
```typescript
|
|
546
|
-
import { Cache } from '@dxtmisha/functional'
|
|
547
|
-
|
|
548
|
-
const cache = new Cache()
|
|
549
|
-
let userId = 1
|
|
550
|
-
|
|
551
|
-
// Data is cached on first call
|
|
552
|
-
const userData = cache.get(
|
|
553
|
-
'user-data',
|
|
554
|
-
() => {
|
|
555
|
-
console.log('Loading user data...')
|
|
556
|
-
return fetchUserData(userId)
|
|
557
|
-
},
|
|
558
|
-
[userId] // dependencies for invalidation
|
|
559
|
-
)
|
|
560
|
-
|
|
561
|
-
// When userId changes, cache invalidates
|
|
562
|
-
userId = 2
|
|
563
|
-
const newUserData = cache.get('user-data', () => fetchUserData(userId), [userId])
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
### Locale-Aware Formatting
|
|
567
|
-
|
|
568
|
-
```typescript
|
|
569
|
-
import { GeoIntl } from '@dxtmisha/functional'
|
|
570
|
-
|
|
571
|
-
const intl = new GeoIntl('en-US')
|
|
572
|
-
|
|
573
|
-
// Numbers
|
|
574
|
-
console.log(intl.number(1234567.89)) // '1,234,567.89'
|
|
575
|
-
|
|
576
|
-
// Currency
|
|
577
|
-
console.log(intl.currency(99.99, 'USD')) // '$99.99'
|
|
578
|
-
|
|
579
|
-
// Dates
|
|
580
|
-
console.log(intl.date(new Date(), 'long')) // 'October 15, 2024'
|
|
581
|
-
|
|
582
|
-
// Relative time
|
|
583
|
-
console.log(intl.relative(-2, 'day')) // '2 days ago'
|
|
584
|
-
|
|
585
|
-
// Plural forms
|
|
586
|
-
console.log(intl.plural(5, ['item', 'items'])) // '5 items'
|
|
587
|
-
```
|
|
588
|
-
|
|
589
|
-
### REST API with Caching
|
|
590
|
-
|
|
591
|
-
```typescript
|
|
592
|
-
import { Api } from '@dxtmisha/functional'
|
|
593
|
-
|
|
594
|
-
// Setup
|
|
595
|
-
Api.setUrl('/api/v1')
|
|
596
|
-
Api.setHeaders({
|
|
597
|
-
'Authorization': 'Bearer token',
|
|
598
|
-
'Content-Type': 'application/json'
|
|
599
|
-
})
|
|
600
|
-
|
|
601
|
-
// Usage
|
|
602
|
-
const api = new Api()
|
|
603
|
-
|
|
604
|
-
// GET with caching
|
|
605
|
-
const users = await api.request('/users', { cache: 3600 }) // cache for 1 hour
|
|
606
|
-
|
|
607
|
-
// POST
|
|
608
|
-
const newUser = await api.post('/users', {
|
|
609
|
-
name: 'John Doe',
|
|
610
|
-
email: 'john@example.com'
|
|
611
|
-
})
|
|
612
|
-
|
|
613
|
-
// PUT
|
|
614
|
-
await api.put('/users/123', { name: 'Jane Doe' })
|
|
615
|
-
|
|
616
|
-
// DELETE
|
|
617
|
-
await api.delete('/users/123')
|
|
618
|
-
```
|
|
619
|
-
|
|
620
|
-
### URL Parameters via Hash
|
|
621
|
-
|
|
622
|
-
```typescript
|
|
623
|
-
import { Hash } from '@dxtmisha/functional'
|
|
624
|
-
|
|
625
|
-
// Set parameters
|
|
626
|
-
Hash.set('page', 'products')
|
|
627
|
-
Hash.set('category', 'electronics')
|
|
628
|
-
Hash.set('sort', 'price')
|
|
629
|
-
|
|
630
|
-
// URL becomes: #page:products/category:electronics/sort:price
|
|
631
|
-
|
|
632
|
-
// Get parameters
|
|
633
|
-
const page = Hash.get('page', 'home')
|
|
634
|
-
const category = Hash.get('category')
|
|
635
|
-
|
|
636
|
-
// Watch for changes
|
|
637
|
-
Hash.addWatch('page', (newPage) => {
|
|
638
|
-
console.log(`Page changed to: ${newPage}`)
|
|
639
|
-
loadPageContent(newPage)
|
|
640
|
-
})
|
|
641
|
-
```
|
|
642
|
-
|
|
643
|
-
### Reactive State in Vue
|
|
644
|
-
|
|
645
|
-
```typescript
|
|
646
|
-
import { useStorageRef, useGeoIntlRef } from '@dxtmisha/functional'
|
|
40
|
+
// Reactive geolocation and formatting
|
|
41
|
+
const { country, language, intl } = useGeoIntlRef()
|
|
647
42
|
|
|
648
|
-
|
|
649
|
-
setup() {
|
|
650
|
-
// Reactive localStorage with auto-save
|
|
43
|
+
// Reactive localStorage with auto-sync across tabs
|
|
651
44
|
const { value: settings, set: setSettings } = useStorageRef('app-settings', {
|
|
652
|
-
theme: 'dark'
|
|
653
|
-
notifications: true,
|
|
654
|
-
language: 'en'
|
|
45
|
+
theme: 'dark'
|
|
655
46
|
})
|
|
656
47
|
|
|
657
|
-
// Reactive
|
|
658
|
-
const {
|
|
659
|
-
|
|
660
|
-
// Format with locale awareness
|
|
661
|
-
const formatPrice = (price: number) => {
|
|
662
|
-
return intl.value.currency(price, 'USD')
|
|
663
|
-
}
|
|
48
|
+
// Reactive API requests with caching and loading states
|
|
49
|
+
const { data, loading, error, reload } = useApiRef('/api/users')
|
|
664
50
|
|
|
665
|
-
|
|
666
|
-
setSettings({
|
|
667
|
-
...settings.value,
|
|
668
|
-
theme: settings.value.theme === 'dark' ? 'light' : 'dark'
|
|
669
|
-
})
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
return {
|
|
673
|
-
settings,
|
|
674
|
-
country,
|
|
675
|
-
language,
|
|
676
|
-
formatPrice,
|
|
677
|
-
toggleTheme
|
|
678
|
-
}
|
|
51
|
+
return { intl, settings, setSettings, data, loading }
|
|
679
52
|
}
|
|
680
53
|
}
|
|
681
54
|
```
|
|
682
55
|
|
|
683
|
-
##
|
|
684
|
-
|
|
685
|
-
```
|
|
686
|
-
@dxtmisha/functional
|
|
687
|
-
├── / # All utilities (recommended)
|
|
688
|
-
├── /flags # Flag utilities
|
|
689
|
-
└── /types/* # TypeScript types
|
|
690
|
-
```
|
|
691
|
-
|
|
692
|
-
## 🔧 Requirements
|
|
693
|
-
|
|
694
|
-
- **Node.js**: ≥18.0.0
|
|
695
|
-
- **TypeScript**: 4.0+ (optional)
|
|
696
|
-
- **Vue**: ≥3.0.0 (optional, only for composables)
|
|
697
|
-
|
|
698
|
-
## 🤝 Compatibility
|
|
699
|
-
|
|
700
|
-
| Environment | Support |
|
|
701
|
-
|-------------|---------|
|
|
702
|
-
| **Browsers** | ✅ ES2020+ (Chrome 80+, Firefox 72+, Safari 13.1+, Edge 80+) |
|
|
703
|
-
| **Node.js** | ✅ 18+ |
|
|
704
|
-
| **Vue.js** | ✅ 3+ (optional) |
|
|
705
|
-
| **TypeScript** | ✅ 4+ |
|
|
706
|
-
| **Vanilla JS** | ✅ Full support |
|
|
707
|
-
| **SSR** | ✅ With environment checks |
|
|
708
|
-
|
|
709
|
-
## 📊 Bundle Size
|
|
710
|
-
|
|
711
|
-
- **Full library**: ~120KB (minified)
|
|
712
|
-
- **With tree-shaking**: only used functions are imported
|
|
713
|
-
- **Minimal import**: ~2KB (single function)
|
|
714
|
-
- **Vue composables**: optional, only when using Vue
|
|
715
|
-
- **Dependencies**: no runtime dependencies
|
|
716
|
-
|
|
717
|
-
## 🎯 Tree-shaking
|
|
718
|
-
|
|
719
|
-
The library fully supports tree-shaking:
|
|
720
|
-
|
|
721
|
-
```typescript
|
|
722
|
-
// ❌ Bad - imports entire library
|
|
723
|
-
import * as functional from '@dxtmisha/functional'
|
|
724
|
-
|
|
725
|
-
// ✅ Good - imports only what's needed
|
|
726
|
-
import { toArray, forEach, Cache } from '@dxtmisha/functional'
|
|
727
|
-
```
|
|
728
|
-
|
|
729
|
-
## 🏆 Advantages
|
|
730
|
-
|
|
731
|
-
- ✅ **Full TypeScript support** — TypeScript out of the box
|
|
732
|
-
- ✅ **Zero dependencies** — no external runtime dependencies
|
|
733
|
-
- ✅ **Tree-shakeable** — optimal bundle size
|
|
734
|
-
- ✅ **SSR friendly** — safe for server-side rendering
|
|
735
|
-
- ✅ **Vue optional** — works with or without Vue
|
|
736
|
-
- ✅ **Comprehensive** — everything you need in one library
|
|
737
|
-
- ✅ **Well documented** — complete documentation
|
|
738
|
-
- ✅ **Production ready** — used in production projects
|
|
739
|
-
- ✅ **Regular updates** — active development and support
|
|
740
|
-
|
|
741
|
-
## 📖 Additional Documentation
|
|
742
|
-
|
|
743
|
-
- [GitHub Repository](https://github.com/dxtmisha/dxt-ui)
|
|
744
|
-
- [Full API Documentation](https://github.com/dxtmisha/dxt-ui/tree/main/packages/wiki/src/media/functional)
|
|
745
|
-
- [DXT UI Documentation](https://dxtmisha.github.io/dxt-ui/)
|
|
746
|
-
|
|
747
|
-
## 🐛 Report Issues
|
|
748
|
-
|
|
749
|
-
If you found a bug or want to suggest an improvement:
|
|
750
|
-
|
|
751
|
-
- [GitHub Issues](https://github.com/dxtmisha/dxt-ui/issues)
|
|
56
|
+
## Principles
|
|
752
57
|
|
|
753
|
-
|
|
58
|
+
- **Full Composition API integration** — every utility is designed with Vue 3's reactivity system in mind, heavily utilizing `ref`, `computed`, and lifecycle hooks.
|
|
59
|
+
- **Separation of concerns** — ideologically encourages extracting validation, state management, and side-effects into specialized classes, maintaining "thin" components.
|
|
60
|
+
- **Type safety** — provides 100% TypeScript type coverage between APIs, storages, and the UI, protecting codebase scaling with smart type inference.
|
|
61
|
+
- **Predictable resource management** — safely manages subscriptions and frees memory. When a component is unmounted, associated tasks and watchers are cleanly terminated.
|
|
754
62
|
|
|
755
|
-
|
|
63
|
+
## Documentation
|
|
756
64
|
|
|
757
|
-
|
|
65
|
+
Full API reference, examples, and guides:
|
|
758
66
|
|
|
759
|
-
|
|
67
|
+
**[📖 https://dxtmisha.github.io/dxt-ui/](https://dxtmisha.github.io/dxt-ui/)**
|
|
760
68
|
|
|
761
|
-
##
|
|
69
|
+
## Difference from @dxtmisha/functional-basic
|
|
762
70
|
|
|
763
|
-
|
|
71
|
+
- **`@dxtmisha/functional-basic`** — core utilities, no framework dependencies. Use this with vanilla JS, React, or any non-Vue stack, or when building a library.
|
|
72
|
+
- **`@dxtmisha/functional`** — extends `functional-basic` with Vue 3 composables and reactive wrappers. Use this when building complex Vue / Nuxt applications.
|
|
764
73
|
|
|
765
|
-
|
|
74
|
+
## License
|
|
766
75
|
|
|
767
|
-
|
|
76
|
+
[MIT](LICENSE)
|