@neko-os/ui 0.0.9 → 0.0.10

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 (139) hide show
  1. package/dist/DynamicStyleTag.js +5 -0
  2. package/dist/DynamicStyleTag.native.js +1 -0
  3. package/dist/NekoUI.js +1 -1
  4. package/dist/abstractions/AnimatedView.web.js +1 -0
  5. package/dist/abstractions/FlatList.js +1 -1
  6. package/dist/abstractions/FlatList.native.js +1 -1
  7. package/dist/abstractions/StaticList.js +1 -0
  8. package/dist/abstractions/helpers/useSafeAreaInsets.js +1 -0
  9. package/dist/abstractions/helpers/useSafeAreaInsets.native.js +1 -0
  10. package/dist/components/actions/Dropdown.js +1 -1
  11. package/dist/components/actions/FloatingButton.js +1 -0
  12. package/dist/components/actions/index.js +1 -1
  13. package/dist/components/actions/menu/VerticalMenu.js +1 -1
  14. package/dist/components/calendar/_helpers/calendarDays.js +1 -1
  15. package/dist/components/feedback/alerter.js +1 -1
  16. package/dist/components/feedback/confirmer.js +1 -1
  17. package/dist/components/helpers/ConditionalLazyRender.js +1 -0
  18. package/dist/components/helpers/LazyAction.js +1 -0
  19. package/dist/components/helpers/LazyRender.js +1 -1
  20. package/dist/components/helpers/LazyRender.native.js +1 -1
  21. package/dist/components/helpers/index.js +1 -1
  22. package/dist/components/index.js +1 -1
  23. package/dist/components/inputs/DateInput.js +1 -1
  24. package/dist/components/inputs/InputWrapper.js +1 -1
  25. package/dist/components/inputs/LinkInput.js +1 -1
  26. package/dist/components/inputs/NumberInput.js +1 -0
  27. package/dist/components/inputs/Picker.js +1 -1
  28. package/dist/components/inputs/Radio.js +1 -1
  29. package/dist/components/inputs/RateInput.js +1 -0
  30. package/dist/components/inputs/SegmentedPicker.js +1 -0
  31. package/dist/components/inputs/Select.js +1 -0
  32. package/dist/components/inputs/datePicker/DayPicker.js +1 -1
  33. package/dist/components/inputs/datePicker/MonthPicker.js +1 -1
  34. package/dist/components/inputs/datePicker/QuarterPicker.js +1 -1
  35. package/dist/components/inputs/datePicker/WeekPicker.js +1 -1
  36. package/dist/components/inputs/datePicker/YearPicker.js +1 -1
  37. package/dist/components/inputs/index.js +1 -1
  38. package/dist/components/list/FlatList.js +1 -1
  39. package/dist/components/presentation/Rate.js +1 -0
  40. package/dist/components/presentation/RateTag.js +1 -0
  41. package/dist/components/presentation/Result.js +1 -1
  42. package/dist/components/presentation/Tooltip.js +1 -1
  43. package/dist/components/presentation/index.js +1 -1
  44. package/dist/components/structure/Accordion.js +1 -1
  45. package/dist/components/structure/Row.js +1 -1
  46. package/dist/components/structure/Segment.js +1 -0
  47. package/dist/components/structure/bottomDrawer/native/BottomDrawer.js +1 -1
  48. package/dist/components/structure/bottomDrawer/native/utils.js +1 -1
  49. package/dist/components/structure/bottomDrawer/web/BottomDrawer.js +1 -1
  50. package/dist/components/structure/index.js +1 -1
  51. package/dist/components/structure/overlay/OverlayHandler.js +1 -1
  52. package/dist/components/structure/popover/Popover.js +1 -1
  53. package/dist/components/structure/popover/Popover_BU.js +1 -0
  54. package/dist/components/tabs/ActiveTabContent.js +1 -0
  55. package/dist/components/tabs/TabsHandler.js +1 -0
  56. package/dist/components/tabs/TabsMenu.js +1 -0
  57. package/dist/components/tabs/index.js +1 -0
  58. package/dist/helpers/string.js +1 -1
  59. package/dist/i18n/I18n.js +1 -0
  60. package/dist/i18n/I18nProvider.js +1 -0
  61. package/dist/i18n/index.js +1 -0
  62. package/dist/index.css +4 -0
  63. package/dist/index.js +1 -1
  64. package/dist/modifiers/animations/fadeEffect.web.js +1 -0
  65. package/dist/modifiers/animations/scrollEffect.web.js +1 -0
  66. package/dist/modifiers/animations/slideEffect.web.js +1 -0
  67. package/dist/modifiers/overflow.js +1 -1
  68. package/dist/modifiers/position.js +1 -1
  69. package/dist/theme/default/base.js +1 -1
  70. package/package.json +1 -1
  71. package/src/DynamicStyleTag.js +21 -0
  72. package/src/DynamicStyleTag.native.js +3 -0
  73. package/src/NekoUI.js +12 -7
  74. package/src/abstractions/AnimatedView.web.js +3 -0
  75. package/src/abstractions/FlatList.js +2 -38
  76. package/src/abstractions/FlatList.native.js +8 -4
  77. package/src/abstractions/StaticList.js +51 -0
  78. package/src/abstractions/helpers/useSafeAreaInsets.js +3 -0
  79. package/src/abstractions/helpers/useSafeAreaInsets.native.js +3 -0
  80. package/src/components/actions/Dropdown.js +13 -9
  81. package/src/components/actions/FloatingButton.js +87 -0
  82. package/src/components/actions/index.js +1 -0
  83. package/src/components/actions/menu/VerticalMenu.js +29 -4
  84. package/src/components/calendar/_helpers/calendarDays.js +2 -0
  85. package/src/components/feedback/alerter.js +1 -1
  86. package/src/components/feedback/confirmer.js +2 -2
  87. package/src/components/helpers/ConditionalLazyRender.js +6 -0
  88. package/src/components/helpers/LazyAction.js +22 -0
  89. package/src/components/helpers/LazyRender.js +2 -2
  90. package/src/components/helpers/LazyRender.native.js +1 -1
  91. package/src/components/helpers/index.js +1 -0
  92. package/src/components/index.js +1 -0
  93. package/src/components/inputs/DateInput.js +11 -1
  94. package/src/components/inputs/InputWrapper.js +0 -1
  95. package/src/components/inputs/LinkInput.js +3 -3
  96. package/src/components/inputs/NumberInput.js +105 -0
  97. package/src/components/inputs/Picker.js +61 -9
  98. package/src/components/inputs/Radio.js +1 -1
  99. package/src/components/inputs/RateInput.js +62 -0
  100. package/src/components/inputs/SegmentedPicker.js +62 -0
  101. package/src/components/inputs/Select.js +189 -0
  102. package/src/components/inputs/datePicker/DayPicker.js +4 -5
  103. package/src/components/inputs/datePicker/MonthPicker.js +2 -2
  104. package/src/components/inputs/datePicker/QuarterPicker.js +2 -2
  105. package/src/components/inputs/datePicker/WeekPicker.js +2 -2
  106. package/src/components/inputs/datePicker/YearPicker.js +9 -6
  107. package/src/components/inputs/index.js +4 -0
  108. package/src/components/list/FlatList.js +41 -4
  109. package/src/components/presentation/Rate.js +58 -0
  110. package/src/components/presentation/RateTag.js +35 -0
  111. package/src/components/presentation/Result.js +2 -2
  112. package/src/components/presentation/Tooltip.js +1 -0
  113. package/src/components/presentation/index.js +2 -0
  114. package/src/components/structure/Accordion.js +1 -1
  115. package/src/components/structure/Row.js +9 -1
  116. package/src/components/structure/Segment.js +51 -0
  117. package/src/components/structure/bottomDrawer/native/BottomDrawer.js +4 -1
  118. package/src/components/structure/bottomDrawer/native/utils.js +29 -22
  119. package/src/components/structure/bottomDrawer/web/BottomDrawer.js +3 -1
  120. package/src/components/structure/index.js +1 -0
  121. package/src/components/structure/overlay/OverlayHandler.js +6 -1
  122. package/src/components/structure/popover/Popover.js +33 -19
  123. package/src/components/structure/popover/Popover_BU.js +157 -0
  124. package/src/components/tabs/ActiveTabContent.js +35 -0
  125. package/src/components/tabs/TabsHandler.js +16 -0
  126. package/src/components/tabs/TabsMenu.js +15 -0
  127. package/src/components/tabs/index.js +3 -0
  128. package/src/helpers/string.js +18 -1
  129. package/src/i18n/I18n.js +97 -0
  130. package/src/i18n/I18nProvider.js +40 -0
  131. package/src/i18n/index.js +2 -0
  132. package/src/index.css +4 -0
  133. package/src/index.js +1 -0
  134. package/src/modifiers/animations/fadeEffect.web.js +3 -0
  135. package/src/modifiers/animations/scrollEffect.web.js +3 -0
  136. package/src/modifiers/animations/slideEffect.web.js +3 -0
  137. package/src/modifiers/overflow.js +6 -1
  138. package/src/modifiers/position.js +7 -0
  139. package/src/theme/default/base.js +6 -2
