@codeleap/web 5.4.4 → 5.4.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.
Files changed (116) hide show
  1. package/dist/components/ActionIcon/types.d.ts +1 -1
  2. package/dist/components/Checkbox/index.js +14 -10
  3. package/dist/components/Checkbox/index.js.map +1 -1
  4. package/dist/components/Checkbox/types.d.ts +4 -2
  5. package/dist/components/DatePicker/components/DayContent.d.ts +11 -0
  6. package/dist/components/DatePicker/components/DayContent.js +43 -0
  7. package/dist/components/DatePicker/components/DayContent.js.map +1 -0
  8. package/dist/components/DatePicker/components/OuterInput.js +2 -2
  9. package/dist/components/DatePicker/components/OuterInput.js.map +1 -1
  10. package/dist/components/DatePicker/components/YearContent.d.ts +9 -0
  11. package/dist/components/DatePicker/components/YearContent.js +33 -0
  12. package/dist/components/DatePicker/components/YearContent.js.map +1 -0
  13. package/dist/components/DatePicker/components/index.d.ts +2 -0
  14. package/dist/components/DatePicker/components/index.js +2 -0
  15. package/dist/components/DatePicker/components/index.js.map +1 -1
  16. package/dist/components/DatePicker/index.js +10 -33
  17. package/dist/components/DatePicker/index.js.map +1 -1
  18. package/dist/components/DatePicker/types.d.ts +5 -6
  19. package/dist/components/InputBase/index.d.ts +2 -5
  20. package/dist/components/InputBase/index.js +19 -11
  21. package/dist/components/InputBase/index.js.map +1 -1
  22. package/dist/components/InputBase/types.d.ts +2 -1
  23. package/dist/components/InputBase/useInputBase.d.ts +60 -0
  24. package/dist/components/InputBase/useInputBase.js +55 -0
  25. package/dist/components/InputBase/useInputBase.js.map +1 -0
  26. package/dist/components/InputBase/useInputBasePartialStyles.d.ts +2 -0
  27. package/dist/components/InputBase/useInputBasePartialStyles.js +40 -0
  28. package/dist/components/InputBase/useInputBasePartialStyles.js.map +1 -0
  29. package/dist/components/Modal/index.d.ts +0 -3
  30. package/dist/components/Modal/index.js +35 -52
  31. package/dist/components/Modal/index.js.map +1 -1
  32. package/dist/components/Modal/types.d.ts +0 -4
  33. package/dist/components/NumberIncrement/index.js +18 -124
  34. package/dist/components/NumberIncrement/index.js.map +1 -1
  35. package/dist/components/NumberIncrement/types.d.ts +5 -6
  36. package/dist/components/NumberIncrement/useNumberIncrement.d.ts +60 -0
  37. package/dist/components/NumberIncrement/useNumberIncrement.js +115 -0
  38. package/dist/components/NumberIncrement/useNumberIncrement.js.map +1 -0
  39. package/dist/components/RadioInput/index.js +14 -14
  40. package/dist/components/RadioInput/index.js.map +1 -1
  41. package/dist/components/RadioInput/types.d.ts +9 -9
  42. package/dist/components/SearchInput/index.js +1 -1
  43. package/dist/components/SearchInput/index.js.map +1 -1
  44. package/dist/components/Select/index.js +5 -7
  45. package/dist/components/Select/index.js.map +1 -1
  46. package/dist/components/Select/styles.d.ts +2 -8
  47. package/dist/components/Select/styles.js.map +1 -1
  48. package/dist/components/Select/types.d.ts +10 -9
  49. package/dist/components/Slider/index.js +16 -46
  50. package/dist/components/Slider/index.js.map +1 -1
  51. package/dist/components/Slider/types.d.ts +4 -2
  52. package/dist/components/Switch/index.js +13 -11
  53. package/dist/components/Switch/index.js.map +1 -1
  54. package/dist/components/Switch/types.d.ts +4 -2
  55. package/dist/components/TextEditor/index.js +7 -14
  56. package/dist/components/TextEditor/index.js.map +1 -1
  57. package/dist/components/TextEditor/types.d.ts +2 -3
  58. package/dist/components/TextInput/index.js +31 -92
  59. package/dist/components/TextInput/index.js.map +1 -1
  60. package/dist/components/TextInput/types.d.ts +8 -7
  61. package/dist/components/TextInput/useTextInput.d.ts +90 -0
  62. package/dist/components/TextInput/useTextInput.js +74 -0
  63. package/dist/components/TextInput/useTextInput.js.map +1 -0
  64. package/dist/lib/tools/index.d.ts +0 -1
  65. package/dist/lib/tools/index.js +0 -1
  66. package/dist/lib/tools/index.js.map +1 -1
  67. package/dist/lib/tools/modal.d.ts +2 -2
  68. package/dist/lib/tools/modal.js +5 -4
  69. package/dist/lib/tools/modal.js.map +1 -1
  70. package/dist/types/utility.d.ts +1 -1
  71. package/package.json +17 -19
  72. package/package.json.bak +1 -3
  73. package/src/components/ActionIcon/types.ts +1 -1
  74. package/src/components/Checkbox/index.tsx +23 -9
  75. package/src/components/Checkbox/types.ts +4 -2
  76. package/src/components/DatePicker/components/DayContent.tsx +52 -0
  77. package/src/components/DatePicker/components/OuterInput.tsx +1 -2
  78. package/src/components/DatePicker/components/YearContent.tsx +39 -0
  79. package/src/components/DatePicker/components/index.tsx +2 -0
  80. package/src/components/DatePicker/index.tsx +33 -84
  81. package/src/components/DatePicker/types.ts +5 -6
  82. package/src/components/InputBase/index.tsx +9 -8
  83. package/src/components/InputBase/types.ts +2 -1
  84. package/src/components/InputBase/useInputBase.ts +56 -0
  85. package/src/components/InputBase/useInputBasePartialStyles.ts +37 -0
  86. package/src/components/Modal/index.tsx +64 -64
  87. package/src/components/Modal/types.ts +0 -4
  88. package/src/components/NumberIncrement/index.tsx +44 -141
  89. package/src/components/NumberIncrement/types.ts +5 -6
  90. package/src/components/NumberIncrement/useNumberIncrement.ts +149 -0
  91. package/src/components/RadioInput/index.tsx +32 -17
  92. package/src/components/RadioInput/types.ts +16 -15
  93. package/src/components/SearchInput/index.tsx +1 -1
  94. package/src/components/Select/index.tsx +6 -11
  95. package/src/components/Select/styles.ts +2 -2
  96. package/src/components/Select/types.ts +10 -9
  97. package/src/components/Slider/index.tsx +28 -52
  98. package/src/components/Slider/types.ts +4 -2
  99. package/src/components/Switch/index.tsx +19 -8
  100. package/src/components/Switch/types.ts +4 -2
  101. package/src/components/TextEditor/index.tsx +6 -14
  102. package/src/components/TextEditor/types.ts +2 -3
  103. package/src/components/TextInput/index.tsx +54 -103
  104. package/src/components/TextInput/types.ts +8 -7
  105. package/src/components/TextInput/useTextInput.ts +101 -0
  106. package/src/lib/tools/index.ts +0 -1
  107. package/src/lib/tools/modal.ts +3 -3
  108. package/src/types/utility.ts +1 -1
  109. package/dist/lib/tools/navigation/index.d.ts +0 -58
  110. package/dist/lib/tools/navigation/index.js +0 -235
  111. package/dist/lib/tools/navigation/index.js.map +0 -1
  112. package/dist/lib/tools/navigation/types.d.ts +0 -32
  113. package/dist/lib/tools/navigation/types.js +0 -3
  114. package/dist/lib/tools/navigation/types.js.map +0 -1
  115. package/src/lib/tools/navigation/index.tsx +0 -282
  116. package/src/lib/tools/navigation/types.ts +0 -53
