@startlibs/components 1.0.4 → 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 (115) hide show
  1. package/lib/BasicBulletList.mjs +9 -0
  2. package/lib/BasicBulletList.mjs.map +1 -0
  3. package/lib/Button.mjs +95 -0
  4. package/lib/Button.mjs.map +1 -0
  5. package/lib/ContextMenu.mjs +452 -0
  6. package/lib/ContextMenu.mjs.map +1 -0
  7. package/lib/Dialog.mjs +232 -0
  8. package/lib/Dialog.mjs.map +1 -0
  9. package/lib/Draggable.mjs +880 -0
  10. package/lib/Draggable.mjs.map +1 -0
  11. package/lib/ErrorBoundary.mjs +108 -0
  12. package/lib/ErrorBoundary.mjs.map +1 -0
  13. package/lib/FillLastLineResizer.mjs +238 -0
  14. package/lib/FillLastLineResizer.mjs.map +1 -0
  15. package/lib/Flip.mjs +604 -0
  16. package/lib/Flip.mjs.map +1 -0
  17. package/lib/FlipList.mjs +186 -0
  18. package/lib/FlipList.mjs.map +1 -0
  19. package/lib/FormatDate.mjs +25 -0
  20. package/lib/FormatDate.mjs.map +1 -0
  21. package/lib/Icon.mjs +50 -0
  22. package/lib/Icon.mjs.map +1 -0
  23. package/lib/Image.mjs +41 -0
  24. package/lib/Image.mjs.map +1 -0
  25. package/lib/Link.mjs +116 -0
  26. package/lib/Link.mjs.map +1 -0
  27. package/lib/Loading.mjs +10 -0
  28. package/lib/Loading.mjs.map +1 -0
  29. package/lib/LoadingDiv.mjs +83 -0
  30. package/lib/LoadingDiv.mjs.map +1 -0
  31. package/lib/Notifications.mjs +63 -0
  32. package/lib/Notifications.mjs.map +1 -0
  33. package/lib/PageLoader.mjs +42 -0
  34. package/lib/PageLoader.mjs.map +1 -0
  35. package/lib/PersistentNotifications.mjs +130 -0
  36. package/lib/PersistentNotifications.mjs.map +1 -0
  37. package/lib/Popup.mjs +49 -0
  38. package/lib/Popup.mjs.map +1 -0
  39. package/lib/SplitColumnsContainer.mjs +43 -0
  40. package/lib/SplitColumnsContainer.mjs.map +1 -0
  41. package/lib/SwitchDiv.mjs +61 -0
  42. package/lib/SwitchDiv.mjs.map +1 -0
  43. package/lib/TextButton.mjs +41 -0
  44. package/lib/TextButton.mjs.map +1 -0
  45. package/lib/ToastNotifications.mjs +215 -0
  46. package/lib/ToastNotifications.mjs.map +1 -0
  47. package/lib/Tooltip.mjs +160 -0
  48. package/lib/Tooltip.mjs.map +1 -0
  49. package/lib/TransitionDiv.mjs +56 -0
  50. package/lib/TransitionDiv.mjs.map +1 -0
  51. package/lib/WarningDialog.mjs +84 -0
  52. package/lib/WarningDialog.mjs.map +1 -0
  53. package/lib/alt/buttons/OnClickLoadingButton.mjs +36 -0
  54. package/lib/alt/buttons/OnClickLoadingButton.mjs.map +1 -0
  55. package/lib/alt/dialogs/DialogWithImageHeader.mjs +14 -0
  56. package/lib/alt/dialogs/DialogWithImageHeader.mjs.map +1 -0
  57. package/lib/alt/dialogs/DialogWithSidebar.mjs +106 -0
  58. package/lib/alt/dialogs/DialogWithSidebar.mjs.map +1 -0
  59. package/lib/alt/dialogs/MobileBubbleDialog.mjs +49 -0
  60. package/lib/alt/dialogs/MobileBubbleDialog.mjs.map +1 -0
  61. package/lib/containers/DialogContainer.mjs +413 -0
  62. package/lib/containers/DialogContainer.mjs.map +1 -0
  63. package/lib/containers/Reposition.mjs +35 -0
  64. package/lib/containers/Reposition.mjs.map +1 -0
  65. package/lib/containers/usePositioning.mjs +294 -0
  66. package/lib/containers/usePositioning.mjs.map +1 -0
  67. package/lib/index.cjs +5000 -0
  68. package/lib/index.cjs.map +1 -0
  69. package/lib/index.mjs +37 -0
  70. package/lib/index.mjs.map +1 -0
  71. package/lib/useDialogWithToggle.mjs +18 -0
  72. package/lib/useDialogWithToggle.mjs.map +1 -0
  73. package/lib/willUseIsSticky.mjs +123 -0
  74. package/lib/willUseIsSticky.mjs.map +1 -0
  75. package/package.json +44 -29
  76. package/src/BasicBulletList.jsx +21 -0
  77. package/src/Button.jsx +288 -0
  78. package/src/ContextMenu.jsx +621 -0
  79. package/src/Dialog.jsx +413 -0
  80. package/src/Draggable.jsx +801 -0
  81. package/src/ErrorBoundary.jsx +75 -0
  82. package/src/FillLastLineResizer.jsx +226 -0
  83. package/src/Flip.jsx +560 -0
  84. package/src/FlipList.jsx +136 -0
  85. package/src/FormatDate.jsx +9 -0
  86. package/src/Icon.jsx +49 -0
  87. package/src/Image.jsx +23 -0
  88. package/src/Link.jsx +68 -0
  89. package/src/Loading.jsx +29 -0
  90. package/src/LoadingDiv.jsx +75 -0
  91. package/src/Notifications.jsx +89 -0
  92. package/src/PageLoader.jsx +48 -0
  93. package/src/PersistentNotifications.jsx +182 -0
  94. package/src/Popup.jsx +49 -0
  95. package/src/SplitColumnsContainer.jsx +63 -0
  96. package/src/SwitchDiv.jsx +30 -0
  97. package/src/TextButton.jsx +34 -0
  98. package/src/ToastNotifications.jsx +298 -0
  99. package/src/Tooltip.jsx +158 -0
  100. package/src/TransitionDiv.jsx +34 -0
  101. package/src/WarningDialog.jsx +70 -0
  102. package/src/alt/buttons/OnClickLoadingButton.jsx +16 -0
  103. package/src/alt/dialogs/DialogWithImageHeader.jsx +42 -0
  104. package/src/alt/dialogs/DialogWithSidebar.jsx +135 -0
  105. package/src/alt/dialogs/MobileBubbleDialog.jsx +56 -0
  106. package/src/containers/DialogContainer.jsx +423 -0
  107. package/src/containers/Reposition.jsx +24 -0
  108. package/src/containers/usePositioning.jsx +305 -0
  109. package/src/index.js +35 -0
  110. package/src/useDialogWithToggle.jsx +12 -0
  111. package/src/willUseIsSticky.jsx +113 -0
  112. package/.babelrc +0 -27
  113. package/lib/index.js +0 -5429
  114. package/rollup.config.js +0 -52
  115. package/yarn-error.log +0 -3724
