@neko-os/ui 0.0.6 → 0.0.8
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 +1 -1
- package/dist/abstractions/AnimatedView.js +1 -1
- package/dist/abstractions/BlurView.js +1 -0
- package/dist/abstractions/BlurView.native.js +1 -0
- package/dist/abstractions/GradientView.js +1 -0
- package/dist/abstractions/GradientView.native.js +1 -0
- package/dist/abstractions/Icon.native.js +1 -1
- package/dist/abstractions/ImageBackground.js +1 -0
- package/dist/abstractions/ImageBackground.native.js +1 -0
- package/dist/abstractions/ImageBackground.web.js +1 -0
- package/dist/abstractions/Pressable.js +1 -0
- package/dist/abstractions/Pressable.native.js +1 -0
- package/dist/abstractions/Pressable.web.js +1 -0
- package/dist/abstractions/ScrollView.js +1 -0
- package/dist/abstractions/ScrollView.native.js +1 -0
- package/dist/abstractions/TextInput.js +1 -1
- package/dist/components/actions/Button.js +1 -1
- package/dist/components/actions/Dropdown.js +1 -1
- package/dist/components/actions/Link.js +1 -1
- package/dist/components/actions/Pressable.js +1 -0
- package/dist/components/actions/index.js +1 -1
- package/dist/components/actions/menu/HorizontalMenu.js +1 -1
- package/dist/components/actions/menu/VerticalMenu.js +1 -1
- package/dist/components/animations/ReanimatedView.js +1 -0
- package/dist/components/calendar/CalendarNav.js +1 -0
- package/dist/components/calendar/WeekDaysBar.js +1 -0
- package/dist/components/calendar/_helpers/calendarDays.js +1 -1
- package/dist/components/calendar/_helpers/dateDisabled.js +1 -0
- package/dist/components/calendar/index.js +0 -1
- package/dist/components/feedback/alerter.js +1 -0
- package/dist/components/feedback/confirmer.js +1 -0
- package/dist/components/feedback/index.js +1 -1
- package/dist/components/feedback/notifications/Notification.js +1 -1
- package/dist/components/feedback/notifications/NotificationsHandler.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/inputs/DateInput.js +1 -0
- package/dist/components/inputs/InputWrapper.js +1 -1
- package/dist/components/inputs/LinkInput.js +1 -0
- package/dist/components/inputs/MaskInput.js +1 -0
- package/dist/components/inputs/TextInput.js +1 -1
- package/dist/components/inputs/_DateInput.native.js +1 -0
- package/dist/components/inputs/datePicker/DatePicker.js +1 -0
- package/dist/components/inputs/datePicker/DayPicker.js +1 -0
- package/dist/components/inputs/datePicker/MonthPicker.js +1 -0
- package/dist/components/inputs/datePicker/QuarterPicker.js +1 -0
- package/dist/components/inputs/datePicker/WeekPicker.js +1 -0
- package/dist/components/inputs/datePicker/YearPicker.js +1 -0
- package/dist/components/inputs/index.js +1 -1
- package/dist/components/list/ScrollView.js +1 -0
- package/dist/components/list/index.js +1 -0
- package/dist/components/presentation/ImageBackground.js +1 -0
- package/dist/components/presentation/Result.js +1 -1
- package/dist/components/presentation/index.js +1 -1
- package/dist/components/structure/Accordion.js +1 -1
- package/dist/components/structure/BlurView.js +1 -0
- package/dist/components/structure/GradientView.js +1 -0
- package/dist/components/structure/bottomDrawer/index.js +1 -0
- package/dist/components/structure/bottomDrawer/index.native.js +1 -0
- package/dist/components/structure/bottomDrawer/index.web.js +1 -0
- package/dist/components/structure/bottomDrawer/native/BottomDrawer.js +1 -0
- package/dist/components/structure/bottomDrawer/native/DrawerContext.js +1 -0
- package/dist/components/structure/bottomDrawer/native/DrawerHandle.js +1 -0
- package/dist/components/structure/bottomDrawer/native/DrawerScrollView.js +1 -0
- package/dist/components/structure/bottomDrawer/native/utils.js +1 -0
- package/dist/components/structure/bottomDrawer/web/BottomDrawer.js +1 -0
- package/dist/components/structure/drawer/Drawer.js +1 -0
- package/dist/components/structure/drawer/Drawer.native.js +1 -0
- package/dist/components/structure/drawer/index.js +1 -0
- package/dist/components/structure/index.js +1 -1
- package/dist/components/structure/modal/Modal.js +1 -0
- package/dist/components/structure/modal/Modal.native.js +1 -0
- package/dist/components/structure/modal/ModalBackdrop.js +1 -0
- package/dist/components/structure/modal/ModalContent.js +1 -0
- package/dist/components/structure/modal/ModalFooter.js +1 -0
- package/dist/components/structure/modal/ModalHeader.js +1 -0
- package/dist/components/structure/modal/handler/ModalsHandler.js +1 -0
- package/dist/components/structure/modal/index.js +1 -0
- package/dist/components/structure/overlay/OverlayWrapper.js +1 -1
- package/dist/components/structure/popover/Popover.js +1 -1
- package/dist/components/structure/popover/Popover.native.js +1 -1
- package/dist/modifiers/animations/animatedEffects.js +1 -1
- package/dist/modifiers/animations/animatedEffects.native.js +1 -1
- package/dist/modifiers/animations/fadeEffect.js +1 -1
- package/dist/modifiers/animations/scaleEffect.js +1 -0
- package/dist/modifiers/animations/scaleEffect.native.js +1 -0
- package/dist/modifiers/animations/slideEffect.js +1 -1
- package/dist/modifiers/background.js +1 -1
- package/dist/modifiers/cursor.js +1 -0
- package/dist/modifiers/display.js +1 -1
- package/dist/modifiers/hover.js +1 -0
- package/dist/modifiers/position.js +1 -1
- package/dist/modifiers/size.js +1 -1
- package/dist/modifiers/state.js +1 -1
- package/dist/responsive/responsiveHooks.js +1 -1
- package/dist/theme/default/blackTheme.js +1 -0
- package/dist/theme/default/cyberpunkTheme.js +1 -1
- package/dist/theme/default/darkTheme.js +1 -1
- package/dist/theme/default/deepWoodsTheme.js +1 -1
- package/dist/theme/default/forestTheme.js +1 -1
- package/dist/theme/default/hackerTheme.js +1 -1
- package/dist/theme/default/lightTheme.js +1 -1
- package/dist/theme/default/midnightTheme.js +1 -1
- package/dist/theme/default/msdosTheme.js +1 -1
- package/dist/theme/default/oceanTheme.js +1 -1
- package/dist/theme/default/pastelTheme.js +1 -1
- package/dist/theme/default/sunsetTheme.js +1 -1
- package/dist/theme/default/themes.js +1 -1
- package/package.json +11 -5
- package/src/NekoUI.js +6 -3
- package/src/abstractions/AnimatedView.js +3 -3
- package/src/abstractions/BlurView.js +43 -0
- package/src/abstractions/BlurView.native.js +39 -0
- package/src/abstractions/GradientView.js +5 -0
- package/src/abstractions/GradientView.native.js +32 -0
- package/src/abstractions/Icon.native.js +4 -2
- package/src/abstractions/ImageBackground.js +17 -0
- package/src/abstractions/ImageBackground.native.js +27 -0
- package/src/abstractions/ImageBackground.web.js +7 -0
- package/src/abstractions/Pressable.js +4 -0
- package/src/abstractions/Pressable.native.js +3 -0
- package/src/abstractions/Pressable.web.js +3 -0
- package/src/abstractions/ScrollView.js +3 -0
- package/src/abstractions/ScrollView.native.js +5 -0
- package/src/abstractions/TextInput.js +2 -2
- package/src/components/actions/Button.js +7 -0
- package/src/components/actions/Dropdown.js +2 -1
- package/src/components/actions/Link.js +16 -2
- package/src/components/actions/Pressable.js +38 -0
- package/src/components/actions/index.js +1 -0
- package/src/components/actions/menu/HorizontalMenu.js +2 -1
- package/src/components/actions/menu/VerticalMenu.js +4 -3
- package/src/components/animations/ReanimatedView.js +40 -0
- package/src/components/calendar/CalendarNav.js +67 -0
- package/src/components/calendar/WeekDaysBar.js +18 -0
- package/src/components/calendar/_helpers/calendarDays.js +1 -3
- package/src/components/calendar/_helpers/dateDisabled.js +24 -0
- package/src/components/calendar/index.js +1 -1
- package/src/components/feedback/alerter.js +31 -0
- package/src/components/feedback/confirmer.js +70 -0
- package/src/components/feedback/index.js +2 -0
- package/src/components/feedback/notifications/Notification.js +1 -1
- package/src/components/feedback/notifications/NotificationsHandler.js +3 -3
- package/src/components/index.js +1 -0
- package/src/components/inputs/DateInput.js +111 -0
- package/src/components/inputs/InputWrapper.js +18 -6
- package/src/components/inputs/LinkInput.js +17 -0
- package/src/components/inputs/MaskInput.js +67 -0
- package/src/components/inputs/TextInput.js +2 -2
- package/src/components/inputs/_DateInput.native.js +89 -0
- package/src/components/inputs/datePicker/DatePicker.js +24 -0
- package/src/components/inputs/datePicker/DayPicker.js +65 -0
- package/src/components/inputs/datePicker/MonthPicker.js +62 -0
- package/src/components/inputs/datePicker/QuarterPicker.js +65 -0
- package/src/components/inputs/datePicker/WeekPicker.js +74 -0
- package/src/components/inputs/datePicker/YearPicker.js +67 -0
- package/src/components/inputs/index.js +4 -0
- package/src/components/list/ScrollView.js +58 -0
- package/src/components/list/index.js +1 -0
- package/src/components/presentation/ImageBackground.js +38 -0
- package/src/components/presentation/Result.js +2 -2
- package/src/components/presentation/index.js +1 -0
- package/src/components/structure/Accordion.js +1 -1
- package/src/components/structure/BlurView.js +58 -0
- package/src/components/structure/GradientView.js +42 -0
- package/src/components/structure/bottomDrawer/index.js +1 -0
- package/src/components/structure/bottomDrawer/index.native.js +4 -0
- package/src/components/structure/bottomDrawer/index.web.js +4 -0
- package/src/components/structure/bottomDrawer/native/BottomDrawer.js +229 -0
- package/src/components/structure/bottomDrawer/native/DrawerContext.js +21 -0
- package/src/components/structure/bottomDrawer/native/DrawerHandle.js +12 -0
- package/src/components/structure/bottomDrawer/native/DrawerScrollView.js +83 -0
- package/src/components/structure/bottomDrawer/native/utils.js +58 -0
- package/src/components/structure/bottomDrawer/web/BottomDrawer.js +3 -0
- package/src/components/structure/drawer/Drawer.js +5 -0
- package/src/components/structure/drawer/Drawer.native.js +3 -0
- package/src/components/structure/drawer/index.js +1 -0
- package/src/components/structure/index.js +5 -0
- package/src/components/structure/modal/Modal.js +84 -0
- package/src/components/structure/modal/Modal.native.js +83 -0
- package/src/components/structure/modal/ModalBackdrop.js +58 -0
- package/src/components/structure/modal/ModalContent.js +28 -0
- package/src/components/structure/modal/ModalFooter.js +31 -0
- package/src/components/structure/modal/ModalHeader.js +50 -0
- package/src/components/structure/modal/handler/ModalsHandler.js +61 -0
- package/src/components/structure/modal/index.js +6 -0
- package/src/components/structure/overlay/OverlayWrapper.js +1 -1
- package/src/components/structure/popover/Popover.js +28 -2
- package/src/components/structure/popover/Popover.native.js +44 -15
- package/src/modifiers/animations/animatedEffects.js +2 -0
- package/src/modifiers/animations/animatedEffects.native.js +3 -1
- package/src/modifiers/animations/fadeEffect.js +4 -2
- package/src/modifiers/animations/scaleEffect.js +45 -0
- package/src/modifiers/animations/scaleEffect.native.js +33 -0
- package/src/modifiers/animations/slideEffect.js +3 -1
- package/src/modifiers/background.js +16 -4
- package/src/modifiers/cursor.js +21 -0
- package/src/modifiers/display.js +2 -2
- package/src/modifiers/hover.js +28 -0
- package/src/modifiers/position.js +24 -3
- package/src/modifiers/size.js +2 -1
- package/src/modifiers/state.js +1 -1
- package/src/responsive/responsiveHooks.js +7 -0
- package/src/theme/default/blackTheme.js +32 -0
- package/src/theme/default/cyberpunkTheme.js +1 -0
- package/src/theme/default/darkTheme.js +1 -0
- package/src/theme/default/deepWoodsTheme.js +1 -0
- package/src/theme/default/forestTheme.js +1 -0
- package/src/theme/default/hackerTheme.js +1 -0
- package/src/theme/default/lightTheme.js +1 -0
- package/src/theme/default/midnightTheme.js +1 -0
- package/src/theme/default/msdosTheme.js +1 -0
- package/src/theme/default/oceanTheme.js +1 -0
- package/src/theme/default/pastelTheme.js +2 -1
- package/src/theme/default/sunsetTheme.js +2 -1
- package/src/theme/default/themes.js +2 -0
- package/dist/components/calendar/DayPicker.js +0 -1
- package/src/components/calendar/DayPicker.js +0 -91
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export function normalizeSnapPoints(snapPoints, screenHeight) {
|
|
2
|
+
return snapPoints.map((point) => {
|
|
3
|
+
if (typeof point === 'string' && point.endsWith('%')) {
|
|
4
|
+
const percentage = parseFloat(point) / 100;
|
|
5
|
+
return screenHeight * percentage;
|
|
6
|
+
}
|
|
7
|
+
return point;
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function findClosestSnapPoint(currentPosition, snapPoints, velocity = 0) {
|
|
12
|
+
'worklet';
|
|
13
|
+
// Reduced velocity impact for more stable snapping
|
|
14
|
+
const velocityImpact = velocity * 0.03;
|
|
15
|
+
const adjustedPosition = currentPosition + velocityImpact;
|
|
16
|
+
|
|
17
|
+
let closestIndex = 0;
|
|
18
|
+
let minDistance = Math.abs(snapPoints[0] - adjustedPosition);
|
|
19
|
+
|
|
20
|
+
for (let i = 1; i < snapPoints.length; i++) {
|
|
21
|
+
const distance = Math.abs(snapPoints[i] - adjustedPosition);
|
|
22
|
+
if (distance < minDistance) {
|
|
23
|
+
minDistance = distance;
|
|
24
|
+
closestIndex = i;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Increased velocity thresholds for more resistance
|
|
29
|
+
// Only change snap points with strong swipe gestures
|
|
30
|
+
|
|
31
|
+
// Bias towards opening more when swiping up very fast
|
|
32
|
+
if (velocity < -1500 && closestIndex < snapPoints.length - 1) {
|
|
33
|
+
closestIndex++;
|
|
34
|
+
}
|
|
35
|
+
// Bias towards closing when swiping down very fast
|
|
36
|
+
else if (velocity > 1500 && closestIndex > 0) {
|
|
37
|
+
closestIndex--;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Add hysteresis: prefer staying at current position unless moved significantly
|
|
41
|
+
// This prevents accidental snap point changes
|
|
42
|
+
if (snapPoints.length > 1) {
|
|
43
|
+
const currentSnapDistance = minDistance;
|
|
44
|
+
// Require at least 20% of the distance between snap points to change
|
|
45
|
+
const snapPointSpacing = Math.abs(snapPoints[Math.min(closestIndex + 1, snapPoints.length - 1)] - snapPoints[closestIndex]);
|
|
46
|
+
if (currentSnapDistance < snapPointSpacing * 0.2) {
|
|
47
|
+
// Stay at current snap point unless moved significantly
|
|
48
|
+
return closestIndex;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return closestIndex;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function clamp(value, min, max) {
|
|
56
|
+
'worklet';
|
|
57
|
+
return Math.min(Math.max(value, min), max);
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Drawer'
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
export * from './Accordion'
|
|
2
2
|
export * from './AccordionGroup'
|
|
3
3
|
export * from './View'
|
|
4
|
+
export * from './GradientView'
|
|
5
|
+
export * from './BlurView'
|
|
4
6
|
export * from './SafeAreaView'
|
|
5
7
|
export * from './Card'
|
|
6
8
|
export * from './Row'
|
|
7
9
|
export * from './Col'
|
|
10
|
+
export * from './modal'
|
|
11
|
+
export * from './drawer'
|
|
12
|
+
export * from './bottomDrawer'
|
|
8
13
|
export * from './popover/Popover'
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { pipe } from 'ramda'
|
|
2
|
+
|
|
3
|
+
import { AnimatedView } from '../../animations/AnimatedView'
|
|
4
|
+
import { ModalBackdrop } from './ModalBackdrop'
|
|
5
|
+
import { ModalContent } from './ModalContent'
|
|
6
|
+
import { ModalFooter } from './ModalFooter'
|
|
7
|
+
import { ModalHeader } from './ModalHeader'
|
|
8
|
+
import { Portal } from '../../helpers/Portal'
|
|
9
|
+
import { useDefaultModifier } from '../../../modifiers/default'
|
|
10
|
+
import { useThemeComponentModifier } from '../../../modifiers/themeComponent'
|
|
11
|
+
|
|
12
|
+
const DEFAULT_PROPS = ([{}, { position }]) => {
|
|
13
|
+
let radiusKey = 'br'
|
|
14
|
+
let height = undefined
|
|
15
|
+
if (position === 'bottom') {
|
|
16
|
+
radiusKey = 'borderRadiusT'
|
|
17
|
+
height = '95%'
|
|
18
|
+
} else if (position === 'top') {
|
|
19
|
+
radiusKey = 'borderRadiusB'
|
|
20
|
+
height = '95%'
|
|
21
|
+
} else if (position === 'right') {
|
|
22
|
+
radiusKey = 'borderRadiusL'
|
|
23
|
+
height = '100%'
|
|
24
|
+
} else if (position === 'left') {
|
|
25
|
+
radiusKey = 'borderRadiusR'
|
|
26
|
+
height = '100%'
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
maxWidth: '100%',
|
|
31
|
+
maxHeight: !position && '95%',
|
|
32
|
+
height,
|
|
33
|
+
scale: !position,
|
|
34
|
+
fade: !!position,
|
|
35
|
+
slide: position && { from: position },
|
|
36
|
+
[radiusKey]: 'xl',
|
|
37
|
+
bg: 'overlayBG',
|
|
38
|
+
overflow: 'hidden',
|
|
39
|
+
shadow: true,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function Modal({
|
|
44
|
+
open,
|
|
45
|
+
onClose,
|
|
46
|
+
title,
|
|
47
|
+
width = 500,
|
|
48
|
+
children,
|
|
49
|
+
header,
|
|
50
|
+
footer,
|
|
51
|
+
noLayout,
|
|
52
|
+
disableOutsideClick,
|
|
53
|
+
...rootProps
|
|
54
|
+
}) {
|
|
55
|
+
const [{}, formattedProps] = pipe(
|
|
56
|
+
useThemeComponentModifier('Modal'),
|
|
57
|
+
useDefaultModifier(DEFAULT_PROPS)
|
|
58
|
+
)([{}, rootProps])
|
|
59
|
+
|
|
60
|
+
const { contentProps, headerProps, footerProps, position, ...props } = formattedProps
|
|
61
|
+
|
|
62
|
+
let content = children
|
|
63
|
+
if (!noLayout) {
|
|
64
|
+
content = (
|
|
65
|
+
<>
|
|
66
|
+
<ModalHeader title={title} onClose={onClose} {...headerProps}>
|
|
67
|
+
{header}
|
|
68
|
+
</ModalHeader>
|
|
69
|
+
<ModalContent {...contentProps}>{children}</ModalContent>
|
|
70
|
+
<ModalFooter {...footerProps}>{footer}</ModalFooter>
|
|
71
|
+
</>
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<Portal>
|
|
77
|
+
<ModalBackdrop open={open} onClose={!disableOutsideClick && onClose} position={position}>
|
|
78
|
+
<AnimatedView className="neko-modal" open={open} width={width} {...props} onPress={(e) => e.stopPropagation()}>
|
|
79
|
+
{content}
|
|
80
|
+
</AnimatedView>
|
|
81
|
+
</ModalBackdrop>
|
|
82
|
+
</Portal>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Modal as RNModal, ScrollView } from 'react-native'
|
|
2
|
+
import { pipe } from 'ramda'
|
|
3
|
+
|
|
4
|
+
import { ModalBackdrop } from './ModalBackdrop'
|
|
5
|
+
import { ModalContent } from './ModalContent'
|
|
6
|
+
import { ModalFooter } from './ModalFooter'
|
|
7
|
+
import { ModalHeader } from './ModalHeader'
|
|
8
|
+
import { Pressable } from '../../actions/Pressable'
|
|
9
|
+
import { View } from '../View'
|
|
10
|
+
import { useDefaultModifier } from '../../../modifiers/default'
|
|
11
|
+
import { useThemeComponentModifier } from '../../../modifiers/themeComponent'
|
|
12
|
+
|
|
13
|
+
const DEFAULT_PROPS = {
|
|
14
|
+
maxWidth: '90%',
|
|
15
|
+
maxHeight: '90%',
|
|
16
|
+
scale: true,
|
|
17
|
+
br: 'xl',
|
|
18
|
+
bg: 'overlayBG',
|
|
19
|
+
overflow: 'hidden',
|
|
20
|
+
shadow: true,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function Modal({
|
|
24
|
+
open,
|
|
25
|
+
onClose,
|
|
26
|
+
title,
|
|
27
|
+
width = 500,
|
|
28
|
+
children,
|
|
29
|
+
header,
|
|
30
|
+
footer,
|
|
31
|
+
noLayout,
|
|
32
|
+
disableOutsideClick,
|
|
33
|
+
...rootProps
|
|
34
|
+
}) {
|
|
35
|
+
const [{}, formattedProps] = pipe(
|
|
36
|
+
useThemeComponentModifier('Modal'),
|
|
37
|
+
useDefaultModifier(DEFAULT_PROPS)
|
|
38
|
+
)([{}, rootProps])
|
|
39
|
+
|
|
40
|
+
const { contentProps, headerProps, footerProps, ...props } = formattedProps
|
|
41
|
+
|
|
42
|
+
let content = children
|
|
43
|
+
if (!noLayout) {
|
|
44
|
+
content = (
|
|
45
|
+
<>
|
|
46
|
+
<ModalHeader title={title} onClose={onClose} {...headerProps}>
|
|
47
|
+
{header}
|
|
48
|
+
</ModalHeader>
|
|
49
|
+
<ScrollView>
|
|
50
|
+
<ModalContent {...contentProps}>{children}</ModalContent>
|
|
51
|
+
</ScrollView>
|
|
52
|
+
<ModalFooter {...footerProps}>{footer}</ModalFooter>
|
|
53
|
+
</>
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<RNModal
|
|
59
|
+
animationType="fade"
|
|
60
|
+
transparent
|
|
61
|
+
visible={open}
|
|
62
|
+
onRequestClose={onClose}
|
|
63
|
+
allowSwipeDismissal
|
|
64
|
+
navigationBarTranslucent
|
|
65
|
+
statusBarTranslucent
|
|
66
|
+
>
|
|
67
|
+
<ModalBackdrop open={open} useSimpleView>
|
|
68
|
+
<Pressable
|
|
69
|
+
onPress={!disableOutsideClick ? onClose : undefined}
|
|
70
|
+
absolute
|
|
71
|
+
top={0}
|
|
72
|
+
left={0}
|
|
73
|
+
right={0}
|
|
74
|
+
bottom={0}
|
|
75
|
+
pointerEvents="box-only"
|
|
76
|
+
/>
|
|
77
|
+
<View width={width} {...props} zIndex={10}>
|
|
78
|
+
{content}
|
|
79
|
+
</View>
|
|
80
|
+
</ModalBackdrop>
|
|
81
|
+
</RNModal>
|
|
82
|
+
)
|
|
83
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { pipe } from 'ramda'
|
|
2
|
+
import React from 'react'
|
|
3
|
+
|
|
4
|
+
import { AnimatedView } from '../../animations/AnimatedView'
|
|
5
|
+
import { SafeAreaView } from '../SafeAreaView'
|
|
6
|
+
import { useDefaultModifier } from '../../../modifiers/default'
|
|
7
|
+
import { useThemeComponentModifier } from '../../../modifiers/themeComponent'
|
|
8
|
+
|
|
9
|
+
const DEFAULT_PROPS = ([{}, { position }]) => {
|
|
10
|
+
let justify = 'center'
|
|
11
|
+
let align = 'center'
|
|
12
|
+
if (position === 'bottom') {
|
|
13
|
+
justify = 'flex-end'
|
|
14
|
+
} else if (position === 'top') {
|
|
15
|
+
justify = 'flex-top'
|
|
16
|
+
} else if (position === 'left') {
|
|
17
|
+
align = 'flex-start'
|
|
18
|
+
} else if (position === 'right') {
|
|
19
|
+
align = 'flex-end'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
fixed: true,
|
|
24
|
+
top: 0,
|
|
25
|
+
left: 0,
|
|
26
|
+
right: 0,
|
|
27
|
+
bottom: 0,
|
|
28
|
+
justify,
|
|
29
|
+
align,
|
|
30
|
+
lazy: true,
|
|
31
|
+
unmountOnClose: true,
|
|
32
|
+
fade: true,
|
|
33
|
+
zIndex: 500,
|
|
34
|
+
bg: 'backdrop_op70',
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function ModalBackdrop({ open, onClose, children, useSimpleView, ...rootProps }) {
|
|
39
|
+
const modalRef = React.useRef()
|
|
40
|
+
const [{}, props] = pipe(
|
|
41
|
+
useThemeComponentModifier('ModalBackdrop'),
|
|
42
|
+
useDefaultModifier(DEFAULT_PROPS)
|
|
43
|
+
)([{}, rootProps])
|
|
44
|
+
|
|
45
|
+
if (useSimpleView) {
|
|
46
|
+
return (
|
|
47
|
+
<SafeAreaView className="neko-modal-backdrop" {...props}>
|
|
48
|
+
{children}
|
|
49
|
+
</SafeAreaView>
|
|
50
|
+
)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return (
|
|
54
|
+
<AnimatedView open={open} className="neko-modal-backdrop" onPress={onClose} {...props}>
|
|
55
|
+
{children}
|
|
56
|
+
</AnimatedView>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { pipe } from 'ramda'
|
|
2
|
+
|
|
3
|
+
import { View } from '../View'
|
|
4
|
+
import { useDefaultModifier } from '../../../modifiers/default'
|
|
5
|
+
import { useThemeComponentModifier } from '../../../modifiers/themeComponent'
|
|
6
|
+
|
|
7
|
+
const DEFAULT_PROPS = {
|
|
8
|
+
fullW: true,
|
|
9
|
+
flex: true,
|
|
10
|
+
// fullH: true,
|
|
11
|
+
scrollY: true,
|
|
12
|
+
padding: 'md',
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function ModalContent({ children, ...rootProps }) {
|
|
16
|
+
const [{}, props] = pipe(
|
|
17
|
+
useThemeComponentModifier('ModalContent'), //
|
|
18
|
+
useDefaultModifier(DEFAULT_PROPS)
|
|
19
|
+
)([{}, rootProps])
|
|
20
|
+
|
|
21
|
+
if (!children) return false
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<View className="neko-modal-content" {...props}>
|
|
25
|
+
{children}
|
|
26
|
+
</View>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { pipe } from 'ramda'
|
|
2
|
+
|
|
3
|
+
import { View } from '../View'
|
|
4
|
+
import { moveScale } from '../../../theme/helpers/sizeScale'
|
|
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
|
+
borderT: true,
|
|
11
|
+
paddingH: sizeCode,
|
|
12
|
+
paddingV: moveScale(sizeCode, -2),
|
|
13
|
+
minHeight: moveScale(sizeCode, 1),
|
|
14
|
+
centerV: true,
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export function ModalFooter({ children, ...rootProps }) {
|
|
18
|
+
const [{}, props] = pipe(
|
|
19
|
+
useSizeConverter('elementHeights', 'md'),
|
|
20
|
+
useThemeComponentModifier('ModalFooter'), //
|
|
21
|
+
useDefaultModifier(DEFAULT_PROPS)
|
|
22
|
+
)([{}, rootProps])
|
|
23
|
+
|
|
24
|
+
if (!children) return false
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<View className="neko-modal-footer" {...props}>
|
|
28
|
+
{children}
|
|
29
|
+
</View>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { pipe } from 'ramda'
|
|
2
|
+
|
|
3
|
+
import { Icon } from '../../presentation/Icon'
|
|
4
|
+
import { Link } from '../../actions/Link'
|
|
5
|
+
import { Text } from '../../text/Text'
|
|
6
|
+
import { View } from '../View'
|
|
7
|
+
import { moveScale } from '../../../theme/helpers/sizeScale'
|
|
8
|
+
import { useDefaultModifier } from '../../../modifiers/default'
|
|
9
|
+
import { useSizeConverter } from '../../../modifiers/sizeConverter'
|
|
10
|
+
import { useThemeComponentModifier } from '../../../modifiers/themeComponent'
|
|
11
|
+
|
|
12
|
+
const DEFAULT_PROPS = ([{ sizeCode }, _]) => ({
|
|
13
|
+
centerV: true,
|
|
14
|
+
paddingH: sizeCode,
|
|
15
|
+
paddingV: moveScale(sizeCode, -2),
|
|
16
|
+
minHeight: moveScale(sizeCode, 1),
|
|
17
|
+
gap: 'md',
|
|
18
|
+
borderB: true,
|
|
19
|
+
justify: 'space-between',
|
|
20
|
+
|
|
21
|
+
titleProps: {
|
|
22
|
+
strong: true,
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
export function ModalHeader({ onClose, title, children, ...rootProps }) {
|
|
27
|
+
const [{}, formattedProps] = pipe(
|
|
28
|
+
useSizeConverter('elementHeights', 'md'),
|
|
29
|
+
useThemeComponentModifier('ModalHeader'),
|
|
30
|
+
useDefaultModifier(DEFAULT_PROPS)
|
|
31
|
+
)([{}, rootProps])
|
|
32
|
+
|
|
33
|
+
const { titleProps, ...props } = formattedProps
|
|
34
|
+
|
|
35
|
+
if (!title && !children) return false
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<View className="neko-modal-header" {...props} row>
|
|
39
|
+
{title && <Text {...titleProps}>{title}</Text>}
|
|
40
|
+
|
|
41
|
+
{children}
|
|
42
|
+
|
|
43
|
+
{!!onClose && (
|
|
44
|
+
<Link onPress={onClose} padding="sm" marginR={-10}>
|
|
45
|
+
<Icon name="close-line" />
|
|
46
|
+
</Link>
|
|
47
|
+
)}
|
|
48
|
+
</View>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { Modal } from '../Modal'
|
|
4
|
+
import { useResponsiveValue } from '../../../../responsive/responsiveHooks'
|
|
5
|
+
|
|
6
|
+
const ModalsContext = React.createContext(null)
|
|
7
|
+
|
|
8
|
+
export const useModals = () => React.useContext(ModalsContext) || {}
|
|
9
|
+
|
|
10
|
+
let idCounter = 0
|
|
11
|
+
|
|
12
|
+
export function useModalOpener() {
|
|
13
|
+
const { add, remove, close } = useModals()
|
|
14
|
+
const open = (init) => {
|
|
15
|
+
const key = ++idCounter
|
|
16
|
+
|
|
17
|
+
const onClose = () => close(key)
|
|
18
|
+
const params = { onClose, key }
|
|
19
|
+
|
|
20
|
+
const data = init(params)
|
|
21
|
+
|
|
22
|
+
add(key, { onClose, ...data, open: true })
|
|
23
|
+
return params
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
open,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function ModalsHandler({ children }) {
|
|
32
|
+
const width = useResponsiveValue({ sm: '100%', df: 400 })
|
|
33
|
+
const [modals, setModals] = React.useState([])
|
|
34
|
+
|
|
35
|
+
const add = React.useCallback((key, data) => {
|
|
36
|
+
setModals((prev) => [...prev, { key, ...data }])
|
|
37
|
+
}, [])
|
|
38
|
+
|
|
39
|
+
const remove = React.useCallback((key) => {
|
|
40
|
+
setModals((prev) => prev.filter((p) => p.key !== key))
|
|
41
|
+
}, [])
|
|
42
|
+
|
|
43
|
+
const close = React.useCallback((key) => {
|
|
44
|
+
setModals((items) => items.map((i) => (i.key === key ? { ...i, open: false } : i)))
|
|
45
|
+
setTimeout(() => remove(key), 600)
|
|
46
|
+
}, [])
|
|
47
|
+
|
|
48
|
+
const value = React.useMemo(() => ({ add, remove, close }), [add, remove, close])
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<ModalsContext.Provider value={value}>
|
|
52
|
+
{children}
|
|
53
|
+
|
|
54
|
+
{modals?.map?.(({ key, content, ...item }) => (
|
|
55
|
+
<Modal key={key} {...item}>
|
|
56
|
+
{content}
|
|
57
|
+
</Modal>
|
|
58
|
+
))}
|
|
59
|
+
</ModalsContext.Provider>
|
|
60
|
+
)
|
|
61
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
2
|
|
|
3
|
+
import { BottomDrawer } from '../bottomDrawer'
|
|
3
4
|
import { PopoverContent } from './PopoverContent'
|
|
4
5
|
import { useRegisterOverlay } from '../overlay/OverlayHandler'
|
|
6
|
+
import { useResponsiveValue } from '../../../responsive'
|
|
5
7
|
|
|
6
8
|
export function Popover({
|
|
7
9
|
renderContent,
|
|
@@ -12,8 +14,10 @@ export function Popover({
|
|
|
12
14
|
children,
|
|
13
15
|
parentWidth,
|
|
14
16
|
parentMinWidth,
|
|
17
|
+
useBottomDrawer = {},
|
|
15
18
|
...props
|
|
16
19
|
}) {
|
|
20
|
+
const shouldUseDrawer = useResponsiveValue(useBottomDrawer)
|
|
17
21
|
const ref = React.useRef(null)
|
|
18
22
|
const { onOpen, onClose, onFastClose, stopDelayedClosing } = useRegisterOverlay({ unmountOnClose })
|
|
19
23
|
|
|
@@ -53,17 +57,39 @@ export function Popover({
|
|
|
53
57
|
),
|
|
54
58
|
triggerRect,
|
|
55
59
|
placement,
|
|
56
|
-
options: { dismissOnClickOutside:
|
|
60
|
+
options: { dismissOnClickOutside: click || focus },
|
|
57
61
|
})
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
React.useEffect(() => () => onClose(), [])
|
|
61
65
|
|
|
66
|
+
if (shouldUseDrawer) {
|
|
67
|
+
return <DrawerPopover content={content} renderContent={renderContent} children={children} {...props} />
|
|
68
|
+
}
|
|
69
|
+
|
|
62
70
|
const child = React.Children.only(children)
|
|
63
71
|
let childProps = { ref, onClick: show }
|
|
64
72
|
|
|
65
73
|
if (hover) childProps = { ref, onMouseEnter: show, onMouseLeave: onClose }
|
|
66
|
-
if (focus) childProps = { ref, onFocus: show
|
|
74
|
+
if (focus) childProps = { ref, onFocus: show }
|
|
67
75
|
|
|
68
76
|
return React.cloneElement(child, childProps)
|
|
69
77
|
}
|
|
78
|
+
|
|
79
|
+
function DrawerPopover({ children, content, renderContent, snapPoints, ...props }) {
|
|
80
|
+
const [open, setOpen] = React.useState(false)
|
|
81
|
+
const onClose = () => setOpen(false)
|
|
82
|
+
|
|
83
|
+
const child = React.Children.only(children)
|
|
84
|
+
let childProps = { onClick: () => setOpen(true) }
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<>
|
|
88
|
+
{React.cloneElement(child, childProps)}
|
|
89
|
+
|
|
90
|
+
<BottomDrawer open={open} onClose={onClose} snapPoints={snapPoints}>
|
|
91
|
+
{renderContent({ onClose })}
|
|
92
|
+
</BottomDrawer>
|
|
93
|
+
</>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
@@ -1,17 +1,34 @@
|
|
|
1
1
|
import { Modal, TouchableWithoutFeedback } from 'react-native'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
|
|
4
|
+
import { BottomDrawer } from '../bottomDrawer'
|
|
4
5
|
import { PopoverContent } from './PopoverContent'
|
|
5
6
|
import { View } from '../View'
|
|
6
7
|
import { calculatePosition } from '../overlay/calculatePosition'
|
|
8
|
+
import { useResponsiveValue } from '../../../responsive'
|
|
7
9
|
|
|
8
|
-
export function Popover({
|
|
10
|
+
export function Popover({
|
|
11
|
+
content,
|
|
12
|
+
renderContent,
|
|
13
|
+
placement = 'bottom',
|
|
14
|
+
children,
|
|
15
|
+
useBottomDrawer = {},
|
|
16
|
+
snapPoints,
|
|
17
|
+
...props
|
|
18
|
+
}) {
|
|
19
|
+
const shouldUseDrawer = useResponsiveValue(useBottomDrawer)
|
|
9
20
|
const ref = React.useRef(null)
|
|
10
|
-
const [
|
|
21
|
+
const [open, setOpen] = React.useState(false)
|
|
11
22
|
const [triggerRect, setTriggerRect] = React.useState(null)
|
|
12
23
|
const [position, setPosition] = React.useState(null)
|
|
13
24
|
|
|
14
|
-
|
|
25
|
+
renderContent = renderContent || (() => content)
|
|
26
|
+
|
|
27
|
+
const onOpen = () => {
|
|
28
|
+
if (shouldUseDrawer) {
|
|
29
|
+
setOpen(true)
|
|
30
|
+
return
|
|
31
|
+
}
|
|
15
32
|
if (ref.current) {
|
|
16
33
|
ref.current.measureInWindow((x, y, width, height) => {
|
|
17
34
|
setTriggerRect({
|
|
@@ -22,29 +39,41 @@ export function Popover({ content, placement = 'bottom', children, ...props }) {
|
|
|
22
39
|
width,
|
|
23
40
|
height,
|
|
24
41
|
})
|
|
25
|
-
|
|
42
|
+
setOpen(true)
|
|
26
43
|
})
|
|
27
44
|
}
|
|
28
45
|
}
|
|
29
46
|
|
|
30
|
-
const
|
|
31
|
-
|
|
47
|
+
const onClose = () => {
|
|
48
|
+
setOpen(false)
|
|
32
49
|
setTriggerRect(null)
|
|
33
50
|
setPosition(null)
|
|
34
51
|
}
|
|
35
52
|
|
|
36
|
-
|
|
37
|
-
|
|
53
|
+
children = React.cloneElement(React.Children.only(children), {
|
|
54
|
+
onPress: onOpen,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
if (shouldUseDrawer) {
|
|
58
|
+
return (
|
|
38
59
|
<View ref={ref}>
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
}
|
|
60
|
+
{children}
|
|
61
|
+
|
|
62
|
+
<BottomDrawer open={open} onClose={onClose} snapPoints={snapPoints}>
|
|
63
|
+
{renderContent({ onClose: onClose })}
|
|
64
|
+
</BottomDrawer>
|
|
42
65
|
</View>
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<>
|
|
71
|
+
<View ref={ref}>{children}</View>
|
|
43
72
|
|
|
44
|
-
{
|
|
45
|
-
<Modal transparent visible={
|
|
73
|
+
{open && (
|
|
74
|
+
<Modal transparent visible={open} animationType="fade" onRequestClose={onClose}>
|
|
46
75
|
<View fullW flex fullH bg="bg_op50">
|
|
47
|
-
<TouchableWithoutFeedback onPress={
|
|
76
|
+
<TouchableWithoutFeedback onPress={onClose}>
|
|
48
77
|
<View style={{ flex: 1 }}>
|
|
49
78
|
{triggerRect && (
|
|
50
79
|
<View
|
|
@@ -61,7 +90,7 @@ export function Popover({ content, placement = 'bottom', children, ...props }) {
|
|
|
61
90
|
}}
|
|
62
91
|
>
|
|
63
92
|
<PopoverContent placement={placement} {...props}>
|
|
64
|
-
{
|
|
93
|
+
{renderContent({ onClose: onClose })}
|
|
65
94
|
</PopoverContent>
|
|
66
95
|
</View>
|
|
67
96
|
)}
|
|
@@ -3,6 +3,7 @@ import React from 'react'
|
|
|
3
3
|
|
|
4
4
|
import { useApplyStyles } from '../applyStyles'
|
|
5
5
|
import { useFadeEffect } from './fadeEffect'
|
|
6
|
+
import { useScaleEffect } from './scaleEffect'
|
|
6
7
|
import { useSlideEffect } from './slideEffect'
|
|
7
8
|
|
|
8
9
|
export function useAnimatedEffects([values, { open, onClose, lazy = false, unmountOnClose = false, ...props }]) {
|
|
@@ -41,6 +42,7 @@ export function useAnimatedEffects([values, { open, onClose, lazy = false, unmou
|
|
|
41
42
|
return pipe(
|
|
42
43
|
useFadeEffect, //
|
|
43
44
|
useSlideEffect,
|
|
45
|
+
useScaleEffect,
|
|
44
46
|
useApplyStyles({ transition: transitions.join(',') })
|
|
45
47
|
)([
|
|
46
48
|
{
|