@chem-po/react-web 0.0.52 → 0.0.53

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 (127) hide show
  1. package/package.json +4 -5
  2. package/src/components/auth/SignIn.tsx +0 -43
  3. package/src/components/auth/index.ts +0 -1
  4. package/src/components/box/CollapseHorizontal.tsx +0 -19
  5. package/src/components/box/ContentBox.tsx +0 -17
  6. package/src/components/box/ExpandOnMount.tsx +0 -48
  7. package/src/components/box/Expandable.tsx +0 -96
  8. package/src/components/box/FullSizeContainer.tsx +0 -50
  9. package/src/components/box/MobileFrame/index.tsx +0 -146
  10. package/src/components/box/MobileFrame/styles.css +0 -35
  11. package/src/components/box/index.ts +0 -6
  12. package/src/components/button/DeleteButton.tsx +0 -178
  13. package/src/components/button/Toggle.tsx +0 -88
  14. package/src/components/button/ViewButton.tsx +0 -30
  15. package/src/components/button/index.ts +0 -3
  16. package/src/components/feed/FeedContentPane.tsx +0 -111
  17. package/src/components/feed/MediaFeed.tsx +0 -200
  18. package/src/components/feed/MediaFeedBackground.tsx +0 -127
  19. package/src/components/feed/MediaFeedRefresh.tsx +0 -78
  20. package/src/components/feed/MediaFeedSwipeUp.tsx +0 -35
  21. package/src/components/feed/constants.ts +0 -11
  22. package/src/components/feed/context.tsx +0 -19
  23. package/src/components/feed/hooks.ts +0 -290
  24. package/src/components/feed/index.ts +0 -2
  25. package/src/components/feed/types.ts +0 -50
  26. package/src/components/form/Condition.tsx +0 -26
  27. package/src/components/form/Field.tsx +0 -39
  28. package/src/components/form/Form.tsx +0 -428
  29. package/src/components/form/FormFooter.tsx +0 -90
  30. package/src/components/form/UploadProgress/index.tsx +0 -38
  31. package/src/components/form/UploadProgress/styles.css +0 -23
  32. package/src/components/form/index.ts +0 -4
  33. package/src/components/form/input/Editable.tsx +0 -155
  34. package/src/components/form/input/InputSlider.tsx +0 -76
  35. package/src/components/form/input/OptionalTag.tsx +0 -33
  36. package/src/components/form/input/StandaloneInput.tsx +0 -41
  37. package/src/components/form/input/boolean/index.tsx +0 -53
  38. package/src/components/form/input/color/index.tsx +0 -126
  39. package/src/components/form/input/date/index.tsx +0 -122
  40. package/src/components/form/input/datetime/index.tsx +0 -93
  41. package/src/components/form/input/file.tsx +0 -379
  42. package/src/components/form/input/hooks/index.ts +0 -2
  43. package/src/components/form/input/hooks/useInputImperativeHandle.ts +0 -16
  44. package/src/components/form/input/hooks/useInputStyles.ts +0 -125
  45. package/src/components/form/input/index.ts +0 -2
  46. package/src/components/form/input/input.css +0 -44
  47. package/src/components/form/input/input.tsx +0 -134
  48. package/src/components/form/input/multipleSelect/index.tsx +0 -89
  49. package/src/components/form/input/number/index.tsx +0 -87
  50. package/src/components/form/input/number/styles.css +0 -8
  51. package/src/components/form/input/select/index.tsx +0 -109
  52. package/src/components/form/input/shared/InputContainer.tsx +0 -13
  53. package/src/components/form/input/socialMedia/index.tsx +0 -165
  54. package/src/components/form/input/text/index.tsx +0 -78
  55. package/src/components/form/input/text/textarea.tsx +0 -43
  56. package/src/components/form/input/time/index.tsx +0 -33
  57. package/src/components/form/input/type.ts +0 -0
  58. package/src/components/form/input/types.ts +0 -4
  59. package/src/components/form/view/file.tsx +0 -36
  60. package/src/components/form/view/index.tsx +0 -52
  61. package/src/components/form/view/multipleSelect.tsx +0 -51
  62. package/src/components/form/view/select.tsx +0 -50
  63. package/src/components/form/view/types.ts +0 -11
  64. package/src/components/index.ts +0 -14
  65. package/src/components/list/Body/InfiniteScrollGridBody.tsx +0 -177
  66. package/src/components/list/Body/InfiniteScrollListBody.tsx +0 -114
  67. package/src/components/list/Body/ListBody.tsx +0 -24
  68. package/src/components/list/Body/PagedGridBody.tsx +0 -104
  69. package/src/components/list/Body/PagedListBody.tsx +0 -92
  70. package/src/components/list/Body/hooks.ts +0 -84
  71. package/src/components/list/DataList.tsx +0 -33
  72. package/src/components/list/ListContainer.tsx +0 -21
  73. package/src/components/list/ListContent.tsx +0 -54
  74. package/src/components/list/ListCreate.tsx +0 -57
  75. package/src/components/list/ListFilters.tsx +0 -182
  76. package/src/components/list/ListFooter.tsx +0 -458
  77. package/src/components/list/ListHeader.tsx +0 -180
  78. package/src/components/list/ListItem/ListCell.tsx +0 -49
  79. package/src/components/list/ListItem/ListRow.tsx +0 -44
  80. package/src/components/list/ListItemView.tsx +0 -53
  81. package/src/components/list/ListSort.tsx +0 -84
  82. package/src/components/list/NoItems.tsx +0 -33
  83. package/src/components/list/constants.ts +0 -1
  84. package/src/components/list/index.ts +0 -4
  85. package/src/components/list/types.ts +0 -26
  86. package/src/components/list/utils.ts +0 -63
  87. package/src/components/loading/CircularProgress.tsx +0 -12
  88. package/src/components/loading/Loading.tsx +0 -160
  89. package/src/components/loading/LoadingImage.tsx +0 -128
  90. package/src/components/loading/LoadingSwitch.tsx +0 -78
  91. package/src/components/loading/index.ts +0 -4
  92. package/src/components/media/PlayButton.tsx +0 -95
  93. package/src/components/media/index.ts +0 -1
  94. package/src/components/modal/DefaultModal.tsx +0 -18
  95. package/src/components/modal/DesktopModal.tsx +0 -16
  96. package/src/components/modal/ForceMobile.tsx +0 -7
  97. package/src/components/modal/MobileModal.tsx +0 -89
  98. package/src/components/modal/index.ts +0 -3
  99. package/src/components/modal/type.ts +0 -7
  100. package/src/components/nav/NavBar.tsx +0 -102
  101. package/src/components/nav/index.ts +0 -1
  102. package/src/components/overlay/ImageViewOverlay.tsx +0 -88
  103. package/src/components/overlay/MobileOverlay.tsx +0 -23
  104. package/src/components/overlay/index.ts +0 -2
  105. package/src/components/text/GradientText/index.tsx +0 -17
  106. package/src/components/text/GradientText/styles.css +0 -5
  107. package/src/components/text/NumberTicker.tsx +0 -28
  108. package/src/components/text/index.ts +0 -1
  109. package/src/components/theme/colorMode/DarkModeToggle.tsx +0 -40
  110. package/src/components/theme/colorMode/index.ts +0 -1
  111. package/src/components/theme/index.ts +0 -1
  112. package/src/components/view/ErrorView.tsx +0 -14
  113. package/src/components/view/RedirectView.tsx +0 -43
  114. package/src/components/view/index.ts +0 -2
  115. package/src/contexts/index.ts +0 -2
  116. package/src/contexts/theme.ts +0 -316
  117. package/src/contexts/view.tsx +0 -26
  118. package/src/custom.d.ts +0 -4
  119. package/src/hooks/index.ts +0 -1
  120. package/src/hooks/ui/index.ts +0 -1
  121. package/src/hooks/ui/useBorderColor.ts +0 -4
  122. package/src/index.ts +0 -5
  123. package/src/store/index.ts +0 -1
  124. package/src/store/usePlayer.ts +0 -75
  125. package/src/store/useScreen.ts +0 -22
  126. package/src/types/forms.ts +0 -5
  127. package/src/types/index.ts +0 -1