@@ -0,0 +1,189 @@
1
+ import React from 'react'
2
+
3
+ import { Icon, IconLabel } from '../presentation'
4
+ import { Link } from '../actions'
5
+ import { LinkInput } from './LinkInput'
6
+ import { Picker, getOptionLabel, searchOptions } from './Picker'
7
+ import { Popover } from '../structure/popover/Popover'
8
+ import { TextInput } from './TextInput'
9
+ import { View } from '../structure'
10
+ import { useResponsiveValue } from '../../responsive'
11
+
12
+ function FullWidthInputWrapper({ ref, ...props }) {
13
+ return (
14
+ <View fullW ref={ref}>
15
+ <TextInput {...props} />
16
+ </View>
17
+ )
18
+ }
19
+
20
+ export function Select({
21
+ value,
22
+ onChange,
23
+ onChangeSearch,
24
+ options,
25
+ placement,
26
+ placeholder,
27
+ initialLabel,
28
+ useBottomDrawer = { native: true, sm: true, md: true },
29
+ useSearch,
30
+ renderOption,
31
+ labelKey,
32
+ valueKey,
33
+ useRawOption,
34
+ multiple,
35
+ onEndReached,
36
+ renderFooter,
37
+ renderHeader,
38
+ pickerProps,
39
+ popoverProps,
40
+ popoverMaxHeight,
41
+ ...props
42
+ }) {
43
+ const [focus, setFocus] = React.useState(false)
44
+ const [search, setSearch] = React.useState('')
45
+ const [inputValue, setInputValue] = React.useState(initialLabel || '')
46
+ const [localValue, setLocalValue] = React.useState(value)
47
+
48
+ labelKey = labelKey || pickerProps?.labelKey || 'label'
49
+ valueKey = valueKey || pickerProps?.valueKey || 'value'
50
+ useRawOption = useRawOption || pickerProps?.useRawOption
51
+ multiple = multiple || pickerProps?.multiple
52
+ onEndReached = onEndReached || pickerProps?.onEndReached
53
+ renderFooter = renderFooter || pickerProps?.renderFooter
54
+ renderHeader = renderHeader || pickerProps?.renderHeader
55
+ pickerProps = { ...pickerProps, labelKey, valueKey, useRawOption, multiple, onEndReached, renderFooter, renderHeader }
56
+
57
+ popoverMaxHeight = popoverMaxHeight || 300
58
+
59
+ useBottomDrawer = useResponsiveValue(useBottomDrawer)
60
+
61
+ value = value || localValue
62
+
63
+ const handleChange = React.useCallback(
64
+ (value, option) => {
65
+ if (!!multiple) {
66
+ setInputValue(value.map((item) => getOptionLabel(options, item, { valueKey, labelKey })).join(', '))
67
+ } else {
68
+ setInputValue(option?.[labelKey] || getOptionLabel(options, option, { valueKey, labelKey }))
69
+ }
70
+ setLocalValue(value)
71
+ onChange?.(value)
72
+ },
73
+ [labelKey, valueKey]
74
+ )
75
+
76
+ React.useEffect(() => {
77
+ if (!!multiple) {
78
+ setInputValue(value?.map?.((item) => getOptionLabel(options, item, { valueKey, labelKey })).join(', '))
79
+ } else {
80
+ const label = value?.[labelKey] || getOptionLabel(options, value, { valueKey, labelKey })
81
+ if (!!label || !value) setInputValue(label)
82
+ }
83
+ }, [value])
84
+
85
+ const handleChangeSearch = React.useCallback((v) => {
86
+ onChangeSearch?.(v)
87
+ setSearch(v)
88
+ }, [])
89
+
90
+ const Input = !useSearch || useBottomDrawer ? LinkInput : FullWidthInputWrapper
91
+ const valueWatcher = multiple && localValue
92
+
93
+ const finalRenderOption = React.useCallback(
94
+ (params) => {
95
+ if (!!renderOption) return renderOption(params)
96
+ const { option, labelKey, selected } = params
97
+ return <IconLabel {...option} label={option?.[labelKey]} flex strong={selected} />
98
+ },
99
+ [renderOption]
100
+ )
101
+
102
+ return (
103
+ <Popover
104
+ trigger="click"
105
+ placement={placement || 'bottomLeft'}
106
+ snapPoints={[450]}
107
+ useBottomDrawer={useBottomDrawer}
108
+ parentWidth
109
+ padding={0}
110
+ watch={[search, options, valueWatcher]}
111
+ unmountOnClose
112
+ maxHeight={popoverMaxHeight}
113
+ {...popoverProps}
114
+ renderContent={({ onClose }) => (
115
+ <>
116
+ {useBottomDrawer && useSearch && (
117
+ <View padding="md" paddingB="xs">
118
+ <TextInput
119
+ prefixIcon="search-line"
120
+ prefixIconColor="text4"
121
+ value={search}
122
+ onChange={handleChangeSearch}
123
+ />
124
+ </View>
125
+ )}
126
+ <Picker
127
+ row={false}
128
+ options={searchOptions(options, search, { labelKey })}
129
+ value={value}
130
+ gap={0}
131
+ maxHeight={!useBottomDrawer && popoverMaxHeight}
132
+ useFlatList
133
+ onlyOnScreen
134
+ itemMinHeight={30}
135
+ onChange={(v, option) => {
136
+ handleChange(v, option)
137
+ if (!multiple) onClose()
138
+ }}
139
+ {...pickerProps}
140
+ renderOption={({ option, selected, onChange }) => (
141
+ <Link
142
+ row
143
+ paddingH={useBottomDrawer ? 'md' : 'sm'}
144
+ paddingV="xs"
145
+ minHeight={useBottomDrawer ? 'xl' : 'md'}
146
+ gap="sm"
147
+ onMouseDown={(e) => !!multiple && e.preventDefault()}
148
+ onPress={onChange}
149
+ centerV
150
+ bg={selected && 'primary_op10'}
151
+ >
152
+ <View flex row>
153
+ {finalRenderOption({ option, labelKey, selected })}
154
+ </View>
155
+ {selected && <Icon name="checkbox-circle-fill" primary />}
156
+ </Link>
157
+ )}
158
+ />
159
+ </>
160
+ )}
161
+ >
162
+ <Input
163
+ value={!!focus ? search : inputValue}
164
+ onChange={handleChangeSearch}
165
+ onFocus={() => {
166
+ handleChangeSearch('')
167
+ setFocus(true)
168
+ }}
169
+ onBlur={() => {
170
+ setTimeout(() => {
171
+ setFocus(false)
172
+ }, 200)
173
+ }}
174
+ // When the option to use tags presentation, use prefix to render the tags
175
+ // _prefix={
176
+ // multiple &&
177
+ // value?.length && (
178
+ // <Text>{value?.map((item) => getOptionLabel(options, item, { labelKey, valueKey })).join(', ')}</Text>
179
+ // )
180
+ // }
181
+ placeholder={(!multiple || !value?.length) && placeholder}
182
+ suffixIcon="arrow-down-s-fill"
183
+ suffixIconColor="text4"
184
+ fullW
185
+ {...props}
186
+ />
187
+ </Popover>
188
+ )
189
+ }
@@ -14,20 +14,19 @@ import { useCalendarDays } from '../../calendar/_helpers/calendarDays'
14
14
  export function DayPicker({ value, onChange, min, max, onCheckDisabled, ...props }) {
15
15
  if (!!value) value = dayjs(value)
16
16
  const [localValue, setLocalValue] = React.useState(value)
17
+ const [currentMonth, setCurrentMonth] = React.useState(() => dayjs(value || undefined).startOf('month'))
18
+ value = value === undefined ? localValue : value
17
19
 
18
20
  React.useEffect(() => {
19
21
  setLocalValue(value)
20
- }, [value])
21
-
22
- value = value === undefined ? localValue : value
22
+ if (value?.isValid?.()) setCurrentMonth(value.startOf('month'))
23
+ }, [value?.day?.(), value?.month?.(), value?.year?.()])
23
24
 
