@codeleap/web 3.10.3 → 3.10.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codeleap/web",
3
- "version": "3.10.3",
3
+ "version": "3.10.5",
4
4
  "main": "src/index.ts",
5
5
  "repository": {
6
6
  "url": "https://github.com/codeleap-uk/internal-libs-monorepo.git",
@@ -22,7 +22,7 @@ const defaultProps: Partial<GridProps> = {
22
22
  ListLoadingIndicatorComponent: null,
23
23
  ListEmptyComponent: EmptyPlaceholder,
24
24
  ListSeparatorComponent: RenderSeparator,
25
- refreshDebounce: 3000,
25
+ refreshDebounce: 1500,
26
26
  refreshSize: 40,
27
27
  refreshThreshold: 0.1,
28
28
  refreshPosition: 16,
@@ -88,7 +88,7 @@ export function Grid<T = any>(props: GridProps<T>) {
88
88
  {_item?.index <= numColumns ? null : separator}
89
89
  <RenderItem {..._itemProps} />
90
90
  </>
91
- }, [])
91
+ }, [RenderItem])
92
92
 
93
93
  return (
94
94
  <ListLayout
@@ -97,14 +97,14 @@ export function Grid<T = any>(props: GridProps<T>) {
97
97
  variantStyles={variantStyles}
98
98
  >
99
99
  <GridMasonry
100
- items={data}
101
- columnGutter={columnItemsSpacing}
102
- rowGutter={rowItemsSpacing}
103
- overscanBy={overscan}
100
+ items={data || []}
104
101
  render={renderItem}
105
- onRender={onLoadMore}
106
102
  itemKey={item => item?.id}
103
+ columnGutter={columnItemsSpacing}
104
+ rowGutter={rowItemsSpacing}
107
105
  columnCount={numColumns}
106
+ onRender={onLoadMore}
107
+ overscanBy={overscan}
108
108
  {...masonryProps}
109
109
  />
110
110
  </ListLayout>
@@ -13,7 +13,6 @@ type ListLayoutProps = Omit<ListProps, 'renderItem'> & UseInfiniteScrollReturn['
13
13
  }
14
14
 
15
15
  type ListRefreshControlComponent = Partial<ListLayoutProps> & {
16
- enabled: boolean
17
16
  variantStyles: StylesOf<ListComposition>
18
17
  }
19
18
 
@@ -26,11 +25,8 @@ const DefaultRefreshIndicator = (props: ListRefreshControlComponent) => {
26
25
  debugName,
27
26
  refreshSize,
28
27
  refreshControlIndicatorProps,
29
- enabled,
30
28
  } = props
31
29
 
32
- if (!enabled) return null
33
-
34
30
  return (
35
31
  <motion.div
36
32
  css={[variantStyles?.refreshControl]}
@@ -85,11 +81,12 @@ export const ListLayout = (props: ListLayoutProps) => {
85
81
  ? <ListEmptyComponent debugName={debugName} {...placeholder} />
86
82
  : (
87
83
  <View css={[getKeyStyle('innerWrapper')]}>
88
- <ListRefreshControlComponent
89
- {...props}
90
- enabled={refresh}
91
- variantStyles={variantStyles}
92
- />
84
+ {(!ListRefreshControlComponent || !refresh) ? null : (
85
+ <ListRefreshControlComponent
86
+ {...props}
87
+ variantStyles={variantStyles}
88
+ />
89
+ )}
93
90
 
94
91
  {children}
95
92
  </View>
@@ -26,7 +26,7 @@ const defaultProps: Partial<ListProps> = {
26
26
  ListLoadingIndicatorComponent: null,
27
27
  ListEmptyComponent: EmptyPlaceholder,
28
28
  ListSeparatorComponent: RenderSeparator,
29
- refreshDebounce: 3000,
29
+ refreshDebounce: 1500,
30
30
  refreshSize: 40,
31
31
  refreshThreshold: 0.1,
32
32
  refreshPosition: 16,
@@ -87,7 +87,7 @@ export function List<T = any>(props: ListProps<T>) {
87
87
  {isFirst ? null : separator}
88
88
  <RenderItem {..._itemProps} />
89
89
  </>
90
- }, [])
90
+ }, [RenderItem])
91
91
 
92
92
  return (
93
93
  <ListLayout
@@ -96,12 +96,12 @@ export function List<T = any>(props: ListProps<T>) {
96
96
  variantStyles={variantStyles}
97
97
  >
98
98
  <ListMasonry
99
- items={data}
100
- rowGutter={rowItemsSpacing}
101
- overscanBy={overscan}
99
+ items={data || []}
102
100
  render={renderItem}
103
- onRender={onLoadMore}
104
101
  itemKey={item => item?.id}
102
+ rowGutter={rowItemsSpacing}
103
+ onRender={onLoadMore}
104
+ overscanBy={overscan}
105
105
  {...masonryProps}
106
106
  />
107
107
  </ListLayout>
@@ -1,8 +1,8 @@
1
1
  import React from 'react'
2
- import { AnyFunction, onUpdate, TypeGuards } from '@codeleap/common'
2
+ import { AnyFunction, TypeGuards, useEffect } from '@codeleap/common'
3
3
  import { ListProps } from '.'
4
4
  import { GridProps } from '../Grid'
5
- import { useInfiniteLoader, LoadMoreItemsCallback, UseInfiniteLoaderOptions, useContainerPosition, useScroller } from 'masonic'
5
+ import { useInfiniteLoader, LoadMoreItemsCallback, UseInfiniteLoaderOptions } from 'masonic'
6
6
 
7
7
  export type UseInfiniteScrollArgs<Item extends Element = any> = {
8
8
  threshold?: number
@@ -31,6 +31,19 @@ type UseRefreshOptions = {
31
31
  enabled: boolean
32
32
  }
33
33
 
34
+ const scrollDebounce = (func, delay) => {
35
+ const timerRef = React.useRef(null)
36
+
37
+ const scrollDebounce = (...args) => {
38
+ clearTimeout(timerRef.current)
39
+ timerRef.current = setTimeout(() => {
40
+ func(...args)
41
+ }, delay)
42
+ }
43
+
44
+ return scrollDebounce
45
+ }
46
+
34
47
  export const useRefresh = (onRefresh = () => null, options: UseRefreshOptions) => {
35
48
  const {
36
49
  threshold,
@@ -45,27 +58,50 @@ export const useRefresh = (onRefresh = () => null, options: UseRefreshOptions) =
45
58
 
46
59
  const [refresh, setRefresh] = React.useState(false)
47
60
 
61
+ const pushToTopRef = React.useRef(0)
48
62
  const containerRef = React.useRef(null)
49
63
 
50
- const { offset } = useContainerPosition(containerRef)
51
- const { scrollTop, isScrolling } = useScroller(offset, 2)
52
-
53
- const handleRefresh = React.useCallback(() => {
54
- if (!refresh && isScrolling) {
55
- setRefresh(true)
56
- onRefresh?.()
57
-
58
- setTimeout(() => {
59
- setRefresh(false)
60
- }, debounce)
64
+ const refresher = React.useCallback(async () => {
65
+ setRefresh(true)
66
+ await onRefresh?.()
67
+
68
+ setTimeout(() => {
69
+ setRefresh(false)
70
+ pushToTopRef.current = 0
71
+ }, 2000)
72
+ }, [])
73
+
74
+ const onScroll = scrollDebounce(() => {
75
+ if (containerRef.current) {
76
+ const rect = containerRef.current?.getBoundingClientRect()
77
+ const scrollTop = window?.pageYOffset || document?.documentElement?.scrollTop
78
+
79
+ const containerTop = rect.top + scrollTop
80
+ const containerHeight = rect.height
81
+
82
+ const distanceFromTop = Math.max(0, scrollTop - containerTop)
83
+ const distanceFromBottom = Math.max(0, containerTop + containerHeight - scrollTop)
84
+
85
+ const totalDistance = containerHeight + distanceFromTop + distanceFromBottom
86
+ const percentage = (distanceFromTop / totalDistance) * 100
87
+
88
+ if (percentage < threshold) {
89
+ if (pushToTopRef.current === 2) {
90
+ refresher()
91
+ }
92
+
93
+ pushToTopRef.current = pushToTopRef.current + 1
94
+ }
61
95
  }
62
- }, [refresh, isScrolling])
96
+ }, debounce)
97
+
98
+ useEffect(() => {
99
+ window.addEventListener('scroll', onScroll)
63
100
 
64
- onUpdate(() => {
65
- if (scrollTop <= threshold) {
66
- handleRefresh()
101
+ return () => {
102
+ window.removeEventListener('scroll', onScroll)
67
103
  }
68
- }, [scrollTop])
104
+ }, [])
69
105
 
70
106
  return {
71
107
  refresh,
@@ -9,7 +9,6 @@ import {
9
9
  onUpdate,
10
10
  useDefaultComponentStyle,
11
11
  useNestedStylesByKey,
12
- useUnmount,
13
12
  StylesOf,
14
13
  PropsOf,
15
14
  useIsomorphicEffect,
@@ -24,8 +23,8 @@ import { Overlay, OverlayProps } from '../Overlay'
24
23
  import { ModalComposition, ModalPresets } from './styles'
25
24
  import { ActionIcon, ActionIconProps } from '../ActionIcon'
26
25
  import { Scroll } from '../Scroll'
27
- import { usePopState } from '../../lib/usePopState'
28
26
  import { ComponentCommonProps } from '../../types'
27
+ import { Touchable, TouchableProps } from '../Touchable'
29
28
 
30
29
  export * from './styles'
31
30
 
@@ -58,6 +57,7 @@ export type ModalProps =
58
57
  zIndex?: number
59
58
  withScrollContainer?: boolean
60
59
  scrollLocked?: boolean
60
+ backdropProps?: Partial<TouchableProps>
61
61
  } & ComponentVariants<typeof ModalPresets> & ComponentCommonProps
62
62
 
63
63
  function focusModal(event: FocusEvent, id: string) {
@@ -178,6 +178,7 @@ export const ModalContent = (
178
178
  withScrollContainer,
179
179
  debugName,
180
180
  scrollLocked,
181
+ backdropProps = {},
181
182
  ...props
182
183
  } = modalProps
183
184
 
@@ -196,8 +197,6 @@ export const ModalContent = (
196
197
  if (TypeGuards.isFunction(onClose)) onClose()
197
198
  }
198
199
 
199
- usePopState(visible, toggle, scrollLocked)
200
-
201
200
  function closeOnEscPress(e: React.KeyboardEvent<HTMLDivElement>) {
202
201
  if (!closeOnEscape) return null
203
202
 
@@ -246,7 +245,12 @@ export const ModalContent = (
246
245
  />
247
246
 
248
247
  <ModalArea css={variantStyles.innerWrapper}>
249
- <View css={variantStyles.backdropPressable} onClick={close} />
248
+ <Touchable
249
+ css={variantStyles.backdropPressable}
250
+ onPress={close}
251
+ debounce={1000}
252
+ {...backdropProps}
253
+ />
250
254
  <View
251
255
  component='section'
252
256
  css={[
@@ -306,19 +310,6 @@ export const Modal = (props) => {
306
310
  } = allProps
307
311
 
308
312
  const modalId = useRef(v4())
309
- const [renderStatus, setRenderStatus] = React.useState(
310
- keepMounted ? 'mounted' : 'unmounted',
311
- )
312
-
313
- // onUpdate(() => {
314
- // if (!keepMounted) {
315
- // if (visible) {
316
- // setRenderStatus('mounted')
317
- // } else {
318
- // setTimeout(() => setRenderStatus('unmounted'), 500)
319
- // }
320
- // }
321
- // }, [keepMounted, visible])
322
313
 
323
314
  onMount(() => {
324
315
  if (accessible) {
@@ -335,9 +326,7 @@ export const Modal = (props) => {
335
326
  appRoot.setAttribute('aria-hidden', `${visible}`)
336
327
  appRoot.setAttribute('tabindex', `${-1}`)
337
328
  }
338
- }, [visible])
339
329
 
340
- onUpdate(() => {
341
330
  if (visible) {
342
331
  document.body.style.overflow = 'hidden'
343
332
  } else {
@@ -28,7 +28,7 @@ export type SegmentedControlProps<T = string> = ComponentVariants<typeof Segment
28
28
  styles?: StylesOf<SegmentedControlComposition>
29
29
 
30
30
  /** view style */
31
- style: PropsOf<typeof View>['style']
31
+ style?: PropsOf<typeof View>['style']
32
32
 
33
33
  /** prop to control when te value of the segmented control changes */
34
34
  onValueChange?: (v: any) => void
@@ -93,7 +93,9 @@ export const SegmentedControl = (props: SegmentedControlProps) => {
93
93
  },
94
94
  )
95
95
 
96
- const currentOptionIdx = options?.findIndex(o => o?.value === value) || 0
96
+ const currentOptionIdx = React.useMemo(() => {
97
+ return options?.findIndex(o => o?.value === value) || 0
98
+ }, [value])
97
99
 
98
100
  const maxDivWidthRef = useRef(null)
99
101
 
@@ -33,6 +33,8 @@ export type SliderProps = Partial<Omit<PrimitiveSliderProps, 'value' | 'onValueC
33
33
  style?: PropsOf<typeof View>['style']
34
34
  trackMarks?: Record<number, string>
35
35
  trackMarkComponent?: React.ComponentType<TrackMarkProps>
36
+ onPressThumbSetValue?: boolean
37
+ onPressThumb?: (value: number, thumbIndex: number) => void
36
38
  } & ComponentVariants<typeof SliderPresets>
37
39
 
38
40
  export type TrackMarkProps = {
@@ -82,6 +84,8 @@ export const Slider = (props: SliderProps) => {
82
84
  description = null,
83
85
  minStepsBetweenThumbs = 8,
84
86
  step = 1,
87
+ onPressThumbSetValue = false,
88
+ onPressThumb = null,
85
89
  ...sliderProps
86
90
  } = others
87
91
 
@@ -246,7 +250,11 @@ export const Slider = (props: SliderProps) => {
246
250
  // @ts-ignore
247
251
  index={i}
248
252
  style={thumbStyle}
249
- onClick={() => currentThumbRef.current = i}
253
+ onClick={() => {
254
+ if (onPressThumbSetValue) onValueChange?.([Number(_thumbValue)])
255
+ if (TypeGuards.isFunction(onPressThumb)) onPressThumb?.(_thumbValue, i)
256
+ currentThumbRef.current = i
257
+ }}
250
258
  onMouseEnter={() => currentThumbRef.current = i}
251
259
  />
252
260
  ))}
@@ -1,4 +1,4 @@
1
- import { ComponentVariants, TypeGuards, useDefaultComponentStyle, useI18N } from '@codeleap/common'
1
+ import { ComponentVariants, TypeGuards, useDefaultComponentStyle } from '@codeleap/common'
2
2
  import React, { ComponentPropsWithoutRef, ElementType } from 'react'
3
3
  import { StylesOf } from '../../types/utility'
4
4
  import { TextComposition, TextPresets } from './styles'
@@ -51,8 +51,6 @@ export const Text = <T extends ElementType>(textProps: TextProps<T>) => {
51
51
 
52
52
  const pressedRef = React.useRef(false)
53
53
 
54
- const { t } = useI18N()
55
-
56
54
  const variantStyles = useDefaultComponentStyle<'u:Text', typeof TextPresets>('u:Text', {
57
55
  responsiveVariants,
58
56
  variants,
@@ -60,14 +58,6 @@ export const Text = <T extends ElementType>(textProps: TextProps<T>) => {
60
58
  rootElement: 'text',
61
59
  })
62
60
 
63
- const _text = TypeGuards.isString(msg) ? msg : text
64
-
65
- let content = t(String(_text))
66
-
67
- if (TypeGuards.isNil(content) || !TypeGuards.isString(content) || content === 'null') {
68
- content = text
69
- }
70
-
71
61
  const isPressable = (TypeGuards.isFunction(onPress) || TypeGuards.isFunction(onClick)) && !pressDisabled
72
62
 
73
63
  const disabled = isPressable === false
@@ -95,12 +85,12 @@ export const Text = <T extends ElementType>(textProps: TextProps<T>) => {
95
85
  }
96
86
  }
97
87
 
98
- const _styles = [
88
+ const _styles = React.useMemo(() => ([
99
89
  variantStyles.text,
100
90
  disabled && variantStyles['text:disabled'],
101
91
  css,
102
92
  style,
103
- ]
93
+ ]), [css, style, disabled])
104
94
 
105
95
  const pressProps = isPressable ? {
106
96
  onClick: disabled ? null : _onPress,
@@ -112,7 +102,7 @@ export const Text = <T extends ElementType>(textProps: TextProps<T>) => {
112
102
  {...props}
113
103
  {...pressProps}
114
104
  >
115
- {content || children}
105
+ {text || children}
116
106
  </Component>
117
107
  )
118
108
  }