@neko-os/ui 0.0.9 → 0.0.11

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 (143) 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/Button.js +1 -1
  11. package/dist/components/actions/Dropdown.js +1 -1
  12. package/dist/components/actions/FloatingButton.js +1 -0
  13. package/dist/components/actions/index.js +1 -1
  14. package/dist/components/actions/menu/VerticalMenu.js +1 -1
  15. package/dist/components/calendar/_helpers/calendarDays.js +1 -1
  16. package/dist/components/feedback/alerter.js +1 -1
  17. package/dist/components/feedback/confirmer.js +1 -1
  18. package/dist/components/helpers/ConditionalLazyRender.js +1 -0
  19. package/dist/components/helpers/LazyAction.js +1 -0
  20. package/dist/components/helpers/LazyRender.js +1 -1
  21. package/dist/components/helpers/LazyRender.native.js +1 -1
  22. package/dist/components/helpers/index.js +1 -1
  23. package/dist/components/index.js +1 -1
  24. package/dist/components/inputs/DateInput.js +1 -1
  25. package/dist/components/inputs/InputWrapper.js +1 -1
  26. package/dist/components/inputs/LinkInput.js +1 -1
  27. package/dist/components/inputs/NumberInput.js +1 -0
  28. package/dist/components/inputs/Picker.js +1 -1
  29. package/dist/components/inputs/Radio.js +1 -1
  30. package/dist/components/inputs/RateInput.js +1 -0
  31. package/dist/components/inputs/SegmentedPicker.js +1 -0
  32. package/dist/components/inputs/Select.js +1 -0
  33. package/dist/components/inputs/datePicker/DayPicker.js +1 -1
  34. package/dist/components/inputs/datePicker/MonthPicker.js +1 -1
  35. package/dist/components/inputs/datePicker/QuarterPicker.js +1 -1
  36. package/dist/components/inputs/datePicker/WeekPicker.js +1 -1
  37. package/dist/components/inputs/datePicker/YearPicker.js +1 -1
  38. package/dist/components/inputs/index.js +1 -1
  39. package/dist/components/list/FlatList.js +1 -1
  40. package/dist/components/presentation/Rate.js +1 -0
  41. package/dist/components/presentation/RateTag.js +1 -0
  42. package/dist/components/presentation/Result.js +1 -1
  43. package/dist/components/presentation/Tooltip.js +1 -1
  44. package/dist/components/presentation/index.js +1 -1
  45. package/dist/components/structure/Accordion.js +1 -1
  46. package/dist/components/structure/Row.js +1 -1
  47. package/dist/components/structure/Segment.js +1 -0
  48. package/dist/components/structure/bottomDrawer/native/BottomDrawer.js +1 -1
  49. package/dist/components/structure/bottomDrawer/native/utils.js +1 -1
  50. package/dist/components/structure/bottomDrawer/web/BottomDrawer.js +1 -1
  51. package/dist/components/structure/index.js +1 -1
  52. package/dist/components/structure/overlay/OverlayHandler.js +1 -1
  53. package/dist/components/structure/popover/Popover.js +1 -1
  54. package/dist/components/structure/popover/Popover_BU.js +1 -0
  55. package/dist/components/tabs/ActiveTabContent.js +1 -0
  56. package/dist/components/tabs/TabsHandler.js +1 -0
  57. package/dist/components/tabs/TabsMenu.js +1 -0
  58. package/dist/components/tabs/index.js +1 -0
  59. package/dist/helpers/string.js +1 -1
  60. package/dist/i18n/I18n.js +1 -0
  61. package/dist/i18n/I18nProvider.js +1 -0
  62. package/dist/i18n/index.js +1 -0
  63. package/dist/index.css +4 -0
  64. package/dist/index.js +1 -1
  65. package/dist/modifiers/animations/fadeEffect.web.js +1 -0
  66. package/dist/modifiers/animations/scrollEffect.web.js +1 -0
  67. package/dist/modifiers/animations/slideEffect.web.js +1 -0
  68. package/dist/modifiers/fullColor.js +1 -1
  69. package/dist/modifiers/overflow.js +1 -1
  70. package/dist/modifiers/position.js +1 -1
  71. package/dist/theme/default/base.js +1 -1
  72. package/package.json +1 -1
  73. package/src/DynamicStyleTag.js +21 -0
  74. package/src/DynamicStyleTag.native.js +3 -0
  75. package/src/NekoUI.js +12 -7
  76. package/src/abstractions/AnimatedView.web.js +3 -0
  77. package/src/abstractions/FlatList.js +2 -38
  78. package/src/abstractions/FlatList.native.js +8 -4
  79. package/src/abstractions/StaticList.js +51 -0
  80. package/src/abstractions/helpers/useSafeAreaInsets.js +3 -0
  81. package/src/abstractions/helpers/useSafeAreaInsets.native.js +3 -0
  82. package/src/components/actions/Button.js +15 -13
  83. package/src/components/actions/Dropdown.js +13 -9
  84. package/src/components/actions/FloatingButton.js +87 -0
  85. package/src/components/actions/index.js +1 -0
  86. package/src/components/actions/menu/VerticalMenu.js +29 -4
  87. package/src/components/calendar/_helpers/calendarDays.js +2 -0
  88. package/src/components/feedback/alerter.js +1 -1
  89. package/src/components/feedback/confirmer.js +2 -2
  90. package/src/components/helpers/ConditionalLazyRender.js +6 -0
  91. package/src/components/helpers/LazyAction.js +22 -0
  92. package/src/components/helpers/LazyRender.js +2 -2
  93. package/src/components/helpers/LazyRender.native.js +1 -1
  94. package/src/components/helpers/index.js +1 -0
  95. package/src/components/index.js +1 -0
  96. package/src/components/inputs/DateInput.js +11 -1
  97. package/src/components/inputs/InputWrapper.js +0 -1
  98. package/src/components/inputs/LinkInput.js +3 -3
  99. package/src/components/inputs/NumberInput.js +105 -0
  100. package/src/components/inputs/Picker.js +61 -9
  101. package/src/components/inputs/Radio.js +1 -1
  102. package/src/components/inputs/RateInput.js +62 -0
  103. package/src/components/inputs/SegmentedPicker.js +62 -0
  104. package/src/components/inputs/Select.js +189 -0
  105. package/src/components/inputs/datePicker/DayPicker.js +4 -5
  106. package/src/components/inputs/datePicker/MonthPicker.js +2 -2
  107. package/src/components/inputs/datePicker/QuarterPicker.js +2 -2
  108. package/src/components/inputs/datePicker/WeekPicker.js +2 -2
  109. package/src/components/inputs/datePicker/YearPicker.js +9 -6
  110. package/src/components/inputs/index.js +4 -0
  111. package/src/components/list/FlatList.js +41 -4
  112. package/src/components/presentation/Rate.js +58 -0
  113. package/src/components/presentation/RateTag.js +35 -0
  114. package/src/components/presentation/Result.js +2 -2
  115. package/src/components/presentation/Tooltip.js +1 -0
  116. package/src/components/presentation/index.js +2 -0
  117. package/src/components/structure/Accordion.js +1 -1
  118. package/src/components/structure/Row.js +9 -1
  119. package/src/components/structure/Segment.js +51 -0
  120. package/src/components/structure/bottomDrawer/native/BottomDrawer.js +4 -1
  121. package/src/components/structure/bottomDrawer/native/utils.js +29 -22
  122. package/src/components/structure/bottomDrawer/web/BottomDrawer.js +3 -1
  123. package/src/components/structure/index.js +1 -0
  124. package/src/components/structure/overlay/OverlayHandler.js +6 -1
  125. package/src/components/structure/popover/Popover.js +33 -19
  126. package/src/components/structure/popover/Popover_BU.js +157 -0
  127. package/src/components/tabs/ActiveTabContent.js +35 -0
  128. package/src/components/tabs/TabsHandler.js +16 -0
  129. package/src/components/tabs/TabsMenu.js +15 -0
  130. package/src/components/tabs/index.js +3 -0
  131. package/src/helpers/string.js +18 -1
  132. package/src/i18n/I18n.js +97 -0
  133. package/src/i18n/I18nProvider.js +40 -0
  134. package/src/i18n/index.js +2 -0
  135. package/src/index.css +4 -0
  136. package/src/index.js +1 -0
  137. package/src/modifiers/animations/fadeEffect.web.js +3 -0
  138. package/src/modifiers/animations/scrollEffect.web.js +3 -0
  139. package/src/modifiers/animations/slideEffect.web.js +3 -0
  140. package/src/modifiers/fullColor.js +5 -2
  141. package/src/modifiers/overflow.js +6 -1
  142. package/src/modifiers/position.js +7 -0
  143. package/src/theme/default/base.js +6 -2
