@startlibs/utils 1.1.2 → 1.2.0-rc.2

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 (107) hide show
  1. package/lib/ActionUtils.mjs +4 -4
  2. package/lib/ActionUtils.mjs.map +1 -1
  3. package/lib/FetchUtils.mjs.map +1 -1
  4. package/lib/animationKeyframes.mjs +11 -0
  5. package/lib/animationKeyframes.mjs.map +1 -0
  6. package/lib/createPressEvent.mjs +1 -1
  7. package/lib/createPressEvent.mjs.map +1 -1
  8. package/lib/fixMediaQuery.mjs +43 -17
  9. package/lib/fixMediaQuery.mjs.map +1 -1
  10. package/lib/fixMediaText.mjs +16 -0
  11. package/lib/fixMediaText.mjs.map +1 -0
  12. package/lib/formatDate.mjs.map +1 -1
  13. package/lib/formatUtils.mjs +2 -2
  14. package/lib/formatUtils.mjs.map +1 -1
  15. package/lib/getClosestOffsetScroll.mjs.map +1 -1
  16. package/lib/hooks/useEventListener.mjs.map +1 -1
  17. package/lib/index.cjs +311 -199
  18. package/lib/index.cjs.map +1 -1
  19. package/lib/index.mjs +5 -3
  20. package/lib/index.mjs.map +1 -1
  21. package/lib/insertKeyframes.mjs +68 -0
  22. package/lib/insertKeyframes.mjs.map +1 -0
  23. package/lib/lodashUtils.mjs +6 -6
  24. package/lib/lodashUtils.mjs.map +1 -1
  25. package/lib/promiseUtils.mjs.map +1 -1
  26. package/lib/reactUtils.mjs +1 -1
  27. package/lib/reactUtils.mjs.map +1 -1
  28. package/lib/reduceUtils.mjs.map +1 -1
  29. package/lib/smoothScroll.mjs.map +1 -1
  30. package/lib/styled.mjs +25 -144
  31. package/lib/styled.mjs.map +1 -1
  32. package/lib/styledShared.mjs +125 -0
  33. package/lib/styledShared.mjs.map +1 -0
  34. package/lib/timeUtils.mjs +1 -1
  35. package/lib/timeUtils.mjs.map +1 -1
  36. package/lib/timerUtils.mjs +0 -1
  37. package/lib/timerUtils.mjs.map +1 -1
  38. package/lib/utils.mjs +1 -1
  39. package/lib/utils.mjs.map +1 -1
  40. package/lib/wrapLazy.mjs +2 -2
  41. package/lib/wrapLazy.mjs.map +1 -1
  42. package/lib/yakDomTag.mjs +44 -0
  43. package/lib/yakDomTag.mjs.map +1 -0
  44. package/lib-yak/ActionUtils.mjs +117 -0
  45. package/lib-yak/ActionUtils.mjs.map +1 -0
  46. package/lib-yak/FetchUtils.mjs +100 -0
  47. package/lib-yak/FetchUtils.mjs.map +1 -0
  48. package/lib-yak/animationKeyframes.mjs +31 -0
  49. package/lib-yak/animationKeyframes.mjs.map +1 -0
  50. package/lib-yak/createPressEvent.mjs +74 -0
  51. package/lib-yak/createPressEvent.mjs.map +1 -0
  52. package/lib-yak/fixMediaQuery.mjs +90 -0
  53. package/lib-yak/fixMediaQuery.mjs.map +1 -0
  54. package/lib-yak/fixMediaText.mjs +16 -0
  55. package/lib-yak/fixMediaText.mjs.map +1 -0
  56. package/lib-yak/formatDate.mjs +110 -0
  57. package/lib-yak/formatDate.mjs.map +1 -0
  58. package/lib-yak/formatUtils.mjs +64 -0
  59. package/lib-yak/formatUtils.mjs.map +1 -0
  60. package/lib-yak/getClosestOffsetScroll.mjs +15 -0
  61. package/lib-yak/getClosestOffsetScroll.mjs.map +1 -0
  62. package/lib-yak/hooks/useEventListener.mjs +27 -0
  63. package/lib-yak/hooks/useEventListener.mjs.map +1 -0
  64. package/lib-yak/index.mjs +21 -0
  65. package/lib-yak/index.mjs.map +1 -0
  66. package/lib-yak/insertKeyframes.mjs +68 -0
  67. package/lib-yak/insertKeyframes.mjs.map +1 -0
  68. package/lib-yak/lodashUtils.mjs +131 -0
  69. package/lib-yak/lodashUtils.mjs.map +1 -0
  70. package/lib-yak/promiseUtils.mjs +92 -0
  71. package/lib-yak/promiseUtils.mjs.map +1 -0
  72. package/lib-yak/reactUtils.mjs +12 -0
  73. package/lib-yak/reactUtils.mjs.map +1 -0
  74. package/lib-yak/reduceUtils.mjs +14 -0
  75. package/lib-yak/reduceUtils.mjs.map +1 -0
  76. package/lib-yak/smoothScroll.mjs +59 -0
  77. package/lib-yak/smoothScroll.mjs.map +1 -0
  78. package/lib-yak/styled.mjs +23 -0
  79. package/lib-yak/styled.mjs.map +1 -0
  80. package/lib-yak/styledShared.mjs +129 -0
  81. package/lib-yak/styledShared.mjs.map +1 -0
  82. package/lib-yak/timeUtils.mjs +81 -0
  83. package/lib-yak/timeUtils.mjs.map +1 -0
  84. package/lib-yak/timerUtils.mjs +10 -0
  85. package/lib-yak/timerUtils.mjs.map +1 -0
  86. package/lib-yak/utils.mjs +386 -0
  87. package/lib-yak/utils.mjs.map +1 -0
  88. package/lib-yak/wrapLazy.mjs +132 -0
  89. package/lib-yak/wrapLazy.mjs.map +1 -0
  90. package/lib-yak/yakDomTag.mjs +44 -0
  91. package/lib-yak/yakDomTag.mjs.map +1 -0
  92. package/package.json +14 -3
  93. package/src/animationKeyframes.js +10 -0
  94. package/src/animationKeyframes.test.mjs +75 -0
  95. package/src/animationKeyframes.yak.js +30 -0
  96. package/src/fixMediaQuery.js +40 -19
  97. package/src/fixMediaText.js +18 -0
  98. package/src/fixMediaText.test.mjs +60 -0
  99. package/src/index.js +1 -0
  100. package/src/insertKeyframes.js +73 -0
  101. package/src/insertKeyframes.test.mjs +144 -0
  102. package/src/styled.js +5 -97
  103. package/src/styled.yak.js +30 -0
  104. package/src/styledShared.js +96 -0
  105. package/src/timerUtils.jsx +0 -2
  106. package/src/yakDomTag.jsx +42 -0
  107. package/src/yakDomTag.test.mjs +49 -0
