@startlibs/utils 1.0.3 → 1.1.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.
Files changed (63) hide show
  1. package/lib/ActionUtils.mjs +117 -0
  2. package/lib/ActionUtils.mjs.map +1 -0
  3. package/lib/FetchUtils.mjs +100 -0
  4. package/lib/FetchUtils.mjs.map +1 -0
  5. package/lib/createPressEvent.mjs +74 -0
  6. package/lib/createPressEvent.mjs.map +1 -0
  7. package/lib/fixMediaQuery.mjs +64 -0
  8. package/lib/fixMediaQuery.mjs.map +1 -0
  9. package/lib/formatDate.mjs +110 -0
  10. package/lib/formatDate.mjs.map +1 -0
  11. package/lib/formatUtils.mjs +64 -0
  12. package/lib/formatUtils.mjs.map +1 -0
  13. package/lib/getClosestOffsetScroll.mjs +15 -0
  14. package/lib/getClosestOffsetScroll.mjs.map +1 -0
  15. package/lib/hooks/useEventListener.mjs +27 -0
  16. package/lib/hooks/useEventListener.mjs.map +1 -0
  17. package/lib/index.cjs +1811 -0
  18. package/lib/index.cjs.map +1 -0
  19. package/lib/index.mjs +19 -0
  20. package/lib/index.mjs.map +1 -0
  21. package/lib/lodashUtils.mjs +131 -0
  22. package/lib/lodashUtils.mjs.map +1 -0
  23. package/lib/promiseUtils.mjs +92 -0
  24. package/lib/promiseUtils.mjs.map +1 -0
  25. package/lib/reactUtils.mjs +12 -0
  26. package/lib/reactUtils.mjs.map +1 -0
  27. package/lib/reduceUtils.mjs +14 -0
  28. package/lib/reduceUtils.mjs.map +1 -0
  29. package/lib/smoothScroll.mjs +59 -0
  30. package/lib/smoothScroll.mjs.map +1 -0
  31. package/lib/styled.mjs +234 -0
  32. package/lib/styled.mjs.map +1 -0
  33. package/lib/timeUtils.mjs +81 -0
  34. package/lib/timeUtils.mjs.map +1 -0
  35. package/lib/timerUtils.mjs +11 -0
  36. package/lib/timerUtils.mjs.map +1 -0
  37. package/lib/utils.mjs +386 -0
  38. package/lib/utils.mjs.map +1 -0
  39. package/lib/wrapLazy.mjs +132 -0
  40. package/lib/wrapLazy.mjs.map +1 -0
  41. package/package.json +44 -30
  42. package/src/ActionUtils.js +90 -0
  43. package/src/FetchUtils.js +87 -0
  44. package/src/createPressEvent.jsx +79 -0
  45. package/src/fixMediaQuery.js +71 -0
  46. package/src/formatDate.js +121 -0
  47. package/src/formatUtils.jsx +63 -0
  48. package/src/getClosestOffsetScroll.js +12 -0
  49. package/src/hooks/useEventListener.js +26 -0
  50. package/src/index.js +19 -0
  51. package/src/lodashUtils.jsx +110 -0
  52. package/src/promiseUtils.jsx +75 -0
  53. package/src/reactUtils.jsx +7 -0
  54. package/src/reduceUtils.jsx +6 -0
  55. package/src/smoothScroll.js +58 -0
  56. package/src/styled.js +177 -0
  57. package/src/timeUtils.jsx +57 -0
  58. package/src/timerUtils.jsx +10 -0
  59. package/src/utils.jsx +342 -0
  60. package/src/wrapLazy.jsx +122 -0
  61. package/.babelrc +0 -26
  62. package/lib/index.js +0 -2382
  63. package/rollup.config.js +0 -44