@@ -0,0 +1,62 @@
1
+ import { pipe } from 'ramda'
2
+
3
+ import { Button } from '../actions'
4
+ import { Picker } from './Picker'
5
+ import { View } from '../structure'
6
+ import { moveScale } from '../../theme/helpers/sizeScale'
7
+ import { useDefaultModifier } from '../../modifiers/default'
8
+ import { useSizeConverter } from '../../modifiers/sizeConverter'
9
+ import { useThemeComponentModifier } from '../../modifiers/themeComponent'
10
+
11
+ const DEFAULT_PROPS = ([{ sizeCode }]) => ({
12
+ gap: 1,
13
+ br: sizeCode,
14
+ minHeight: sizeCode,
15
+ bg: 'overlayBG',
16
+ padding: 2,
17
+ wrap: false,
18
+ row: true,
19
+ border: true,
20
+ buttonProps: {
21
+ fullH: true,
22
+ size: sizeCode,
23
+ },
24
+ })
25
+
26
+ function PickerWrapper({ renderItem, options, ...props }) {
27
+ return (
28
+ <View row>
29
+ <View {...props}>{options?.map?.((option) => renderItem(option))}</View>
30
+ </View>
31
+ )
32
+ }
33
+
34
+ export function SegmentedPicker({ ...rootProps }) {
35
+ const [{ sizeCode }, formattedProps] = pipe(
36
+ useSizeConverter('elementHeights', 'md'),
37
+ useThemeComponentModifier('SegmentPicker'),
38
+ useDefaultModifier(DEFAULT_PROPS)
39
+ )([{}, rootProps])
40
+
41
+ const { buttonProps, color, ...props } = formattedProps
42
+
43
+ return (
44
+ <Picker
45
+ className="neko-segmented-picker"
46
+ Wrapper={PickerWrapper}
47
+ {...props}
48
+ renderOption={({ option, selected, onChange, labelKey, ...props }) => (
49
+ <Button
50
+ label={option[labelKey]}
51
+ onPress={onChange}
52
+ color={selected ? color || 'primary' : rootProps?.bg || 'overlayBG'}
53
+ round={rootProps?.round}
54
+ textProps={{ strong: selected }}
55
+ opacity={!selected && 0.8}
56
+ {...option}
57
+ {...buttonProps}
58
+ />
59
+ )}
60
+ />
61
+ )
62
+ }
@@ -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