package/src/styled.js CHANGED
@@ -1,52 +1,13 @@
1
+ /* @startlibs-yak keep-styled-components */
1
2
  // @flow
3
+ // Na lib-yak, este arquivo é trocado por styled.yak.js (sem styled-components).
2
4
  import _ from 'lodash/fp'
3
- import {darken} from 'polished'
4
- import React from 'react'
5
5
  import styled, {css} from 'styled-components'
6
- import createEmotion from 'create-emotion'
7
6
  import {scrollWidth} from './fixMediaQuery'
8
- import {_s} from './lodashUtils'
9
7
  import {callIfFunction} from './utils'
8
+ import {ifPropValue} from './styledShared'
10
9
 
11
- export const getColor = (propsOrColor, hover) => {
12
- if (propsOrColor === undefined) {
13
- return ({theme})=>theme.colors.gray150
14
- }
15
- if (typeof propsOrColor==='string') {
16
- return ({theme})=>theme.colors[propsOrColor] || propsOrColor
17
- }
18
- const {theme,...props} = propsOrColor
19
- if (props.dark) {
20
- return darken(0.1, getColor({theme, ..._.unset( 'dark', props)}))
21
- } else if (hover && props.hover) {
22
- return getColor({theme, color: props.hover})
23
- } else if (props.color) {
24
- return theme.colors[props.color] || props.color
25
- } else if (props.highlight) {
26
- return theme.colors.main
27
- } else if (props.alert) {
28
- return theme.colors.alert
29
- } else if (props.success) {
30
- return theme.colors.success
31
- } else {
32
- return theme.colors.gray150
33
- }
34
- }
35
-
36
- export const getMargin = (enumeratedMargins) => (props) => enumeratedMargins[props.margin] || props.margin || enumeratedMargins['default'] || 0
37
-
38
- /**
39
- * Returns the value of `props[path]` or `defaultValue`
40
- * @example
41
- * const Button = styled.button`
42
- * color: ${prop('color', 'red')};
43
- * `
44
- */
45
- export const prop = (path,defaultValue) =>
46
- (props = {}) => _.get(path.trim(), props) || defaultValue
47
-
48
- export const customTheme = (type) =>
49
- (props = {}) => _.get(["theme","startlibs",type], props) || ''
10
+ export {getColor, getMargin, prop, customTheme, vheight, oneWayAnimation, twoWayAnimation, animationTiming, identityTranslateFrames, identityOpacityFrames} from './styledShared'
50
11
 