@@ -0,0 +1,305 @@
1
+ import React, {useEffect, useLayoutEffect, useRef, useState} from 'react'
2
+ import _ from 'lodash/fp'
3
+ import styled from 'styled-components'
4
+ import {getClosestOffsetScroll} from '@startlibs/utils'
5
+ import {useEnsureRef} from '@startlibs/core'
6
+ import {getDialogLayersSize} from './DialogContainer'
7
+
8
+ const Placeholder = styled.span`
9
+ top:0;
10
+ left:0;
11
+ padding: 0 !important;
12
+ position: absolute;
13
+ `
14
+ /*
15
+ type Alignment = 'top left' | 'top center' | 'top right' |
16
+ 'center left' | 'center center' | 'center right' |
17
+ 'bottom left' | 'bottom center' | 'bottom right'
18
+
19
+ type Collision = 'fit fit' | 'fit flip' | 'fit fitflip' | 'fit none' |
20
+ 'flip fit' | 'flip flip' | 'flip fitflip' | 'flip none' |
21
+ 'flipfit fit' | 'flipfit flip' | 'flipfit fitflip' | 'flipfit none' |
22
+ 'none fit' | 'none flip' | 'none fitflip' | 'none none'
23
+ */
24
+
25
+ const HORIZONTAL_MAPPING = ['left', 'center', 'right']
26
+ const VERTICAL_MAPPING = ['top', 'center', 'bottom']
27
+ const ARROW_KEY_POSITIONS = {left: '0', right: '-0', top: '0', bottom: '-0'}
28
+
29
+ const POSITIONING_BOUNDS = {left:0,top:0,right:0,bottom:0}
30
+ export const addPositioningBound = (key,value) => {
31
+ POSITIONING_BOUNDS[key] += value
32
+ return () => POSITIONING_BOUNDS[key] -= value
33
+ }
34
+
35
+ function getPosition(origin, offset, max, originSize, selfSize, originalAlignment, selfAlignment, onCollision, mapping, boundMargin) {
36
+
37
+ // 0 pra left ou top, 1/2 pra center, 1 pra right ou bottom
38
+ const originDiff = originSize * (mapping.indexOf(originalAlignment) / 2)
39
+ // 0 pra left ou top, -1/2 pra center, -1 pra right ou bottom
40
+ const selfDiff = -(selfSize * (mapping.indexOf(selfAlignment) / 2))
41
+
42
+ const respectingBounds = boundMargin !== false
43
+ const upperBound = respectingBounds ? (POSITIONING_BOUNDS[mapping[0]] + boundMargin) : Number.MIN_SAFE_INTEGER
44
+ const lowerBound = respectingBounds ? (POSITIONING_BOUNDS[mapping[2]] + boundMargin) : 0
45
+ const newPosition = Math.max(upperBound, origin + selfDiff + originDiff + offset)
46
+
47
+ const collision = Math.max(-newPosition, newPosition + selfSize - max + lowerBound)
48
+ if (collision > 0 && onCollision !== 'none') {
49
+ if (onCollision.indexOf('flip') >= 0) {
50
+ const flippedPosition = getPosition(origin, -offset, max, originSize, selfSize, originalAlignment, selfAlignment, onCollision.indexOf('fit') >= 0 ? 'fit' : 'none', mapping.slice().reverse(), boundMargin)
51
+ const flippedCollision = Math.max(-flippedPosition[0], flippedPosition[0] + selfSize - max)
52
+ if ((collision > 0 && flippedCollision > 0) || flippedPosition[0] < upperBound) {
53
+ return getPosition(origin, offset, max, originSize, selfSize, originalAlignment, selfAlignment, 'fit', mapping, boundMargin)
54
+ }
55
+ return collision < flippedCollision ? [newPosition, 'none'] : [flippedPosition[0], flippedPosition[1] === 'fit' ? 'flipfit' : 'flip']
56
+ } else {
57
+ const minBound = respectingBounds ? upperBound : 0
58
+ const fittedPosition = Math.max(minBound, Math.min(newPosition, max - selfSize - lowerBound))
59
+ return [fittedPosition, fittedPosition !== newPosition ? 'fit' : 'none']
60
+ }
61
+ } else {
62
+ return [newPosition, 'none']
63
+ }
64
+ }
65
+
66
+ const arrowShadow = {
67
+ top: '-1px -1px 2px -1px rgba(0,0,0,.25)',
68
+ right: '1px -1px 2px -1px rgba(0,0,0,.25)',
69
+ bottom: '1px 1px 2px -1px rgba(0,0,0,.25)',
70
+ left: '-1px 1px 2px -1px rgba(0,0,0,.25)'
71
+ }
72
+
73
+ const translate = (position, offset) => (position === 'left' ? '-50%' : position === 'right' ? '50%' : offset) + ',' +
74
+ (position === 'top' ? '-50%' : position === 'bottom' ? '50%' : offset)
75
+
76
+ const ARROW_DEFAULT_SIZE = 14
77
+
78
+ export const DefaultArrow = styled.div`
79
+ background-color: #fff;
80
+ position: absolute;
81
+ width: ${ARROW_DEFAULT_SIZE}px;
82
+ height: ${ARROW_DEFAULT_SIZE}px;
83
+ transform: translate(-50%,50%) rotate(45deg);
84
+ bottom: 0;
85
+ left: 50%;
86
+ box-shadow: ${arrowShadow.bottom};
87
+ `
88
+
89
+ export const usePositioning = (
90
+ element,
91
+ {
92
+ my = 'top right',
93
+ offset = '0 0', // x y
94
+ at = 'bottom right',
95
+ onCollision = 'flip flip',
96
+ arrow,
97
+ arrowPadding = 10,
98
+ fill,
99
+ useLayers = true,
100
+ fixed,
101
+ bottom: onBottom,
102
+ left: onLeft,
103
+ right: onRight,
104
+ top: onTop,
105
+ keepWidth = true,
106
+ boundMargin = 6,
107
+ respectBounds,
108
+ respectOffsetScroll,
109
+ on,
110
+ placeholderAs
111
+ },
112
+ arrowRefOpt
113
+ ) => {
114
+ const placeholder = useRef()
115
+ const arrowRef = useEnsureRef(arrowRefOpt)
116
+ const [positionInfo, setPositionInfo] = useState()
117
+
118
+ const setPosition = (retry=0) => {
119
+ if (retry>10) { return }
120
+ if (!element.current?.style || !(placeholder.current?.offsetParent || placeholder.current?.parentNode?.offsetParent)) {
121
+ setTimeout(()=>setPosition(retry+1),100)
122
+ return
123
+ }
124
+ if (keepWidth) {
125
+ element.current.style.width = ''
126
+ } else {
127
+ element.current.style.maxWidth = ''
128
+ }
129
+ const placeholderOffsetParent = (placeholder.current?.offsetParent || placeholder.current?.parentNode?.offsetParent)
130
+ const usingLayer = respectOffsetScroll || useLayers && getDialogLayersSize() > 0
131
+ const scrollOwner =
132
+ usingLayer
133
+ ? (_.isFunction(respectOffsetScroll) ? respectOffsetScroll(element.current.offsetParent) : getClosestOffsetScroll(element.current.offsetParent))
134
+ : {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset}
135
+
136
+ // console.log({scrollOwner,scrollTop:scrollOwner.scrollTop,pageYOffset:window.pageYOffset})
137
+
138
+ const scrollY = !isNaN(scrollOwner.scrollTop) ? scrollOwner.scrollTop : window.pageYOffset
139
+ const scrollX = !isNaN(scrollOwner.scrollLeft) ? scrollOwner.scrollLeft : window.pageXOffset
140
+ const getRespectOffsetScrollTopLeft = () => {
141
+ const {top,left} = placeholder.current.getBoundingClientRect()
142
+ const {top:scrollOwnerTop, left: scrollOwnerLeft} = scrollOwner.getBoundingClientRect()
143
+ return {top: top-scrollOwnerTop,left: left-scrollOwnerLeft}
144
+ }
145
+ const {left: leftPlusBorder, top: topPlusBorder} =
146
+ respectOffsetScroll
147
+ ? getRespectOffsetScrollTopLeft()
148
+ :placeholder.current.getBoundingClientRect()
149
+
150
+ const {borderLeftWidth, borderTopWidth} = window.getComputedStyle(placeholderOffsetParent)
151
+ const left = leftPlusBorder - parseInt(borderLeftWidth, 10)
152
+ const top = topPlusBorder - parseInt(borderTopWidth, 10)
153
+ const {offsetWidth: parentOffsetWidth, offsetHeight: parentOffsetHeight} = (placeholderOffsetParent)
154
+ const {offsetWidth: popupOffsetWidth, offsetHeight: popupOffsetHeight} = element.current
155
+ const {width:popupCurrentWidth} = element.current.getBoundingClientRect()
156
+ const [offsetX, offsetY] = [].concat(offset).join(' ').split(' ').map(_ => Number(_ || 0))
157
+ const simplePositioning = [onTop, onRight, onBottom, onLeft].map(_ => _ === true ? 'center' : _)
158
+ const simplePositioningIndex = simplePositioning.findIndex(_ => _)
159
+ const bodyWidth = document.body.offsetWidth - (usingLayer ? parseInt(getComputedStyle(document.body).paddingRight, 10) : 0)
160
+ // Barra fixa inferior (footer mobile) registrada em POSITIONING_BOUNDS conta como
161
+ // borda da tela: sem isso o popup se posiciona atrás dela. Com respectBounds o
162
+ // desconto já vem do lowerBound em getPosition, não descontar duas vezes.
163
+ const windowHeight = window.innerHeight - (respectBounds ? 0 : POSITIONING_BOUNDS.bottom)
164
+
165
+ const [verticalCollision, horizontalCollision] = onCollision.split(' ')
166
+ const [verticalMy, horizontalMy] = [my, 'bottom $', '$ left', 'top $', '$ right'][simplePositioningIndex + 1].replace('$', simplePositioning[simplePositioningIndex]).split(' ')
167
+ const [verticalAt, horizontalAt] = [at, 'top $', '$ right', 'bottom $', '$ left'][simplePositioningIndex + 1].replace('$', simplePositioning[simplePositioningIndex]).split(' ')
168
+
169
+ const [processedLeft, collisionH] = getPosition(left, offsetX, bodyWidth, parentOffsetWidth, fill ? parentOffsetWidth : popupOffsetWidth, horizontalAt, horizontalMy, horizontalCollision, HORIZONTAL_MAPPING,!!respectBounds && boundMargin)
170
+ const [processedTop, collisionV] = getPosition(top, offsetY, windowHeight, parentOffsetHeight, popupOffsetHeight, verticalAt, verticalMy, verticalCollision, VERTICAL_MAPPING,!!respectBounds && boundMargin)
171
+
172
+
173
+ const flippedV = collisionV.indexOf('flip') >= 0
174
+ const flippedH = collisionH.indexOf('flip') >= 0
175
+
176
+
177
+ //arrow
178
+ const arrowSide = Math.abs(VERTICAL_MAPPING.indexOf(verticalMy) - VERTICAL_MAPPING.indexOf(verticalAt)) === 2 ? (flippedV ? verticalAt : verticalMy) :
179
+ Math.abs(HORIZONTAL_MAPPING.indexOf(horizontalMy) - HORIZONTAL_MAPPING.indexOf(horizontalAt)) === 2 ? (flippedH ? horizontalAt : horizontalMy) : ''
180
+ const arrowElement = arrowRef.current
181
+ const arrowOnVerticalSide = arrowSide === 'left' || arrowSide === 'right'
182
+ const arrowSize = arrowElement ? arrowElement.getBoundingClientRect()[arrowOnVerticalSide ? 'height' : 'width'] : (ARROW_DEFAULT_SIZE * Math.sqrt(2))
183
+ const [arrowOffset, popupArrowOffset] = arrowOnVerticalSide ?
184
+ processArrow(ARROW_KEY_POSITIONS[arrow] || arrow, arrowSize, arrowOnVerticalSide, parentOffsetHeight, popupOffsetHeight, processedTop - top, flippedV) :
185
+ processArrow(ARROW_KEY_POSITIONS[arrow] || arrow, arrowSize, arrowOnVerticalSide, parentOffsetWidth, popupOffsetWidth, processedLeft - left, flippedV)
186
+
187
+
188
+ const maxHeight = window.innerHeight - (POSITIONING_BOUNDS.top + POSITIONING_BOUNDS.bottom) - (respectBounds ? boundMargin*2 : 0)
189
+ const maxWidth = window.innerWidth - (POSITIONING_BOUNDS.left + POSITIONING_BOUNDS.right) - (respectBounds ? boundMargin*2 : 0)
190
+
191
+ element.current.style.maxHeight = ''
192
+ if (parseInt(window.getComputedStyle(element.current).maxHeight) > maxHeight) {
193
+ element.current.style.maxHeight = maxHeight+'px'
194
+ }
195
+ if (keepWidth) {
196
+ element.current.style.width = Math.ceil(popupCurrentWidth)+"px"
197
+ } else {
198
+ element.current.style.maxWidth = maxWidth+'px'
199
+ }
200
+ // console.log({processedTop,top,offsetY,scrollY})
201
+
202
+
203
+ element.current.style.top = (processedTop + (arrowOnVerticalSide ? popupArrowOffset : 0) + (fixed ? 0 : scrollY)) + 'px'
204
+ element.current.style.left = (processedLeft + (arrowOnVerticalSide ? 0 : popupArrowOffset) + (fixed ? 0 : scrollX)) + 'px'
205
+
206
+ const arrowStyle = {
207
+ transform: `translate(${translate(arrowSide, arrowOffset[0] === 'top' || arrowOffset[0] === 'left' ? '-50%' : '50%')}) rotate(45deg)`,
208
+ bottom:"auto",
209
+ left:"auto",
210
+ [arrowSide]: '0',
211
+ boxShadow: arrowShadow[arrowSide],
212
+ [arrowOffset[0]]: arrowOffset[1]+'px'
213
+ }
214
+ if (arrowRef.current) {
215
+ Object.assign(arrowRef.current.style,arrowStyle)
216
+ }
217
+
218
+ setPositionInfo({
219
+ atTop: (verticalAt === 'top' && !flippedV) || (verticalAt === 'bottom' && flippedV),
220
+ atBottom: (verticalAt === 'bottom' && !flippedV) || (verticalAt === 'top' && flippedV),
221
+ atLeft: (horizontalAt === 'left' && !flippedH) || (verticalAt === 'right' && flippedH),
222
+ atRight: (horizontalAt === 'right' && !flippedH) || (verticalAt === 'left' && flippedH),
223
+ fullHeight: popupOffsetHeight > maxHeight,
224
+ fullWidth: popupOffsetWidth > maxWidth,
225
+ arrowSide,
226
+ arrowOffset,
227
+ arrowStyle
228
+ })
229
+
230
+ if (fill) {
231
+ element.current.style.width = parentOffsetWidth + 'px'
232
+ }
233
+ if (fixed) {
234
+ element.current.style.position = 'fixed'
235
+ }
236
+ }
237
+
238
+ useLayoutEffect(setPosition, [on])
239
+
240
+
241
+ useEffect(() => {
242
+ window.addEventListener('portalReposition', setPosition)
243
+ window.addEventListener('stepResize', setPosition)
244
+ window.addEventListener('scroll', setPosition, {passive:true})
245
+ return () => {
246
+ window.removeEventListener('portalReposition', setPosition)
247
+ window.removeEventListener('stepResize', setPosition)
248
+ window.removeEventListener('scroll', setPosition)
249
+ }
250
+ }, []
251
+ )
252
+
253
+
254
+ const processArrow = (arrow, arrowSize, onVerticalSide, arrowContainerWidth, popupSize, deltaPopupPosition, flipped) => {
255
+ if (!arrow) {
256
+ return ['', 0]
257
+ }
258
+ const margin = arrowPadding + (arrowSize / 2)
259
+ const [invertDirection, percent, px] = (arrow === true ? '50%' : arrow).replace(/(-)?(\d+%)?\s?(-?\d+)?/, '$1:$2:$3').split(':')
260
+ const invertAndFlipDirection = flipped ? !invertDirection : invertDirection
261
+ const arrowPosition = onVerticalSide ? (invertAndFlipDirection ? 'bottom' : 'top') : (invertAndFlipDirection ? 'right' : 'left')
262
+ const fromOriginCorner = arrowPosition === 'left' || arrowPosition === 'top'
263
+
264
+ const popupOffset = fromOriginCorner ? deltaPopupPosition : (arrowContainerWidth - deltaPopupPosition - popupSize)
265
+
266
+ /* ____________________________
267
+ | arrow container |
268
+ |___________________________|
269
+ ..../\_______
270
+ | popup |
271
+ |____________|
272
+
273
+ |-------| = delta popup position (popupOffset)
274
+
275
+ .... = arrowPadding prop, applies to both sides, moves popup or does nothing
276
+
277
+ arrow prop = invert percent px // relative to arrow container
278
+ invert = -?
279
+ percent = (\d+%)?
280
+ px = (-?\d+)?
281
+
282
+ procedure:
283
+ 1- position arrow according to container - arrowInitialPos
284
+ 2- constrain position inside container - constrainedArrowPosition
285
+ 3- move popup according to arrowPadding (margin) - popupDelta
286
+ 4- final arrow position, relative to final popup position - finalArrowPosition
287
+ */
288
+
289
+ const arrowInitialPos = (parseInt(percent || 0, 10) * arrowContainerWidth / 100) + parseInt(px || 0, 10)
290
+ const constrainedArrowPosition = (Math.min(Math.max(arrowInitialPos, 0), arrowContainerWidth))
291
+ const arrowPositionRelativeToPopup = fromOriginCorner ? constrainedArrowPosition - popupOffset : (arrowContainerWidth - popupOffset - constrainedArrowPosition)
292
+ const popupDelta = arrowPositionRelativeToPopup < margin ?
293
+ (arrowPositionRelativeToPopup - margin) :
294
+ arrowPositionRelativeToPopup > (popupSize - margin) ?
295
+ (margin + arrowPositionRelativeToPopup - popupSize) :
296
+ 0
297
+ const finalPopupPosition = fromOriginCorner ? popupOffset + popupDelta : (arrowContainerWidth - popupOffset - popupDelta - popupSize)
298
+ return [[arrowPosition,(constrainedArrowPosition - finalPopupPosition)], popupDelta]
299
+ }
300
+
301
+ const arrowElement = arrow && <DefaultArrow ref={arrowRef} />
302
+
303
+ const placeholderElement = <Placeholder as={placeholderAs} ref={placeholder}/>
304
+ return [positionInfo,placeholderElement,arrowElement]
305
+ }
package/src/index.js ADDED
@@ -0,0 +1,35 @@
1
+ export * from './Icon'
2
+ export * from './Loading'
3
+ export * from './Button'
4
+ export * from './alt/buttons/OnClickLoadingButton'
5
+ export * from './TextButton'
6
+ export * from './LoadingDiv'
7
+ export * from './Dialog'
8
+ export * from './useDialogWithToggle'
9
+ export * from './WarningDialog'
10
+ export * from './Notifications'
11
+ export * from './ToastNotifications'
12
+ export * from './PersistentNotifications'
13
+ export * from './containers/usePositioning'
14
+ export * from './containers/Reposition'
15
+ export * from './containers/DialogContainer'
16
+ export * from './Draggable'
17
+ export * from './Popup'
18
+ export * from './Tooltip'
19
+ export * from './SplitColumnsContainer'
20
+ export * from './ContextMenu'
21
+ export * from './ErrorBoundary'
22
+ export * from './PageLoader'
23
+ export * from './FillLastLineResizer'
24
+ export * from './Flip'
25
+ export * from './FlipList'
26
+ export * from './TransitionDiv'
27
+ export * from './SwitchDiv'
28
+ export * from './willUseIsSticky'
29
+ export * from './FormatDate'
30
+ export * from './Image'
31
+ export * from './alt/dialogs/DialogWithImageHeader'
32
+ export * from './alt/dialogs/DialogWithSidebar'
33
+ export * from './alt/dialogs/MobileBubbleDialog'
34
+ export * from './Link'
35
+ export * from './BasicBulletList'
@@ -0,0 +1,12 @@
1
+ import {useToggle,useFill} from '@startlibs/core'
2
+
3
+ export const useDialog = (dialog, args = [], toggleCallback) => {
4
+ const toggle = useToggle(false,toggleCallback)
5
+ useFill("Dialog", toggle.isOpen !== false && dialog(toggle.close), [toggle.isOpen, ...args])
6
+ return toggle.open
7
+ }
8
+ export const useDialogWithToggle = (dialog, args = []) => {
9
+ const toggle = useToggle()
10
+ useFill("Dialog", toggle.isOpen !== false && dialog(toggle), [toggle.isOpen, ...args])
11
+ return toggle
12
+ }
@@ -0,0 +1,113 @@
1
+ import React, {useEffect, useState} from 'react'
2
+ import {useEnsureRef, willUseSharedState, willUseSharedCallback} from '@startlibs/core'
3
+ import styled from 'styled-components'
4
+ import _ from 'lodash/fp'
5
+ import {callIfFunction} from '@startlibs/utils'
6
+
7
+
8
+ const TOP_TRIGGER = (posInfo,refInfo) => {
9
+ // Started sticking.
10
+ if (posInfo.bottom < refInfo.top) {
11
+ return true
12
+ }
13
+ // Stopped sticking.
14
+ if (posInfo.bottom >= refInfo.top &&
15
+ posInfo.bottom < refInfo.bottom) {
16
+ return false
17
+ }
18
+ }
19
+ const BOTTOM_TRIGGER = (posInfo,refInfo) => {
20
+ // Started sticking.
21
+ if (posInfo.top > refInfo.bottom) {
22
+ return true
23
+ }
24
+ if (posInfo.top <= refInfo.bottom &&
25
+ posInfo.top > refInfo.top) {
26
+ return false
27
+ }
28
+ }
29
+
30
+ const SentinelStyle = styled.div`
31
+ position:absolute;
32
+ visibility: hidden;
33
+ height:1px;
34
+ width: 1px;
35
+ ${props => props.addCss}
36
+ `
37
+
38
+ export const willUseIsSticky = (options = {}) => {
39
+
40
+ const [useRegister, onChange] = willUseSharedCallback()
41
+ const [useSharedIsSticky,, setSharedIsSticky] = willUseSharedState()
42
+
43
+ const createObserver = (root) => window.IntersectionObserver ? new window.IntersectionObserver((records, observer) => {
44
+ for (const record of records) {
45
+ const targetInfo = record.boundingClientRect
46
+ const rootBoundsInfo = record.rootBounds
47
+ if (!rootBoundsInfo) {
48
+ return
49
+ }
50
+ onChange(targetInfo,rootBoundsInfo, record.target, record.isIntersecting)
51
+ }
52
+ },{root,...options}) : {observe:_.identity,unobserve:_.identity}
53
+
54
+ const observerMap = new Map()
55
+ const getObserver = (root = null) => {
56
+ const result = observerMap.get(root)
57
+ if (result) {
58
+ return result
59
+ }
60
+ const observer = createObserver(root)
61
+ observerMap.set(root,observer)
62
+ return observer
63
+ }
64
+
65
+ let activeObserved = []
66
+ const resetObservers = (root = null) => {
67
+ const observer = getObserver(root)
68
+ activeObserved.forEach((observed) => {
69
+ observer.unobserve(observed)
70
+ observer.observe(observed)
71
+ })
72
+ }
73
+
74
+ const WithIsSticky = React.forwardRef(({className, id, css, children,bottom, root, intersection,onChange},ref) => {
75
+ const ensuredRef = useEnsureRef(ref)
76
+ const [isSticky,setIsSticky] = useState(false)
77
+
78
+ useRegister((posInfo,refInfo,target, isIntersecting) => {
79
+ if (ensuredRef.current === target) {
80
+ const value = intersection ? isIntersecting : (bottom ? BOTTOM_TRIGGER(posInfo,refInfo) : TOP_TRIGGER(posInfo,refInfo))
81
+ if (value!==undefined) {
82
+ setIsSticky(value)
83
+ callIfFunction(onChange,value)
84
+ if (!id) {
85
+ setSharedIsSticky(value)
86
+ } else if (value) {
87
+ setSharedIsSticky(id)
88
+ }
89
+ }
90
+ }
91
+ })
92
+
93
+ useEffect(() => {
94
+ setIsSticky(false)
95
+ getObserver(callIfFunction(root)).observe(ensuredRef.current)
96
+ activeObserved = activeObserved.concat(ensuredRef.current)
97
+ return () => {
98
+ // observer.unobserve(ref.current)
99
+ activeObserved = _.without([ensuredRef.current],activeObserved)
100
+ }
101
+ },[])
102
+
103
+ const renderSentinel = (css = "") => <SentinelStyle addCss={css} className={className} ref={ensuredRef} />
104
+
105
+ return children
106
+ ? children(renderSentinel,isSticky)
107
+ : renderSentinel(css)
108
+
109
+ })
110
+
111
+
112
+ return [WithIsSticky, useSharedIsSticky, resetObservers]
113
+ }
package/.babelrc DELETED
@@ -1,27 +0,0 @@
1
- // .babelrc
2
- {
3
- "presets": [
4
- "@babel/preset-react",
5
- "@babel/preset-flow",
6
- [
7
- "@babel/preset-env",
8
- {
9
- "modules": false
10
- }
11
- ]
12
- ],
13
- "plugins": [
14
- "lodash",
15
- "macros",
16
- "fbjs-scripts/babel-6/dev-expression",
17
- "@babel/plugin-proposal-export-namespace-from",
18
- "@babel/plugin-proposal-throw-expressions",
19
- "@babel/plugin-syntax-import-meta",
20
- "@babel/plugin-proposal-json-strings",
21
- "@babel/plugin-syntax-dynamic-import",
22
- "@babel/plugin-transform-arrow-functions",
23
- "@babel/plugin-transform-spread",
24
- "@babel/plugin-proposal-object-rest-spread",
25
- ["@babel/plugin-proposal-class-properties", {"loose": true}]
26
- ]
27
- }