@@ -0,0 +1,39 @@
1
+ import { StyleRecord } from '@codeleap/styles'
2
+ import { DatePickerProps, YearComponentProps } from '../types'
3
+ import { DatePickerComposition } from '../styles'
4
+ import { TypeGuards } from '@codeleap/types'
5
+ import { View } from '../../View'
6
+ import { Text } from '../../Text'
7
+ import { useInputBasePartialStyles } from '../../InputBase/useInputBasePartialStyles'
8
+
9
+ type Props = YearComponentProps & {
10
+ styles: StyleRecord<DatePickerComposition>
11
+ component: DatePickerProps['yearComponent']
12
+ }
13
+
14
+ export const YearContent = (props: Props) => {
15
+ const { value, year, styles, component: Component } = props
16
+
17
+ const isSelected = String(value)?.includes(year as string)
18
+
19
+ const partialStyles = useInputBasePartialStyles(styles, ['yearWrapper', 'year'], {
20
+ selected: isSelected,
21
+ })
22
+
23
+ if (TypeGuards.isFunction(Component)) {
24
+ return (
25
+ <Component
26
+ {...props}
27
+ value={value}
28
+ selected={isSelected}
29
+ styles={styles}
30
+ />
31
+ )
32
+ }
33
+
34
+ return (
35
+ <View style={partialStyles?.yearWrapper}>
36
+ <Text style={partialStyles?.year} text={year as string} />
37
+ </View>
38
+ )
39
+ }
@@ -1,2 +1,4 @@
1
1
  export * from './OuterInput'
