@codeleap/web 3.3.2 → 3.5.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 (59) hide show
  1. package/package.json +3 -1
  2. package/src/components/ActionIcon/index.tsx +49 -30
  3. package/src/components/ActionIcon/styles.ts +8 -5
  4. package/src/components/ActivityIndicator/index.tsx +6 -5
  5. package/src/components/Badge/index.tsx +135 -0
  6. package/src/components/Badge/styles.ts +15 -0
  7. package/src/components/Button/index.tsx +79 -69
  8. package/src/components/Button/styles.ts +10 -14
  9. package/src/components/Checkbox/index.tsx +9 -3
  10. package/src/components/Collapse/index.tsx +6 -3
  11. package/src/components/Drawer/index.tsx +72 -44
  12. package/src/components/Drawer/styles.ts +11 -3
  13. package/src/components/EmptyPlaceholder/index.tsx +135 -0
  14. package/src/components/EmptyPlaceholder/styles.ts +16 -0
  15. package/src/components/Grid/index.tsx +169 -0
  16. package/src/components/Grid/styles.ts +10 -0
  17. package/src/components/Grid/types.ts +24 -0
  18. package/src/components/Icon/index.tsx +7 -4
  19. package/src/components/InputBase/styles.ts +8 -56
  20. package/src/components/InputBase/utils.ts +63 -0
  21. package/src/components/List/ListLayout.tsx +98 -0
  22. package/src/components/List/PaginationIndicator.tsx +102 -0
  23. package/src/components/List/index.tsx +104 -91
  24. package/src/components/List/styles.ts +17 -5
  25. package/src/components/List/types.ts +51 -0
  26. package/src/components/List/useInfiniteScroll.ts +113 -0
  27. package/src/components/LoadingOverlay/index.tsx +5 -3
  28. package/src/components/Modal/index.tsx +30 -29
  29. package/src/components/NumberIncrement/index.tsx +3 -2
  30. package/src/components/Overlay/index.tsx +12 -2
  31. package/src/components/Pager/index.tsx +5 -1
  32. package/src/components/RadioInput/index.tsx +4 -3
  33. package/src/components/SearchInput/index.tsx +93 -0
  34. package/src/components/SegmentedControl/SegmentedControlOption.tsx +15 -9
  35. package/src/components/SegmentedControl/index.tsx +12 -5
  36. package/src/components/Select/index.tsx +18 -14
  37. package/src/components/Select/styles.ts +4 -3
  38. package/src/components/Select/types.ts +4 -3
  39. package/src/components/Slider/index.tsx +3 -2
  40. package/src/components/Switch/index.tsx +4 -2
  41. package/src/components/Text/index.tsx +98 -25
  42. package/src/components/Text/styles.ts +4 -4
  43. package/src/components/TextInput/index.tsx +6 -15
  44. package/src/components/Tooltip/index.tsx +163 -131
  45. package/src/components/Tooltip/styles.ts +13 -9
  46. package/src/components/Touchable/index.tsx +88 -26
  47. package/src/components/Touchable/styles.ts +4 -6
  48. package/src/components/View/index.tsx +1 -1
  49. package/src/components/components.ts +5 -1
  50. package/src/components/defaultStyles.ts +10 -3
  51. package/src/index.ts +2 -0
  52. package/src/lib/hooks.ts +27 -13
  53. package/src/lib/index.ts +4 -1
  54. package/src/lib/useBreakpointMatch.ts +33 -0
  55. package/src/lib/usePopState.ts +30 -0
  56. package/src/lib/useSearchParams.ts +54 -0
  57. package/src/lib/utils/stopPropagation.ts +3 -3
  58. package/src/types/index.ts +1 -1
  59. package/src/types/utility.ts +4 -0
@@ -1,7 +1,7 @@
1
1
  /** @jsx jsx */
2
2
  import { jsx } from '@emotion/react'
3
3
  import React, { useRef, forwardRef, useImperativeHandle } from 'react'