package/package.json CHANGED
@@ -1,44 +1,44 @@
1
1
  {
2
2
  "name": "@startlibs/utils",
3
- "version": "1.0.3",
3
+ "version": "1.1.0",
4
4
  "description": "Startlibs Utils",
5
- "main": "lib/index.js",
5
+ "main": "lib/index.cjs",
6
+ "exports": {
7
+ ".": {
8
+ "source": "./src/index.js",
9
+ "require": "./lib/index.cjs",
10
+ "import": "./lib/index.mjs",
11
+ "default": "./lib/index.mjs"
12
+ },
13
+ "./package.json": "./package.json",
14
+ "./*": {
15
+ "import": "./lib/*.mjs"
16
+ }
17
+ },
6
18
  "sideEffects": false,
7
- "source": true,
19
+ "source": "./src/index.js",
8
20
  "peerDependencies": {
9
- "@startlabs/core": "^1.0.0",
10
- "create-emotion": "*",
11
- "lodash": "*",
12
- "react": "*",
13
- "react-dom": "*",
14
- "styled-components": "^5.1.1"
21
+ "@startlibs/core": "*",
22
+ "lodash": "^4.17.21",
23
+ "react": ">=16.8",
24
+ "styled-components": ">=5"
15
25
  },
16
26
  "devDependencies": {
17
- "@babel/core": "^7.2.0",
18
- "@babel/plugin-external-helpers": "^7.2.0",
19
- "@babel/plugin-proposal-class-properties": "^7.2.1",
20
- "@babel/plugin-proposal-export-namespace-from": "^7.2.0",
21
- "@babel/plugin-proposal-json-strings": "^7.2.0",
22
- "@babel/plugin-proposal-object-rest-spread": "^7.2.0",
23
- "@babel/plugin-proposal-optional-chaining": "^7.12.0",
24
- "@babel/plugin-proposal-throw-expressions": "^7.2.0",
25
- "@babel/plugin-syntax-dynamic-import": "^7.2.0",
26
- "@babel/plugin-syntax-import-meta": "^7.2.0",
27
- "@babel/plugin-transform-runtime": "^7.2.0",
28
- "@babel/plugin-transform-spread": "^7.2.0",
29
- "@babel/plugin-transform-unicode-property-regex": "^7.27.1",
30
- "@babel/preset-env": "^7.2.0",
31
- "@babel/preset-flow": "^7.0.0",
32
- "@babel/preset-react": "^7.0.0",
27
+ "@babel/core": "^7.26.0",
28
+ "@babel/plugin-transform-runtime": "^7.26.0",
29
+ "@babel/preset-env": "^7.26.0",
30
+ "@babel/preset-flow": "^7.25.0",
31
+ "@babel/preset-react": "^7.26.0",
33
32
  "babel-plugin-lodash": "^3.3.4",
34
33
  "babel-plugin-macros": "^2.4.2",
35
34
  "babel-plugin-styled-components": "^1.10.0",
36
- "fbjs-scripts": "^0.6.0-alpha.3",
37
- "rollup": "^2.16.1",
35
+ "lodash": "^4.17.21",
36
+ "rollup": "^2.79.2",
38
37
  "rollup-plugin-auto-external": "^2.0.0",
39
38
  "rollup-plugin-babel": "^4.0.3",
40
39
  "rollup-plugin-commonjs": "^9.2.0",
41
- "rollup-plugin-node-resolve": "^3.4.0"
40
+ "rollup-plugin-node-resolve": "^3.4.0",
41
+ "styled-components": "^5.3.11"
42
42
  },
43
43
  "scripts": {
44
44
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -59,7 +59,21 @@
59
59
  },
60
60
  "homepage": "https://github.com/felipeko/startlibs#readme",
61
61
  "dependencies": {
62
+ "@babel/runtime": "^7.20.0",
62
63
  "create-emotion": "10.0.27",
63
- "styled-components": "5.1.1"
64
- }
64
+ "polished": "^2.0.0 || ^3.0.0 || ^4.0.0"
65
+ },
66
+ "files": [
67
+ "lib",
68
+ "src"
69
+ ],
70
+ "module": "lib/index.mjs",
71
+ "browserslist": [
72
+ "chrome >= 61",
73
+ "edge >= 79",
74
+ "firefox >= 60",
75
+ "safari >= 11",
76
+ "ios_saf >= 11",
77
+ "samsung >= 8.2"
78
+ ]
65
79
  }
