@neko-os/ui 0.5.4 → 0.6.1
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/NekoUI.js +12 -9
- package/dist/abstractions/WindowOverlay.js +3 -0
- package/dist/abstractions/WindowOverlay.native.js +21 -0
- package/dist/abstractions/helpers/storage.js +14 -4
- package/dist/abstractions/helpers/storage.native.js +9 -1
- package/dist/components/feedback/notifications/NotificationsHandler.js +10 -6
- package/dist/components/index.js +3 -1
- package/dist/components/inputs/DateInput.js +10 -6
- package/dist/components/inputs/InputWrapper.js +2 -3
- package/dist/components/inputs/NumberWheelInput.js +50 -0
- package/dist/components/inputs/NumberWheelPicker.js +43 -0
- package/dist/components/inputs/UploadInput.js +4 -4
- package/dist/components/inputs/WheelPicker.js +49 -0
- package/dist/components/inputs/WheelPicker.native.js +88 -0
- package/dist/components/inputs/WheelPicker.web.js +1 -0
- package/dist/components/inputs/dateWheelPicker/DateWheelPicker.js +24 -0
- package/dist/components/inputs/dateWheelPicker/DayWheelPicker.js +48 -0
- package/dist/components/inputs/dateWheelPicker/MonthWheelPicker.js +19 -0
- package/dist/components/inputs/dateWheelPicker/QuarterWheelPicker.js +61 -0
- package/dist/components/inputs/dateWheelPicker/WeekWheelPicker.js +66 -0
- package/dist/components/inputs/dateWheelPicker/YearWheelPicker.js +35 -0
- package/dist/components/inputs/index.js +5 -1
- package/dist/components/inputs/upload/Upload.native.js +60 -52
- package/dist/components/inputs/upload/useUploadState.js +11 -3
- package/dist/components/measurements/FeetInchesInput.js +91 -0
- package/dist/components/measurements/LengthInput.js +32 -0
- package/dist/components/measurements/LengthText.js +10 -0
- package/dist/components/measurements/MeasurementHandler.js +26 -0
- package/dist/components/measurements/WeightInput.js +25 -0
- package/dist/components/measurements/WeightText.js +10 -0
- package/dist/components/measurements/helpers/detectMeasurementSystem.js +15 -0
- package/dist/components/measurements/helpers/detectMeasurementSystem.native.js +9 -0
- package/dist/components/measurements/helpers/index.js +2 -0
- package/dist/components/measurements/helpers/length.js +112 -0
- package/dist/components/measurements/helpers/weight.js +56 -0
- package/dist/components/measurements/index.js +9 -0
- package/dist/components/measurements/useLengthFormatter.js +35 -0
- package/dist/components/measurements/useLocalInputValue.js +32 -0
- package/dist/components/measurements/useWeightFormatter.js +29 -0
- package/dist/components/routing/ReturnButton.js +20 -0
- package/dist/components/routing/ReturnButton.native.js +20 -0
- package/dist/components/routing/ReturnButton.web.js +2 -0
- package/dist/components/routing/ReturnLink.js +25 -0
- package/dist/components/routing/ReturnLink.native.js +25 -0
- package/dist/components/routing/ReturnLink.web.js +2 -0
- package/dist/components/routing/RoutedStepsContent.js +21 -0
- package/dist/components/routing/RoutedStepsContent.native.js +94 -0
- package/dist/components/routing/RoutedStepsContent.web.js +3 -0
- package/dist/components/routing/index.js +3 -0
- package/dist/components/state/StatePresenter.js +1 -1
- package/dist/components/steps/StepsHandler.js +2 -0
- package/dist/components/structure/TopBar.js +18 -16
- package/dist/components/theme/ThemePickerDrawer.js +1 -1
- package/dist/helpers/compress.js +61 -0
- package/dist/helpers/compress.native.js +49 -0
- package/dist/helpers/files.js +7 -0
- package/dist/helpers/files.native.js +55 -0
- package/dist/helpers/index.js +6 -1
- package/dist/helpers/media.js +4 -0
- package/dist/helpers/media.native.js +41 -0
- package/dist/helpers/numbers.js +13 -0
- package/dist/helpers/pickAssets.js +7 -0
- package/dist/helpers/pickAssets.native.js +66 -0
- package/dist/helpers/storage.js +17 -0
- package/dist/i18n/I18n.js +4 -4
- package/dist/index.js +1 -1
- package/dist/responsive/responsiveHooks.js +17 -0
- package/package.json +2 -14
- package/src/NekoUI.js +16 -13
- package/src/abstractions/WindowOverlay.js +3 -0
- package/src/abstractions/WindowOverlay.native.js +21 -0
- package/src/abstractions/helpers/storage.js +13 -3
- package/src/abstractions/helpers/storage.native.js +8 -0
- package/src/components/feedback/notifications/NotificationsHandler.js +12 -8
- package/src/components/index.js +2 -0
- package/src/components/inputs/DateInput.js +8 -4
- package/src/components/inputs/InputWrapper.js +1 -2
- package/src/components/inputs/NumberWheelInput.js +50 -0
- package/src/components/inputs/NumberWheelPicker.js +43 -0
- package/src/components/inputs/UploadInput.js +2 -2
- package/src/components/inputs/WheelPicker.js +49 -0
- package/src/components/inputs/WheelPicker.native.js +88 -0
- package/src/components/inputs/WheelPicker.web.js +1 -0
- package/src/components/inputs/dateWheelPicker/DateWheelPicker.js +24 -0
- package/src/components/inputs/dateWheelPicker/DayWheelPicker.js +48 -0
- package/src/components/inputs/dateWheelPicker/MonthWheelPicker.js +19 -0
- package/src/components/inputs/dateWheelPicker/QuarterWheelPicker.js +61 -0
- package/src/components/inputs/dateWheelPicker/WeekWheelPicker.js +66 -0
- package/src/components/inputs/dateWheelPicker/YearWheelPicker.js +35 -0
- package/src/components/inputs/index.js +4 -0
- package/src/components/inputs/upload/Upload.native.js +58 -50
- package/src/components/inputs/upload/useUploadState.js +11 -3
- package/src/components/measurements/FeetInchesInput.js +91 -0
- package/src/components/measurements/LengthInput.js +32 -0
- package/src/components/measurements/LengthText.js +10 -0
- package/src/components/measurements/MeasurementHandler.js +26 -0
- package/src/components/measurements/WeightInput.js +25 -0
- package/src/components/measurements/WeightText.js +10 -0
- package/src/components/measurements/helpers/detectMeasurementSystem.js +15 -0
- package/src/components/measurements/helpers/detectMeasurementSystem.native.js +9 -0
- package/src/components/measurements/helpers/index.js +2 -0
- package/src/components/measurements/helpers/length.js +112 -0
- package/src/components/measurements/helpers/weight.js +56 -0
- package/src/components/measurements/index.js +9 -0
- package/src/components/measurements/useLengthFormatter.js +35 -0
- package/src/components/measurements/useLocalInputValue.js +32 -0
- package/src/components/measurements/useWeightFormatter.js +29 -0
- package/src/components/routing/ReturnButton.js +20 -0
- package/src/components/routing/ReturnButton.native.js +20 -0
- package/src/components/routing/ReturnButton.web.js +2 -0
- package/src/components/routing/ReturnLink.js +25 -0
- package/src/components/routing/ReturnLink.native.js +25 -0
- package/src/components/routing/ReturnLink.web.js +2 -0
- package/src/components/routing/RoutedStepsContent.js +21 -0
- package/src/components/routing/RoutedStepsContent.native.js +94 -0
- package/src/components/routing/RoutedStepsContent.web.js +3 -0
- package/src/components/routing/index.js +3 -0
- package/src/components/state/StatePresenter.js +1 -1
- package/src/components/steps/StepsHandler.js +2 -0
- package/src/components/structure/TopBar.js +16 -14
- package/src/components/theme/ThemePickerDrawer.js +1 -1
- package/src/helpers/compress.js +61 -0
- package/src/helpers/compress.native.js +49 -0
- package/src/helpers/files.js +7 -0
- package/src/helpers/files.native.js +55 -0
- package/src/helpers/index.js +6 -1
- package/src/helpers/media.js +4 -0
- package/src/helpers/media.native.js +41 -0
- package/src/helpers/numbers.js +13 -0
- package/src/helpers/pickAssets.js +7 -0
- package/src/helpers/pickAssets.native.js +66 -0
- package/src/helpers/storage.js +17 -0
- package/src/i18n/I18n.js +2 -2
- package/src/index.js +1 -1
- package/src/responsive/responsiveHooks.js +17 -0
package/src/components/index.js
CHANGED
|
@@ -11,6 +11,7 @@ dayjs.extend(advancedFormat)
|
|
|
11
11
|
dayjs.extend(weekOfYear)
|
|
12
12
|
|
|
13
13
|
import { DatePicker } from './datePicker/DatePicker'
|
|
14
|
+
import { DateWheelPicker } from './dateWheelPicker/DateWheelPicker'
|
|
14
15
|
import { MaskInput } from './MaskInput'
|
|
15
16
|
import { Popover } from '../structure/popover/Popover'
|
|
16
17
|
import { isValidDate } from '../calendar/_helpers/dateDisabled'
|
|
@@ -46,6 +47,7 @@ export function DateInput({
|
|
|
46
47
|
onCheckDisabled,
|
|
47
48
|
placement,
|
|
48
49
|
type = 'day',
|
|
50
|
+
presentation = 'calendar',
|
|
49
51
|
format,
|
|
50
52
|
startsOpen,
|
|
51
53
|
allowClear,
|
|
@@ -85,26 +87,28 @@ export function DateInput({
|
|
|
85
87
|
setInputValue(!!value ? dayjs(value).format(format) : '')
|
|
86
88
|
}, [value])
|
|
87
89
|
|
|
90
|
+
const isWheel = presentation === 'wheel'
|
|
88
91
|
const Input = useBottomDrawer ? LinkInput : FullWidthInputWrapper
|
|
92
|
+
const Picker = isWheel ? DateWheelPicker : DatePicker
|
|
89
93
|
|
|
90
94
|
return (
|
|
91
95
|
<Popover
|
|
92
96
|
trigger="click"
|
|
93
97
|
startsOpen={startsOpen}
|
|
94
98
|
placement={placement || 'bottomLeft'}
|
|
95
|
-
snapPoints={[450]}
|
|
99
|
+
snapPoints={[isWheel ? 275 : 450]}
|
|
96
100
|
useBottomDrawer={useBottomDrawer}
|
|
97
101
|
bottomDrawerProps={{ contentProps: { padding: 'md' } }}
|
|
98
102
|
watch={[value?.format?.('YYYYMMDD')]}
|
|
99
103
|
renderContent={({ onClose }) => (
|
|
100
104
|
<View flex centerH onMouseDown={(e) => e.preventDefault()}>
|
|
101
|
-
<
|
|
105
|
+
<Picker
|
|
102
106
|
value={value}
|
|
103
107
|
onChange={(v) => {
|
|
104
108
|
handleChange(v)
|
|
105
|
-
onClose()
|
|
109
|
+
if (!isWheel) onClose()
|
|
106
110
|
}}
|
|
107
|
-
width={useBottomDrawer ? '100%' : 275}
|
|
111
|
+
width={!isWheel && (useBottomDrawer ? '100%' : 275)}
|
|
108
112
|
allowClear={allowClear}
|
|
109
113
|
{...validations}
|
|
110
114
|
type={type}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { BottomDrawer } from '../modals/bottomDrawer'
|
|
4
|
+
import { LinkInput } from './LinkInput'
|
|
5
|
+
import { NumberWheelPicker } from './NumberWheelPicker'
|
|
6
|
+
import { View } from '../structure/View'
|
|
7
|
+
|
|
8
|
+
export function NumberWheelInput({
|
|
9
|
+
value,
|
|
10
|
+
onChange,
|
|
11
|
+
min,
|
|
12
|
+
max,
|
|
13
|
+
step,
|
|
14
|
+
decimalStep,
|
|
15
|
+
useInt,
|
|
16
|
+
precision,
|
|
17
|
+
suffix,
|
|
18
|
+
...props
|
|
19
|
+
}) {
|
|
20
|
+
const [open, setOpen] = React.useState(false)
|
|
21
|
+
const [localValue, setLocalValue] = React.useState(value)
|
|
22
|
+
value = value ?? localValue
|
|
23
|
+
|
|
24
|
+
const handleChange = (v) => {
|
|
25
|
+
setLocalValue(v)
|
|
26
|
+
onChange?.(v)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const displayValue = value != null ? `${value}${suffix ? ` ${suffix}` : ''}` : ''
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
<LinkInput value={displayValue} onPress={() => setOpen(true)} {...props} />
|
|
34
|
+
<BottomDrawer open={open} onClose={() => setOpen(false)} snapPoints={[275]} contentProps={{ padding: 'md' }}>
|
|
35
|
+
<View flex centerH>
|
|
36
|
+
<NumberWheelPicker
|
|
37
|
+
value={value}
|
|
38
|
+
onChange={handleChange}
|
|
39
|
+
min={min}
|
|
40
|
+
max={max}
|
|
41
|
+
step={step}
|
|
42
|
+
decimalStep={decimalStep}
|
|
43
|
+
useInt={useInt}
|
|
44
|
+
precision={precision}
|
|
45
|
+
/>
|
|
46
|
+
</View>
|
|
47
|
+
</BottomDrawer>
|
|
48
|
+
</>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Text } from '../text'
|
|
2
|
+
import { View } from '../structure'
|
|
3
|
+
import { WheelPicker } from './WheelPicker'
|
|
4
|
+
|
|
5
|
+
export function NumberWheelPicker({ value, onChange, min = 0, max = 100, step = 1, decimalStep = 1, useInt, precision = 2 }) {
|
|
6
|
+
if (useInt) precision = 0
|
|
7
|
+
|
|
8
|
+
const intValue = value != null ? Math.trunc(value) : min
|
|
9
|
+
const decFactor = Math.pow(10, precision)
|
|
10
|
+
const decValue = value != null ? Math.round((Math.abs(value) - Math.abs(intValue)) * decFactor) : 0
|
|
11
|
+
|
|
12
|
+
const handleIntChange = (v) => {
|
|
13
|
+
onChange?.(precision === 0 ? v : v + decValue / decFactor)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const handleDecChange = (v) => {
|
|
17
|
+
onChange?.(intValue + v / decFactor)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<View row gap="xs" centerV>
|
|
22
|
+
<View flex>
|
|
23
|
+
<WheelPicker range={[min, max]} step={step} value={intValue} onChange={handleIntChange} />
|
|
24
|
+
</View>
|
|
25
|
+
{precision > 0 && (
|
|
26
|
+
<>
|
|
27
|
+
<Text h3 strong>
|
|
28
|
+
.
|
|
29
|
+
</Text>
|
|
30
|
+
<View flex>
|
|
31
|
+
<WheelPicker
|
|
32
|
+
range={[0, decFactor - 1]}
|
|
33
|
+
step={decimalStep}
|
|
34
|
+
value={decValue}
|
|
35
|
+
onChange={handleDecChange}
|
|
36
|
+
formatLabel={(v) => String(v).padStart(precision, '0')}
|
|
37
|
+
/>
|
|
38
|
+
</View>
|
|
39
|
+
</>
|
|
40
|
+
)}
|
|
41
|
+
</View>
|
|
42
|
+
)
|
|
43
|
+
}
|
|
@@ -111,7 +111,7 @@ function Content({ value, open, remove, isDragging, multiple, area, grid, maxCou
|
|
|
111
111
|
return (
|
|
112
112
|
<View row wrap gap="sm">
|
|
113
113
|
{items.map((item) => (
|
|
114
|
-
<GridItem key={item._id} value={item} remove={remove} />
|
|
114
|
+
<GridItem key={item._id ?? item.id} value={item} remove={remove} />
|
|
115
115
|
))}
|
|
116
116
|
{showAdd && <AddTile onPress={open} isDragging={isDragging} />}
|
|
117
117
|
</View>
|
|
@@ -129,7 +129,7 @@ function Content({ value, open, remove, isDragging, multiple, area, grid, maxCou
|
|
|
129
129
|
<View gap="xs">
|
|
130
130
|
{showAdd && link}
|
|
131
131
|
{items.map((item) => (
|
|
132
|
-
<ListItem key={item._id} value={item} remove={remove} />
|
|
132
|
+
<ListItem key={item._id ?? item.id} value={item} remove={remove} />
|
|
133
133
|
))}
|
|
134
134
|
</View>
|
|
135
135
|
)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { NumberInput } from './NumberInput'
|
|
2
|
+
|
|
3
|
+
export function WheelPicker({
|
|
4
|
+
value,
|
|
5
|
+
onChange,
|
|
6
|
+
options,
|
|
7
|
+
suffix,
|
|
8
|
+
range,
|
|
9
|
+
step = 1,
|
|
10
|
+
labelKey = 'label',
|
|
11
|
+
valueKey = 'value',
|
|
12
|
+
useRawOption,
|
|
13
|
+
formatLabel,
|
|
14
|
+
...props
|
|
15
|
+
}) {
|
|
16
|
+
let min = 0
|
|
17
|
+
let max = 100
|
|
18
|
+
|
|
19
|
+
if (!!range || !options) {
|
|
20
|
+
const [from, to] = range || [0, 100]
|
|
21
|
+
const count = Math.floor((to - from) / step) + 1
|
|
22
|
+
options = Array.from({ length: count }, (_, i) => {
|
|
23
|
+
const v = from + i * step
|
|
24
|
+
return { [labelKey]: formatLabel ? formatLabel(v) : v, [valueKey]: v }
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const values = (options || []).map((o) => o[valueKey]).filter((v) => typeof v === 'number')
|
|
29
|
+
if (values.length) {
|
|
30
|
+
min = Math.min(...values)
|
|
31
|
+
max = Math.max(...values)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function handleChange(newValue) {
|
|
35
|
+
if (useRawOption) {
|
|
36
|
+
// NumberInput allows free typing — snap to the nearest option on miss
|
|
37
|
+
const match = options.find((o) => o[valueKey] === newValue)
|
|
38
|
+
return onChange(
|
|
39
|
+
match ||
|
|
40
|
+
options.reduce((best, o) =>
|
|
41
|
+
Math.abs(o[valueKey] - newValue) < Math.abs(best[valueKey] - newValue) ? o : best
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
onChange(newValue)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return <NumberInput value={value} onChange={handleChange} suffix={suffix} min={min} max={max} precision={0} {...props} />
|
|
49
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { Text } from '../text'
|
|
4
|
+
import { View } from '../structure'
|
|
5
|
+
import { useColors } from '../../theme'
|
|
6
|
+
import { debounce } from '../../helpers/debounce'
|
|
7
|
+
|
|
8
|
+
let QuidoneWheelPicker
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
QuidoneWheelPicker = require('@quidone/react-native-wheel-picker').default
|
|
12
|
+
} catch {
|
|
13
|
+
QuidoneWheelPicker = null
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function WheelPicker({
|
|
17
|
+
value,
|
|
18
|
+
onChange,
|
|
19
|
+
options,
|
|
20
|
+
suffix,
|
|
21
|
+
range,
|
|
22
|
+
step = 1,
|
|
23
|
+
labelKey = 'label',
|
|
24
|
+
valueKey = 'value',
|
|
25
|
+
useRawOption,
|
|
26
|
+
formatLabel,
|
|
27
|
+
...props
|
|
28
|
+
}) {
|
|
29
|
+
const colors = useColors()
|
|
30
|
+
const handleChange = React.useMemo(() => debounce(onChange, 300), [onChange])
|
|
31
|
+
|
|
32
|
+
if (!!range || !options) {
|
|
33
|
+
const [from, to] = range || [0, 100]
|
|
34
|
+
const count = Math.floor((to - from) / step) + 1
|
|
35
|
+
options = Array.from({ length: count }, (_, i) => {
|
|
36
|
+
const v = from + i * step
|
|
37
|
+
return { [labelKey]: formatLabel ? formatLabel(v) : v, [valueKey]: v }
|
|
38
|
+
})
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const data = React.useMemo(() => {
|
|
42
|
+
if (!options) return []
|
|
43
|
+
return options.map((opt) => ({
|
|
44
|
+
value: opt[valueKey],
|
|
45
|
+
label: String(opt[labelKey] ?? opt[valueKey]),
|
|
46
|
+
}))
|
|
47
|
+
}, [options, labelKey, valueKey])
|
|
48
|
+
|
|
49
|
+
if (!QuidoneWheelPicker) {
|
|
50
|
+
console.warn('@quidone/react-native-wheel-picker not installed.')
|
|
51
|
+
return null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const resolveValue = (item) => {
|
|
55
|
+
if (useRawOption) return options.find((o) => o[valueKey] === item.value)
|
|
56
|
+
return item.value
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return (
|
|
60
|
+
<View relative hiddenOverflow>
|
|
61
|
+
{!!suffix && (
|
|
62
|
+
<View absoluteFill row centerV>
|
|
63
|
+
<View flex />
|
|
64
|
+
<View flex paddingL={20}>
|
|
65
|
+
<Text text2>{suffix}</Text>
|
|
66
|
+
</View>
|
|
67
|
+
</View>
|
|
68
|
+
)}
|
|
69
|
+
<QuidoneWheelPicker
|
|
70
|
+
data={data}
|
|
71
|
+
value={value}
|
|
72
|
+
itemTextStyle={{ color: colors.text }}
|
|
73
|
+
itemHeight={40}
|
|
74
|
+
overlayItemStyle={{
|
|
75
|
+
backgroundColor: 'transparent',
|
|
76
|
+
borderWidth: 1,
|
|
77
|
+
borderLeftWidth: 0,
|
|
78
|
+
borderRightWidth: 0,
|
|
79
|
+
borderColor: colors.divider,
|
|
80
|
+
opacity: 1,
|
|
81
|
+
}}
|
|
82
|
+
_onValueChanging={({ item }) => handleChange(resolveValue(item))}
|
|
83
|
+
onValueChanged={({ item }) => onChange(resolveValue(item))}
|
|
84
|
+
{...props}
|
|
85
|
+
/>
|
|
86
|
+
</View>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { WheelPicker } from './WheelPicker.native'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DayWheelPicker } from './DayWheelPicker'
|
|
2
|
+
import { MonthWheelPicker } from './MonthWheelPicker'
|
|
3
|
+
import { QuarterWheelPicker } from './QuarterWheelPicker'
|
|
4
|
+
import { WeekWheelPicker } from './WeekWheelPicker'
|
|
5
|
+
import { YearWheelPicker } from './YearWheelPicker'
|
|
6
|
+
|
|
7
|
+
export function DateWheelPicker({ type, ...props }) {
|
|
8
|
+
switch (type) {
|
|
9
|
+
case 'year':
|
|
10
|
+
return <YearWheelPicker {...props} />
|
|
11
|
+
|
|
12
|
+
case 'quarter':
|
|
13
|
+
return <QuarterWheelPicker {...props} />
|
|
14
|
+
|
|
15
|
+
case 'month':
|
|
16
|
+
return <MonthWheelPicker {...props} />
|
|
17
|
+
|
|
18
|
+
case 'week':
|
|
19
|
+
return <WeekWheelPicker {...props} />
|
|
20
|
+
|
|
21
|
+
default:
|
|
22
|
+
return <DayWheelPicker {...props} />
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import dayjs from 'dayjs'
|
|
2
|
+
|
|
3
|
+
import { ClearLink } from '../../actions/ClearLink'
|
|
4
|
+
import { View } from '../../structure'
|
|
5
|
+
import { useColors } from '../../../theme'
|
|
6
|
+
|
|
7
|
+
let DatePicker
|
|
8
|
+
|
|
9
|
+
try {
|
|
10
|
+
DatePicker = require('@quidone/react-native-wheel-picker').DatePicker
|
|
11
|
+
} catch {
|
|
12
|
+
DatePicker = null
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function DayWheelPicker({ value, onChange, min, max, onCheckDisabled, allowClear, ...props }) {
|
|
16
|
+
const colors = useColors()
|
|
17
|
+
if (!DatePicker) {
|
|
18
|
+
console.warn('@quidone/react-native-wheel-picker not installed.')
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
value = value ? dayjs(value) : dayjs()
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<View center height={40 * 5} overflow="hidden" relative>
|
|
26
|
+
<DatePicker
|
|
27
|
+
locale={'pt'}
|
|
28
|
+
date={value.format('YYYY-MM-DD')}
|
|
29
|
+
minDate={min ? dayjs(min).format('YYYY-MM-DD') : undefined}
|
|
30
|
+
maxDate={max ? dayjs(max).format('YYYY-MM-DD') : undefined}
|
|
31
|
+
onDateChanged={({ date }) => onChange(dayjs(date))}
|
|
32
|
+
itemTextStyle={{ color: colors.text }}
|
|
33
|
+
itemHeight={40}
|
|
34
|
+
overlayItemStyle={{
|
|
35
|
+
backgroundColor: 'transparent',
|
|
36
|
+
borderWidth: 1,
|
|
37
|
+
borderLeftWidth: 0,
|
|
38
|
+
borderRightWidth: 0,
|
|
39
|
+
borderColor: colors.divider,
|
|
40
|
+
opacity: 1,
|
|
41
|
+
}}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
|
|
45
|
+
<ClearLink hide={!allowClear} value={value} onChange={onChange} />
|
|
46
|
+
</View>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { View } from '../../structure'
|
|
2
|
+
import { DayWheelPicker } from './DayWheelPicker'
|
|
3
|
+
|
|
4
|
+
let DatePickerDate
|
|
5
|
+
try {
|
|
6
|
+
DatePickerDate = require('@quidone/react-native-wheel-picker').DatePicker.Date
|
|
7
|
+
} catch {
|
|
8
|
+
DatePickerDate = null
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const renderHiddenDate = () => (
|
|
12
|
+
<View width={0} hiddenOverflow pointerEvents="none">
|
|
13
|
+
{DatePickerDate ? <DatePickerDate /> : null}
|
|
14
|
+
</View>
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
export function MonthWheelPicker({ value, ...props }) {
|
|
18
|
+
return <DayWheelPicker {...props} value={value?.startOf?.('month') ?? value} renderDate={renderHiddenDate} />
|
|
19
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import dayjs from 'dayjs'
|
|
3
|
+
|
|
4
|
+
import { ClearLink } from '../../actions/ClearLink'
|
|
5
|
+
import { View } from '../../structure'
|
|
6
|
+
import { WheelPicker } from '../WheelPicker'
|
|
7
|
+
|
|
8
|
+
const QUARTERS = [
|
|
9
|
+
{ value: 1, label: 'Q1' },
|
|
10
|
+
{ value: 2, label: 'Q2' },
|
|
11
|
+
{ value: 3, label: 'Q3' },
|
|
12
|
+
{ value: 4, label: 'Q4' },
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
function getYearOptions(min, max) {
|
|
16
|
+
const minYear = min ? dayjs(min).year() : dayjs().year() - 100
|
|
17
|
+
const maxYear = max ? dayjs(max).year() : dayjs().year() + 100
|
|
18
|
+
const options = []
|
|
19
|
+
for (let y = minYear; y <= maxYear; y++) options.push({ value: y, label: String(y) })
|
|
20
|
+
return options
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function QuarterWheelPicker({ value, onChange, min, max, allowClear }) {
|
|
24
|
+
const current = value ? dayjs(value) : dayjs()
|
|
25
|
+
const quarter = Math.floor(current.month() / 3) + 1
|
|
26
|
+
const year = current.year()
|
|
27
|
+
|
|
28
|
+
const yearOptions = useMemo(() => getYearOptions(min, max), [min, max])
|
|
29
|
+
|
|
30
|
+
const handleQuarterChange = (q) => {
|
|
31
|
+
onChange?.(
|
|
32
|
+
dayjs()
|
|
33
|
+
.year(year)
|
|
34
|
+
.month((q - 1) * 3)
|
|
35
|
+
.startOf('month')
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const handleYearChange = (y) => {
|
|
40
|
+
onChange?.(
|
|
41
|
+
dayjs()
|
|
42
|
+
.year(y)
|
|
43
|
+
.month((quarter - 1) * 3)
|
|
44
|
+
.startOf('month')
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<View>
|
|
50
|
+
<View row>
|
|
51
|
+
<View flex>
|
|
52
|
+
<WheelPicker options={QUARTERS} value={quarter} onChange={handleQuarterChange} />
|
|
53
|
+
</View>
|
|
54
|
+
<View flex>
|
|
55
|
+
<WheelPicker options={yearOptions} value={year} onChange={handleYearChange} />
|
|
56
|
+
</View>
|
|
57
|
+
</View>
|
|
58
|
+
<ClearLink hide={!allowClear} value={value} onChange={onChange} />
|
|
59
|
+
</View>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { useMemo } from 'react'
|
|
2
|
+
import dayjs from 'dayjs'
|
|
3
|
+
import weekOfYear from 'dayjs/esm/plugin/weekOfYear'
|
|
4
|
+
|
|
5
|
+
import { ClearLink } from '../../actions/ClearLink'
|
|
6
|
+
import { View } from '../../structure'
|
|
7
|
+
import { WheelPicker } from '../WheelPicker'
|
|
8
|
+
|
|
9
|
+
dayjs.extend(weekOfYear)
|
|
10
|
+
|
|
11
|
+
function getWeekOptions(year) {
|
|
12
|
+
const options = []
|
|
13
|
+
let d = dayjs().year(year).startOf('year').startOf('week')
|
|
14
|
+
|
|
15
|
+
while (d.year() <= year) {
|
|
16
|
+
const weekStart = d
|
|
17
|
+
const weekEnd = d.endOf('week')
|
|
18
|
+
const label = `W${d.week()} ${weekStart.format('MMM D')} - ${weekEnd.format('MMM D')}`
|
|
19
|
+
options.push({ value: d.week(), label, date: weekStart })
|
|
20
|
+
d = d.add(1, 'week')
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return options
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getYearOptions(min, max) {
|
|
27
|
+
const minYear = min ? dayjs(min).year() : dayjs().year() - 100
|
|
28
|
+
const maxYear = max ? dayjs(max).year() : dayjs().year() + 100
|
|
29
|
+
const options = []
|
|
30
|
+
for (let y = minYear; y <= maxYear; y++) options.push({ value: y, label: String(y) })
|
|
31
|
+
return options
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function WeekWheelPicker({ value, onChange, min, max, allowClear }) {
|
|
35
|
+
const current = value ? dayjs(value) : dayjs()
|
|
36
|
+
const week = current.week()
|
|
37
|
+
const year = current.year()
|
|
38
|
+
|
|
39
|
+
const weekOptions = useMemo(() => getWeekOptions(year), [year])
|
|
40
|
+
const yearOptions = useMemo(() => getYearOptions(min, max), [min, max])
|
|
41
|
+
|
|
42
|
+
const handleWeekChange = (w) => {
|
|
43
|
+
const opt = weekOptions.find((o) => o.value === w)
|
|
44
|
+
if (opt) onChange?.(opt.date.startOf('week'))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const handleYearChange = (y) => {
|
|
48
|
+
const newWeeks = getWeekOptions(y)
|
|
49
|
+
const closest = newWeeks.find((o) => o.value === week) || newWeeks[0]
|
|
50
|
+
onChange?.(closest.date.startOf('week'))
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<View>
|
|
55
|
+
<View row>
|
|
56
|
+
<View flex>
|
|
57
|
+
<WheelPicker options={weekOptions} value={week} onChange={handleWeekChange} />
|
|
58
|
+
</View>
|
|
59
|
+
<View width={120}>
|
|
60
|
+
<WheelPicker options={yearOptions} value={year} onChange={handleYearChange} />
|
|
61
|
+
</View>
|
|
62
|
+
</View>
|
|
63
|
+
<ClearLink hide={!allowClear} value={value} onChange={onChange} />
|
|
64
|
+
</View>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { View } from '../../structure'
|
|
2
|
+
import { DayWheelPicker } from './DayWheelPicker'
|
|
3
|
+
|
|
4
|
+
let DatePickerDate, DatePickerMonth
|
|
5
|
+
try {
|
|
6
|
+
const dp = require('@quidone/react-native-wheel-picker').DatePicker
|
|
7
|
+
DatePickerDate = dp.Date
|
|
8
|
+
DatePickerMonth = dp.Month
|
|
9
|
+
} catch {
|
|
10
|
+
DatePickerDate = null
|
|
11
|
+
DatePickerMonth = null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const renderHiddenDate = () => (
|
|
15
|
+
<View width={0} hiddenOverflow pointerEvents="none">
|
|
16
|
+
{DatePickerDate ? <DatePickerDate /> : null}
|
|
17
|
+
</View>
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
const renderHiddenMonth = () => (
|
|
21
|
+
<View width={0} hiddenOverflow pointerEvents="none">
|
|
22
|
+
{DatePickerMonth ? <DatePickerMonth /> : null}
|
|
23
|
+
</View>
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
export function YearWheelPicker({ value, ...props }) {
|
|
27
|
+
return (
|
|
28
|
+
<DayWheelPicker
|
|
29
|
+
{...props}
|
|
30
|
+
value={value?.startOf?.('year') ?? value}
|
|
31
|
+
renderDate={renderHiddenDate}
|
|
32
|
+
renderMonth={renderHiddenMonth}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
}
|
|
@@ -21,3 +21,7 @@ export * from './SegmentedPicker'
|
|
|
21
21
|
export * from './Editable'
|
|
22
22
|
export * from './upload/Upload'
|
|
23
23
|
export * from './UploadInput'
|
|
24
|
+
export * from './WheelPicker'
|
|
25
|
+
export * from './dateWheelPicker/DateWheelPicker'
|
|
26
|
+
export * from './NumberWheelInput'
|
|
27
|
+
export * from './NumberWheelPicker'
|