4
- import { FormTypes, useValidate, useState, TypeGuards, onUpdate } from '@codeleap/common'
4
+ import { FormTypes, useValidate, useState, TypeGuards, onUpdate, IconPlaceholder } from '@codeleap/common'
5
5
  import _Select, { components, MenuListProps, MenuProps, MultiValueProps, NoticeProps } from 'react-select'
6
6
  import Async from 'react-select/async'
7
7
  import { useSelectStyles } from './styles'
@@ -18,7 +18,7 @@ export * from './styles'
18
18
  export * from './types'
19
19
 
20
20
  const DefaultOption = (props: TCustomOption & { component: (props: TCustomOption) => JSX.Element }) => {
21
- const { isSelected, optionsStyles, label, selectedIcon, component = null, itemProps = {} as TCustomOption['itemProps'], isFocused } = props
21
+ const { isSelected, optionsStyles, label, selectedIcon, component = null, itemProps = {} as TCustomOption['itemProps'], isFocused, debugName } = props
22
22
 
23
23
  const styles = optionsStyles({ isSelected, isFocused, baseStyles: (itemProps?.styles ?? {}) })
24
24
 
@@ -30,6 +30,7 @@ const DefaultOption = (props: TCustomOption & { component: (props: TCustomOption
30
30
  text={label}
31
31
  // @ts-ignore
32
32
  rightIcon={isSelected && selectedIcon}
33
+ debugName={debugName}
33
34
  {...itemProps}
34
35
  styles={styles}
35
36
  />
@@ -69,13 +70,13 @@ const CustomMenuList = (props: MenuListProps & { defaultStyles: { wrapper: React
69
70
  }
70
71
 
71
72
  const DefaultPlaceholder = (props: PlaceholderProps) => {
72
- const { text: TextPlaceholder, defaultStyles, icon: IconPlaceholder } = props
73
+ const { text: TextPlaceholder, defaultStyles, icon: _IconPlaceholder, debugName } = props
73
74
 
74
75
  const _Text = () => {
75
76
  if (TypeGuards.isNil(TextPlaceholder)) return null
76
77
 
77
78
  if (TypeGuards.isString(TextPlaceholder)) {
78
- return <Text text={TextPlaceholder} css={[defaultStyles.text]} />
79
+ return <Text debugName={debugName} text={TextPlaceholder} css={[defaultStyles.text]} />
79
80
  } else if (React.isValidElement(TextPlaceholder)) {
80
81
  return TextPlaceholder as JSX.Element
81
82
  } else if (TypeGuards.isFunction(TextPlaceholder)) {
@@ -84,22 +85,22 @@ const DefaultPlaceholder = (props: PlaceholderProps) => {
84
85
  }
85
86
 
86
87
  const _Image = () => {
87
- if (TypeGuards.isNil(IconPlaceholder)) return null
88
+ if (TypeGuards.isNil(_IconPlaceholder)) return null
88
89
 
89
- if (TypeGuards.isString(IconPlaceholder)) {
90
- return <Icon name={TextPlaceholder as any} forceStyle={defaultStyles.icon} />
91
- } else if (React.isValidElement(IconPlaceholder)) {
90
+ if (TypeGuards.isString(_IconPlaceholder)) {
91
+ return <Icon debugName={debugName} name={_IconPlaceholder as IconPlaceholder} forceStyle={defaultStyles.icon as React.CSSProperties} />
92
+ } else if (React.isValidElement(_IconPlaceholder)) {
92
93
  // @ts-ignore
93
94
  return <View style={defaultStyles.icon}>
94
- { IconPlaceholder}
95
+ {_IconPlaceholder}
95
96
  </View>
96
- } else if (TypeGuards.isFunction(IconPlaceholder)) {
97
- return <IconPlaceholder {...props} />
97
+ } else if (TypeGuards.isFunction(_IconPlaceholder)) {
98
+ return <_IconPlaceholder {...props} />
98
99
  }
99
100
  }
100
101
 
101
102
  return (
102
- <View css={[defaultStyles.wrapper]}>
103
+ <View style={defaultStyles.wrapper as React.CSSProperties}>
103
104
  <_Image />
104
105
  <_Text />
105
106
  </View>
@@ -107,11 +108,11 @@ const DefaultPlaceholder = (props: PlaceholderProps) => {
107
108
  }
108
109
 
109
110
  const LoadingIndicator = (props: LoadingIndicatorProps) => {
110
- const { defaultStyles } = props
111
+ const { defaultStyles, debugName } = props
111
112
 
112
113
  return (
113
114
  <View css={[defaultStyles.wrapper]}>
114
- <ActivityIndicator />
115
+ <ActivityIndicator debugName={debugName} />
115
116
  </View>
116
117
  )
117
118
  }
@@ -317,6 +318,7 @@ export const Select = forwardRef<HTMLInputElement, SelectProps>(
317
318
  error: !!hasError,
318
319
  disabled: isDisabled,
319
320
  variantStyles,
321
+ debugName: debugName,
320
322
  }
321
323
 
322
324
  const _Placeholder = (props: NoticeProps) => {
@@ -332,6 +334,7 @@ export const Select = forwardRef<HTMLInputElement, SelectProps>(
332
334
  }
333
335
 
334
336
  if (!hasInputValue) {
337
+
335
338
  return <PlaceholderComponent {...placeholderProps} text={placeholderText} />
336
339
  } else {
337
340
  const _Text = TypeGuards.isString(noItemsText) ? formatPlaceholderNoItems({ ...placeholderProps, text: noItemsText }) : noItemsText
@@ -407,6 +410,7 @@ export const Select = forwardRef<HTMLInputElement, SelectProps>(
407
410
  {...props}
408
411
  defaultStyles={loadingStyles}
409
412
  size={loadingIndicatorSize}
413
+ debugName={debugName}
410
414
  />
411
415
  ),
412
416
  DropdownIndicator: props => showDropdownIcon ? <components.DropdownIndicator {...props} /> : null,
@@ -3,10 +3,9 @@ import { CSSInterpolation } from '@emotion/css'
3
3
  import { CSSObjectWithLabel, GroupBase, StylesConfig } from 'react-select'
4
4
  import { ButtonParts as _ButtonParts } from '../Button'
5
5
  import { InputBaseParts } from '../InputBase'
6
- import { LoadingOverlayComposition } from '../LoadingOverlay'
7
6
  import { SelectProps } from './types'
8
7
 
9
- type ButtonParts = Exclude<_ButtonParts, `loading${Capitalize<LoadingOverlayComposition>}` | 'badgeText' | 'badgeWrapper'>
8
+ type ButtonParts = _ButtonParts
10
9
 
11
10
  export type ItemParts = `item${Capitalize<ButtonParts>}`
12
11
 
@@ -62,6 +61,7 @@ export type OptionState = {
62
61
 
63
62
  export function useSelectStyles<T, Multi extends boolean>(props: SelectProps<T, Multi>, state: ComponentState) {
64
63
  const {
64
+ responsiveVariants = {},
65
65
  variants,
66
66
  styles,
67
67
  } = props
@@ -75,6 +75,7 @@ export function useSelectStyles<T, Multi extends boolean>(props: SelectProps<T,
75
75
  const variantStyles = useDefaultComponentStyle<'u:Select', typeof SelectPresets>(
76
76
  'u:Select',
77
77
  {
78
+ responsiveVariants,
78
79
  variants,
79
80
  styles,
80
81
  },
@@ -109,7 +110,7 @@ export function useSelectStyles<T, Multi extends boolean>(props: SelectProps<T,
109
110
  text: optionStyleKey('text', state),
110
111
  leftIcon: optionStyleKey('leftIcon', state),
111
112
  icon: optionStyleKey('icon', state),
112
- inner: optionStyleKey('inner', state),
113
+ loaderWrapper: optionStyleKey('loaderWrapper', state),
113
114
  })
114
115
 
115
116
  const placeholderStyles = {
@@ -3,6 +3,7 @@ import { CSSInterpolation } from '@emotion/css'
3
3
  import { CSSObject } from '@emotion/react'
4
4
  import { GroupBase, NoticeProps, OptionProps, Props } from 'react-select'
5
5
  import { AsyncProps } from 'react-select/async'
6
+ import { ComponentCommonProps } from '../../types'
6
7
  import { ButtonProps } from '../Button'
7
8
  import { InputBaseProps } from '../InputBase'
8
9
  import { SelectPresets, SelectComposition, OptionState } from './styles'
@@ -40,7 +41,7 @@ export type ComponentPartProps = {
40
41
  variantStyles: Record<SelectComposition, React.CSSProperties>
41
42
  }
42
43
 
43
- export type TCustomOption = OptionProps & ComponentPartProps & {
44
+ export type TCustomOption = OptionProps & ComponentPartProps & ComponentCommonProps & {
44
45
  optionsStyles: (state: OptionState) => OptionState['baseStyles']
45
46
  selectedIcon?: string
46
47
  itemProps?: ButtonProps
@@ -57,12 +58,12 @@ export type PlaceholderProps = NoticeProps & ComponentPartProps & {
57
58
  icon: CSSInterpolation
58
59
  }
59
60
  icon: SelectPlaceholderElement
60
- }
61
+ } & ComponentCommonProps
61
62
 
62
63
  export type LoadingIndicatorProps = NoticeProps & {
63
64
  defaultStyles: { wrapper: CSSInterpolation }
64
65
  size?: number
65
- }
66
+ } & ComponentCommonProps
66
67
 
67
68
  export type SelectProps<T = any, Multi extends boolean = false> = React.PropsWithChildren<
68
69
  {
@@ -29,12 +29,11 @@ export type SliderProps = Partial<Omit<PrimitiveSliderProps, 'value' | 'onValueC
29
29
  }
30
30
  value: number[]
31
31
  onValueChange: (val: number[]) => void
32
- variants?: ComponentVariants<typeof SliderPresets>['variants']
33
32
  styles?: StylesOf<SliderComposition>
34
33
  style?: PropsOf<typeof View>['style']
35
34
  trackMarks?: Record<number, string>
36
35
  trackMarkComponent?: React.ComponentType<TrackMarkProps>
37
- }
36
+ } & ComponentVariants<typeof SliderPresets>
38
37
 
39
38
  export type TrackMarkProps = {
40
39
  index: number
@@ -70,6 +69,7 @@ export const Slider = (props: SliderProps) => {
70
69
  label,
71
70
  debugName,
72
71
  styles = {},
72
+ responsiveVariants = {},
73
73
  style,
74
74
  disabled,
75
75
  variants,
@@ -127,6 +127,7 @@ export const Slider = (props: SliderProps) => {
127
127
  }
128
128
 
129
129
  const variantStyles = useDefaultComponentStyle<'u:Slider', typeof SliderPresets>('u:Slider', {
130
+ responsiveVariants,
130
131
  variants,
131
132
  styles,
132
133
  })
@@ -14,14 +14,13 @@ export type SwitchProps = Pick<
14
14
  InputBaseProps,
15
15
  'debugName' | 'disabled' | 'label'
16
16
  > & {
17
- variants?: ComponentVariants<typeof SwitchPresets>['variants']
18
17
  styles?: StylesOf<SwitchComposition>
19
18
  value: boolean
20
19
  onValueChange: (value: boolean) => void
21
20
  onChange?: (value: boolean) => void
22
21
  style?: PropsOf<typeof View>['style']
23
22
  switchOnLeft?: boolean
24
- }
23
+ } & ComponentVariants<typeof SwitchPresets>
25
24
 
26
25
  const reversedOrder = [...InputBaseDefaultOrder].reverse()
27
26
 
@@ -30,7 +29,9 @@ export const Switch = (props: SwitchProps) => {
30
29
  inputBaseProps,
31
30
  others,
32
31
  } = selectInputBaseProps(props)
32
+
33
33
  const {
34
+ responsiveVariants = {},
34
35
  variants = [],
35
36
  style = {},
36
37
  styles = {},
@@ -43,6 +44,7 @@ export const Switch = (props: SwitchProps) => {
43
44
  } = others
44
45
 
45
46
  const variantStyles = useDefaultComponentStyle<'u:Switch', typeof SwitchPresets>('u:Switch', {
47
+ responsiveVariants,
46
48
  variants,
47
49
  styles,
48
50
  rootElement: 'wrapper',
@@ -1,47 +1,120 @@
1
- /** @jsx jsx */
2
- import { jsx } from '@emotion/react'
3
- import {
4
- ComponentVariants,
5
- useDefaultComponentStyle,
6
- } from '@codeleap/common'
7
- import { NativeHTMLElement } from '../../types/utility'
8
- import { TextPresets } from './styles'
9
- import { View, ViewProps } from '../View'
1
+ import { ComponentVariants, TypeGuards, useDefaultComponentStyle, useI18N } from '@codeleap/common'
2
+ import React, { ComponentPropsWithoutRef, ElementType } from 'react'
3
+ import { StylesOf } from '../../types/utility'
4
+ import { TextComposition, TextPresets } from './styles'
10
5
 
11
6
  export * from './styles'
12
7
 
13
- export type TextProps<T extends NativeHTMLElement> =
14
- Omit<ViewProps<T>, 'variants'|'responsiveVariants'> &
15
- ComponentVariants<typeof TextPresets> &
16
- {
17
- text?: string
8
+ export type TextProps<T extends ElementType> =
9
+ ComponentPropsWithoutRef<T> &
10
+ ComponentVariants<typeof TextPresets> & {
11
+ component?: T
12
+ text: string
13
+ styles?: StylesOf<TextComposition>
14
+ msg?: string
15
+ debugName?: string
16
+ debounce?: number
17
+ pressDisabled?: boolean
18
+ onPress?: (event: React.MouseEventHandler<T>) => void
19
+ }
20
+
21
+ const defaultProps: Partial<TextProps<'p'>> = {
22
+ debugName: 'Text component',
23
+ component: 'p',
24
+ debounce: null,
25
+ pressDisabled: false,
26
+ }
27
+
28
+ export const Text = <T extends ElementType>(textProps: TextProps<T>) => {
29
+ const allProps = {
30
+ ...Text.defaultProps,
31
+ ...textProps,
18
32
  }
19
33
 
20
- export const Text = <T extends NativeHTMLElement>(textProps: TextProps<T>) => {
21
34
  const {
22
35
  variants = [],
23
36
  responsiveVariants = {},
37
+ styles = {},
38
+ style = {},
39
+ css,
24
40
  text = null,
25
41
  children,
26
- // style,
42
+ component: Component,
43
+ debugName,
44
+ msg = null,
45
+ onPress,
46
+ debounce,
47
+ pressDisabled,
48
+ onClick,
27
49
  ...props
28
- } = textProps
50
+ } = allProps
51
+
52
+ const pressedRef = React.useRef(false)
53
+
54
+ const { t } = useI18N()
29
55
 
30
56
  const variantStyles = useDefaultComponentStyle<'u:Text', typeof TextPresets>('u:Text', {
31
- rootElement: 'text',
32
57
  responsiveVariants,
33
58
  variants,
34
-
59
+ styles,
60
+ rootElement: 'text',
35
61
  })
36
62
 
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
+ const isPressable = (TypeGuards.isFunction(onPress) || TypeGuards.isFunction(onClick)) && !pressDisabled
72
+
73
+ const disabled = isPressable === false
74
+
75
+ const _onPress = (e: React.MouseEventHandler<T>) => {
76
+ if (disabled) return
77
+
78
+ const handlePress = () => {
79
+ onClick?.(e)
80
+ onPress?.(e)
81
+ }
82
+
83
+ if (TypeGuards.isNumber(debounce)) {
84
+ if (pressedRef.current) {
85
+ return
86
+ }
87
+
88
+ pressedRef.current = true
89
+ handlePress()
90
+ setTimeout(() => {
91
+ pressedRef.current = false
92
+ }, debounce)
93
+ } else {
94
+ handlePress()
95
+ }
96
+ }
97
+
98
+ const _styles = [
99
+ variantStyles.text,
100
+ disabled && variantStyles['text:disabled'],
101
+ css,
102
+ style,
103
+ ]
104
+
105
+ const pressProps = isPressable ? {
106
+ onClick: disabled ? null : _onPress,
107
+ } : {}
108
+
37
109
  return (
38
- // @ts-ignore
39
- <View
40
- css={variantStyles.text}
41
- component={'p'}
110
+ <Component
111
+ css={_styles}
42
112
  {...props}
113
+ {...pressProps}
43
114
  >
44
- {text || children}
45
- </View>
115
+ {content || children}
116
+ </Component>
46
117
  )
47
118
  }
119
+
120
+ Text.defaultProps = defaultProps
@@ -1,9 +1,9 @@
1
1
  import { createDefaultVariantFactory, includePresets } from "@codeleap/common"
2
2
 
3
- export type TextComposition = 'text'
3
+ export type TextComposition = 'text' | 'text:disabled'
4
4
 
5
5
  const createTextStyle = createDefaultVariantFactory<TextComposition>()
6
6
 
7
- export const TextPresets = includePresets((styles) =>
8
- createTextStyle(() => ({ text: styles }))
9
- )
7
+ export const TextPresets = includePresets((styles) => createTextStyle(() => ({
8
+ text: styles
9
+ })))
@@ -39,7 +39,6 @@ export type TextInputProps =
39
39
  validate?: FormTypes.ValidatorWithoutForm<string> | yup.SchemaOf<string>
40
40
  debugName?: string
41
41
  visibilityToggle?: boolean
42
- variants?: ComponentVariants<typeof TextInputPresets>['variants']
43
42
  value?: NativeTextInputProps['value']
44
43
  multiline?: boolean
45
44
  onPress?: TouchableProps['onPress']
@@ -49,7 +48,7 @@ export type TextInputProps =
49
48
  _error?: boolean
50
49
  rows?: number
51
50
  masking?: TextInputMaskingProps
52
- }
51
+ } & ComponentVariants<typeof TextInputPresets>
53
52
 
54
53
  type InputRef = HTMLInputElement & { isTextInput?: boolean }
55
54
 
@@ -62,8 +61,9 @@ export const TextInput = forwardRef<InputRef, TextInputProps>((props, inputRef)
62
61
  } = selectInputBaseProps(props)
63
62
 
64
63
  const {
65
- variants,
66
- styles,
64
+ variants = [],
65
+ responsiveVariants = {},
66
+ styles = {},
67
67
  value,
68
68
  validate,
69
69
  debugName,
@@ -76,7 +76,7 @@ export const TextInput = forwardRef<InputRef, TextInputProps>((props, inputRef)
76
76
  _error,
77
77
  masking = null,
78
78
  ...textInputProps
79
- } = others
79
+ } = others as TextInputProps
80
80
 
81
81
  const [_isFocused, setIsFocused] = useState(false)
82
82
 
@@ -92,6 +92,7 @@ export const TextInput = forwardRef<InputRef, TextInputProps>((props, inputRef)
92
92
  const InputElement = isMasked ? InputMask : isMultiline ? TextareaAutosize : 'input'
93
93
 
94
94
  const variantStyles = useDefaultComponentStyle<'u:TextInput', typeof TextInputPresets>('u:TextInput', {
95
+ responsiveVariants,
95
96
  variants,
96
97
  styles,
97
98
  })
@@ -182,12 +183,6 @@ export const TextInput = forwardRef<InputRef, TextInputProps>((props, inputRef)
182
183
 
183
184
  const inputBaseAction = isPressable ? 'onPress' : 'onClick'
184
185
 
185
- const _wrapperOnInputFocus = {
186
- [inputBaseAction]: () => {
187
- innerInputRef.current?.focus?.()
188
- },
189
- }
190
-
191
186
  return (
192
187
  <InputBase
193
188
  innerWrapper={isPressable ? Touchable : undefined}
@@ -213,10 +208,6 @@ export const TextInput = forwardRef<InputRef, TextInputProps>((props, inputRef)
213
208
  }}
214
209
  rightIcon={rightIcon}
215
210
  focused={isFocused}
216
- wrapperProps={{
217
- ...(inputBaseProps.wrapperProps || {}),
218
- ..._wrapperOnInputFocus,
219
- }}
220
211
  >
221
212
 
222
213
  <InputElement