2
2
  export * from './Header'
3
+ export * from './DayContent'
4
+ export * from './YearContent'
@@ -1,13 +1,11 @@
1
- import { TypeGuards } from '@codeleap/types'
2
1
  import { useCallback, useConditionalState } from '@codeleap/hooks'
3
- import { Text, View } from '../components'
4
- import { DatePickerProps, DayComponentProps } from './types'
2
+ import { View } from '../components'
3
+ import { DatePickerProps } from './types'
5
4
  import ReactDatePicker from 'react-datepicker'
6
- import { Header, OuterInput } from './components'
5
+ import { DayContent, Header, OuterInput, YearContent } from './components'
7
6
  import { useStylesFor } from '../../lib/hooks/useStylesFor'
8
7
  import { WebStyleRegistry } from '../../lib/WebStyleRegistry'
9
8
  import { AnyRecord, IJSX, StyledComponentProps, useCompositionStyles } from '@codeleap/styles'
10
- import dayjs from 'dayjs'
11
9
 
12
10
  export * from './styles'
13
11
  export * from './types'
@@ -23,19 +21,19 @@ export function DatePicker(props: DatePickerProps) {
23
21
  outerInputComponent: OuterInputComponent,
24
22
  headerComponent: HeaderComponent,
25
23
  headerProps: _headerProps,
26
- dayComponent: DayComponent,
27
- dayProps,
28
- yearComponent: YearComponent,
29
- yearProps,
24
+ dayComponent,
25
+ dayProps: providedDayProps,
26
+ yearComponent,
27
+ yearProps: providedYearProps,
30
28
  datePickerProps,
31
29
  minDate,
32
30
  maxDate,
33
31
  startDate,
34
- visible: _visible,
35
- toggle: _toggle,
36
- yearShow: _yearShow,
37
- setYearShow: _setYearShow,
38
32
  disabled,
33
+ visible: providedVisible,
34
+ toggle: providedToggle,
35
+ yearShow: providedYearShow,
36
+ setYearShow: providedSetYearShow,
39
37
  ...otherProps
40
38
  } = {
41
39
  ...DatePicker.defaultProps,
@@ -44,87 +42,38 @@ export function DatePicker(props: DatePickerProps) {
44
42
 
45
43
  const styles = useStylesFor(DatePicker.styleRegistryName, style)
46
44
 
47
- const [visible, toggle] = useConditionalState(_visible, _toggle, { initialValue: false })
48
- const [yearShow, setYearShow] = useConditionalState(_yearShow, _setYearShow, { initialValue: false })
49
-
50
- const DayContentComponent = useCallback((_param: DayComponentProps) => {
51
- const param = {
52
- ..._param,
53
- ...dayProps,
54
- }
55
-
56
- const date = dayjs(param?.date).format('DD MMM YYYY');
57
- const dateValue = value ? dayjs(value).format('DD MMM YYYY') : ''
58
-
59
- const isSelected = date === dateValue
60
-
61
- const isDisabled = [
62
- dayjs(param?.date).isBefore(dayjs(minDate)),
63
- dayjs(param?.date).isAfter(dayjs(maxDate))
64
- ].some(Boolean)
65
-
66
- const getStyles = (key) => {
67
- return {
68
- ...styles[key],
69
- ...(isSelected && styles[`${key}:selected`]),
70
- ...(!isSelected && isDisabled && styles[`${key}:disabled`]),
71
- }
72
- }
45
+ const compositionStyles = useCompositionStyles(['outerInput', 'header'], styles)
73
46
 
74
- if (TypeGuards.isFunction(DayComponent)) {
75
- return (
76
- <DayComponent
77
- {...param}
78
- value={value}
79
- disabled={isDisabled}
80
- selected={isSelected}
81
- styles={styles}
82
- />
83
- )
84
- }
47
+ const [visible, toggle] = useConditionalState(providedVisible, providedToggle, { initialValue: false })
48
+ const [yearShow, setYearShow] = useConditionalState(providedYearShow, providedSetYearShow, { initialValue: false })
85
49
 
50
+ const DayContentComponent = useCallback(({ day, date }) => {
86
51
  return (
87
- <View style={getStyles('dayWrapper')}>
88
- <Text style={getStyles('day')} text={String(param?.day)} />
89
- </View>
52
+ <DayContent
53
+ day={day}
54
+ date={date}
55
+ {...providedDayProps}
56
+ value={value}
57
+ minDate={minDate}
58
+ maxDate={maxDate}
59
+ component={dayComponent}
60
+ styles={styles}
61
+ />
90
62
  )
91
63
  }, [value])
92
64
 
93
- const YearContentComponent = useCallback((_param) => {
94
- const param = {
95
- ..._param,
96
- ...yearProps,
97
- }
98
-
99
- const isSelected = String(value)?.includes(param?.year)
100
-
101
- const getStyles = (key) => {
102
- return {
103
- ...styles[key],
104
- ...(isSelected && styles[`${key}:selected`]),
105
- }
106
- }
107
-
108
- if (TypeGuards.isFunction(YearComponent)) {
109
- return (
110
- <YearComponent
111
- {...param}
112
- value={value}
113
- selected={isSelected}
114
- styles={styles}
115
- />
116
- )
117
- }
118
-
65
+ const YearContentComponent = useCallback(({ year }) => {
119
66
  return (
120
- <View style={getStyles('yearWrapper')}>
121
- <Text style={getStyles('year')} text={param?.year} />
122
- </View>
67
+ <YearContent
68
+ year={year}
69
+ {...providedYearProps}
70
+ value={value}
71
+ component={yearComponent}
72
+ styles={styles}
73
+ />
123
74
  )
124
75
  }, [value])
125
76
 
126
- const compositionStyles = useCompositionStyles(['outerInput', 'header'], styles)
127
-
128
77
  return (
129
78
  <View style={styles.wrapper}>
130
79
  <ReactDatePicker
@@ -1,12 +1,11 @@
1
1
  import { StylesOf } from '@codeleap/types'
2
- import { FormTypes } from '@codeleap/deprecated'
3
2
  import { ReactDatePickerCustomHeaderProps, ReactDatePickerProps } from 'react-datepicker'
4
3
  import { ActionIconProps, TextInputProps } from '../components'
5
4
  import { DatePickerComposition, DatePickerHeaderComposition } from './styles'
6
5
  import { StyledProp } from '@codeleap/styles'
7
6
 
8
7
  export type DatePickerOuterInputProps = TextInputProps & {
9
- valueLabel: FormTypes.Label
8
+ valueLabel: React.ReactNode
10
9
  hideInput?: boolean
11
10
  }
12
11
 
@@ -31,7 +30,7 @@ export type DayComponentProps = {
31
30
  export type YearComponentProps = {
32
31
  year: string | number
33
32
  value: Date
34
- selected: boolean
33
+ selected?: boolean
35
34
  styles: DatePickerProps['style']
36
35
  }
37
36
 
@@ -43,7 +42,6 @@ export type DatePickerProps =
43
42
  {
44
43
  style?: StyledProp<DatePickerComposition>
45
44
  hideInput?: boolean
46
- value: Date
47
45
  outerInputComponent?: React.ComponentType<Partial<DatePickerOuterInputProps>>
48
46
  headerComponent?: React.ComponentType<Partial<DatePickerHeaderComponent>>
49
47
  headerProps?: Partial<DatePickerHeaderComponent>
@@ -51,12 +49,13 @@ export type DatePickerProps =
51
49
  dayProps?: Partial<DayComponentProps>
52
50
  yearComponent?: React.ComponentType<Partial<YearComponentProps>>
53
51
  yearProps?: Partial<YearComponentProps>
54
- formatDate?: (date: Date | string) => FormTypes.Label
52
+ formatDate?: (date: Date | string) => React.ReactNode
55
53
  datePickerProps?: Omit<Partial<ReactDatePickerProps>, 'customInput' | 'renderCustomHeader' | RootDatePickerProps>
56
- onValueChange: (date: Date) => void
57
54
  defaultValue?: Date
58
55
  visible?: boolean
59
56
  toggle?: () => void
60
57
  yearShow?: boolean
61
58
  setYearShow?: () => void
59
+ value: Date
60
+ onValueChange: (date: Date) => void
62
61
  }
@@ -1,4 +1,4 @@
1
- import React from 'react'
1
+ import React, { forwardRef } from 'react'
2
2
  import { TypeGuards } from '@codeleap/types'
3
3
  import { getRenderedComponent } from '@codeleap/utils'
4
4
  import { ActionIcon, ActionIconProps } from '../ActionIcon'
@@ -6,6 +6,7 @@ import { View } from '../View'
6
6
  import { useInputBaseStyles } from './styles'
7
7
  import { InputBaseProps } from './types'
8
8
  import { Text } from '../Text'
9
+ import { StyledComponentWithProps } from '@codeleap/styles'
9
10
 
10
11
  export * from './styles'
11
12
  export * from './utils'
@@ -22,7 +23,7 @@ const KeyPassthrough = (props: React.PropsWithChildren<any>) => {
22
23
  return <React.Fragment>{props.children}</React.Fragment>
23
24
  }
24
25
 
25
- export const InputBase = (props: InputBaseProps) => {
26
+ export const InputBase = forwardRef((props: InputBaseProps, ref) => {
26
27
  const allProps = {
27
28
  ...InputBase.defaultProps,
28
29
  ...props,
@@ -35,9 +36,9 @@ export const InputBase = (props: InputBaseProps) => {
35
36
  description,
36
37
  leftIcon,
37
38
  rightIcon,
38
- wrapper,
39
+ wrapper: WrapperComponent,
39
40
  debugName,
40
- innerWrapper,
41
+ innerWrapper: InnerWrapperComponent,
41
42
  focused,
42
43
  innerWrapperProps,
43
44
  wrapperProps,
@@ -50,9 +51,6 @@ export const InputBase = (props: InputBaseProps) => {
50
51
  ...otherProps
51
52
  } = allProps
52
53
 
53
- const WrapperComponent = wrapper || View
54
- const InnerWrapperComponent = innerWrapper || View
55
-
56
54
  const styles = useInputBaseStyles(allProps)
57
55
 
58
56
  const _leftIcon = getRenderedComponent<Partial<ActionIconProps>>(leftIcon, ActionIcon, {
@@ -101,6 +99,7 @@ export const InputBase = (props: InputBaseProps) => {
101
99
  {...otherProps}
102
100
  {...wrapperProps}
103
101
  style={styles.wrapperStyle}
102
+ ref={ref}
104
103
  >
105
104
  {
106
105
  order.map((key) => (
@@ -111,7 +110,7 @@ export const InputBase = (props: InputBaseProps) => {
111
110
  }
112
111
  </WrapperComponent>
113
112
  )
114
- }
113
+ }) as StyledComponentWithProps<InputBaseProps>
115
114
 
116
115
  InputBase.elements = [
117
116
  'wrapper',
@@ -134,4 +133,6 @@ InputBase.defaultProps = {
134
133
  leftIcon: null,
135
134
  description: null,
136
135
  error: null,
136
+ wrapper: View,
137
+ innerWrapper: View,
137
138
  } as Partial<InputBaseProps>
@@ -15,13 +15,14 @@ export type InputBaseProps = React.PropsWithChildren<{
15
15
  innerWrapperProps?: any
16
16
  style?: StylesOf<InputBaseComposition>
17
17
  description?: React.ReactNode
18
- debugName: string
18
+ debugName?: string
19
19
  focused?: boolean
20
20
  disabled?: boolean
21
21
  order?: OrderedParts[]
22
22
  labelAsRow?: boolean
23
23
  noError?: boolean
24
24
  innerWrapperRef?: React.MutableRefObject<HTMLDivElement | null>
25
+ ref?: React.MutableRefObject<HTMLDivElement>
25
26
  }>
26
27
 
27
28
  export type OmitDiff<T1, T2> = {
@@ -0,0 +1,56 @@
1
+ import { useMemo, useRef } from 'react'
2
+ // import { useWrappingScrollable } from ''
3
+ import { Field, IFieldRef, fields, useField } from '@codeleap/form'
4
+ import { AnyRecord, TypeGuards } from '@codeleap/types'
5
+
6
+ export function useInputBase<V, T extends Field<V, any, any, unknown> = Field<V, any, any, unknown>>(
7
+ field: T,
8
+ defaultField: (options?: AnyRecord) => T = fields.text as () => T,
9
+ internalState: { value: V; onValueChange: (value: V) => void },
10
+ params: Partial<IFieldRef<V>> = {},
11
+ deps: any[] = []
12
+ ) {
13
+ const { value, onValueChange } = internalState
14
+
15
+ const hasInternalState = useMemo(() => TypeGuards.isFunction(onValueChange) && !TypeGuards.isNil(value), [])
16
+
17
+ const wrapperRef = useRef<HTMLDivElement>()
18
+
19
+ const innerInputRef = useRef<HTMLInputElement>(null)
20
+
21
+ // const scrollable = useWrappingScrollable()
22
+
23
+ const fieldHandle = hasInternalState ? {} as Partial<ReturnType<typeof useField>> : useField<V, T>(field as T, [
24
+ {
25
+ blur() {
26
+ innerInputRef.current.blur()
27
+ },
28
+ focus() {
29
+ innerInputRef.current.focus()
30
+ },
31
+ getValue() {
32
+ return innerInputRef.current.value as V
33
+ },
34
+ scrollIntoView() {
35
+ // @todo implement
36
+ return
37
+ // return field.measurePosition(wrapperRef).then((measureResult) => {
38
+ // field.scrollTo(scrollable, measureResult)
39
+ // })
40
+ },
41
+ ...params,
42
+ },
43
+ deps
44
+ ] as unknown as Parameters<T['use']>, defaultField)
45
+
46
+ const validation = fieldHandle?.validation
47
+
48
+ return {
49
+ fieldHandle,
50
+ validation,
51
+ wrapperRef,
52
+ innerInputRef,
53
+ inputValue: (hasInternalState ? value : fieldHandle?.value) as V,
54
+ onInputValueChange: hasInternalState ? onValueChange : fieldHandle?.setValue,
55
+ }
56
+ }
@@ -0,0 +1,37 @@
1
+ import { CSSProperties, useMemo } from 'react'
2
+
3
+ export function useInputBasePartialStyles<C extends string, S extends Record<string, boolean>>(
4
+ styles: Record<C, CSSProperties>,
5
+ styleKeys: Array<C | [C, boolean]>,
6
+ states: S,
7
+ ) {
8
+ return useMemo(() => {
9
+ return styleKeys.reduce((acc, value) => {
10
+ const [key, overrideWithDefault] = Array.isArray(value) ? value : [value, true]
11
+
12
+ const result = Object.entries(states).reduce((acc, [state, is]) => {
13
+ if (!is) return acc
14
+
15
+ const style = styles?.[`${key}:${state}` as C]
16
+
17
+ if (!style) return acc
18
+
19
+ return {
20
+ ...acc,
21
+ ...styles[`${key}:${state}` as C]
22
+ }
23
+ }, {})
24
+
25
+ if (overrideWithDefault && !!styles?.[key]) {
26
+ acc[key] = {
27
+ ...styles[key],
28
+ ...result,
29
+ }
30
+ } else {
31
+ acc[key] = result
32
+ }
33
+
34
+ return acc
35
+ }, {} as Record<C, CSSProperties>)
36
+ }, [states])
37
+ }
@@ -1,6 +1,6 @@
1
1
  import { TypeGuards } from '@codeleap/types'
2
2
  import { onMount, onUpdate } from '@codeleap/hooks'
3
- import React, { useId, useRef } from 'react'
3
+ import React, { useCallback, useId, useRef } from 'react'
4
4
  import ReactDOM from 'react-dom'
5
5
  import { v4 } from 'uuid'
6
6
  import { View } from '../View'
@@ -76,7 +76,58 @@ const ModalDefaultHeader = (props: ModalHeaderProps) => {
76
76
  )
77
77
  }
78
78
 
79
- export const ModalContent = (modalProps: ModalProps & { id: string }) => {
79
+ const ModalWrapper = ({ styles, visible, modalId, autoIndex, children, closeOnEscPress }) => {
80
+ const index = modalsState.use(state => state.indexes?.[modalId] ?? 0)
81
+
82
+ const modalRef = useRef(null)
83
+
84
+ const handleTabKeyPress = useCallback((e: React.KeyboardEvent<HTMLDivElement>, { firstElement, lastElement }: Record<'firstElement' | 'lastElement', HTMLDivElement>) => {
85
+ if (e.key === 'Tab' || e?.keyCode === 9) {
86
+ if (e.shiftKey && document.activeElement === firstElement) {
87
+ e.preventDefault()
88
+ lastElement.focus()
89
+ } else if (
90
+ !e.shiftKey &&
91
+ document.activeElement === lastElement
92
+ ) {
93
+ e.preventDefault()
94
+ firstElement.focus()
95
+ }
96
+ }
97
+ }, [])
98
+
99
+ onUpdate(() => {
100
+ if (visible) {
101
+ const modalElement = modalRef.current
102
+
103
+ const focusableElements = modalElement.querySelectorAll('[tabindex]:not([tabindex="-1"])') as NodeListOf<HTMLDivElement>
104
+ const firstElement = focusableElements[0]
105
+ const lastElement = focusableElements[focusableElements.length - 1]
106
+
107
+ modalElement.addEventListener('keydown', (e) => handleTabKeyPress(e, { firstElement, lastElement }))
108
+ modalElement.addEventListener('keydown', closeOnEscPress)
109
+
110
+ return () => {
111
+ modalElement.removeEventListener('keydown', (e) => handleTabKeyPress(e, { firstElement, lastElement }))
112
+ modalElement.removeEventListener('keydown', closeOnEscPress)
113
+ }
114
+ }
115
+ }, [visible])
116
+
117
+ return <View
118
+ ref={modalRef}
119
+ aria-hidden={!visible}
120
+ style={[
121
+ styles.wrapper,
122
+ visible ? styles['wrapper:visible'] : styles['wrapper:hidden'],
123
+ autoIndex ? { zIndex: index } : null,
124
+ ]}
125
+ >
126
+ {children}
127
+ </View>
128
+ }
129
+
130
+ const ModalContent = (modalProps: ModalProps & { id: string }) => {
80
131
  const {
81
132
  children,
82
133
  visible,
@@ -89,14 +140,11 @@ export const ModalContent = (modalProps: ModalProps & { id: string }) => {
89
140
  withOverlay,
90
141
  showClose,
91
142
  closeIconName,
92
- scroll,
93
- renderModalBody,
143
+ renderModalBody: ModalBody,
94
144
  closeOnEscape,
95
145
  onClose,
96
146
  overlayProps,
97
147
  dismissOnBackdrop,
98
- zIndex,
99
- withScrollContainer,
100
148
  debugName,
101
149
  backdropProps,
102
150
  alterHistory,
@@ -107,10 +155,7 @@ export const ModalContent = (modalProps: ModalProps & { id: string }) => {
107
155
 
108
156
  const styles = useStylesFor(Modal.styleRegistryName, style)
109
157
 
110
- const index = modalsState.use(state => state.indexes?.[modalId] ?? 0)
111
-
112
158
  const id = useId()
113
- const modalRef = useRef(null)
114
159
 
115
160
  const toggleAndReturn = () => {
116
161
  toggle?.()
@@ -122,7 +167,7 @@ export const ModalContent = (modalProps: ModalProps & { id: string }) => {
122
167
  if (TypeGuards.isFunction(onClose)) onClose()
123
168
  }
124
169
 
125
- function closeOnEscPress(e: React.KeyboardEvent<HTMLDivElement>) {
170
+ const closeOnEscPress = (e: React.KeyboardEvent<HTMLDivElement>) => {
126
171
  if (!closeOnEscape) return null
127
172
 
128
173
  if (e?.key === 'Escape' || e?.keyCode === 27) {
@@ -130,62 +175,20 @@ export const ModalContent = (modalProps: ModalProps & { id: string }) => {
130
175
  }
131
176
  }
132
177
 
133
- const handleTabKeyPress = (e: React.KeyboardEvent<HTMLDivElement>, { firstElement, lastElement }: Record<'firstElement' | 'lastElement', HTMLDivElement>) => {
134
- if (e.key === 'Tab' || e?.keyCode === 9) {
135
- if (e.shiftKey && document.activeElement === firstElement) {
136
- e.preventDefault()
137
- lastElement.focus()
138
- } else if (
139
- !e.shiftKey &&
140
- document.activeElement === lastElement
141
- ) {
142
- e.preventDefault()
143
- firstElement.focus()
144
- }
145
- }
146
- }
147
-
148
- onUpdate(() => {
149
- if (visible) {
150
- const modalElement = modalRef.current
151
-
152
- const focusableElements = modalElement.querySelectorAll('[tabindex]:not([tabindex="-1"])') as NodeListOf<HTMLDivElement>
153
- const firstElement = focusableElements[0]
154
- const lastElement = focusableElements[focusableElements.length - 1]
155
-
156
- modalElement.addEventListener('keydown', (e) => handleTabKeyPress(e, { firstElement, lastElement }))
157
- modalElement.addEventListener('keydown', closeOnEscPress)
158
-
159
- return () => {
160
- modalElement.removeEventListener('keydown', (e) => handleTabKeyPress(e, { firstElement, lastElement }))
161
- modalElement.removeEventListener('keydown', closeOnEscPress)
162
- }
163
- }
164
- }, [visible])
178
+ const close = (closable && dismissOnBackdrop) ? toggleAndReturn : () => null
165
179
 
166
180
  useIsomorphicEffect(() => {
167
181
  const modal = document.getElementById(id)
168
182
  if (modal) modal.focus()
169
183
  }, [id])
170
184
 
171
- const close = (closable && dismissOnBackdrop) ? toggleAndReturn : () => null
172
-
173
- const ModalBody = renderModalBody || View
174
-
175
- const _zIndex = React.useMemo(() => {
176
- return TypeGuards.isNumber(zIndex) ? { zIndex } : {}
177
- }, [zIndex])
178
-
179
185
  return (
180
- <View
181
- ref={modalRef}
182
- aria-hidden={!visible}
183
- style={[
184
- styles.wrapper,
185
- visible ? styles['wrapper:visible'] : styles['wrapper:hidden'],
186
- autoIndex ? { zIndex: index } : null,
187
- _zIndex,
188
- ]}
186
+ <ModalWrapper
187
+ styles={styles}
188
+ modalId={modalId}
189
+ autoIndex={autoIndex}
190
+ visible={visible}
191
+ closeOnEscPress={closeOnEscPress}
189
192
  >
190
193
  <Overlay
191
194
  debugName={debugName}
@@ -240,7 +243,7 @@ export const ModalContent = (modalProps: ModalProps & { id: string }) => {
240
243
  ) : null}
241
244
  </View>
242
245
  </View>
243
- </View>
246
+ </ModalWrapper>
244
247
  )
245
248
  }
246
249
 
@@ -328,14 +331,11 @@ Modal.defaultProps = {
328
331
  closable: true,
329
332
  withOverlay: true,
330
333
  showClose: true,
331
- scroll: false,
332
334
  closeOnEscape: true,
333
335
  renderHeader: ModalDefaultHeader,
334
- keepMounted: true,
336
+ renderModalBody: View,
335
337
  dismissOnBackdrop: true,
336
- zIndex: null,
337
338
  description: null,
338
- withScrollContainer: false,
339
339
  scrollLock: false,
340
340
  autoIndex: false,
341
341
  alterHistory: false,
@@ -19,20 +19,16 @@ export type ModalProps =
19
19
  showClose?: boolean
20
20
  closable?: boolean
21
21
  dismissOnBackdrop?: boolean
22
- scroll?: boolean
23
22
  header?: React.ReactElement
24
23
  footer?: React.ReactNode
25
24
  withOverlay?: boolean
26
25
  closeIconName?: AppIcon
27
- keepMounted?: boolean
28
26
  renderHeader?: (props: ModalHeaderProps) => React.ReactElement
29
27
  debugName?: string
30
28
  closeButtonProps?: Partial<ActionIconProps>
31
29
  closeOnEscape?: boolean
32
30
  onClose?: () => void
33
31
  overlayProps?: Partial<OverlayProps>
34
- zIndex?: number
35
- withScrollContainer?: boolean
36
32
  scrollLock?: boolean
37
33
  backdropProps?: Partial<TouchableProps>
38
34
  alterHistory?: boolean