51
12
  /**
52
13
  * Returns `pass` if prop is truthy. Otherwise returns `fail`
@@ -64,17 +25,7 @@ export const customTheme = (type) =>
64
25
  */
65
26
  export const ifProp = (path, pass, fail) => {
66
27
  if (pass && !_.isFunction(pass)) { // old version
67
- return (props = {}) => {
68
- let result = false
69
- if (Array.isArray(path)) {
70
- result = path.every(p=> testSinglePath(props,p))
71
- } else if (typeof path === 'object') {
72
- result = !Object.entries(path).find(([k,v])=>props[k]!==v)
73
- } else {
74
- result = testSinglePath(props,path)
75
- }
76
- return result ? pass : fail
77
- }
28
+ return ifPropValue(path, pass, fail)
78
29
  } else {
79
30
  return (...argsTrue) => {
80
31
  const check = pass || _.identity
@@ -116,49 +67,6 @@ media.max = (n) => media([n,'max-width'])
116
67
  media.min = (n) => media([n,'min-width'])
117
68
  media.desktop = media([601,'min-width'])
118
69
 
119
- export const vheight = (strings,size) => {
120
- const propType = strings[0]
121
- const calc = (strings[1]||"").replace(";","").trim()
122
- return `
123
- ${propType} ${calc ? `calc(${size}vh ${calc})` : `${size}vh`};
124
- ${propType} ${calc ? `calc(calc(var(--vh, 1vh) * ${size}) ${calc})` : `calc(var(--vh, 1vh) * ${size})`};
125
- `
126
- }
127
-
128
- function testSinglePath(props,path) {
129
- if (typeof path === 'string') {
130
- return !!_s.get(path, props)
131
- } else if (typeof path === 'number') {
132
- return !!props[path]
133
- } else {
134
- return false
135
- }
136
- }
137
-
138
- const getFrameOffset = (i,total) => Math.round(i*100/(total-1))
139
-
140
-
141
- const emotion = createEmotion({
142
- nonce: (typeof document !== 'undefined' &&
143
- (document.querySelector('meta[property="csp-nonce"]') || {}).content) || 'animation_nonce'
144
- })
145
-
146
- export const oneWayAnimation = (...frames) => {
147
- return emotion.keyframes`
148
- ${frames.map((frame,i) =>
149
- !frame ? '' : `${getFrameOffset(i,frames.length)}% {
150
- ${frame}
151
- }`
152
- )}`
153
- }
154
-
155
- export const twoWayAnimation = (...frames) => [frames,_.reverse(frames)].map((frames)=>oneWayAnimation(...frames))
156
-
157
- export const animationTiming = (props) => (...animations) => animations.filter(_=>_).map(_=>_+' '+props).join(',')
158
-
159
- export const identityTranslateFrames = oneWayAnimation('transform: translateY(0);', 'transform: translateY(0);')
160
- export const identityOpacityFrames = oneWayAnimation('opacity: 1;', 'opacity:1;')
161
-
162
70
  export const styledExtend = ({target,componentStyle}) => (...template) => {
163
71
  const wasStatic = !_.find(_.isFunction,componentStyle.rules)
164
72
  const v = styled(target)(...template,...(wasStatic ? [] : [() => ""]))
@@ -0,0 +1,30 @@
1
+ // Saída yak (lib-yak/) de styled.js, sem styled-components: o runtime dele não vai para o bundle.
2
+ // O plugin startlibs-to-yak reduz ifProp (template), media, styledExtend e printerMedia a CSS
3
+ // estático no build da startlibs. No app em modo yak, esses helpers não têm como funcionar em
4
+ // runtime: falham com uma mensagem clara em vez de gerar CSS errado.
5
+ import _ from 'lodash/fp'
6
+ import {ifPropValue} from './styledShared'
7
+
8
+ export {getColor, getMargin, prop, customTheme, vheight, oneWayAnimation, twoWayAnimation, animationTiming, identityTranslateFrames, identityOpacityFrames} from './styledShared'
9
+
10
+ const notInYak = (name, instead) => () => {
11
+ throw new Error(`@startlibs/utils: ${name} usa styled-components e não existe no modo yak. Use ${instead}.`)
12
+ }
13
+
14
+ export const ifProp = (path, pass, fail) =>
15
+ pass && !_.isFunction(pass)
16
+ ? ifPropValue(path, pass, fail)
17
+ : notInYak('ifProp com template', 'uma função de props com css`` do @yak/react')
18
+ export const ifPropEquals = (path,str) => ifProp(path,_.isEqual(str))
19
+ export const ifNotProp = (path) => ifProp(path,v => !v)
20
+
21
+ export const media = () => notInYak('media', '@media no próprio CSS')
22
+ media.mobile = media()
23
+ media.between = media
24
+ media.max = media
25
+ media.min = media
26
+ media.desktop = media()
27
+
28
+ export const styledExtend = notInYak('styledExtend', 'styled(Componente)')
29
+ export const printerMedia = notInYak('printerMedia', '@media print')
30
+ export const notPrinterMedia = notInYak('notPrinterMedia', '@media screen')
@@ -0,0 +1,96 @@
1
+ // Helpers de estilo que não dependem de styled-components: valem na lib/ e na lib-yak/.
2
+ import _ from 'lodash/fp'
3
+ import {darken} from 'polished'
4
+ import {animationKeyframes} from './animationKeyframes'
5
+ import {_s} from './lodashUtils'
6
+
7
+ export const getColor = (propsOrColor, hover) => {
8
+ if (propsOrColor === undefined) {
9
+ return ({theme})=>theme.colors.gray150
10
+ }
11
+ if (typeof propsOrColor==='string') {
12
+ return ({theme})=>theme.colors[propsOrColor] || propsOrColor
13
+ }
14
+ const {theme,...props} = propsOrColor
15
+ if (props.dark) {
16
+ return darken(0.1, getColor({theme, ..._.unset( 'dark', props)}))
17
+ } else if (hover && props.hover) {
18
+ return getColor({theme, color: props.hover})
19
+ } else if (props.color) {
20
+ return theme.colors[props.color] || props.color
21
+ } else if (props.highlight) {
22
+ return theme.colors.main
23
+ } else if (props.alert) {
24
+ return theme.colors.alert
25
+ } else if (props.success) {
26
+ return theme.colors.success
27
+ } else {
28
+ return theme.colors.gray150
29
+ }
30
+ }
31
+
32
+ export const getMargin = (enumeratedMargins) => (props) => enumeratedMargins[props.margin] || props.margin || enumeratedMargins['default'] || 0
33
+
34
+ /**
35
+ * Returns the value of `props[path]` or `defaultValue`
36
+ * @example
37
+ * const Button = styled.button`
38
+ * color: ${prop('color', 'red')};
39
+ * `
40
+ */
41
+ export const prop = (path,defaultValue) =>
42
+ (props = {}) => _.get(path.trim(), props) || defaultValue
43
+
44
+ export const customTheme = (type) =>
45
+ (props = {}) => _.get(["theme","startlibs",type], props) || ''
46
+
47
+ export const vheight = (strings,size) => {
48
+ const propType = strings[0]
49
+ const calc = (strings[1]||"").replace(";","").trim()
50
+ return `
51
+ ${propType} ${calc ? `calc(${size}vh ${calc})` : `${size}vh`};
52
+ ${propType} ${calc ? `calc(calc(var(--vh, 1vh) * ${size}) ${calc})` : `calc(var(--vh, 1vh) * ${size})`};
53
+ `
54
+ }
55
+
56
+ const getFrameOffset = (i,total) => Math.round(i*100/(total-1))
57
+
58
+
59
+ export const oneWayAnimation = (...frames) => {
60
+ return animationKeyframes`
61
+ ${frames.map((frame,i) =>
62
+ !frame ? '' : `${getFrameOffset(i,frames.length)}% {
63
+ ${frame}
64
+ }`
65
+ )}`
66
+ }
67
+
68
+ export const twoWayAnimation = (...frames) => [frames,_.reverse(frames)].map((frames)=>oneWayAnimation(...frames))
69
+
70
+ export const animationTiming = (props) => (...animations) => animations.filter(_=>_).map(_=>_+' '+props).join(',')
71
+
72
+ export const identityTranslateFrames = oneWayAnimation('transform: translateY(0);', 'transform: translateY(0);')
73
+ export const identityOpacityFrames = oneWayAnimation('opacity: 1;', 'opacity:1;')
74
+
75
+ function testSinglePath(props,path) {
76
+ if (typeof path === 'string') {
77
+ return !!_s.get(path, props)
78
+ } else if (typeof path === 'number') {
79
+ return !!props[path]
80
+ } else {
81
+ return false
82
+ }
83
+ }
84
+
85
+ // ifProp na forma antiga (valor pronto, não template): devolve pass ou fail
86
+ export const ifPropValue = (path, pass, fail) => (props = {}) => {
87
+ let result = false
88
+ if (Array.isArray(path)) {
89
+ result = path.every(p=> testSinglePath(props,p))
90
+ } else if (typeof path === 'object') {
91
+ result = !Object.entries(path).find(([k,v])=>props[k]!==v)
92
+ } else {
93
+ result = testSinglePath(props,path)
94
+ }
95
+ return result ? pass : fail
96
+ }
@@ -1,7 +1,5 @@
1
1
  import React from 'react'
2
- import styled from 'styled-components/macro'
3
2
 
4
- styled
5
3
  export const timerPromise = (time) => new Promise((res) => setTimeout(res,time))
6
4
 
7
5
  export const cancelableTimer = (res,time) => {
@@ -0,0 +1,42 @@
1
+ import React from 'react'
2
+ import isPropValid from '@emotion/is-prop-valid'
3
+
4
+ // Task 13c: @yak/react só filtra props `$`-prefixadas e `undefined` antes de repassar pro
5
+ // elemento real; qualquer prop custom (string, número, objeto) lida por um `styled.<tag>` no yak
6
+ // vaza como atributo no DOM. styled-components v5 evita isso sozinho pra tags string, usando
7
+ // @emotion/is-prop-valid. yakDomTag(tag) devolve um componente equivalente: filtra pelas mesmas
8
+ // regras antes de renderizar `tag`, pra o DOM do yak ficar idêntico ao do sc.
9
+ //
10
+ // Resolvido via `@startlibs/utils/yakDomTag` (exports["./*"] do package.json) — não passa pelo
11
+ // index: só existe nessa saída porque o babel-plugin-startlibs-to-yak importa explicitamente
12
+ // (ver tools/babel-plugin-startlibs-to-yak/domTag.cjs), nunca no fonte sc.
13
+ //
14
+ // Memoizado por nome de tag: `styled(yakDomTag('div'))` precisa devolver sempre o MESMO
15
+ // componente de DOM final pra identidade ficar estável entre `${X}` e composições
16
+ // (`styled(X)`/`styledExtend(X)`) de um mesmo `styled.div` — ver @yak/react runtime, que carrega
17
+ // esse componente até o fim da cadeia de composição.
18
+ //
19
+ // `as` (styled-components troca a tag renderizada com essa prop, ex.: components/src/containers/
20
+ // usePositioning.jsx's Placeholder as={placeholderAs}, form/src/TextInput.jsx's Input
21
+ // as={inputTag}) não é filtrada pelo @emotion/is-prop-valid (`isPropValid('as')` é false) — sem
22
+ // tratar à parte, o yak renderizaria sempre a tag original, ignorando a troca.
23
+ const cache = new Map()
24
+
25
+ export const yakDomTag = (tag) => {
26
+ let Component = cache.get(tag)
27
+ if (!Component) {
28
+ Component = React.forwardRef((props, ref) => {
29
+ const domProps = {}
30
+ for (const key in props) {
31
+ // `as` troca a tag renderizada (como styled-components faz); não é uma prop do DOM.
32
+ if (key === 'as') continue
33
+ if (key === 'className' || isPropValid(key)) domProps[key] = props[key]
34
+ }
35
+ domProps.ref = ref
36
+ return React.createElement(props.as || tag, domProps)
37
+ })
38
+ Component.displayName = `yakDomTag(${tag})`
39
+ cache.set(tag, Component)
40
+ }
41
+ return Component
42
+ }
@@ -0,0 +1,49 @@
1
+ import {test} from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import React from 'react'
4
+ import {yakDomTag} from './yakDomTag.jsx'
5
+
6
+ // yakDomTag's component is a React.forwardRef — `.render(props, ref)` runs the exact same logic
7
+ // a real render would, and React.createElement just returns a plain element descriptor
8
+ // ({type, props, ...}), so this is enough to assert on without react-dom/mounting.
9
+ const render = (tag, props, ref) => yakDomTag(tag).render(props, ref)
10
+
11
+ test('filtra prop custom (não aceita por @emotion/is-prop-valid)', () => {
12
+ const el = render('div', {rounded: true, children: 'x'})
13
+ assert.equal(el.type, 'div')
14
+ assert.equal('rounded' in el.props, false)
15
+ assert.equal(el.props.children, 'x')
16
+ })
17
+
18
+ test('mantém className, style e props de DOM válidas', () => {
19
+ const el = render('div', {className: 'a', style: {color: 'red'}, id: 'x', 'data-foo': '1'})
20
+ assert.equal(el.props.className, 'a')
21
+ assert.deepEqual(el.props.style, {color: 'red'})
22
+ assert.equal(el.props.id, 'x')
23
+ assert.equal(el.props['data-foo'], '1')
24
+ })
25
+
26
+ test('repassa ref pro elemento real', () => {
27
+ // React.createElement extrai `ref` do objeto de config pro próprio elemento (el.ref), não
28
+ // deixa em el.props (acessar el.props.ref em dev dispara um warning do React — por isso o
29
+ // teste não toca em el.props aqui, só em el.ref).
30
+ const ref = {current: null}
31
+ const el = render('div', {}, ref)
32
+ assert.equal(el.ref, ref)
33
+ })
34
+
35
+ test('as troca a tag renderizada (como no sc) e não vaza pro DOM', () => {
36
+ const el = render('span', {as: 'textarea', children: 'x'})
37
+ assert.equal(el.type, 'textarea')
38
+ assert.equal('as' in el.props, false)
39
+ })
40
+
41
+ test('sem as, renderiza a tag original', () => {
42
+ const el = render('input', {type: 'text'})
43
+ assert.equal(el.type, 'input')
44
+ })
45
+
46
+ test('memoiza por nome de tag: mesmo tag devolve o mesmo componente', () => {
47
+ assert.equal(yakDomTag('div'), yakDomTag('div'))
48
+ assert.notEqual(yakDomTag('div'), yakDomTag('span'))
49
+ })