@@ -0,0 +1,90 @@
1
+ import {useMemo} from 'react'
2
+ import {callIfFunction} from './utils'
3
+ import {_s} from './lodashUtils'
4
+ import _ from 'lodash/fp'
5
+
6
+ const isNotSelector = (v) => (typeof v !== 'function' || v.length === 0)
7
+
8
+ const toSelector = (v) => isNotSelector(v) ? (s) => _s.get(callIfFunction(v),s) : v
9
+
10
+ const mergeSelectors = (prev, next) => (v) => next(prev(v))
11
+ export const concatSelectors = (...paths) => paths.reduce(([selector, isSelector], path) =>
12
+ isNotSelector(path) && !isSelector
13
+ ? [selector.concat(path), false]
14
+ : [mergeSelectors(toSelector(selector), path), true],
15
+ [[], false]
16
+ )
17
+
18
+ export const COMPLETE_ACTION = {}
19
+ export const REDUCE = {}
20
+ export const FETCH = {}
21
+ export const SKIP_FETCH = {}
22
+ export const SKIP_DISPATCH = {}
23
+ export const SKIPPED_ACTION = {}
24
+
25
+ const ACTION_TYPES = [COMPLETE_ACTION,REDUCE,FETCH,SKIP_FETCH,SKIP_DISPATCH]
26
+
27
+ export const selectPath = (useState, ...paths) => {
28
+ const [selector] = useMemo(() => concatSelectors(...paths), paths)
29
+ const [value] = useState(selector)
30
+ return value
31
+ }
32
+
33
+ export const Action = (fnOrArray, prevArgs = []) => {
34
+ const isArray = Array.isArray(fnOrArray)
35
+ if (isArray) {
36
+ // excessive paramaeters called on the action, used for options.
37
+ const actionType = _.last(prevArgs)
38
+ const [fetcher, reducer, rollbacker] = fnOrArray
39
+ if (actionType === REDUCE) {
40
+ return reducer(null,prevArgs)
41
+ } else if (actionType === FETCH) {
42
+ return fetcher()
43
+ } else {
44
+ return _.set('extra',fnOrArray.extra,[
45
+ actionType === SKIP_FETCH ? () => Promise.resolve() : fetcher,
46
+ actionType === SKIP_DISPATCH ? undefined : reducer,
47
+ ].concat(rollbacker || []))
48
+ }
49
+ } else {
50
+ return prevArgs.length < fnOrArray.length ? (...moreArgs) => Action(fnOrArray,[...prevArgs,...moreArgs]) : Action(fnOrArray(...prevArgs),prevArgs)
51
+ }
52
+ }
53
+
54
+ const mapAction = (get, dispatcher, firstRun) => (action) => {
55
+ if (Array.isArray(action)) {
56
+ if (firstRun) {
57
+ return () => mapAction(get,dispatcher)(action)
58
+ }
59
+ const [fetcher, reducer, rollbacker] = action
60
+ const {skip} = action.extra || {}
61
+ if (skip && skip(get())) {
62
+ return Promise.resolve(SKIPPED_ACTION)
63
+ }
64
+ const fetched = fetcher()
65
+ if (rollbacker) {
66
+ dispatcher(prevState => {
67
+ const nextState = reducer(null)(prevState)
68
+ fetched.catch((response)=> {
69
+ dispatcher(rollbacker(prevState,nextState,response))
70
+ })
71
+ return nextState
72
+ })
73
+ }
74
+ if (reducer !== undefined) {
75
+ fetched.then((response) => dispatcher(reducer(response)))
76
+ }
77
+ return fetched
78
+ } else {
79
+ return (...moreMetas) => mapAction(get,dispatcher)(action(...moreMetas))
80
+ }
81
+ }
82
+
83
+ export const activateActions = (get, dispatcher, ...actions) => {
84
+ return actions.map(mapAction(get, dispatcher,true))
85
+ }
86
+
87
+ export const SkipAction = (skip,action) => {
88
+ action.extra = {...action.extra,skip}
89
+ return action
90
+ }
@@ -0,0 +1,87 @@
1
+ import {callIfFunction} from './utils'
2
+ import _ from 'lodash/fp'
3
+
4
+ const resolveFetch = async (url, fetchOptions) => {
5
+ try {
6
+ const response = await fetch(url, {
7
+ credentials: 'same-origin',
8
+ ...fetchOptions
9
+ })
10
+ const text = await response.text()
11
+ try {
12
+ const json = JSON.parse(text)
13
+ return [json, response]
14
+ } catch (eror) {
15
+ return [text, response]
16
+ }
17
+ } catch (error) {
18
+ return [error, false]
19
+ }
20
+ }
21
+
22
+ const innerFetcher = async (url, fetchOptions) => {
23
+ const [data, response] = await resolveFetch(url, fetchOptions)
24
+ if (!response || response.status >= 400) {
25
+ throw [data, response]
26
+ } else {
27
+ return [data, response]
28
+ }
29
+ }
30
+ export const queryStringToObj = (str = window.location.search) => Object.fromEntries(new URLSearchParams(str).entries())
31
+
32
+ export const addQueryString = (existingUrl = '',obj) => {
33
+ const [onlyUrl, otherQueryString] = existingUrl.split('?')
34
+ const params = new URLSearchParams(otherQueryString)
35
+ for (let key in obj) {
36
+ const value = obj[key]
37
+ if (value === null) {
38
+ params.delete(key)
39
+ } else {
40
+ params.set(key, obj[key])
41
+ }
42
+ }
43
+ const paramsStr = params.toString()
44
+ if (!paramsStr) {
45
+ return onlyUrl
46
+ }
47
+ return onlyUrl + '?' + paramsStr
48
+ }
49
+
50
+ const cleanNulls = (str) => str.replace(/\0/g, '')
51
+
52
+ // Cross-origin o X-Requested-With só custa: dispara preflight e impede o reuso do
53
+ // <link rel=preload as=fetch>, cujo request vai sem ele. Quem lê o header é servidor nosso.
54
+ const isSameOrigin = (url) => new URL(url, window.location.href).origin === window.location.origin
55
+
56
+ export let postFetcherWithResponse = async (url, jsonOrForm, fetchOptions = {}) => innerFetcher(url, {
57
+ method: 'POST',
58
+ body: typeof jsonOrForm === 'string'
59
+ ? jsonOrForm
60
+ : !jsonOrForm || jsonOrForm.constructor === window.FormData || jsonOrForm.constructor === window.File
61
+ ? jsonOrForm
62
+ : cleanNulls(JSON.stringify(jsonOrForm)),
63
+ ...fetchOptions,
64
+ headers:
65
+ (_.isPlainObject(fetchOptions.headers) || !fetchOptions.headers)
66
+ ? {
67
+ ...(jsonOrForm && (typeof jsonOrForm === 'string' || jsonOrForm.constructor === window.FormData) ? {} : {'Content-Type': 'application/json; charset=UTF-8'}),
68
+ ...(isSameOrigin(url) ? {'X-Requested-With': 'XMLHttpRequest'} : {}),
69
+ ...fetchOptions.headers
70
+ }
71
+ : fetchOptions.headers
72
+ })
73
+
74
+ export let getFetcherWithResponse = async (url, jsonParams, fetchOptions) => innerFetcher(addQueryString(url, jsonParams), {
75
+ method: 'GET',
76
+ ...fetchOptions,
77
+ headers: {
78
+ ...(isSameOrigin(url) ? {'X-Requested-With': 'XMLHttpRequest'} : {}),
79
+ ...fetchOptions?.headers
80
+ }
81
+ })
82
+
83
+ export let postFetcher = async (url, json, options) => postFetcherWithResponse(url, json, options).then(([json]) => json)
84
+ export let getFetcher = async (url, json, options) => getFetcherWithResponse(url, json, options).then(([json]) => json)
85
+
86
+ export const formFetchWithResponse = (url, options) => (values, meta) => postFetcherWithResponse(callIfFunction(url, meta, values), values, callIfFunction(options, meta, values))
87
+ export const formFetch = (url, options) => (values, meta) => postFetcher(callIfFunction(url, meta, values), values, callIfFunction(options, meta, values))
@@ -0,0 +1,79 @@
1
+ import React from 'react'
2
+ import {callIfFunction, normalizePress} from './utils'
3
+
4
+
5
+ const disableSelect = (e) => {
6
+ e.preventDefault();
7
+ }
8
+
9
+ export const createPressEvent = (onStart) => normalizePress((startEvent, info) => {
10
+ const onEnd = onStart(startEvent,info)
11
+
12
+ const finish = normalizePress((e,info) => {
13
+ callIfFunction(onEnd,e,info)
14
+ window.removeEventListener('selectstart', disableSelect)
15
+ window.removeEventListener('touchend',finish)
16
+ window.removeEventListener('mouseup',finish)
17
+ })
18
+
19
+
20
+ window.addEventListener('selectstart', disableSelect);
21
+ if (startEvent.touches) {
22
+ window.addEventListener('touchend', finish)
23
+ } else {
24
+ window.addEventListener("mouseup", finish);
25
+ }
26
+
27
+ })
28
+
29
+ export const createPressAndHoldEvent = (onStart,interval) => createPressEvent((startEvent,info) => {
30
+
31
+ const [onInterval,onEnd] = [].concat(onStart(startEvent,info))
32
+
33
+ let i = 0;
34
+ if (interval) {
35
+ const intervalId = setInterval(() => {
36
+ onInterval(i++)
37
+ }, interval)
38
+
39
+ return normalizePress((e, info) => {
40
+ callIfFunction(onEnd, e, info)
41
+ clearInterval(intervalId)
42
+ })
43
+ } else {
44
+ let running = true
45
+ const run = () => window.requestAnimationFrame(() => {
46
+ if (running) {
47
+ onInterval(i++)
48
+ run()
49
+ }
50
+ })
51
+ run()
52
+ return normalizePress((e,info) => {
53
+ callIfFunction(onEnd, e, info)
54
+ running = false
55
+ })
56
+ }
57
+ })
58
+
59
+
60
+ export const createPressAndMoveEvent = (onStart) => createPressEvent((startEvent, info) => {
61
+
62
+ const [onMove,onEnd] = [].concat(onStart(startEvent,info))
63
+
64
+ const finish = normalizePress((e,info) => {
65
+ callIfFunction(onEnd,e,info)
66
+ window.removeEventListener('touchmove',move)
67
+ window.removeEventListener('mousemove',move)
68
+ })
69
+ const move = normalizePress(onMove,finish)
70
+
71
+ if (startEvent.touches) {
72
+ window.addEventListener('touchmove', move, {passive: false})
73
+ } else {
74
+ window.addEventListener("mousemove", move);
75
+ }
76
+
77
+ return finish
78
+ })
79
+
@@ -0,0 +1,71 @@
1
+ let fixed = false
2
+ export const scrollWidth = (function() {
3
+ if (!window.document) return 0
4
+ const html = document.documentElement
5
+ const oldOverflow = html.style.overflowY
6
+ html.style.overflowY = 'scroll'
7
+ const width = window.innerWidth - html.clientWidth
8
+ html.style.overflowY = oldOverflow
9
+ return width
10
+ })()
11
+
12
+ const fixMediaQueryFn = function() {
13
+
14
+ const fontSize = parseFloat(window.getComputedStyle(document.body).getPropertyValue('font-size'))
15
+
16
+ if (scrollWidth > 0) {
17
+
18
+ [].slice.call(document.styleSheets).filter(styleSheet => isValidExternal(styleSheet) || isInline(styleSheet)).forEach(stylesheet => {
19
+ try {
20
+ [].slice.call(stylesheet.cssRules || stylesheet.media).filter(rule => rule.constructor === window.CSSMediaRule).forEach(rule => {
21
+ rule.media.mediaText = rule.media.mediaText.replace(/m(in|ax)-width:\s*(\d|\.)+(px|em)/gi, function(strA) {
22
+ if (strA.match('px')) {
23
+ return strA.replace(/\d+px/gi, function(strB) {
24
+ return parseInt(strB, 10) + scrollWidth + 'px'
25
+ })
26
+ }
27
+ else {
28
+ return strA.replace(/\d.+?em/gi, function(strB) {
29
+ return ((parseFloat(strB) * fontSize) + scrollWidth) / fontSize + 'em'
30
+ })
31
+ }
32
+ })
33
+ })
34
+ } catch (e) {}
35
+ })
36
+ }
37
+
38
+ fixed = true
39
+
40
+ function sameOrigin(url) {
41
+ const loc = window.location,
42
+ a = document.createElement('a')
43
+ a.href = url
44
+ return (a.hostname === loc.hostname && a.protocol === loc.protocol)
45
+ }
46
+
47
+ function isInline(stylesheet) {
48
+ try {
49
+ return stylesheet.ownerNode.constructor === HTMLStyleElement && stylesheet.ownerNode.getAttribute("data-styled") === null
50
+ } catch (e) {
51
+ return stylesheet.ownerNode.constructor === HTMLStyleElement
52
+ }
53
+ }
54
+
55
+ function isValidExternal(stylesheet) {
56
+ return stylesheet.href && (sameOrigin(stylesheet.href) || stylesheet.ownerNode?.crossOrigin === "anonymous")
57
+ }
58
+
59
+ }
60
+
61
+
62
+ export function fixMediaQuery() {
63
+ if (fixed || !document || !document.readyState)
64
+ return
65
+ if (process.env.NODE_ENV === 'test') { return }
66
+ if (document.readyState !== 'loading') {
67
+ fixMediaQueryFn()
68
+ } else {
69
+ document.addEventListener('DOMContentLoaded', fixMediaQueryFn)
70
+ }
71
+ }
@@ -0,0 +1,121 @@
1
+
2
+ const escapedValidParts = /(^|[^\\])(dd?|DD?|mm?|LL?|hh?|MM?|ss|SSS|yy(?:yy)?)/g
3
+ const validParts = /(dd?|DD?|mm?|LL?|hh?|MM?|yy(?:yy)|yy|ss|SSS)$/
4
+ export const addZero = (v) => (v < 10 ? '0' : '') + v
5
+
6
+ const getSet = (index, ttype, plus = 0, format = (v) => v, parse = (v, defaultDate) => (v === '0' ? '' : v)) => ([
7
+ (date,_,noUTC) => format((typeof date === 'number' ? new Date(date) : date)['get'+(noUTC?'':'UTC') + ttype]() + plus),
8
+ (unformatedStr, date, _, failOnFormat, noUTC) => {
9
+ const str = parse(unformatedStr, date, failOnFormat)
10
+ if (str === '' || isNaN(date.getTime()))
11
+ return date
12
+ if (str=== '\0')
13
+ return date.setTime(NaN)
14
+ const utcSTR = noUTC ? '' : 'UTC'
15
+ const v = parseInt(str, 10) - plus
16
+ const prevDay = date['get'+utcSTR+'Date']()
17
+ if (ttype !== 'Date') {
18
+ date['set'+utcSTR+'Date'](1)
19
+ }
20
+ date['set'+ utcSTR + ttype](v)
21
+ if (date['get' + utcSTR + ttype]() !== v) {
22
+ date['set' + utcSTR + ttype](NaN)
23
+ return date
24
+ }
25
+ if (ttype !== 'Date') {
26
+ date['set'+utcSTR+'Date'](prevDay)
27
+ if (date['get' + utcSTR + ttype]() !== v) {
28
+ date['set'+utcSTR+'Date'](0)
29
+ return date
30
+ }
31
+ }
32
+ return date
33
+ },
34
+ index
35
+ ])
36
+
37
+ const getText = (type, total, slice = 99) => [
38
+ (date, messages,noUTC) => messages(type.toLowerCase(),date['get'+(noUTC? '': 'UTC') + type]()).slice(0, slice)
39
+ ]
40
+
41
+ const yearParse = (y, date, failOnFormat) => {
42
+ const formattedY = y.length === 2 && y !== '20' ? '20' + y : y.length === 4 ? y : ''
43
+ if (formattedY === '') {
44
+ if (failOnFormat) {
45
+ const found = date.getUTCFullYear().toString().indexOf(y)
46
+ return found === 0 || found === 2 ? date.getUTCFullYear() : '\0'
47
+ } else {
48
+ return date.getUTCFullYear()
49
+ }
50
+ } else {
51
+ return formattedY
52
+ }
53
+ }
54
+
55
+ const val = {
56
+ yyyy: getSet(0,'FullYear', 0, (v) => v, yearParse),
57
+ yy: getSet(0,'FullYear', 0, (v) => (v+"").slice(2,4), yearParse),
58
+ M: getSet(1,'Month', 1),
59
+ MM: getSet(1,'Month', 1, addZero),
60
+ L: getText('Month',12,3),
61
+ LL: getText('Month',12),
62
+ d: getSet(2,'Date'),
63
+ dd: getSet(2,'Date', 0, addZero),
64
+ D: getText('Day', 7, 3),
65
+ DD: getText('Day', 7),
66
+ m: getSet(4,'Minutes'),
67
+ mm: getSet(4,'Minutes', 0, addZero),
68
+ h: getSet(5,'Hours'),
69
+ hh: getSet(5,'Hours', 0, addZero),
70
+ ss: getSet(6,'Seconds', 0, addZero),
71
+ SSS: getSet(7,'Milliseconds', 0, addZero),
72
+
73
+ }
74
+
75
+ export function formatDateToPattern(format) {
76
+ return format.replace(escapedValidParts, (_, _1, _2) => _1 + (_2 === 'yy' ? '##' : _2 === 'yyyy' ? '####' : '0#'))
77
+ }
78
+
79
+ export function formatDate(date, format, messages,noUTC) {
80
+ if (!date)
81
+ return ''
82
+ const separators = format.replace(escapedValidParts, '\0').split('\0')
83
+ const parts = format.match(escapedValidParts)
84
+ const formattedDate = parts.reduce((acc, part) =>
85
+ acc.concat(
86
+ separators.length ? [separators.shift()] : [],
87
+ part.replace(validParts, ''),
88
+ val[part.match(validParts)[0]][0](date, messages,noUTC)
89
+ ),
90
+ []
91
+ )
92
+ return formattedDate.join('').replace(/\\([dDmLhMy])/g, '$1')
93
+ }
94
+
95
+ const now = () => new Date()
96
+
97
+ export function parseDate(str, possibleDate, format, messages, failOnFormat, noUTC) {
98
+ if (!str)
99
+ return possibleDate
100
+ const separators = format.replace(escapedValidParts, '\0').split('\0')
101
+ const parts = format.match(escapedValidParts)
102
+ const mutations = []
103
+ parts.reduce((rest, part, i) => {
104
+ const separator = (separators.length ? separators.shift() : '') + part.replace(validParts, '')
105
+ const current = rest.slice(separator.length)
106
+ if (current && separator === rest.slice(0, separator.length)) {
107
+ const setType = part.match(validParts)[0]
108
+ const nextSeparator = separators[0]
109
+ const nextStrIndex = current.indexOf(nextSeparator + (parts[i + 1] || '').replace(validParts, ''))
110
+ mutations[val[setType][2]] = [val[setType][1],nextStrIndex ? current.slice(0,nextStrIndex) : current]
111
+ return current.slice(nextStrIndex)
112
+ } else {
113
+ return ''
114
+ }
115
+ },
116
+ str
117
+ )
118
+ const date = possibleDate && possibleDate.getTime()!==-1 ? new Date(possibleDate) : now()
119
+ mutations.forEach(([setter,text])=> setter(text,date,messages,failOnFormat,noUTC))
120
+ return date
121
+ }
@@ -0,0 +1,63 @@
1
+ import React from 'react'
2
+ import _ from 'lodash/fp'
3
+
4
+ export const formatJoin = (arr,separator = ', ', lastSeparator = ' e ') => [arr.slice(0,-1).join(separator),arr.slice(-1)].join(lastSeparator)
5
+
6
+ export const formatJoinArr = (arr,separator,lastSeparator) =>
7
+ arr.flatMap((v,i) => i < arr.length - 2 ? [v,separator] : (i < arr.length - 1 ? [v,lastSeparator] : [v]))
8
+
9
+ export const removeAccents = (str) => (str||"").normalize('NFD').replace(/\p{Diacritic}/gu, "")
10
+ export const asciify = (str) => removeAccents(str||"").replace(/[^\x00-\x7F]/g, "")
11
+ export const normalizeText = (str) => removeAccents(str).toLowerCase()
12
+ export const normalizeTextUrl = (str) => removeAccents(str).replace(/[\s.\u0022&/]/g, '-').replace(/-{2,}/g,'-').toLowerCase()
13
+
14
+
15
+ export const willFormatDecimal = (digits = 2,{max,min,padTo,zeroless,clean} = {}) => {
16
+ const splitRegex = new RegExp(`(\\d+)(\\d{${digits}})`)
17
+ const singleRegex = new RegExp(`/^([^,]*,\\d{0,${digits}).*/`)
18
+ const pad = (str) =>
19
+ padTo
20
+ ? (str.indexOf(",") >= 0
21
+ ? _.padCharsEnd("0", str.indexOf(",") + padTo + 1,str)
22
+ : _.padCharsEnd("0", str.length + 1 + padTo, str + ",")
23
+ )
24
+ : str
25
+ const constrain = (val) => {
26
+ if (_.isNumber(max) && parseFloat(val.replace(",",".")) > max) return max.toString()
27
+ if (_.isNumber(min) && parseFloat(val.replace(",",".")) < min) return min.toString()
28
+ return val
29
+ }
30
+ const cleaned = (val) =>
31
+ clean
32
+ ? (val.replace(/,$/,'').replace(/^0*,/,'0,') || "0")
33
+ : val
34
+
35
+ return (v) => {
36
+ const skipZero = (finalV) => v!=='0' && zeroless && finalV === '0' ? '' : finalV.replace(/^0+([^,])/,'$1')
37
+ const formatted = _.flow(constrain,pad,skipZero,cleaned)
38
+ if (_.isNumber(v)) {
39
+ return formatted(v.toString().replace(".",","))
40
+ }
41
+ const fixComma = (v) => v.replace(/,/g, '').replace(splitRegex, "$1,$2")
42
+
43
+ const format = () => {
44
+ const allowedChars = (v||"").replace(/[^\d,]/g, "")
45
+ const commaIndex = allowedChars.indexOf(',')
46
+ if (commaIndex >= 0 && commaIndex < allowedChars.length - 1 - digits) {
47
+ const alteredComma = fixComma(allowedChars)
48
+ if (_.isNumber(max) && parseFloat(alteredComma.replace(",",".")) > max) {
49
+ return fixComma(allowedChars.slice(0, commaIndex + 1 + digits))
50
+ }
51
+ return alteredComma
52
+ }
53
+ const simpleNumber = allowedChars.replace(singleRegex, "$1")
54
+ if (_.isNumber(max) && parseInt(simpleNumber) > max) {
55
+ return simpleNumber.slice(0, -1)
56
+ }
57
+ return simpleNumber
58
+ }
59
+ const result = format()
60
+ return formatted(result)
61
+ }
62
+ }
63
+ export const parseDecimalToNumber = (v) => _.isString(v) ? Number(v.replace(/\./g,'').replace(',', ".")) : (v || 0)
@@ -0,0 +1,12 @@
1
+ export const getClosestOffsetScroll = (node) => {
2
+ if (!node) {
3
+ return ((document.body))
4
+ }
5
+ const overflowY = window.getComputedStyle(node).overflowY
6
+ const isScrollable = overflowY !== 'visible' && overflowY !== 'hidden';
7
+ if (isScrollable && node.scrollHeight > node.clientHeight) {
8
+ return node;
9
+ } else {
10
+ return getClosestOffsetScroll((node.offsetParent));
11
+ }
12
+ }
@@ -0,0 +1,26 @@
1
+ import {useEffect} from 'react'
2
+
3
+ export const useEventListener = (eventName,callback,deps = []) => {
4
+ useEffect(() => {
5
+ window.addEventListener(eventName,callback)
6
+ return () => window.removeEventListener(eventName,callback)
7
+ },deps)
8
+
9
+ }
10
+
11
+ export const useEventListenerIf = (check,eventName,callback,deps = []) => {
12
+ useEffect(() => {
13
+ if (!check()) return
14
+ window.addEventListener(eventName,callback)
15
+ return () => window.removeEventListener(eventName,callback)
16
+ },deps)
17
+
18
+ }
19
+
20
+ export const useEventListenerFor = (element,eventName,callback,deps = []) => {
21
+ useEffect(() => {
22
+ element.addEventListener(eventName,callback)
23
+ return () => element.removeEventListener(eventName,callback)
24
+ },deps.concat(element))
25
+
26
+ }
package/src/index.js ADDED
@@ -0,0 +1,19 @@
1
+ export * from './promiseUtils'
2
+ export * from './getClosestOffsetScroll'
3
+ export * from './smoothScroll'
4
+ export * from './fixMediaQuery'
5
+ export * from './FetchUtils'
6
+ export * from './styled'
7
+ export * from './formatDate'
8
+ export * from './lodashUtils'
9
+ export * from './ActionUtils'
10
+ export * from './reduceUtils'
11
+ export * from './reactUtils'
12
+ export * from './hooks/useEventListener'
13
+ export * from './utils'
14
+ export * from './createPressEvent'
15
+ export * from './wrapLazy'
16
+ export * from './timeUtils'
17
+ export * from './timerUtils'
18
+ export * from './formatUtils'
19
+