@user-xxy/utils
v0.1.0
Published
Framework-agnostic utility functions for browser & web apps.
Maintainers
Readme
@user-xxy/utils
Framework-agnostic utilities for browser-based web apps. Tree-shakeable,
TypeScript-first, zero runtime dependencies. The request-cancellation helper
accepts axios's CancelToken as an injected argument so you don't have to
install axios unless you actually use it.
pnpm add @user-xxy/utilsModules
number
import { formatNumber, formatToW, numberToChinese, moneyFormat, padZero, getLatencyColor } from '@user-xxy/utils'
formatNumber(1234567) // "1,234,567"
formatToW(12345) // "1.23w"
numberToChinese(42) // "四十二"
moneyFormat('12.3') // "12.30"
padZero(7) // "07"
getLatencyColor(120) // "#FF8C00"string
import { maskString, byteLength, graphemeLength, snakeToCamel, camelToSnake, bin2hex, compareVersion } from '@user-xxy/utils'
maskString('13812345678', { prefix: 3, suffix: 4 }) // "138***5678"
graphemeLength('👨👩👧') // 1
compareVersion('v1.2.3', '1.2.10') // -1date
import { formatDate, formatRelativeDate, formatExpireTime, formatOverdueDuration, getDayRange } from '@user-xxy/utils'
formatDate(Date.now(), 'YYYY/MM/DD') // "2026/05/24"
formatRelativeDate(Date.now() - 86_400_000) // "昨天 12:00"
formatExpireTime(Date.now() + 3 * 86_400_000) // "3天后过期"
getDayRange([new Date(), new Date()])
// { start_time: '2026/05/24 00:00:00', end_time: '2026/05/24 23:59:59' }function
import { debounce, throttle, sleep, retry, withLoading, runWithLoading } from '@user-xxy/utils'
const onResize = debounce(() => layout(), 200)
const onScroll = throttle(() => sync(), 100)
await sleep(500)
await retry(() => fetchUser(id), { retries: 3, backoff: 2 })
// withLoading decouples UI from business logic
const loadable = withLoading(api.save, {
start: () => ElLoading.service({ text: '保存中...' }),
stop: (h) => h.close(),
})
await loadable(payload)object
import { deepClone, filterEmpty, enumToOptions, findLabel, removeByIds, setSingleKeyTrue, groupBy } from '@user-xxy/utils'
filterEmpty({ a: 1, b: '', c: null }) // { a: 1 }
enumToOptions(Status) // [{ label, value }, ...]
removeByIds(items, [2, 4])
setSingleKeyTrue({ a: true, b: false, c: false }, 'b')browser
import {
isBrowser, isMobileDevice, isMobileViewport, isIOS, isWechat, isTouchSupported,
getUrlParams, parseUrl, copyToClipboard, downloadBlob, downloadFile, setupRem, uuid,
} from '@user-xxy/utils'
await copyToClipboard('hello')
const stop = setupRem({ designWidth: 375, baseSize: 37.5 })
// later (e.g. unmount)
stop()image
import { compressImage, imageToBase64, captureVideoFrame, pickFile } from '@user-xxy/utils'
const file = await pickFile({ accept: '.xlsx' })
const small = await compressImage(file as File, { targetSize: 500 })
const poster = await captureVideoFrame('https://x.com/v.mp4')storage
import { createStorage, setItemWithExpiry, getItemWithExpiry } from '@user-xxy/utils'
const cache = createStorage({ prefix: 'app.' })
cache.set('user', { id: 1 })
cache.get<{ id: number }>('user')?.id
setItemWithExpiry('token', 'abc', 60_000)
const token = getItemWithExpiry<string>('token')http — request-cancellation
import axios from 'axios'
import { createPendingRequests } from '@user-xxy/utils'
const pending = createPendingRequests(axios.CancelToken)
const instance = axios.create({ baseURL: '/api' })
instance.interceptors.request.use((cfg) => {
pending.remove(cfg) // cancel a duplicate in flight
pending.add(cfg)
return cfg
})
instance.interceptors.response.use(
(res) => { pending.remove(res.config); return res },
(err) => { if (err?.config) pending.remove(err.config); return Promise.reject(err) },
)wechat
import { getWxSignUrl, resetWxSignUrl, initWxJsSdk, wxScanQRCode } from '@user-xxy/utils'
const url = getWxSignUrl() // iOS-safe (persists first URL)
const sig = await fetchSign(url) // your backend
await initWxJsSdk({ appId, timestamp, nonceStr, signature: sig, jsApiList: ['scanQRCode'] })
const code = await wxScanQRCode()validate
import { validators, inputFilters } from '@user-xxy/utils'
validators.mobileCN('13812345678') // true
validators.email('[email protected]') // true
// in an input handler
input.value = inputFilters.decimal(input.value, 2)
input.value = inputFilters.integer(input.value)
input.value = inputFilters.percentInt(input.value)License
MIT