24
25
  const handleChange = (v) => {
25
26
  setLocalValue(v)
26
27
  onChange?.(v)
27
28
  }
28
29
 
29
- const [currentMonth, setCurrentMonth] = React.useState(() => dayjs(value).startOf('month'))
30
-
31
30
  const { cells } = useCalendarDays(currentMonth)
32
31
 
33
32
  return (
@@ -14,10 +14,12 @@ const months = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
14
14
 
15
15
  export function MonthPicker({ value, onChange, min, max, onCheckDisabled, ...props }) {
16
16
  const [localValue, setLocalValue] = React.useState(value)
17
+ const [currentYear, setCurrentYear] = React.useState(() => dayjs(value || undefined).startOf('year'))
17
18
  value = value === undefined ? localValue : value
18
19
 
19
20
  React.useEffect(() => {
20
21
  setLocalValue(value)
22
+ if (value?.isValid?.()) setCurrentYear(value.startOf('year'))
21
23
  }, [value?.month?.(), value?.year?.()])
22
24
 
23
25
  const handleChange = (v) => {
@@ -26,8 +28,6 @@ export function MonthPicker({ value, onChange, min, max, onCheckDisabled, ...pro
26
28
  onChange?.(newValue)
27
29
  }
28
30
 
29
- const [currentYear, setCurrentYear] = React.useState(() => dayjs(value).startOf('year'))
30
-
31
31
  return (
32
32
  <View className="neko-day-picker" width={275} {...props}>
33
33
  <CalendarNav value={currentYear} onChange={setCurrentYear} level="year" />
@@ -17,10 +17,12 @@ const quarters = [1, 2, 3, 4]
17
17
 
18
18
  export function QuarterPicker({ value, onChange, min, max, onCheckDisabled, ...props }) {
19
19
  const [localValue, setLocalValue] = React.useState(value)
20
+ const [currentYear, setCurrentYear] = React.useState(() => dayjs(value || undefined).startOf('year'))
20
21
  value = value === undefined ? localValue : value
21
22
 
22
23
  React.useEffect(() => {
23
24
  setLocalValue(value)
25
+ if (value?.isValid?.()) setCurrentYear(value.startOf('year'))
24
26
  }, [value?.quarter?.(), value?.year?.()])
25
27
 
26
28
  const handleChange = (v) => {
@@ -29,8 +31,6 @@ export function QuarterPicker({ value, onChange, min, max, onCheckDisabled, ...p
29
31
  onChange?.(newValue)
30
32
  }
31
33
 
32
- const [currentYear, setCurrentYear] = React.useState(() => dayjs(value).startOf('year'))
33
-
34
34
  return (
35
35
  <View className="neko-day-picker" width={275} {...props}>
36
36
  <CalendarNav value={currentYear} onChange={setCurrentYear} level="year" />
@@ -14,10 +14,12 @@ import { useCalendarDays } from '../../calendar/_helpers/calendarDays'
14
14
 
15
15
  export function WeekPicker({ value, onChange, min, max, onCheckDisabled, ...props }) {
16
16
  const [localValue, setLocalValue] = React.useState(value)
17
+ const [currentMonth, setCurrentMonth] = React.useState(() => dayjs(value || undefined).startOf('month'))
17
18
  value = value === undefined ? localValue : value
18
19
 
19
20
  React.useEffect(() => {
20
21
  setLocalValue(value)
22
+ if (value?.isValid?.()) setCurrentMonth(value.startOf('month'))
21
23
  }, [value?.day?.(), value?.month?.(), value?.year?.()])
22
24
 
23
25
  const handleChange = (v) => {
@@ -26,8 +28,6 @@ export function WeekPicker({ value, onChange, min, max, onCheckDisabled, ...prop
26
28
  onChange?.(newValue)
27
29
  }
28
30
 
29
- const [currentMonth, setCurrentMonth] = React.useState(() => dayjs(value).startOf('month'))
30
-
31
31
  const { cells } = useCalendarDays(currentMonth)
32
32
  const weeks = splitEvery(7, cells)
33
33
 
@@ -11,12 +11,21 @@ import { Text } from '../../text/Text'
11
11
  import { View } from '../../structure/View'
12
12
  import { isDateDisabled } from '../../calendar/_helpers/dateDisabled'
13
13
 
14
+ function getDecade(value) {
15
+ const year = dayjs(value || undefined).year()
16
+ const decadeStartYear = Math.floor(year / 10) * 10
17
+ return dayjs().year(decadeStartYear).startOf('year')
18
+ }
19
+
14
20
  export function YearPicker({ value, onChange, min, max, onCheckDisabled, ...props }) {
15
21
  const [localValue, setLocalValue] = React.useState(value)
22
+ const [currentDecade, setCurrentDecade] = React.useState(() => getDecade(value))
23
+
16
24
  value = value === undefined ? localValue : value
17
25
 
18
26
  React.useEffect(() => {
19
27
  setLocalValue(value)
28
+ if (value?.isValid?.()) setCurrentDecade(getDecade(value))
20
29
  }, [value?.year?.()])
21
30
 
22
31
  const handleChange = (v) => {
@@ -25,12 +34,6 @@ export function YearPicker({ value, onChange, min, max, onCheckDisabled, ...prop
25
34
  onChange?.(newValue)
26
35
  }
27
36
 
28
- const [currentDecade, setCurrentDecade] = React.useState(() => {
29
- const year = dayjs(value).year()
30
- const decadeStartYear = Math.floor(year / 10) * 10
31
- return dayjs().year(decadeStartYear).startOf('year')
32
- })
33
-
34
37
  const years = range(currentDecade.year(), currentDecade.year() + 10)
35
38
 
36
39
  return (
@@ -3,8 +3,12 @@ export * from './Radio'
3
3
  export * from './Switch'
4
4
  export * from './InputWrapper'
5
5
  export * from './TextInput'
6
+ export * from './NumberInput'
6
7
  export * from './LinkInput'
7
8
  export * from './MaskInput'
8
9
  export * from './DateInput'
9
10
  export * from './datePicker/DatePicker'
10
11
  export * from './Picker'
12
+ export * from './Select'
13
+ export * from './RateInput'
14
+ export * from './SegmentedPicker'
@@ -1,6 +1,9 @@
1
1
  import { pipe } from 'ramda'
2
+ import React from 'react'
2
3
 
3
4
  import { AbsFlatList } from '../../abstractions/FlatList'
5
+ import { AbsStaticList } from '../../abstractions/StaticList'
6
+ import { ConditionalLazyRender, Divider } from '../helpers'
4
7
  import { useAnimationModifier } from '../../modifiers/animation'
5
8
  import { useBackgroundModifier } from '../../modifiers/background'
6
9
  import { useBorderModifier } from '../../modifiers/border'
@@ -12,6 +15,7 @@ import { useMarginModifier } from '../../modifiers/margin'
12
15
  import { useOverflowModifier } from '../../modifiers/overflow'
13
16
  import { usePaddingModifier } from '../../modifiers/padding'
14
17
  import { usePositionModifier } from '../../modifiers/position'
18
+ import { useResponsiveValue } from '../../responsive'
15
19
  import { useShadowModifier } from '../../modifiers/shadow'
16
20
  import { useSizeModifier } from '../../modifiers/size'
17
21
  import { useStateModifier } from '../../modifiers/state'
@@ -27,7 +31,7 @@ const DEFAULT_PROPS = ([_, { horizontal }]) => {
27
31
  }
28
32
 
29
33
  export function FlatList({ children, ...rootProps }) {
30
- const [_, props] = pipe(
34
+ const [_, formattedProps] = pipe(
31
35
  useThemeComponentModifier('FlatList'),
32
36
  useDefaultModifier(DEFAULT_PROPS),
33
37
  useFlexWrapperModifier,
@@ -44,11 +48,44 @@ export function FlatList({ children, ...rootProps }) {
44
48
  useBorderModifier,
45
49
  useShadowModifier
46
50
  )([{}, rootProps])
47
- // useNormalView = useResponsiveValue(useNormalView)
51
+
52
+ let {
53
+ divider,
54
+ dividerColor,
55
+ dividerProps,
56
+ renderSeparator,
57
+ renderItem,
58
+ lazy,
59
+ onlyOnScreen,
60
+ itemMinHeight,
61
+ ...props
62
+ } = formattedProps
63
+ const noScroll = useResponsiveValue(rootProps.noScroll)
64
+ const Wrapper = noScroll ? AbsStaticList : AbsFlatList
65
+
66
+ const formattedRenderItem = React.useCallback(
67
+ (...params) => (
68
+ <ConditionalLazyRender
69
+ whenVisible={lazy || onlyOnScreen}
70
+ destroyOffScreen={onlyOnScreen}
71
+ minHeight={itemMinHeight}
72
+ >
73
+ {renderItem?.(...params)}
74
+ </ConditionalLazyRender>
75
+ ),
76
+ [renderItem]
77
+ )
78
+
79
+ if (!renderSeparator && !!divider) {
80
+ if (divider === true) divider = 1
81
+ renderSeparator = () => <Divider line={divider} height={divider} color={dividerColor} {...dividerProps} />
82
+ }
48
83
 
49
84
  return (
50
- <AbsFlatList className="neko-flat-list" {...props}>
85
+ <Wrapper className="neko-flat-list" renderSeparator={renderSeparator} renderItem={formattedRenderItem} {...props}>
51
86
  {children}
52
- </AbsFlatList>
87
+ </Wrapper>
53
88
  )
54
89
  }
90
+
91
+ export const List = (props) => <FlatList noScroll {...props} />
@@ -0,0 +1,58 @@
1
+ import { pipe, range, is } from 'ramda'
2
+
3
+ import { Icon } from '../presentation'
4
+ import { View } from '../structure/View'
5
+ import { useColorConverter } from '../../modifiers/colorConverter'
6
+ import { useDefaultModifier } from '../../modifiers/default'
7
+ import { useSizeConverter } from '../../modifiers/sizeConverter'
8
+ import { useThemeComponentModifier } from '../../modifiers/themeComponent'
9
+
10
+ const DEFAULT_PROPS = {
11
+ color: 'primary',
12
+ inactiveColor: 'text4_op50',
13
+ max: 5,
14
+ icon: 'star-fill',
15
+ }
16
+
17
+ export function Rate({ value, ...rootProps }) {
18
+ let [{ size, sizeCode, color }, formattedProps] = pipe(
19
+ useColorConverter('primary'),
20
+ useSizeConverter('icons', 'md'),
21
+ useThemeComponentModifier('Rate'),
22
+ useDefaultModifier(DEFAULT_PROPS)
23
+ )([{}, rootProps])
24
+
25
+ const { icon, max, inactiveColor, tag, ...props } = formattedProps
26
+
27
+ return (
28
+ <View className="neko-rate" row gap="xxs" centerV minHeight={sizeCode} {...props}>
29
+ {range(1, max + 1).map((i) => {
30
+ const active = value >= i
31
+ const partial = getDecimalOrEdge(value, i)
32
+
33
+ let finalIcon = icon
34
+ if (is(Function, icon)) finalIcon = icon?.({ value, optionValue: i, active })
35
+
36
+ let finalColor = color
37
+ if (is(Function, color)) finalColor = color?.({ value, optionValue: i, active })
38
+
39
+ return (
40
+ <View center key={i} relative>
41
+ <Icon name={finalIcon} size={sizeCode} color={inactiveColor} />
42
+ {!!partial && (
43
+ <View absolute overflow="hidden" left={0} width={100 * partial + '%'}>
44
+ <Icon name={finalIcon} size={sizeCode} color={finalColor} />
45
+ </View>
46
+ )}
47
+ </View>
48
+ )
49
+ })}
50
+ </View>
51
+ )
52
+ }
53
+
54
+ function getDecimalOrEdge(value, i) {
55
+ if (value >= i) return 1
56
+ if (value < i - 1) return 0
57
+ return value - Math.floor(value)
58
+ }
@@ -0,0 +1,35 @@
1
+ import { pipe } from 'ramda'
2
+
3
+ import { Tag } from './Tag'
4
+ import { moveScale } from '../../theme/helpers/sizeScale'
5
+ import { useColorConverter } from '../../modifiers/colorConverter'
6
+ import { useDefaultModifier } from '../../modifiers/default'
7
+ import { useSizeConverter } from '../../modifiers/sizeConverter'
8
+ import { useThemeComponentModifier } from '../../modifiers/themeComponent'
9
+
10
+ const DEFAULT_PROPS = {
11
+ icon: 'star-fill', //
12
+ // outline: false,
13
+ }
14
+
15
+ export function RateTag({ value, ...rootProps }) {
16
+ let [{ size, sizeCode, color }, formattedProps] = pipe(
17
+ useColorConverter('primary'),
18
+ useSizeConverter('icons', 'md'),
19
+ useThemeComponentModifier('RateTag'),
20
+ useDefaultModifier(DEFAULT_PROPS)
21
+ )([{}, rootProps])
22
+
23
+ const { icon, ...props } = formattedProps
24
+
25
+ return (
26
+ <Tag
27
+ icon={icon}
28
+ label={value}
29
+ color={color}
30
+ textProps={{ size: moveScale(sizeCode, -1) }}
31
+ gap={moveScale(sizeCode, -3)}
32
+ {...props}
33
+ />
34
+ )
35
+ }
@@ -46,11 +46,11 @@ export function Result({
46
46
  <View className="neko-result" center padding="lg" {...props}>
47
47
  {!!icon && <Icon name={icon} color={iconColor} size={42} primary {...iconProps} />}
48
48
  {!!icon && <Divider height={10} />}
49
- <Text h3 {...textProps} {...titleProps}>
49
+ <Text h4 {...textProps} {...titleProps}>
50
50
  {title}
51
51
  </Text>
52
52
  {!!description && (
53
- <Text text3 sm {...textProps} {...descriptionProps}>
53
+ <Text text3 sm marginT="sm" {...textProps} {...descriptionProps}>
54
54
  {description}
55
55
  </Text>
56
56
  )}
@@ -21,6 +21,7 @@ export function Tooltip(rootProps) {
21
21
  return (
22
22
  <Popover
23
23
  className="neko-tooltip"
24
+ padding="xs"
24
25
  {...props}
25
26
  content={
26
27
  <IconLabel
@@ -10,3 +10,5 @@ export * from './AvatarLabel'
10
10
  export * from './Image'
11
11
  export * from './ImageBackground'
12
12
  export * from './LabelValue'
13
+ export * from './Rate'
14
+ export * from './RateTag'
@@ -43,7 +43,7 @@ export function Accordion({ children, title, open, onChange, ...rootProps }) {
43
43
  row
44
44
  gap={moveScale(sizeCode, -2)}
45
45
  borderB={open ? props.border || true : open}
46
- borderColor={props.borderColor || 'bg'}
46
+ borderColor={props.borderColor || 'divider_op40'}
47
47
  centerV
48
48
  {...headerProps}
49
49
  onPress={toggle}
@@ -2,12 +2,16 @@ import { pipe } from 'ramda'
2
2
  import React from 'react'
3
3
 
4
4
  import { AbsView } from '../../abstractions/View'
5
+ import { useBackgroundModifier } from '../../modifiers/background'
6
+ import { useBorderModifier } from '../../modifiers/border'
5
7
  import { useFlexModifier } from '../../modifiers/flex'
6
8
  import { useFlexWrapperModifier } from '../../modifiers/flexWrapper'
7
9
  import { useGridModifier } from '../../modifiers/grid'
8
10
  import { useMarginModifier } from '../../modifiers/margin'
11
+ import { usePaddingModifier } from '../../modifiers/padding'
9
12
  import { usePositionModifier } from '../../modifiers/position'
10
13
  import { useResponsiveConverter } from '../../modifiers/responsiveConverter'
14
+ import { useShadowModifier } from '../../modifiers/shadow'
11
15
  import { useSizeModifier } from '../../modifiers/size'
12
16
  import { useThemeComponentModifier } from '../../modifiers/themeComponent'
13
17
 
@@ -20,7 +24,11 @@ export function Row({ children, ...rootProps }) {
20
24
  usePositionModifier,
21
25
  useFlexWrapperModifier,
22
26
  useFlexModifier,
23
- useMarginModifier
27
+ useMarginModifier,
28
+ usePaddingModifier,
29
+ useBackgroundModifier,
30
+ useBorderModifier,
31
+ useShadowModifier
24
32
  )([{}, rootProps])
25
33
 
26
34
  // Memoiza os children clonados para evitar recriação se childPaddingProps não mudar
@@ -0,0 +1,51 @@
1
+ import { pipe } from 'ramda'
2
+ import React from 'react'
3
+
4
+ import { View } from './View'
5
+ import { useDefaultModifier } from '../../modifiers/default'
6
+ import { useSizeConverter } from '../../modifiers/sizeConverter'
7
+ import { useThemeComponentModifier } from '../../modifiers/themeComponent'
8
+
9
+ const DEFAULT_PROPS = ([{ sizeCode }]) => ({
10
+ row: true,
11
+ justify: 'stretch',
12
+ br: sizeCode,
13
+ // overflow: 'hidden',
14
+ })
15
+
16
+ export function Segment({ children, ...rootProps }) {
17
+ const [{ sizeCode }, formattedProps] = pipe(
18
+ useSizeConverter('elementHeights', 'md'),
19
+ useThemeComponentModifier('Segment'),
20
+ useDefaultModifier(DEFAULT_PROPS)
21
+ )([{}, rootProps])
22
+
23
+ const { br, ...props } = formattedProps
24
+ const size = children?.length
25
+
26
+ return (
27
+ <View className="neko-segment" {...props}>
28
+ {React.Children.map(children, (child, index) => {
29
+ if (!React.isValidElement(child)) return child
30
+ const isFirst = index === 0
31
+ const isLast = size - 1 === index
32
+
33
+ const childProps = child.props || {}
34
+ const newProps = {
35
+ brL: br,
36
+ brR: br,
37
+ size: sizeCode,
38
+ }
39
+
40
+ if (!isLast) {
41
+ newProps.brR = 0
42
+ }
43
+ if (!isFirst) {
44
+ newProps.brL = 0
45
+ }
46
+
47
+ return React.cloneElement(child, newProps)
48
+ })}
49
+ </View>
50
+ )
51
+ }
@@ -53,7 +53,10 @@ function InnerContent({
53
53
  const snapIndex = useSharedValue(0)
54
54
  const velocityY = useSharedValue(0)
55
55
 
56
- const normalizedSnapPoints = React.useMemo(() => normalizeSnapPoints(snapPoints, SCREEN_HEIGHT), [snapPoints])
56
+ const normalizedSnapPoints = React.useMemo(
57
+ () => normalizeSnapPoints(snapPoints, SCREEN_HEIGHT, bottomInset),
58
+ [snapPoints, useSafeArea]
59
+ )
57
60
  const maxSnapPoint = React.useMemo(() => Math.max(...normalizedSnapPoints), [normalizedSnapPoints])
58
61
  const minSnapPoint = React.useMemo(() => Math.min(...normalizedSnapPoints), [normalizedSnapPoints])
59
62