@@ -1,88 +0,0 @@
1
- import { Box, Flex, IconButton, IconButtonProps, Tooltip } from '@chakra-ui/react'
2
- import React, { JSX } from 'react'
3
- import { useBorderColor } from '../../hooks'
4
-
5
- export interface ToggleOption<Option extends string = string> {
6
- id: Option
7
- label: string
8
- disabledMessage?: string
9
- Render: (selected: boolean) => JSX.Element
10
- }
11
- export interface ToggleProps<Option extends string> {
12
- options: ToggleOption<Option>[]
13
- value: Option
14
- size?: number
15
- onChange: (value: Option) => Promise<void> | void
16
- }
17
-
18
- const ToggleButton = <Option extends string>({
19
- selected,
20
- option: { Render, label, disabledMessage },
21
- size,
22
- ...props
23
- }: Omit<IconButtonProps, 'children' | 'aria-label' | 'size'> & {
24
- option: ToggleOption<Option>
25
- size: number
26
- selected: boolean
27
- }) => {
28
- const body = (
29
- <Box>
30
- <IconButton
31
- variant="unstyled"
32
- w={`${size}px`}
33
- h={`${size}px`}
34
- minW={0}
35
- borderRadius={0}
36
- outline="none"
37
- display="flex"
38
- alignItems="center"
39
- justifyContent="center"
40
- opacity={!disabledMessage ? 1 : 0.6}
41
- filter={!disabledMessage ? 'none' : 'grayscale(1)'}
42
- bg={selected ? 'whiteAlpha.500' : 'blackAlpha.100'}
43
- _dark={{ bg: selected ? 'blackAlpha.500' : 'whiteAlpha.200' }}
44
- icon={Render(selected)}
45
- pointerEvents={selected ? 'none' : 'auto'}
46
- aria-label={label}
47
- {...props}
48
- />
49
- </Box>
50
- )
51
-
52
- return (
53
- <Tooltip label={disabledMessage ?? label} aria-label={label}>
54
- {body}
55
- </Tooltip>
56
- )
57
- }
58
-
59
- export const Toggle = <Option extends string>({
60
- value,
61
- onChange,
62
- size = 28,
63
- options,
64
- }: ToggleProps<Option>) => {
65
- const borderColor = useBorderColor()
66
- return (
67
- <Flex
68
- bg="whiteAlpha.300"
69
- _dark={{ bg: 'blackAlpha.300' }}
70
- border={`1px solid ${borderColor}`}
71
- borderRadius={3}>
72
- {options.map((option, i) => (
73
- <ToggleButton<Option>
74
- key={option.id}
75
- onClick={() => {
76
- onChange(option.id)
77
- }}
78
- option={option}
79
- size={size}
80
- borderLeftRadius={i ? 0 : 3}
81
- borderRightRadius={i === options.length - 1 ? 3 : 0}
82
- selected={option.id === value}
83
- borderLeft={i ? `1px solid ${borderColor}` : 'none'}
84
- />
85
- ))}
86
- </Flex>
87
- )
88
- }
@@ -1,30 +0,0 @@
1
- import { ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons'
2
- import { IconButton } from '@chakra-ui/react'
3
- import React, { FC, MouseEvent } from 'react'
4
-
5
- export const ViewButton: FC<{
6
- onClick: (e: MouseEvent) => void
7
- isOpen: boolean
8
- viewText?: string
9
- hideText?: string
10
- color?: string
11
- }> = ({ viewText = 'View', hideText = 'Hide', onClick, isOpen, color }) => (
12
- <IconButton
13
- icon={
14
- isOpen ? <ChevronUpIcon width={5} height={5} /> : <ChevronDownIcon width={5} height={5} />
15
- }
16
- aria-label={isOpen ? hideText : viewText}
17
- variant="ghost"
18
- p="2px"
19
- ml="auto"
20
- size="xs"
21
- fontSize="xs"
22
- borderRadius="full"
23
- _hover={{ bg: 'blackAlpha.200' }}
24
- color={color ?? '#777'}
25
- onClick={e => {
26
- e.stopPropagation()
27
- onClick(e)
28
- }}
29
- />
30
- )
@@ -1,3 +0,0 @@
1
- export * from './DeleteButton'
2
- export * from './Toggle'
3
- export * from './ViewButton'
@@ -1,111 +0,0 @@
1
- import { AnyObject, WithId } from '@chem-po/core'
2
- import { MobileFrameContextData, useDocument, useMobileFrame } from '@chem-po/react'
3
- import { motion, MotionValue, useMotionValue, useSpring, useTransform } from 'framer-motion'
4
- import React, { JSX, useEffect, useMemo, useRef } from 'react'
5
- import { springConfig } from './constants'
6
- import { PanelStatus } from './types'
7
-
8
- const getContentScale = (status: PanelStatus) => {
9
- // if (status === 'current') return 1
10
- if (status === 'current') return 1
11
- return 0
12
- }
13
- const getContentX = (status: PanelStatus, contentSize: { width: number; height: number }) => {
14
- const { width: cWidth } = contentSize
15
- if (status === 'current') return 0
16
- if (status === 'next') return cWidth
17
- if (status === 'prev') return -cWidth
18
- return 0
19
- }
20
-
21
- const getContentY = (status: PanelStatus, contentSize: { width: number; height: number }) => {
22
- const { height: cHeight } = contentSize
23
- if (status === 'current') return 0
24
- if (status === 'next') return cHeight * 1.1
25
- if (status === 'prev') return -cHeight * 1.1
26
- return 0
27
- }
28
-
29
- interface FeedContentPaneProps<T extends AnyObject = AnyObject> {
30
- id: string
31
- collectionPath: string
32
- RenderItem: (i: WithId<T>) => JSX.Element
33
- onItemLoad: (data: WithId<T> | null) => void
34
- status: PanelStatus
35
- enterStatus?: PanelStatus | null
36
- offsetY: MotionValue<number>
37
- }
38
-
39
- export const FeedContentPane = <T extends AnyObject = AnyObject>({
40
- id,
41
- collectionPath,
42
- onItemLoad,
43
- RenderItem,
44
- status,
45
- offsetY,
46
- enterStatus,
47
- }: FeedContentPaneProps<T>) => {
48
- const contentSize = useMobileFrame()
49
- const scale = useSpring(0, springConfig)
50
- const baseY = useMotionValue(getContentY(enterStatus ?? 'next', contentSize))
51
- const yVal = useTransform(() => baseY.get() + offsetY.get())
52
- const y = useSpring(yVal, springConfig)
53
-
54
- const docPath = useMemo(() => `${collectionPath}/${id}`, [collectionPath, id])
55
- const { data: item } = useDocument<T>(docPath, onItemLoad)
56
-
57
- const init = useRef<{
58
- status: PanelStatus
59
- contentSize: MobileFrameContextData
60
- y: number
61
- scale: number
62
- }>({
63
- contentSize,
64
- status: enterStatus ?? status,
65
- // x: getContentX(fromStatus || status, contentSize),
66
- y: getContentY(enterStatus ?? status, contentSize),
67
- scale: getContentScale(enterStatus ?? status),
68
- })
69
-
70
- useEffect(() => {
71
- const newScale = getContentScale(status)
72
- const updatedX = getContentX(status, contentSize)
73
- baseY.set(updatedX)
74
- scale.set(newScale)
75
- }, [status, baseY, scale, contentSize])
76
-
77
- return (
78
- // <AnimatePresence>
79
- <motion.div
80
- initial={{
81
- x: 0,
82
- y: init.current.y,
83
- scale: init.current.scale,
84
- }}
85
- style={{
86
- position: 'absolute',
87
- top: 0,
88
- left: 0,
89
- display: 'flex',
90
- alignItems: 'center',
91
- justifyContent: 'center',
92
- touchAction: 'none',
93
- userSelect: 'none',
94
- height: '100%',
95
- y,
96
- scale,
97
- opacity: scale,
98
- width: '100%',
99
- }}
100
- exit={{
101
- opacity: 0,
102
- scale: 0,
103
- // x: getContentX(fromStatus || status, contentSize),
104
- x: 0,
105
- y: getContentY(enterStatus === 'next' ? 'prev' : 'next', contentSize),
106
- }}>
107
- {item ? RenderItem(item) : null}
108
- </motion.div>
109
- // </AnimatePresence>
110
- )
111
- }
@@ -1,200 +0,0 @@
1
- import { Center } from '@chakra-ui/react'
2
- import { AnyObject, WithId } from '@chem-po/core'
3
- import { useMobileFrame } from '@chem-po/react'
4
- import { useMotionValue } from 'framer-motion'
5
- import React, {
6
- CSSProperties,
7
- Dispatch,
8
- PropsWithChildren,
9
- useCallback,
10
- useMemo,
11
- useRef,
12
- useState,
13
- } from 'react'
14
- import { LoadingOverlay } from '../loading'
15
- import { REFRESH_THRESHOLD, SWIPE_THRESHOLD } from './constants'
16
- import { MediaFeedProvider } from './context'
17
- import { FeedContentPane } from './FeedContentPane'
18
- import { useMediaFeed } from './hooks'
19
- import { MediaFeedBackground } from './MediaFeedBackground'
20
- import { MediaFeedRefresh } from './MediaFeedRefresh'
21
- import { MediaBackgroundRef, MediaFeedProps, PanelData, UpdatePanelsArgs } from './types'
22
-
23
- const useUpdatePanels = (setItems: Dispatch<React.SetStateAction<Array<PanelData>>>) =>
24
- useCallback(
25
- (data: UpdatePanelsArgs) => {
26
- const updated: PanelData[] = []
27
- if (data.prev) updated.push({ status: 'prev', id: data.prev })
28
- if (data.curr) {
29
- updated.push({
30
- status: 'current',
31
- id: data.curr,
32
- })
33
- }
34
- if (data.next) updated.push({ status: 'next', id: data.next })
35
- setItems(updated)
36
- },
37
- [setItems],
38
- )
39
-
40
- export const MediaFeed = <T extends AnyObject = AnyObject>({
41
- fetch,
42
- collection: collectionPath,
43
- RenderItem,
44
- authRequired,
45
- getBackgroundUrl,
46
- getBackgroundValue,
47
- limit,
48
- defaultBackground,
49
- swipeDisabled,
50
- children,
51
- }: PropsWithChildren<MediaFeedProps<T>>) => {
52
- const { width, height } = useMobileFrame()
53
-
54
- const contentRef = useRef<HTMLDivElement>(null)
55
-
56
- const containerRef = useRef<HTMLDivElement>(null)
57
- // const panels = useRef<Array<FeedContentPaneRef>>([])
58
- const [direction, setDirection] = useState<'next' | 'prev' | null>(null)
59
- const [panels, setPanels] = useState<Array<PanelData>>([])
60
-
61
- const offsetY = useMotionValue(0)
62
- const onNewData = useUpdatePanels(setPanels)
63
-
64
- const backgroundRef = useRef<MediaBackgroundRef<T>>(null)
65
-
66
- const { goNext, goPrev, loading, canGoNext, canGoPrev, refresh, refreshing } = useMediaFeed(
67
- fetch,
68
- onNewData,
69
- limit,
70
- authRequired,
71
- )
72
-
73
- const pointerDown = useRef(false)
74
- const dragStart = useRef({ x: 0, y: 0 })
75
-
76
- const onDragStart = useCallback(
77
- (e: React.PointerEvent) => {
78
- if (swipeDisabled) return
79
- pointerDown.current = true
80
- dragStart.current = { x: e.clientX, y: e.clientY }
81
- const dragEndListener = (ev: PointerEvent) => {
82
- // const oX = Math.max(-width / 4, Math.min(width / 4, ev.clientX - dragStart.current.x))
83
- const maxY = canGoPrev ? SWIPE_THRESHOLD : REFRESH_THRESHOLD
84
- const minY = canGoNext ? -SWIPE_THRESHOLD : -REFRESH_THRESHOLD
85
- const oY = Math.max(minY, Math.min(maxY, ev.clientY - dragStart.current.y))
86
- if (contentRef.current) contentRef.current.style.setProperty('pointer-events', 'auto')
87
- if (canGoNext && oY < -(SWIPE_THRESHOLD - 10)) {
88
- setDirection('next')
89
- goNext()
90
- } else if (canGoPrev && oY > SWIPE_THRESHOLD - 10) {
91
- setDirection('prev')
92
- goPrev()
93
- } else if (oY > REFRESH_THRESHOLD - 10 || oY < -(REFRESH_THRESHOLD - 10)) {
94
- refresh()
95
- if (backgroundRef.current) backgroundRef.current.onNewData(null)
96
- }
97
- // else if (onSwipeUp && oY < -97) {
98
- // onSwipeUp()
99
- // }
100
- offsetY.set(0)
101
- pointerDown.current = false
102
- window.removeEventListener('pointerup', dragEndListener)
103
- }
104
-
105
- window.addEventListener('pointerup', dragEndListener)
106
- },
107
- [offsetY, goNext, goPrev, canGoNext, canGoPrev, refresh, swipeDisabled],
108
- )
109
-
110
- const onDragMove = useCallback(
111
- (e: React.PointerEvent) => {
112
- requestAnimationFrame(() => {
113
- if (pointerDown.current) {
114
- const oX = Math.max(-10, Math.min(10, e.clientX - dragStart.current.x))
115
- const maxY = canGoPrev ? SWIPE_THRESHOLD : REFRESH_THRESHOLD
116
- const minY = canGoNext ? -SWIPE_THRESHOLD : -REFRESH_THRESHOLD
117
- const oY = Math.max(minY, Math.min(maxY, e.clientY - dragStart.current.y))
118
-
119
- const dist = Math.sqrt(oX ** 2 + oY ** 2)
120
- if (dist > 10 && contentRef.current) {
121
- contentRef.current.style.setProperty('pointer-events', 'none')
122
- }
123
- // offsetX.jump(oX)
124
- offsetY.set(oY)
125
- }
126
- })
127
- },
128
- [offsetY, canGoNext, canGoPrev],
129
- )
130
-
131
- const containerStyle = useMemo<CSSProperties>(
132
- () => ({
133
- height: `${height}px`,
134
- width: `${width}px`,
135
- overflow: 'hidden',
136
- pointerEvents: swipeDisabled ? 'none' : 'auto',
137
- }),
138
- [width, height, swipeDisabled],
139
- )
140
- const [curr, setCurr] = useState<WithId<T> | null>(null)
141
-
142
- const handleItemLoad = useCallback(
143
- (data: WithId<T> | null) => {
144
- const isCurr = panels.find(p => p.status === 'current')?.id === data?.id
145
- if (isCurr) setCurr(data)
146
- },
147
- [panels],
148
- )
149
-
150
- return (
151
- <MediaFeedProvider curr={curr}>
152
- <Center
153
- background={defaultBackground ?? 'background.100'}
154
- style={{ touchAction: 'none' }}
155
- userSelect="none"
156
- position="relative"
157
- w="100%"
158
- h="100%"
159
- overflow="hidden"
160
- onPointerDown={onDragStart}
161
- onPointerMove={onDragMove}>
162
- <MediaFeedBackground
163
- item={curr}
164
- getBackgroundValue={getBackgroundValue}
165
- getBackgroundUrl={getBackgroundUrl}
166
- />
167
- <div ref={containerRef} style={containerStyle}>
168
- <Center ref={contentRef} h="100%" w="100%">
169
- {panels.map(panel => (
170
- <FeedContentPane<T>
171
- key={panel.id}
172
- id={panel.id}
173
- collectionPath={collectionPath}
174
- RenderItem={RenderItem}
175
- onItemLoad={handleItemLoad}
176
- status={panel.status}
177
- enterStatus={direction}
178
- offsetY={offsetY}
179
- />
180
- ))}
181
- </Center>
182
- </div>
183
- <MediaFeedRefresh canRefresh={!canGoPrev} refreshing={refreshing} offsetY={offsetY} />
184
- {/* {onSwipeUp ? <MediaFeedSwipeUp offsetY={offsetY} /> : null} */}
185
- <LoadingOverlay
186
- inFeed
187
- zIndex={2}
188
- bg="transparent"
189
- pointerEvents="none"
190
- isLoading={loading}
191
- />
192
- {children ? (
193
- <Center position="absolute" bottom="0" left="0" right="0" zIndex={3} pointerEvents="none">
194
- {children}
195
- </Center>
196
- ) : null}
197
- </Center>
198
- </MediaFeedProvider>
199
- )
200
- }
@@ -1,127 +0,0 @@
1
- import { Center, CenterProps } from '@chakra-ui/react'
2
- import { AnyObject, WithId } from '@chem-po/core'
3
- import { useObjectUrl } from '@chem-po/react'
4
- import React, { useEffect, useMemo, useRef, useState } from 'react'
5
- import { LoadingLogo } from '../loading'
6
- import { GetBackgroundUrl, GetBackgroundValue } from './types'
7
-
8
- const emptyPng =
9
- 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkAAIAAAoAAv/lxKUAAAAASUVORK5CYII='
10
- const FillBackground = ({
11
- background,
12
- ...props
13
- }: Omit<CenterProps, 'background'> & { background: string | null }) => (
14
- <Center
15
- position="absolute"
16
- top="0"
17
- left="0"
18
- opacity={background ? 0.7 : 0}
19
- transition="opacity 500ms"
20
- right="0"
21
- bottom="0"
22
- zIndex={0}
23
- transform="scale(1.075)"
24
- pointerEvents="none"
25
- backgroundImage={`url(${background ?? emptyPng})`}
26
- backgroundSize="cover"
27
- backgroundPosition="center"
28
- {...props}
29
- filter={props.filter ?? 'blur(15px) brightness(70%)'}
30
- />
31
- )
32
-
33
- interface FileValueBackgroundProps<T extends AnyObject = AnyObject> {
34
- getBackgroundValue: GetBackgroundValue<T>
35
- item: WithId<T> | null
36
- filter?: string
37
- }
38
- const FileValueBackground = <T extends AnyObject = AnyObject>({
39
- getBackgroundValue,
40
- item,
41
- filter,
42
- }: FileValueBackgroundProps<T>) => {
43
- const background = useMemo(
44
- () => (item ? getBackgroundValue(item) : null),
45
- [getBackgroundValue, item],
46
- )
47
- const { loading, url } = useObjectUrl(background)
48
- const usedIndex = useRef(0)
49
- const [index, setIndex] = useState(0)
50
- const [url1, setUrl1] = useState<string | null>(null)
51
- const [url2, setUrl2] = useState<string | null>(null)
52
-
53
- useEffect(() => {
54
- const usedIdx = usedIndex.current
55
- if (usedIdx === 0) {
56
- setUrl1(url)
57
- usedIndex.current = 1
58
- setIndex(0)
59
- } else {
60
- setUrl2(url)
61
- usedIndex.current = 0
62
- setIndex(1)
63
- }
64
- }, [url])
65
-
66
- return (
67
- <Center position="absolute" top="0" left="0" right="0" bottom="0" zIndex={0}>
68
- <FillBackground filter={filter} opacity={index === 0 ? 1 : 0} background={url1} />
69
- <FillBackground filter={filter} opacity={index === 1 ? 1 : 0} background={url2} />
70
- <LoadingLogo isLoading={loading} />
71
- </Center>
72
- )
73
- }
74
-
75
- const UrlBackground = <T extends AnyObject = AnyObject>({
76
- getBackgroundUrl,
77
- item,
78
- filter,
79
- }: {
80
- getBackgroundUrl: GetBackgroundUrl<T>
81
- item: T | null
82
- filter?: string
83
- }) => {
84
- const background = useMemo(() => (item ? getBackgroundUrl(item) : null), [getBackgroundUrl, item])
85
- const usedIndex = useRef(0)
86
- const [index, setIndex] = useState(0)
87
- const [url1, setUrl1] = useState<string | null>(null)
88
- const [url2, setUrl2] = useState<string | null>(null)
89
-
90
- useEffect(() => {
91
- if (!background) return
92
- if (usedIndex.current === 0) {
93
- setUrl1(background)
94
- usedIndex.current = 1
95
- setIndex(0)
96
- } else {
97
- setUrl2(background)
98
- usedIndex.current = 0
99
- setIndex(1)
100
- }
101
- }, [background])
102
-
103
- return (
104
- <Center position="absolute" top="0" left="0" right="0" bottom="0" zIndex={0}>
105
- <FillBackground filter={filter} opacity={index === 0 ? 1 : 0} background={url1} />
106
- <FillBackground filter={filter} opacity={index === 1 ? 1 : 0} background={url2} />
107
- </Center>
108
- )
109
- }
110
-
111
- interface MediaFeedBackgroundProps<T extends AnyObject = AnyObject> {
112
- getBackgroundValue?: GetBackgroundValue<T>
113
- getBackgroundUrl?: GetBackgroundUrl<T>
114
- filter?: string
115
- item: WithId<T> | null
116
- }
117
-
118
- export const MediaFeedBackground = <T extends AnyObject = AnyObject>({
119
- getBackgroundValue,
120
- getBackgroundUrl,
121
- ...props
122
- }: MediaFeedBackgroundProps<T>) => {
123
- if (getBackgroundValue)
124
- return <FileValueBackground getBackgroundValue={getBackgroundValue} {...props} />
125
- if (getBackgroundUrl) return <UrlBackground getBackgroundUrl={getBackgroundUrl} {...props} />
126
- return null
127
- }
@@ -1,78 +0,0 @@
1
- import { RepeatIcon } from '@chakra-ui/icons'
2
- import { Center } from '@chakra-ui/react'
3
- import { motion, MotionValue, useSpring, useTransform } from 'framer-motion'
4
- import React, { useEffect } from 'react'
5
- import { CircularProgress } from '../loading/CircularProgress'
6
- import { REFRESH_THRESHOLD, SWIPE_THRESHOLD } from './constants'
7
-
8
- const WINDOW = REFRESH_THRESHOLD - SWIPE_THRESHOLD
9
- export const MediaFeedRefresh = ({
10
- offsetY,
11
- refreshing,
12
- canRefresh,
13
- }: {
14
- offsetY: MotionValue<number>
15
- refreshing: boolean
16
- canRefresh: boolean
17
- }) => {
18
- const progress = useTransform(offsetY, v => {
19
- const dist = Math.max(0, v - SWIPE_THRESHOLD)
20
- return dist / WINDOW
21
- })
22
- const baseY = useSpring(0)
23
- const isIn = useSpring(0)
24
- useEffect(() => {
25
- if (refreshing) {
26
- baseY.set(50)
27
- } else {
28
- baseY.set(0)
29
- }
30
- }, [refreshing, baseY])
31
-
32
- useEffect(() => {
33
- if (canRefresh) {
34
- isIn.set(1)
35
- } else {
36
- isIn.set(0)
37
- }
38
- }, [isIn, canRefresh])
39
-
40
- const y = useTransform(
41
- () => isIn.get() * Math.min(20, Math.max(0, baseY.get() + progress.get() ** 0.5 * 20)),
42
- )
43
- const scale = useTransform(y, v => isIn.get() * Math.min(1, Math.max(0, v / 30)))
44
- const rotate = useTransform(() => isIn.get() * progress.get() * 180)
45
- return (
46
- <motion.div
47
- style={{
48
- opacity: scale,
49
- pointerEvents: 'none',
50
- y,
51
- position: 'absolute',
52
- top: 0,
53
- left: 0,
54
- right: 0,
55
- height: 'auto',
56
- scale,
57
- rotate,
58
- }}>
59
- <Center w="100%">
60
- <RepeatIcon
61
- opacity={refreshing ? 0 : 1}
62
- transition={`opacity 300ms ease ${!refreshing ? 300 : 0}ms`}
63
- w={8}
64
- h={8}
65
- color="white"
66
- filter="drop-shadow(1px 1px 3px #000000aa)"
67
- />
68
- <CircularProgress
69
- size={8}
70
- position="absolute"
71
- isIndeterminate
72
- opacity={refreshing ? 1 : 0}
73
- transition={`opacity 300ms ease ${refreshing ? 300 : 0}ms`}
74
- />
75
- </Center>
76
- </motion.div>
77
- )
78
- }
@@ -1,35 +0,0 @@
1
- import { ChevronUpIcon } from '@chakra-ui/icons'
2
- import { Center } from '@chakra-ui/react'
3
- import { motion, MotionValue, useTransform } from 'framer-motion'
4
- import React from 'react'
5
-
6
- export const MediaFeedSwipeUp = ({ offsetY }: { offsetY: MotionValue<number> }) => {
7
- const progress = useTransform(offsetY, v => {
8
- if (v > -30) return 0
9
- return Math.max(0, -(v + 30) / 20)
10
- })
11
- const y = useTransform(progress, v => -(v ** 0.5) * 10)
12
- return (
13
- <motion.div
14
- style={{
15
- opacity: progress,
16
- pointerEvents: 'none',
17
- y,
18
- position: 'absolute',
19
- bottom: 0,
20
- left: 0,
21
- right: 0,
22
- height: 'auto',
23
- scale: progress,
24
- }}>
25
- <Center w="100%">
26
- <ChevronUpIcon
27
- w={8}
28
- h={8}
29
- color="whiteAlpha.700"
30
- filter="drop-shadow(1px 1px 3px #000000aa)"
31
- />
32
- </Center>
33
- </motion.div>
34
- )
35
- }
@@ -1,11 +0,0 @@
1
- import { SpringOptions } from 'framer-motion'
2
-
3
- export const springConfig: SpringOptions = {
4
- damping: 25,
5
- stiffness: 200,
6
- bounce: 0.5,
7
- // restSpeed: 0.1,
8
- }
9
-
10
- export const SWIPE_THRESHOLD = 75
11
- export const REFRESH_THRESHOLD = 100