@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.
- package/dist/DynamicStyleTag.js +5 -0
- package/dist/DynamicStyleTag.native.js +1 -0
- package/dist/NekoUI.js +1 -1
- package/dist/abstractions/AnimatedView.web.js +1 -0
- package/dist/abstractions/FlatList.js +1 -1
- package/dist/abstractions/FlatList.native.js +1 -1
- package/dist/abstractions/StaticList.js +1 -0
- package/dist/abstractions/helpers/useSafeAreaInsets.js +1 -0
- package/dist/abstractions/helpers/useSafeAreaInsets.native.js +1 -0
- package/dist/components/actions/Dropdown.js +1 -1
- package/dist/components/actions/FloatingButton.js +1 -0
- package/dist/components/actions/index.js +1 -1
- package/dist/components/actions/menu/VerticalMenu.js +1 -1
- package/dist/components/calendar/_helpers/calendarDays.js +1 -1
- package/dist/components/feedback/alerter.js +1 -1
- package/dist/components/feedback/confirmer.js +1 -1
- package/dist/components/helpers/ConditionalLazyRender.js +1 -0
- package/dist/components/helpers/LazyAction.js +1 -0
- package/dist/components/helpers/LazyRender.js +1 -1
- package/dist/components/helpers/LazyRender.native.js +1 -1
- package/dist/components/helpers/index.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/inputs/DateInput.js +1 -1
- package/dist/components/inputs/InputWrapper.js +1 -1
- package/dist/components/inputs/LinkInput.js +1 -1
- package/dist/components/inputs/NumberInput.js +1 -0
- package/dist/components/inputs/Picker.js +1 -1
- package/dist/components/inputs/Radio.js +1 -1
- package/dist/components/inputs/RateInput.js +1 -0
- package/dist/components/inputs/SegmentedPicker.js +1 -0
- package/dist/components/inputs/Select.js +1 -0
- package/dist/components/inputs/datePicker/DayPicker.js +1 -1
- package/dist/components/inputs/datePicker/MonthPicker.js +1 -1
- package/dist/components/inputs/datePicker/QuarterPicker.js +1 -1
- package/dist/components/inputs/datePicker/WeekPicker.js +1 -1
- package/dist/components/inputs/datePicker/YearPicker.js +1 -1
- package/dist/components/inputs/index.js +1 -1
- package/dist/components/list/FlatList.js +1 -1
- package/dist/components/presentation/Rate.js +1 -0
- package/dist/components/presentation/RateTag.js +1 -0
- package/dist/components/presentation/Result.js +1 -1
- package/dist/components/presentation/Tooltip.js +1 -1
- package/dist/components/presentation/index.js +1 -1
- package/dist/components/structure/Accordion.js +1 -1
- package/dist/components/structure/Row.js +1 -1
- package/dist/components/structure/Segment.js +1 -0
- package/dist/components/structure/bottomDrawer/native/BottomDrawer.js +1 -1
- package/dist/components/structure/bottomDrawer/native/utils.js +1 -1
- package/dist/components/structure/bottomDrawer/web/BottomDrawer.js +1 -1
- package/dist/components/structure/index.js +1 -1
- package/dist/components/structure/overlay/OverlayHandler.js +1 -1
- package/dist/components/structure/popover/Popover.js +1 -1
- package/dist/components/structure/popover/Popover_BU.js +1 -0
- package/dist/components/tabs/ActiveTabContent.js +1 -0
- package/dist/components/tabs/TabsHandler.js +1 -0
- package/dist/components/tabs/TabsMenu.js +1 -0
- package/dist/components/tabs/index.js +1 -0
- package/dist/helpers/string.js +1 -1
- package/dist/i18n/I18n.js +1 -0
- package/dist/i18n/I18nProvider.js +1 -0
- package/dist/i18n/index.js +1 -0
- package/dist/index.css +4 -0
- package/dist/index.js +1 -1
- package/dist/modifiers/animations/fadeEffect.web.js +1 -0
- package/dist/modifiers/animations/scrollEffect.web.js +1 -0
- package/dist/modifiers/animations/slideEffect.web.js +1 -0
- package/dist/modifiers/overflow.js +1 -1
- package/dist/modifiers/position.js +1 -1
- package/dist/theme/default/base.js +1 -1
- package/package.json +1 -1
- package/src/DynamicStyleTag.js +21 -0
- package/src/DynamicStyleTag.native.js +3 -0
- package/src/NekoUI.js +12 -7
- package/src/abstractions/AnimatedView.web.js +3 -0
- package/src/abstractions/FlatList.js +2 -38
- package/src/abstractions/FlatList.native.js +8 -4
- package/src/abstractions/StaticList.js +51 -0
- package/src/abstractions/helpers/useSafeAreaInsets.js +3 -0
- package/src/abstractions/helpers/useSafeAreaInsets.native.js +3 -0
- package/src/components/actions/Dropdown.js +13 -9
- package/src/components/actions/FloatingButton.js +87 -0
- package/src/components/actions/index.js +1 -0
- package/src/components/actions/menu/VerticalMenu.js +29 -4
- package/src/components/calendar/_helpers/calendarDays.js +2 -0
- package/src/components/feedback/alerter.js +1 -1
- package/src/components/feedback/confirmer.js +2 -2
- package/src/components/helpers/ConditionalLazyRender.js +6 -0
- package/src/components/helpers/LazyAction.js +22 -0
- package/src/components/helpers/LazyRender.js +2 -2
- package/src/components/helpers/LazyRender.native.js +1 -1
- package/src/components/helpers/index.js +1 -0
- package/src/components/index.js +1 -0
- package/src/components/inputs/DateInput.js +11 -1
- package/src/components/inputs/InputWrapper.js +0 -1
- package/src/components/inputs/LinkInput.js +3 -3
- package/src/components/inputs/NumberInput.js +105 -0
- package/src/components/inputs/Picker.js +61 -9
- package/src/components/inputs/Radio.js +1 -1
- package/src/components/inputs/RateInput.js +62 -0
- package/src/components/inputs/SegmentedPicker.js +62 -0
- package/src/components/inputs/Select.js +189 -0
- package/src/components/inputs/datePicker/DayPicker.js +4 -5
- package/src/components/inputs/datePicker/MonthPicker.js +2 -2
- package/src/components/inputs/datePicker/QuarterPicker.js +2 -2
- package/src/components/inputs/datePicker/WeekPicker.js +2 -2
- package/src/components/inputs/datePicker/YearPicker.js +9 -6
- package/src/components/inputs/index.js +4 -0
- package/src/components/list/FlatList.js +41 -4
- package/src/components/presentation/Rate.js +58 -0
- package/src/components/presentation/RateTag.js +35 -0
- package/src/components/presentation/Result.js +2 -2
- package/src/components/presentation/Tooltip.js +1 -0
- package/src/components/presentation/index.js +2 -0
- package/src/components/structure/Accordion.js +1 -1
- package/src/components/structure/Row.js +9 -1
- package/src/components/structure/Segment.js +51 -0
- package/src/components/structure/bottomDrawer/native/BottomDrawer.js +4 -1
- package/src/components/structure/bottomDrawer/native/utils.js +29 -22
- package/src/components/structure/bottomDrawer/web/BottomDrawer.js +3 -1
- package/src/components/structure/index.js +1 -0
- package/src/components/structure/overlay/OverlayHandler.js +6 -1
- package/src/components/structure/popover/Popover.js +33 -19
- package/src/components/structure/popover/Popover_BU.js +157 -0
- package/src/components/tabs/ActiveTabContent.js +35 -0
- package/src/components/tabs/TabsHandler.js +16 -0
- package/src/components/tabs/TabsMenu.js +15 -0
- package/src/components/tabs/index.js +3 -0
- package/src/helpers/string.js +18 -1
- package/src/i18n/I18n.js +97 -0
- package/src/i18n/I18nProvider.js +40 -0
- package/src/i18n/index.js +2 -0
- package/src/index.css +4 -0
- package/src/index.js +1 -0
- package/src/modifiers/animations/fadeEffect.web.js +3 -0
- package/src/modifiers/animations/scrollEffect.web.js +3 -0
- package/src/modifiers/animations/slideEffect.web.js +3 -0
- package/src/modifiers/overflow.js +6 -1
- package/src/modifiers/position.js +7 -0
- 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
|
-
|
|
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 [_,
|
|
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
|
-
|
|
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
|
-
<
|
|
85
|
+
<Wrapper className="neko-flat-list" renderSeparator={renderSeparator} renderItem={formattedRenderItem} {...props}>
|
|
51
86
|
{children}
|
|
52
|
-
</
|
|
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
|
|
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
|
)}
|
|
@@ -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 || '
|
|
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(
|
|
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
|
|