@neko-os/ui 0.4.0 → 0.5.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/abstractions/KeyboardDismissView.js +3 -0
- package/dist/abstractions/KeyboardDismissView.native.js +9 -0
- package/dist/abstractions/index.js +1 -0
- package/dist/components/actions/ClearLink.js +6 -0
- package/dist/components/actions/FloatingMenu.js +1 -1
- package/dist/components/calendar/CalendarNav.js +6 -6
- package/dist/components/carousel/Carousel.js +48 -0
- package/dist/components/carousel/CarouselArrows.js +40 -0
- package/dist/components/carousel/CarouselArrows.native.js +40 -0
- package/dist/components/carousel/CarouselDots.js +32 -0
- package/dist/components/carousel/CarouselDots.native.js +36 -0
- package/dist/components/carousel/CarouselHandler.js +86 -0
- package/dist/components/carousel/CarouselSlider.js +124 -0
- package/dist/components/carousel/CarouselSlider.native.js +121 -0
- package/dist/components/carousel/InfiniteCarousel.js +50 -0
- package/dist/components/carousel/index.js +6 -0
- package/dist/components/form/Form.js +5 -3
- package/dist/components/index.js +3 -1
- package/dist/components/inputs/DateInput.js +7 -4
- package/dist/components/inputs/InputWrapper.js +1 -2
- package/dist/components/inputs/Select.js +56 -52
- package/dist/components/inputs/TextInput.js +7 -6
- package/dist/components/inputs/datePicker/DayPicker.js +71 -23
- package/dist/components/inputs/datePicker/MonthPicker.js +61 -32
- package/dist/components/inputs/datePicker/QuarterPicker.js +62 -33
- package/dist/components/inputs/datePicker/WeekPicker.js +65 -24
- package/dist/components/inputs/datePicker/YearPicker.js +69 -40
- package/dist/components/keyboard/KeyboardDismissButton.js +3 -0
- package/dist/components/keyboard/KeyboardDismissButton.native.js +38 -0
- package/dist/components/keyboard/index.js +1 -0
- package/dist/components/modals/bottomDrawer/native/BottomDrawer.js +28 -7
- package/dist/components/presentation/LabelValue.js +1 -1
- package/dist/components/presentation/Result.js +11 -3
- package/dist/components/structure/KeyboardAvoidingView.js +9 -2
- package/dist/components/theme/ThemePicker.js +7 -12
- package/dist/components/theme/ThemeThumb.js +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/ThemeHandler.js +31 -3
- package/package.json +1 -1
- package/src/abstractions/KeyboardDismissView.js +3 -0
- package/src/abstractions/KeyboardDismissView.native.js +9 -0
- package/src/abstractions/index.js +1 -0
- package/src/components/actions/ClearLink.js +6 -0
- package/src/components/actions/FloatingMenu.js +1 -1
- package/src/components/calendar/CalendarNav.js +6 -6
- package/src/components/carousel/Carousel.js +48 -0
- package/src/components/carousel/CarouselArrows.js +40 -0
- package/src/components/carousel/CarouselArrows.native.js +40 -0
- package/src/components/carousel/CarouselDots.js +32 -0
- package/src/components/carousel/CarouselDots.native.js +36 -0
- package/src/components/carousel/CarouselHandler.js +86 -0
- package/src/components/carousel/CarouselSlider.js +124 -0
- package/src/components/carousel/CarouselSlider.native.js +121 -0
- package/src/components/carousel/InfiniteCarousel.js +50 -0
- package/src/components/carousel/index.js +6 -0
- package/src/components/form/Form.js +2 -0
- package/src/components/index.js +2 -0
- package/src/components/inputs/DateInput.js +4 -1
- package/src/components/inputs/InputWrapper.js +1 -2
- package/src/components/inputs/Select.js +19 -15
- package/src/components/inputs/TextInput.js +5 -4
- package/src/components/inputs/datePicker/DayPicker.js +69 -21
- package/src/components/inputs/datePicker/MonthPicker.js +60 -31
- package/src/components/inputs/datePicker/QuarterPicker.js +60 -31
- package/src/components/inputs/datePicker/WeekPicker.js +63 -22
- package/src/components/inputs/datePicker/YearPicker.js +68 -39
- package/src/components/keyboard/KeyboardDismissButton.js +3 -0
- package/src/components/keyboard/KeyboardDismissButton.native.js +38 -0
- package/src/components/keyboard/index.js +1 -0
- package/src/components/modals/bottomDrawer/native/BottomDrawer.js +27 -6
- package/src/components/presentation/LabelValue.js +1 -1
- package/src/components/presentation/Result.js +10 -2
- package/src/components/structure/KeyboardAvoidingView.js +9 -2
- package/src/components/theme/ThemePicker.js +8 -13
- package/src/components/theme/ThemeThumb.js +1 -1
- package/src/index.js +1 -0
- package/src/theme/ThemeHandler.js +31 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
var _jsxFileName = "/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/components/structure/KeyboardAvoidingView.js";var _excluded = ["children", "keyboardVerticalOffset"];function _slicedToArray(r, e) {return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();}function _nonIterableRest() {throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}function _unsupportedIterableToArray(r, a) {if (r) {if ("string" == typeof r) return _arrayLikeToArray(r, a);var t = {}.toString.call(r).slice(8, -1);return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;}}function _arrayLikeToArray(r, a) {(null == a || a > r.length) && (a = r.length);for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];return n;}function _iterableToArrayLimit(r, l) {var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];if (null != t) {var e,n,i,u,a = [],f = !0,o = !1;try {if (i = (t = t.call(r)).next, 0 === l) {if (Object(t) !== t) return;f = !1;} else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);} catch (r) {o = !0, n = r;} finally {try {if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;} finally {if (o) throw n;}}return a;}}function _arrayWithHoles(r) {if (Array.isArray(r)) return r;}function _objectWithoutProperties(e, t) {if (null == e) return {};var o,r,i = _objectWithoutPropertiesLoose(e, t);if (Object.getOwnPropertySymbols) {var n = Object.getOwnPropertySymbols(e);for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);}return i;}function _objectWithoutPropertiesLoose(r, e) {if (null == r) return {};var t = {};for (var n in r) if ({}.hasOwnProperty.call(r, n)) {if (-1 !== e.indexOf(n)) continue;t[n] = r[n];}return t;}import { pipe } from 'ramda';
|
|
1
|
+
var _jsxFileName = "/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/components/structure/KeyboardAvoidingView.js";var _excluded = ["children", "keyboardVerticalOffset", "dismissOnTap"];function _slicedToArray(r, e) {return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();}function _nonIterableRest() {throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}function _unsupportedIterableToArray(r, a) {if (r) {if ("string" == typeof r) return _arrayLikeToArray(r, a);var t = {}.toString.call(r).slice(8, -1);return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;}}function _arrayLikeToArray(r, a) {(null == a || a > r.length) && (a = r.length);for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];return n;}function _iterableToArrayLimit(r, l) {var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];if (null != t) {var e,n,i,u,a = [],f = !0,o = !1;try {if (i = (t = t.call(r)).next, 0 === l) {if (Object(t) !== t) return;f = !1;} else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);} catch (r) {o = !0, n = r;} finally {try {if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;} finally {if (o) throw n;}}return a;}}function _arrayWithHoles(r) {if (Array.isArray(r)) return r;}function _objectWithoutProperties(e, t) {if (null == e) return {};var o,r,i = _objectWithoutPropertiesLoose(e, t);if (Object.getOwnPropertySymbols) {var n = Object.getOwnPropertySymbols(e);for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]);}return i;}function _objectWithoutPropertiesLoose(r, e) {if (null == r) return {};var t = {};for (var n in r) if ({}.hasOwnProperty.call(r, n)) {if (-1 !== e.indexOf(n)) continue;t[n] = r[n];}return t;}import { pipe } from 'ramda';
|
|
2
2
|
|
|
3
3
|
import { AbsKeyboardAvoidingView } from "../../abstractions/KeyboardAvoidingView";
|
|
4
|
+
import { AbsKeyboardDismissView } from "../../abstractions/KeyboardDismissView";
|
|
4
5
|
import { Platform } from "../../abstractions/Platform";
|
|
5
6
|
import { useSafeAreaInsets } from "../../abstractions/helpers/useSafeAreaInsets";
|
|
6
7
|
import { useAnimationModifier } from "../../modifiers/animation";
|
|
@@ -19,7 +20,7 @@ import { useSizeModifier } from "../../modifiers/size";
|
|
|
19
20
|
import { useStateModifier } from "../../modifiers/state";
|
|
20
21
|
import { useThemeComponentModifier } from "../../modifiers/themeComponent";import { jsx as _jsx } from "react/jsx-runtime";
|
|
21
22
|
|
|
22
|
-
export function KeyboardAvoidingView(_ref) {var children = _ref.children,_ref$keyboardVertical = _ref.keyboardVerticalOffset,keyboardVerticalOffset = _ref$keyboardVertical === void 0 ? 0 : _ref$keyboardVertical,rootProps = _objectWithoutProperties(_ref, _excluded);
|
|
23
|
+
export function KeyboardAvoidingView(_ref) {var children = _ref.children,_ref$keyboardVertical = _ref.keyboardVerticalOffset,keyboardVerticalOffset = _ref$keyboardVertical === void 0 ? 0 : _ref$keyboardVertical,_ref$dismissOnTap = _ref.dismissOnTap,dismissOnTap = _ref$dismissOnTap === void 0 ? true : _ref$dismissOnTap,rootProps = _objectWithoutProperties(_ref, _excluded);
|
|
23
24
|
var _useSafeAreaInsets = useSafeAreaInsets(),bottom = _useSafeAreaInsets.bottom;
|
|
24
25
|
|
|
25
26
|
var _pipe = pipe(
|
|
@@ -46,7 +47,13 @@ export function KeyboardAvoidingView(_ref) {var children = _ref.children,_ref$ke
|
|
|
46
47
|
keyboardVerticalOffset: keyboardVerticalOffset + bottom },
|
|
47
48
|
props, { children:
|
|
48
49
|
|
|
50
|
+
dismissOnTap ?
|
|
51
|
+
_jsx(AbsKeyboardDismissView, { style: { flex: 1 }, children:
|
|
52
|
+
children }
|
|
53
|
+
) :
|
|
54
|
+
|
|
49
55
|
children })
|
|
56
|
+
|
|
50
57
|
));
|
|
51
58
|
|
|
52
59
|
}
|
|
@@ -1,25 +1,20 @@
|
|
|
1
|
-
var _jsxFileName = "/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/components/theme/ThemePicker.js";import { mapObjIndexed,
|
|
1
|
+
var _jsxFileName = "/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/components/theme/ThemePicker.js";import { mapObjIndexed, values, pipe, reject, propEq } from 'ramda';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useAllThemes, useThemeHandler } from "../../theme";
|
|
4
4
|
import { IconLabel } from "../presentation";
|
|
5
5
|
import { Link } from "../actions";
|
|
6
6
|
import { Picker } from "../inputs";
|
|
7
7
|
import { ThemeThumb } from "./ThemeThumb";import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
8
|
|
|
9
|
-
export function ThemePicker(_ref) {var _this = this;var _onChange = _ref.onChange
|
|
10
|
-
var _useThemeHandler = useThemeHandler(),activeThemeKey = _useThemeHandler.activeThemeKey,
|
|
9
|
+
export function ThemePicker(_ref) {var _this = this;var _onChange = _ref.onChange;
|
|
10
|
+
var _useThemeHandler = useThemeHandler(),activeThemeKey = _useThemeHandler.activeThemeKey,onChangeTheme = _useThemeHandler.onChangeTheme;
|
|
11
|
+
var allThemes = useAllThemes();
|
|
11
12
|
|
|
12
13
|
var options = pipe(
|
|
13
|
-
mergeDeepRight(DEFAULT_THEMES),
|
|
14
14
|
mapObjIndexed(function (obj, key) {return Object.assign({}, obj, { value: key, key: key });}),
|
|
15
15
|
values,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (onlyKeys && onlyKeys.includes(item.value)) return true;
|
|
19
|
-
if (hideKeys && hideKeys.includes(item.value)) return false;
|
|
20
|
-
return true;
|
|
21
|
-
})
|
|
22
|
-
)(themes);
|
|
16
|
+
reject(propEq('_all', 'value'))
|
|
17
|
+
)(allThemes);
|
|
23
18
|
|
|
24
19
|
return (
|
|
25
20
|
_jsx(Picker, {
|
|
@@ -4,7 +4,7 @@ import { useResponsiveValue } from "../../responsive";
|
|
|
4
4
|
import { useThemeHandler } from "../../theme";import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
5
5
|
|
|
6
6
|
export function ThemeThumb(_ref) {var value = _ref.value;
|
|
7
|
-
var _useThemeHandler = useThemeHandler(),themes = _useThemeHandler.
|
|
7
|
+
var _useThemeHandler = useThemeHandler(),themes = _useThemeHandler.rawThemesParam;
|
|
8
8
|
var _useFormattedTheme = useFormattedTheme(themes, value),colors = _useFormattedTheme.colors,label = _useFormattedTheme.label;
|
|
9
9
|
var isMobile = useResponsiveValue({ smd: true, df: false });
|
|
10
10
|
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
var _jsxFileName = "/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/theme/ThemeHandler.js";function _slicedToArray(r, e) {return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();}function _nonIterableRest() {throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}function _unsupportedIterableToArray(r, a) {if (r) {if ("string" == typeof r) return _arrayLikeToArray(r, a);var t = {}.toString.call(r).slice(8, -1);return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;}}function _arrayLikeToArray(r, a) {(null == a || a > r.length) && (a = r.length);for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];return n;}function _iterableToArrayLimit(r, l) {var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];if (null != t) {var e,n,i,u,a = [],f = !0,o = !1;try {if (i = (t = t.call(r)).next, 0 === l) {if (Object(t) !== t) return;f = !1;} else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);} catch (r) {o = !0, n = r;} finally {try {if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;} finally {if (o) throw n;}}return a;}}function _arrayWithHoles(r) {if (Array.isArray(r)) return r;}import { mergeDeepRight } from 'ramda';
|
|
1
|
+
var _jsxFileName = "/Users/christianstorch/Apps/nekoapps/libs/neko-ui/src/theme/ThemeHandler.js";function _slicedToArray(r, e) {return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest();}function _nonIterableRest() {throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");}function _unsupportedIterableToArray(r, a) {if (r) {if ("string" == typeof r) return _arrayLikeToArray(r, a);var t = {}.toString.call(r).slice(8, -1);return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;}}function _arrayLikeToArray(r, a) {(null == a || a > r.length) && (a = r.length);for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];return n;}function _iterableToArrayLimit(r, l) {var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];if (null != t) {var e,n,i,u,a = [],f = !0,o = !1;try {if (i = (t = t.call(r)).next, 0 === l) {if (Object(t) !== t) return;f = !1;} else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0);} catch (r) {o = !0, n = r;} finally {try {if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;} finally {if (o) throw n;}}return a;}}function _arrayWithHoles(r) {if (Array.isArray(r)) return r;}import { keys, mergeDeepRight, omit, pick, pickBy } from 'ramda';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
4
|
import { DEFAULT_LIGHT_THEME } from "./default/lightTheme";
|
|
5
|
+
import { DEFAULT_THEMES } from "./default/themes";
|
|
5
6
|
import { getThemeValue } from "./helpers/relatedScales";
|
|
6
7
|
import { useFormattedTheme } from "./format/formatTheme";import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
8
|
|
|
@@ -52,8 +53,33 @@ export function useMergeThemeComponent(name, props) {
|
|
|
52
53
|
var themeProps = useThemeComponent(name);
|
|
53
54
|
return mergeDeepRight(themeProps, props);
|
|
54
55
|
}
|
|
56
|
+
export function useAllThemes() {
|
|
57
|
+
var _useThemeHandler2 = useThemeHandler(),disableDefaultThemes = _useThemeHandler2.disableDefaultThemes,enableOnlyThemes = _useThemeHandler2.enableOnlyThemes,rawThemesParam = _useThemeHandler2.rawThemesParam;
|
|
58
|
+
var themes = rawThemesParam || {};
|
|
59
|
+
var themesParamKeys = keys(themes);
|
|
60
|
+
|
|
61
|
+
var allThemes = mergeDeepRight(DEFAULT_THEMES, themes);
|
|
62
|
+
if (disableDefaultThemes === true) {
|
|
63
|
+
allThemes = pickBy(function (_, key) {return themesParamKeys.includes(key);}, allThemes);
|
|
64
|
+
} else if (disableDefaultThemes != null && disableDefaultThemes.length) {
|
|
65
|
+
allThemes = omit(disableDefaultThemes, allThemes);
|
|
66
|
+
}
|
|
67
|
+
if (enableOnlyThemes != null && enableOnlyThemes.length) {
|
|
68
|
+
allThemes = pick(enableOnlyThemes, allThemes);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return allThemes;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function ThemeHandler(_ref)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
|
|
55
81
|
|
|
56
|
-
|
|
82
|
+
{var breakpoints = _ref.breakpoints,themes = _ref.themes,initTheme = _ref.initTheme,onChangeTheme = _ref.onChangeTheme,children = _ref.children,disableDefaultThemes = _ref.disableDefaultThemes,enableOnlyThemes = _ref.enableOnlyThemes;
|
|
57
83
|
var _React$useState = React.useState(false),_React$useState2 = _slicedToArray(_React$useState, 2),themePickerOpen = _React$useState2[0],setThemePickerOpen = _React$useState2[1];
|
|
58
84
|
var openThemePicker = function openThemePicker() {return setThemePickerOpen(true);};
|
|
59
85
|
var _React$useState3 = React.useState(initTheme || 'light'),_React$useState4 = _slicedToArray(_React$useState3, 2),activeThemeKey = _React$useState4[0],setActiveThemeKey = _React$useState4[1];
|
|
@@ -66,7 +92,9 @@ export function ThemeHandler(_ref) {var breakpoints = _ref.breakpoints,themes =
|
|
|
66
92
|
|
|
67
93
|
var value = {
|
|
68
94
|
theme: theme,
|
|
69
|
-
|
|
95
|
+
rawThemesParam: themes,
|
|
96
|
+
disableDefaultThemes: disableDefaultThemes,
|
|
97
|
+
enableOnlyThemes: enableOnlyThemes,
|
|
70
98
|
activeThemeKey: activeThemeKey,
|
|
71
99
|
toggleTheme: toggleTheme,
|
|
72
100
|
themePickerOpen: themePickerOpen,
|
package/package.json
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Platform'
|
|
@@ -14,7 +14,7 @@ export function FloatingMenu({ fixed, onChange, items, activeIndex, size = 'md',
|
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
16
|
<View absolute={!fixed} fixed={fixed} left="md" right="md" centerH bottom={Math.max(insets.bottom / 2, 16)}>
|
|
17
|
-
<WrapperView height={height} shadow round row paddingH="sm" bg={bg} {...props}>
|
|
17
|
+
<WrapperView height={height} shadow round row paddingH="sm" bg={bg} border="overlayDivider" {...props}>
|
|
18
18
|
{items.map((item, index) => {
|
|
19
19
|
const isActive = index === activeIndex
|
|
20
20
|
|
|
@@ -20,7 +20,7 @@ export function CalendarNav({ value, onChange, level, ...props }) {
|
|
|
20
20
|
|
|
21
21
|
return (
|
|
22
22
|
<View className="neko-calendar-nav" row centerV gap="xxs" height={30} {...props}>
|
|
23
|
-
<Link onPress={prevDecade} aria-label="Previous decade" padding="
|
|
23
|
+
<Link onPress={prevDecade} aria-label="Previous decade" padding="sm" paddingL={0}>
|
|
24
24
|
<Icon name="arrow-left-double-line" />
|
|
25
25
|
</Link>
|
|
26
26
|
|
|
@@ -28,7 +28,7 @@ export function CalendarNav({ value, onChange, level, ...props }) {
|
|
|
28
28
|
{year}-{year + 9}
|
|
29
29
|
</Text>
|
|
30
30
|
|
|
31
|
-
<Link onPress={nextDecade} aria-label="Next decade" padding="
|
|
31
|
+
<Link onPress={nextDecade} aria-label="Next decade" padding="sm" paddingR={0}>
|
|
32
32
|
<Icon name="arrow-right-double-line" />
|
|
33
33
|
</Link>
|
|
34
34
|
</View>
|
|
@@ -37,12 +37,12 @@ export function CalendarNav({ value, onChange, level, ...props }) {
|
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
39
|
<View className="neko-calendar-nav" row centerV gap="xxs" height={30} {...props}>
|
|
40
|
-
<Link onPress={prevYear} aria-label="Previous year" padding="
|
|
40
|
+
<Link onPress={prevYear} aria-label="Previous year" padding="sm" paddingR={0}>
|
|
41
41
|
<Icon name="arrow-left-double-line" />
|
|
42
42
|
</Link>
|
|
43
43
|
|
|
44
44
|
{showMonth && (
|
|
45
|
-
<Link onPress={prevMonth} aria-label="Previous month" padding="
|
|
45
|
+
<Link onPress={prevMonth} aria-label="Previous month" padding="sm">
|
|
46
46
|
<Icon name="arrow-left-s-line" />
|
|
47
47
|
</Link>
|
|
48
48
|
)}
|
|
@@ -54,12 +54,12 @@ export function CalendarNav({ value, onChange, level, ...props }) {
|
|
|
54
54
|
</View>
|
|
55
55
|
|
|
56
56
|
{showMonth && (
|
|
57
|
-
<Link onPress={nextMonth} aria-label="Next month" padding="
|
|
57
|
+
<Link onPress={nextMonth} aria-label="Next month" padding="sm">
|
|
58
58
|
<Icon name="arrow-right-s-line" />
|
|
59
59
|
</Link>
|
|
60
60
|
)}
|
|
61
61
|
|
|
62
|
-
<Link onPress={nextYear} aria-label="Next year" padding="
|
|
62
|
+
<Link onPress={nextYear} aria-label="Next year" padding="sm" paddingL={0}>
|
|
63
63
|
<Icon name="arrow-right-double-line" />
|
|
64
64
|
</Link>
|
|
65
65
|
</View>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { View } from '../structure/View'
|
|
2
|
+
import { CarouselArrows } from './CarouselArrows'
|
|
3
|
+
import { CarouselDots } from './CarouselDots'
|
|
4
|
+
import { CarouselHandler } from './CarouselHandler'
|
|
5
|
+
import { CarouselSlider } from './CarouselSlider'
|
|
6
|
+
|
|
7
|
+
export function Carousel({
|
|
8
|
+
items,
|
|
9
|
+
activeIndex,
|
|
10
|
+
activeKey,
|
|
11
|
+
onChange,
|
|
12
|
+
afterChange,
|
|
13
|
+
autoplay,
|
|
14
|
+
autoplaySpeed,
|
|
15
|
+
draggable,
|
|
16
|
+
loop,
|
|
17
|
+
showDots,
|
|
18
|
+
showArrows,
|
|
19
|
+
floatingDots,
|
|
20
|
+
dotsProps,
|
|
21
|
+
arrowsProps,
|
|
22
|
+
children,
|
|
23
|
+
...rootProps
|
|
24
|
+
}) {
|
|
25
|
+
return (
|
|
26
|
+
<CarouselHandler
|
|
27
|
+
items={items}
|
|
28
|
+
activeIndex={activeIndex}
|
|
29
|
+
activeKey={activeKey}
|
|
30
|
+
onChange={onChange}
|
|
31
|
+
afterChange={afterChange}
|
|
32
|
+
autoplay={autoplay}
|
|
33
|
+
autoplaySpeed={autoplaySpeed}
|
|
34
|
+
draggable={draggable}
|
|
35
|
+
loop={loop}
|
|
36
|
+
>
|
|
37
|
+
<View {...rootProps}>
|
|
38
|
+
<View relative>
|
|
39
|
+
<CarouselSlider />
|
|
40
|
+
{showArrows && <CarouselArrows {...arrowsProps} />}
|
|
41
|
+
{showDots && floatingDots && <CarouselDots absolute bottom="xs" left={0} right={0} {...dotsProps} />}
|
|
42
|
+
</View>
|
|
43
|
+
{showDots && !floatingDots && <CarouselDots {...dotsProps} />}
|
|
44
|
+
{children}
|
|
45
|
+
</View>
|
|
46
|
+
</CarouselHandler>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { Icon } from '../presentation/Icon'
|
|
4
|
+
import { Link } from '../actions/Link'
|
|
5
|
+
import { View } from '../structure/View'
|
|
6
|
+
import { useCarousel } from './CarouselHandler'
|
|
7
|
+
|
|
8
|
+
export function CarouselArrows({ iconSize = 'md', ...props }) {
|
|
9
|
+
const { goToNext, goToPrev, activeIndex, itemsCount, loop } = useCarousel()
|
|
10
|
+
|
|
11
|
+
const showPrev = loop || activeIndex > 0
|
|
12
|
+
const showNext = loop || activeIndex < itemsCount - 1
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<View
|
|
16
|
+
absoluteFill
|
|
17
|
+
row
|
|
18
|
+
centerV
|
|
19
|
+
paddingH="xs"
|
|
20
|
+
justify="space-between"
|
|
21
|
+
style={{ pointerEvents: 'none' }}
|
|
22
|
+
{...props}
|
|
23
|
+
>
|
|
24
|
+
{showPrev ? (
|
|
25
|
+
<Link onPress={goToPrev} bg="overlayBG_op80" round padding="xs" shadow style={{ pointerEvents: 'auto' }}>
|
|
26
|
+
<Icon name="arrow-left-s-line" text3 size={iconSize} />
|
|
27
|
+
</Link>
|
|
28
|
+
) : (
|
|
29
|
+
<View />
|
|
30
|
+
)}
|
|
31
|
+
{showNext ? (
|
|
32
|
+
<Link onPress={goToNext} bg="overlayBG_op80" round padding="xs" shadow style={{ pointerEvents: 'auto' }}>
|
|
33
|
+
<Icon name="arrow-right-s-line" text3 size={iconSize} />
|
|
34
|
+
</Link>
|
|
35
|
+
) : (
|
|
36
|
+
<View />
|
|
37
|
+
)}
|
|
38
|
+
</View>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { Icon } from '../presentation/Icon'
|
|
4
|
+
import { Link } from '../actions/Link'
|
|
5
|
+
import { View } from '../structure/View'
|
|
6
|
+
import { useCarousel } from './CarouselHandler'
|
|
7
|
+
|
|
8
|
+
export function CarouselArrows({ iconSize = 'md', ...props }) {
|
|
9
|
+
const { goToNext, goToPrev, activeIndex, itemsCount, loop } = useCarousel()
|
|
10
|
+
|
|
11
|
+
const showPrev = loop || activeIndex > 0
|
|
12
|
+
const showNext = loop || activeIndex < itemsCount - 1
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<View
|
|
16
|
+
absoluteFill
|
|
17
|
+
row
|
|
18
|
+
centerV
|
|
19
|
+
paddingH="xs"
|
|
20
|
+
justify="space-between"
|
|
21
|
+
pointerEvents="box-none"
|
|
22
|
+
{...props}
|
|
23
|
+
>
|
|
24
|
+
{showPrev ? (
|
|
25
|
+
<Link onPress={goToPrev} bg="overlayBG_op80" round padding="xs" shadow>
|
|
26
|
+
<Icon name="arrow-left-s-line" text3 size={iconSize} />
|
|
27
|
+
</Link>
|
|
28
|
+
) : (
|
|
29
|
+
<View />
|
|
30
|
+
)}
|
|
31
|
+
{showNext ? (
|
|
32
|
+
<Link onPress={goToNext} bg="overlayBG_op80" round padding="xs" shadow>
|
|
33
|
+
<Icon name="arrow-right-s-line" text3 size={iconSize} />
|
|
34
|
+
</Link>
|
|
35
|
+
) : (
|
|
36
|
+
<View />
|
|
37
|
+
)}
|
|
38
|
+
</View>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { Pressable } from '../actions/Pressable'
|
|
4
|
+
import { View } from '../structure/View'
|
|
5
|
+
import { useCarousel } from './CarouselHandler'
|
|
6
|
+
|
|
7
|
+
function Dot({ active, onPress }) {
|
|
8
|
+
return (
|
|
9
|
+
<Pressable
|
|
10
|
+
onPress={onPress}
|
|
11
|
+
width={active ? 20 : 8}
|
|
12
|
+
height={8}
|
|
13
|
+
round
|
|
14
|
+
bg={active ? 'primary' : 'text4_op30'}
|
|
15
|
+
style={{ transition: 'all 200ms ease-in-out' }}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function CarouselDots(props) {
|
|
21
|
+
const { items, activeIndex, goTo } = useCarousel()
|
|
22
|
+
|
|
23
|
+
if (!items?.length) return null
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<View row center gap="xs" paddingV="sm" {...props}>
|
|
27
|
+
{items.map((item, index) => (
|
|
28
|
+
<Dot key={item.key} active={index === activeIndex} onPress={() => goTo(index)} />
|
|
29
|
+
))}
|
|
30
|
+
</View>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Animated, { useAnimatedStyle, withTiming } from 'react-native-reanimated'
|
|
3
|
+
|
|
4
|
+
import { Pressable } from '../actions/Pressable'
|
|
5
|
+
import { View } from '../structure/View'
|
|
6
|
+
import { useColors } from '../../theme/ThemeHandler'
|
|
7
|
+
import { useCarousel } from './CarouselHandler'
|
|
8
|
+
|
|
9
|
+
function Dot({ active, onPress }) {
|
|
10
|
+
const colors = useColors()
|
|
11
|
+
|
|
12
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
13
|
+
width: withTiming(active ? 20 : 8, { duration: 200 }),
|
|
14
|
+
backgroundColor: withTiming(active ? colors.primary : colors.text4_op30, { duration: 200 }),
|
|
15
|
+
}), [active])
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<Pressable onPress={onPress}>
|
|
19
|
+
<Animated.View style={[{ height: 8, borderRadius: 4 }, animatedStyle]} />
|
|
20
|
+
</Pressable>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function CarouselDots(props) {
|
|
25
|
+
const { items, activeIndex, goTo } = useCarousel()
|
|
26
|
+
|
|
27
|
+
if (!items?.length) return null
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<View row center gap="xs" paddingV="sm" {...props}>
|
|
31
|
+
{items.map((item, index) => (
|
|
32
|
+
<Dot key={item.key} active={index === activeIndex} onPress={() => goTo(index)} />
|
|
33
|
+
))}
|
|
34
|
+
</View>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
const CarouselContext = React.createContext(null)
|
|
4
|
+
export const useCarousel = () => React.useContext(CarouselContext) || {}
|
|
5
|
+
|
|
6
|
+
export function CarouselHandler({
|
|
7
|
+
children,
|
|
8
|
+
items,
|
|
9
|
+
activeIndex: controlledIndex,
|
|
10
|
+
activeKey,
|
|
11
|
+
onChange,
|
|
12
|
+
afterChange,
|
|
13
|
+
autoplay,
|
|
14
|
+
autoplaySpeed = 3000,
|
|
15
|
+
draggable,
|
|
16
|
+
loop,
|
|
17
|
+
}) {
|
|
18
|
+
const itemsCount = items?.length || 0
|
|
19
|
+
const isControlled = controlledIndex !== undefined || activeKey !== undefined
|
|
20
|
+
|
|
21
|
+
const [internalIndex, setInternalIndex] = React.useState(() => {
|
|
22
|
+
if (controlledIndex !== undefined) return controlledIndex
|
|
23
|
+
if (activeKey !== undefined) return Math.max(0, items?.findIndex((i) => i.key === activeKey) || 0)
|
|
24
|
+
return 0
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const resolvedIndex = isControlled
|
|
28
|
+
? activeKey !== undefined
|
|
29
|
+
? Math.max(0, items?.findIndex((i) => i.key === activeKey) || 0)
|
|
30
|
+
: controlledIndex
|
|
31
|
+
: internalIndex
|
|
32
|
+
|
|
33
|
+
const activeItem = React.useMemo(() => items?.[resolvedIndex], [items, resolvedIndex])
|
|
34
|
+
|
|
35
|
+
const pausedRef = React.useRef(false)
|
|
36
|
+
|
|
37
|
+
const goTo = React.useCallback(
|
|
38
|
+
(index) => {
|
|
39
|
+
let next = index
|
|
40
|
+
if (loop) next = ((next % itemsCount) + itemsCount) % itemsCount
|
|
41
|
+
else next = Math.max(0, Math.min(next, itemsCount - 1))
|
|
42
|
+
|
|
43
|
+
if (!isControlled) setInternalIndex(next)
|
|
44
|
+
onChange?.(items?.[next]?.key, next)
|
|
45
|
+
},
|
|
46
|
+
[loop, itemsCount, isControlled, onChange, items]
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const goToNext = React.useCallback(() => goTo(resolvedIndex + 1), [goTo, resolvedIndex])
|
|
50
|
+
const goToPrev = React.useCallback(() => goTo(resolvedIndex - 1), [goTo, resolvedIndex])
|
|
51
|
+
|
|
52
|
+
const pauseAutoplay = React.useCallback(() => {
|
|
53
|
+
pausedRef.current = true
|
|
54
|
+
}, [])
|
|
55
|
+
|
|
56
|
+
const resumeAutoplay = React.useCallback(() => {
|
|
57
|
+
pausedRef.current = false
|
|
58
|
+
}, [])
|
|
59
|
+
|
|
60
|
+
React.useEffect(() => {
|
|
61
|
+
if (!autoplay || itemsCount <= 1) return
|
|
62
|
+
|
|
63
|
+
const interval = setInterval(() => {
|
|
64
|
+
if (!pausedRef.current) goToNext()
|
|
65
|
+
}, autoplaySpeed)
|
|
66
|
+
|
|
67
|
+
return () => clearInterval(interval)
|
|
68
|
+
}, [autoplay, autoplaySpeed, itemsCount, resolvedIndex, goToNext])
|
|
69
|
+
|
|
70
|
+
const value = {
|
|
71
|
+
items,
|
|
72
|
+
activeIndex: resolvedIndex,
|
|
73
|
+
activeItem,
|
|
74
|
+
itemsCount,
|
|
75
|
+
goTo,
|
|
76
|
+
goToNext,
|
|
77
|
+
goToPrev,
|
|
78
|
+
afterChange,
|
|
79
|
+
draggable,
|
|
80
|
+
loop,
|
|
81
|
+
pauseAutoplay,
|
|
82
|
+
resumeAutoplay,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return <CarouselContext.Provider value={value}>{children}</CarouselContext.Provider>
|
|
86
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import { View } from '../structure/View'
|
|
4
|
+
import { useCarousel } from './CarouselHandler'
|
|
5
|
+
|
|
6
|
+
function SlideContent({ item }) {
|
|
7
|
+
const Content = React.useMemo(
|
|
8
|
+
() => item.render || item.renderContent || item.Content,
|
|
9
|
+
[item.render, item.renderContent, item.Content]
|
|
10
|
+
)
|
|
11
|
+
return Content ? <Content /> : null
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function CarouselSlider() {
|
|
15
|
+
const { items, activeIndex, itemsCount, draggable, loop, afterChange, goToNext, goToPrev, pauseAutoplay, resumeAutoplay } =
|
|
16
|
+
useCarousel()
|
|
17
|
+
|
|
18
|
+
const containerRef = React.useRef(null)
|
|
19
|
+
const [isDragging, setIsDragging] = React.useState(false)
|
|
20
|
+
const [dragOffset, setDragOffset] = React.useState(0)
|
|
21
|
+
const startXRef = React.useRef(0)
|
|
22
|
+
const startTimeRef = React.useRef(0)
|
|
23
|
+
const prevItemsRef = React.useRef(items)
|
|
24
|
+
const skipTransitionRef = React.useRef(false)
|
|
25
|
+
|
|
26
|
+
if (items !== prevItemsRef.current) {
|
|
27
|
+
skipTransitionRef.current = true
|
|
28
|
+
prevItemsRef.current = items
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
React.useEffect(() => {
|
|
32
|
+
if (skipTransitionRef.current) {
|
|
33
|
+
const id = requestAnimationFrame(() => {
|
|
34
|
+
skipTransitionRef.current = false
|
|
35
|
+
})
|
|
36
|
+
return () => cancelAnimationFrame(id)
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
if (!items?.length) return null
|
|
41
|
+
|
|
42
|
+
const baseTranslate = -(activeIndex * 100) / itemsCount
|
|
43
|
+
const dragPercent =
|
|
44
|
+
isDragging && containerRef.current ? (dragOffset / containerRef.current.offsetWidth) * (100 / itemsCount) : 0
|
|
45
|
+
const transformX = baseTranslate + dragPercent
|
|
46
|
+
|
|
47
|
+
const dragStateRef = React.useRef({ isDragging: false, dragOffset: 0 })
|
|
48
|
+
|
|
49
|
+
const handlePointerDown = (e) => {
|
|
50
|
+
if (!draggable) return
|
|
51
|
+
startXRef.current = e.clientX
|
|
52
|
+
startTimeRef.current = Date.now()
|
|
53
|
+
dragStateRef.current = { isDragging: true, dragOffset: 0 }
|
|
54
|
+
setIsDragging(true)
|
|
55
|
+
setDragOffset(0)
|
|
56
|
+
pauseAutoplay()
|
|
57
|
+
|
|
58
|
+
const onMove = (ev) => {
|
|
59
|
+
const raw = ev.clientX - startXRef.current
|
|
60
|
+
let offset = raw
|
|
61
|
+
if (!loop) {
|
|
62
|
+
const containerWidth = containerRef.current?.offsetWidth || 1
|
|
63
|
+
const atStart = activeIndex === 0 && raw > 0
|
|
64
|
+
const atEnd = activeIndex === itemsCount - 1 && raw < 0
|
|
65
|
+
if (atStart || atEnd) offset = raw * 0.3
|
|
66
|
+
}
|
|
67
|
+
dragStateRef.current.dragOffset = offset
|
|
68
|
+
setDragOffset(offset)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const onUp = () => {
|
|
72
|
+
window.removeEventListener('pointermove', onMove)
|
|
73
|
+
window.removeEventListener('pointerup', onUp)
|
|
74
|
+
window.removeEventListener('pointercancel', onUp)
|
|
75
|
+
|
|
76
|
+
const offset = dragStateRef.current.dragOffset
|
|
77
|
+
const containerWidth = containerRef.current?.offsetWidth || 1
|
|
78
|
+
const threshold = containerWidth * 0.25
|
|
79
|
+
const elapsed = Date.now() - startTimeRef.current
|
|
80
|
+
const velocity = Math.abs(offset) / (elapsed || 1)
|
|
81
|
+
|
|
82
|
+
if (offset < -threshold || (offset < 0 && velocity > 0.5)) {
|
|
83
|
+
goToNext()
|
|
84
|
+
} else if (offset > threshold || (offset > 0 && velocity > 0.5)) {
|
|
85
|
+
goToPrev()
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
dragStateRef.current = { isDragging: false, dragOffset: 0 }
|
|
89
|
+
setIsDragging(false)
|
|
90
|
+
setDragOffset(0)
|
|
91
|
+
resumeAutoplay()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
window.addEventListener('pointermove', onMove)
|
|
95
|
+
window.addEventListener('pointerup', onUp)
|
|
96
|
+
window.addEventListener('pointercancel', onUp)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<View hiddenOverflow fullW ref={containerRef}>
|
|
101
|
+
<View
|
|
102
|
+
row
|
|
103
|
+
style={{
|
|
104
|
+
width: `${itemsCount * 100}%`,
|
|
105
|
+
transform: `translateX(${transformX}%)`,
|
|
106
|
+
transition: isDragging || skipTransitionRef.current ? 'none' : 'transform 300ms ease-in-out',
|
|
107
|
+
touchAction: 'pan-y',
|
|
108
|
+
cursor: draggable ? (isDragging ? 'grabbing' : 'grab') : undefined,
|
|
109
|
+
userSelect: 'none',
|
|
110
|
+
}}
|
|
111
|
+
onTransitionEnd={afterChange ? (e) => {
|
|
112
|
+
if (e.propertyName === 'transform') afterChange(items?.[activeIndex]?.key, activeIndex)
|
|
113
|
+
} : undefined}
|
|
114
|
+
onPointerDown={draggable ? handlePointerDown : undefined}
|
|
115
|
+
>
|
|
116
|
+
{items.map((item) => (
|
|
117
|
+
<View key={item.key} style={{ width: `${100 / itemsCount}%` }}>
|
|
118
|
+
<SlideContent item={item} />
|
|
119
|
+
</View>
|
|
120
|
+
))}
|
|
121
|
+
</View>
|
|
122
|
+
</View>
|
|
123
|
+
)
|
|
124
|
+
}
|