@tecsinapse/react-native-kit 1.12.4 → 1.12.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/CHANGELOG.md +32 -0
- package/dist/components/atoms/BottomNavigator/styled.js +4 -2
- package/dist/components/atoms/BottomNavigator/styled.js.map +1 -1
- package/dist/components/atoms/Input/styled.js +1 -1
- package/dist/components/atoms/Input/styled.js.map +1 -1
- package/dist/components/atoms/Modal/ModalGroupManager.d.ts +4 -0
- package/dist/components/atoms/Modal/ModalGroupManager.js +41 -0
- package/dist/components/atoms/Modal/ModalGroupManager.js.map +1 -0
- package/dist/components/atoms/Modal/ModalLifecycleHandler.d.ts +23 -0
- package/dist/components/atoms/Modal/ModalLifecycleHandler.js +110 -0
- package/dist/components/atoms/Modal/ModalLifecycleHandler.js.map +1 -0
- package/dist/components/atoms/Modal/index.d.ts +5 -0
- package/dist/components/atoms/Modal/index.js +71 -0
- package/dist/components/atoms/Modal/index.js.map +1 -0
- package/dist/components/atoms/Modal/ui/BaseModalView.d.ts +3 -0
- package/dist/components/atoms/Modal/ui/BaseModalView.js +140 -0
- package/dist/components/atoms/Modal/ui/BaseModalView.js.map +1 -0
- package/dist/components/atoms/Modal/ui/styled.d.ts +6 -0
- package/dist/components/atoms/Modal/ui/styled.js +38 -0
- package/dist/components/atoms/Modal/ui/styled.js.map +1 -0
- package/dist/components/atoms/Modal/ui/types.d.ts +9 -0
- package/dist/components/atoms/Modal/ui/types.js +6 -0
- package/dist/components/atoms/Modal/ui/types.js.map +1 -0
- package/dist/components/atoms/Modal/useModalManager.d.ts +6 -0
- package/dist/components/atoms/Modal/useModalManager.js +35 -0
- package/dist/components/atoms/Modal/useModalManager.js.map +1 -0
- package/dist/components/atoms/Select/styled.js +2 -2
- package/dist/components/atoms/Select/styled.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +38 -1
- package/dist/index.js.map +1 -1
- package/package.json +9 -4
- package/src/components/atoms/BottomNavigator/styled.ts +3 -3
- package/src/components/atoms/Input/styled.ts +3 -2
- package/src/components/atoms/Modal/ModalGroupManager.tsx +28 -0
- package/src/components/atoms/Modal/ModalLifecycleHandler.ts +141 -0
- package/src/components/atoms/Modal/index.ts +5 -0
- package/src/components/atoms/Modal/ui/BaseModalView.tsx +127 -0
- package/src/components/atoms/Modal/ui/styled.ts +23 -0
- package/src/components/atoms/Modal/ui/types.ts +12 -0
- package/src/components/atoms/Modal/useModalManager.ts +35 -0
- package/src/components/atoms/Select/styled.ts +4 -3
- package/src/index.ts +1 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.useModalManager = void 0;
|
|
7
|
+
|
|
8
|
+
var _react = require("react");
|
|
9
|
+
|
|
10
|
+
var _uuid = require("uuid");
|
|
11
|
+
|
|
12
|
+
var _ModalGroupManager = require("./ModalGroupManager");
|
|
13
|
+
|
|
14
|
+
const useModalManager = modal => {
|
|
15
|
+
const [id] = (0, _react.useState)((0, _uuid.v4)());
|
|
16
|
+
|
|
17
|
+
_ModalGroupManager.modalLifecycle.sync(id, modal);
|
|
18
|
+
|
|
19
|
+
const show = (0, _react.useCallback)(() => {
|
|
20
|
+
_ModalGroupManager.modalLifecycle.show(id);
|
|
21
|
+
}, [id]);
|
|
22
|
+
const close = (0, _react.useCallback)(() => {
|
|
23
|
+
_ModalGroupManager.modalLifecycle.close(id);
|
|
24
|
+
}, [id]);
|
|
25
|
+
(0, _react.useEffect)(() => {
|
|
26
|
+
return () => _ModalGroupManager.modalLifecycle.destroy(id);
|
|
27
|
+
}, []);
|
|
28
|
+
return {
|
|
29
|
+
show,
|
|
30
|
+
close
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
exports.useModalManager = useModalManager;
|
|
35
|
+
//# sourceMappingURL=useModalManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/atoms/Modal/useModalManager.ts"],"names":["useModalManager","modal","id","modalLifecycle","sync","show","close","destroy"],"mappings":";;;;;;;AAAA;;AACA;;AACA;;AAWO,MAAMA,eAAe,GAAIC,KAAD,IAA2C;AAEtE,QAAM,CAACC,EAAD,IAAO,qBAAS,eAAT,CAAb;;AACAC,oCAAeC,IAAf,CAAoBF,EAApB,EAAwBD,KAAxB;;AAEA,QAAMI,IAAI,GAAG,wBAAY,MAAM;AAC3BF,sCAAeE,IAAf,CAAoBH,EAApB;AACH,GAFY,EAEV,CAACA,EAAD,CAFU,CAAb;AAIA,QAAMI,KAAK,GAAG,wBAAY,MAAM;AAC5BH,sCAAeG,KAAf,CAAqBJ,EAArB;AACH,GAFa,EAEX,CAACA,EAAD,CAFW,CAAd;AAIA,wBAAU,MAAM;AACZ,WAAO,MAAMC,kCAAeI,OAAf,CAAuBL,EAAvB,CAAb;AACH,GAFD,EAEG,EAFH;AAIA,SAAO;AACHG,IAAAA,IADG;AAEHC,IAAAA;AAFG,GAAP;AAIH,CArBM","sourcesContent":["import { ReactElement, useCallback, useEffect, useState } from \"react\"\nimport { v4 as uuidv4 } from 'uuid'\nimport { modalLifecycle } from \"./ModalGroupManager\"\nimport { IBaseModal } from \"./ui/types\"\n\n/**\n * Use this hook to tell the modal lifecycle handler that you want to add\n * a new modal component. \n * \n * @param id \n * @param modal \n * @returns\n */\nexport const useModalManager = (modal: () => ReactElement<IBaseModal>) => {\n\n const [id] = useState(uuidv4())\n modalLifecycle.sync(id, modal)\n\n const show = useCallback(() => {\n modalLifecycle.show(id)\n }, [id])\n\n const close = useCallback(() => {\n modalLifecycle.close(id)\n }, [id])\n \n useEffect(() => {\n return () => modalLifecycle.destroy(id)\n }, [])\n\n return {\n show,\n close\n }\n}"],"file":"useModalManager.js"}
|
|
@@ -56,7 +56,7 @@ const Header = (0, _native.default)(_reactNative.View)`
|
|
|
56
56
|
padding: ${({
|
|
57
57
|
theme
|
|
58
58
|
}) => theme.spacing.deca};
|
|
59
|
-
height: 75px;
|
|
59
|
+
height: ${(0, _reactCore.RFValueStr)('75px')};
|
|
60
60
|
`;
|
|
61
61
|
exports.Header = Header;
|
|
62
62
|
const CloseButton = (0, _native.default)(_reactCore.Button)`
|
|
@@ -78,7 +78,7 @@ const SearchBar = (0, _native.default)(_Input.Input)`
|
|
|
78
78
|
`;
|
|
79
79
|
exports.SearchBar = SearchBar;
|
|
80
80
|
const ListItem = (0, _native.default)(_reactCore.PressableSurface)`
|
|
81
|
-
border-bottom-width: 1px;
|
|
81
|
+
border-bottom-width: ${(0, _reactCore.RFValueStr)('1px')};
|
|
82
82
|
border-color: ${({
|
|
83
83
|
theme
|
|
84
84
|
}) => theme.color.secondary.light};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/components/atoms/Select/styled.ts"],"names":["StyledModal","View","theme","miscellaneous","bodyColor","StyledSelectionText","Text","props","typography","h5","lineHeight","Dummy","StyledPressableSurface","PressableSurface","Header","spacing","deca","CloseButton","Button","SearchBarContainer","SearchBar","Input","ListItem","color","secondary","light","mili","ModalFooter","SelectIcon","Icon","centi","medium","FetchIndicator","ActivityIndicator"],"mappings":";;;;;;;AAAA;;AACA;;
|
|
1
|
+
{"version":3,"sources":["../../../../src/components/atoms/Select/styled.ts"],"names":["StyledModal","View","theme","miscellaneous","bodyColor","StyledSelectionText","Text","props","typography","h5","lineHeight","Dummy","StyledPressableSurface","PressableSurface","Header","spacing","deca","CloseButton","Button","SearchBarContainer","SearchBar","Input","ListItem","color","secondary","light","mili","ModalFooter","SelectIcon","Icon","centi","medium","FetchIndicator","ActivityIndicator"],"mappings":";;;;;;;AAAA;;AACA;;AAWA;;AACA;;AACA;;;;;;AAEO,MAAMA,WAAW,GAAG,qBAAOC,iBAAP,CAA+C;AAC1E;AACA,sBAAsB,CAAC;AAAEC,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACC,aAAN,CAAoBC,SAAU;AACnE;AACA;AACA,CALO;;AAOA,MAAMC,mBAAmB,GAAG,qBAAOC,UAAP,EAChCC,KAAD;AAAA;;AAAA,SAA+D,gBAAI;AACrE,mBADoE,gBACjDA,KAAK,CAACL,KAD2C,iDACjD,aAAaM,UAAb,CAAwBC,EAAxB,CAA2BC,UAAW;AACzD,MAAM,oCAAoBH,KAApB,CAA2B;AACjC,GAHE;AAAA,CADiC,CAA5B;;AAOA,MAAMI,KAAK,GAAG,qBAAOV,iBAAP,CAAa;AAClC;AACA;AACA,CAHO;;AAKA,MAAMW,sBAAsB,GAAG,qBACpCC,2BADoC,CAEb;AACzB;AACA,CAJO;;AAMA,MAAMC,MAAM,GAAG,qBAAOb,iBAAP,CAA8C;AACpE;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,CAAC;AAAEC,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACa,OAAN,CAAcC,IAAK;AAC/C,YAAY,2BAAW,MAAX,CAAmB;AAC/B,CATO;;AAWA,MAAMC,WAAW,GAAG,qBAAOC,iBAAP,CAAkD;AAC7E;AACA;AACA,CAHO;;AAKA,MAAMC,kBAAkB,GAAG,qBAAOlB,iBAAP,CAA8C;AAChF,aAAa,CAAC;AAAEC,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACa,OAAN,CAAcC,IAAK;AAC/C;AACA,CAHO;;AAKA,MAAMI,SAAS,GAAG,qBAAOC,YAAP,CAAsD;AAC/E,mBAAmB,CAAC;AAAEnB,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACa,OAAN,CAAcC,IAAK;AACrD,CAFO;;AAIA,MAAMM,QAAQ,GAAG,qBAAOT,2BAAP,CAEtB;AACF,yBAAyB,2BAAW,KAAX,CAAkB;AAC3C,kBAAkB,CAAC;AAAEX,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACqB,KAAN,CAAYC,SAAZ,CAAsBC,KAAM;AAC7D,sBAAsB,CAAC;AAAEvB,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACa,OAAN,CAAcW,IAAK;AACxD,wBAAwB,CAAC;AAAExB,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACa,OAAN,CAAcC,IAAK;AAC1D,CAPO;;AASA,MAAMW,WAAW,GAAG,qBAAO1B,iBAAP,CAAkC;AAC7D;AACA;AACA;AACA,sBAAsB,CAAC;AAAEC,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACC,aAAN,CAAoBC,SAAU;AACnE,aAAa,CAAC;AAAEF,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACa,OAAN,CAAcC,IAAK;AAC/C,CANO;;AAQA,MAAMY,UAAU,GAAG,qBAAOC,eAAP,CAAkC;AAC5D,aAAa,CAAC;AAAE3B,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACa,OAAN,CAAce,KAAM;AAChD,WAAW,CAAC;AAAE5B,EAAAA;AAAF,CAAD,KAAeA,KAAK,CAACqB,KAAN,CAAYC,SAAZ,CAAsBO,MAAO;AACvD,CAHO;;AAKA,MAAMC,cAAc,GAAG,qBAAOC,8BAAP,CAA0B;AACxD;AACA,CAFO","sourcesContent":["import styled, { css } from '@emotion/native';\nimport {\n Button,\n ButtonProps,\n disabledInputStyles,\n Icon,\n InputContainerProps,\n PressableSurface,\n PressableSurfaceProps,\n RFValueStr,\n StyleProps\n} from '@tecsinapse/react-core';\nimport { ActivityIndicator, ModalProps, View, ViewProps } from 'react-native';\nimport { Input, InputNativeProps } from '../Input';\nimport { Text } from '../Text';\n\nexport const StyledModal = styled(View)<ModalProps & Partial<StyleProps>>`\n position: relative;\n background-color: ${({ theme }) => theme.miscellaneous.bodyColor};\n height: 100%;\n width: 100%;\n`;\n\nexport const StyledSelectionText = styled(Text)(\n (props: Partial<InputContainerProps> & Partial<StyleProps>) => css`\n line-height: ${props.theme?.typography.h5.lineHeight};\n ${disabledInputStyles(props)};\n `\n);\n\nexport const Dummy = styled(View)`\n aspect-ratio: 1;\n height: 100%;\n`;\n\nexport const StyledPressableSurface = styled(\n PressableSurface\n)<PressableSurfaceProps>`\n width: 100%;\n`;\n\nexport const Header = styled(View)<ViewProps & Partial<StyleProps>>`\n position: relative;\n width: 100%;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n padding: ${({ theme }) => theme.spacing.deca};\n height: ${RFValueStr('75px')};\n`;\n\nexport const CloseButton = styled(Button)<ButtonProps & Partial<StyleProps>>`\n aspect-ratio: 1;\n height: 100%;\n`;\n\nexport const SearchBarContainer = styled(View)<ViewProps & Partial<StyleProps>>`\n padding: ${({ theme }) => theme.spacing.deca};\n position: relative;\n`;\n\nexport const SearchBar = styled(Input)<InputNativeProps & Partial<StyleProps>>`\n margin-bottom: ${({ theme }) => theme.spacing.deca};\n`;\n\nexport const ListItem = styled(PressableSurface)<\n PressableSurfaceProps & Partial<StyleProps>\n>`\n border-bottom-width: ${RFValueStr('1px')};\n border-color: ${({ theme }) => theme.color.secondary.light};\n padding-vertical: ${({ theme }) => theme.spacing.mili};\n padding-horizontal: ${({ theme }) => theme.spacing.deca};\n`;\n\nexport const ModalFooter = styled(View)<Partial<StyleProps>>`\n width: 100%;\n height: auto;\n bottom: 0;\n background-color: ${({ theme }) => theme.miscellaneous.bodyColor};\n padding: ${({ theme }) => theme.spacing.deca};\n`;\n\nexport const SelectIcon = styled(Icon)<Partial<StyleProps>>`\n padding: ${({ theme }) => theme.spacing.centi};\n color: ${({ theme }) => theme.color.secondary.medium};\n`;\n\nexport const FetchIndicator = styled(ActivityIndicator)`\n align-self: center;\n`;\n"],"file":"styled.js"}
|
package/dist/index.d.ts
CHANGED
|
@@ -17,3 +17,4 @@ export { DateTimePicker } from './components/molecules/DateTimePicker';
|
|
|
17
17
|
export { Avatar } from './components/atoms/Avatar';
|
|
18
18
|
export { Calendar } from './components/molecules/Calendar';
|
|
19
19
|
export { DateTimeSelector } from './components/molecules/DateTimeSelector';
|
|
20
|
+
export { ModalGroupManager, ModalView, ModalLifecycleHandler, useModalManager, IBaseModal } from './components/atoms/Modal';
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,12 @@ var _exportNames = {
|
|
|
36
36
|
DateTimePicker: true,
|
|
37
37
|
Avatar: true,
|
|
38
38
|
Calendar: true,
|
|
39
|
-
DateTimeSelector: true
|
|
39
|
+
DateTimeSelector: true,
|
|
40
|
+
ModalGroupManager: true,
|
|
41
|
+
ModalView: true,
|
|
42
|
+
ModalLifecycleHandler: true,
|
|
43
|
+
useModalManager: true,
|
|
44
|
+
IBaseModal: true
|
|
40
45
|
};
|
|
41
46
|
Object.defineProperty(exports, "Header", {
|
|
42
47
|
enumerable: true,
|
|
@@ -236,6 +241,36 @@ Object.defineProperty(exports, "DateTimeSelector", {
|
|
|
236
241
|
return _DateTimeSelector.DateTimeSelector;
|
|
237
242
|
}
|
|
238
243
|
});
|
|
244
|
+
Object.defineProperty(exports, "ModalGroupManager", {
|
|
245
|
+
enumerable: true,
|
|
246
|
+
get: function () {
|
|
247
|
+
return _Modal.ModalGroupManager;
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
Object.defineProperty(exports, "ModalView", {
|
|
251
|
+
enumerable: true,
|
|
252
|
+
get: function () {
|
|
253
|
+
return _Modal.ModalView;
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
Object.defineProperty(exports, "ModalLifecycleHandler", {
|
|
257
|
+
enumerable: true,
|
|
258
|
+
get: function () {
|
|
259
|
+
return _Modal.ModalLifecycleHandler;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
Object.defineProperty(exports, "useModalManager", {
|
|
263
|
+
enumerable: true,
|
|
264
|
+
get: function () {
|
|
265
|
+
return _Modal.useModalManager;
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
Object.defineProperty(exports, "IBaseModal", {
|
|
269
|
+
enumerable: true,
|
|
270
|
+
get: function () {
|
|
271
|
+
return _Modal.IBaseModal;
|
|
272
|
+
}
|
|
273
|
+
});
|
|
239
274
|
|
|
240
275
|
var _reactCore = require("@tecsinapse/react-core");
|
|
241
276
|
|
|
@@ -286,4 +321,6 @@ var _Avatar = require("./components/atoms/Avatar");
|
|
|
286
321
|
var _Calendar = require("./components/molecules/Calendar");
|
|
287
322
|
|
|
288
323
|
var _DateTimeSelector = require("./components/molecules/DateTimeSelector");
|
|
324
|
+
|
|
325
|
+
var _Modal = require("./components/atoms/Modal");
|
|
289
326
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AAIA;;AAIA;;AACA;;AAIA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA;;AACA","sourcesContent":["export * from '@tecsinapse/react-core';\nexport { Header, HeaderProps } from './components/atoms/Header';\nexport { Select, SelectNativeProps } from './components/atoms/Select';\nexport { Input, InputNativeProps } from './components/atoms/Input';\nexport { TextArea, TextAreaProps } from './components/atoms/TextArea';\nexport { Text, TextNativeProps } from './components/atoms/Text';\nexport { Error, Loading, Success, Button, ButtonNativeProps } from './components/atoms/Button';\nexport { GroupButtonOption } from './components/atoms/GroupButton';\nexport {\n InputPassword,\n InputPasswordNativeProps,\n} from './components/molecules/InputPassword';\nexport {\n BottomNavigator,\n BottomNavigatorProps,\n} from './components/atoms/BottomNavigator';\nexport { Tag, TagProps } from './components/atoms/Tag';\nexport {\n SnappingSlider,\n SnappingSliderProps,\n} from './components/atoms/SnappingSlider';\nexport { Badge, BadgeNativeProps } from './components/atoms/Badge';\nexport { Snackbar, SnackbarNativeProps } from './components/molecules/Snackbar';\nexport { DatePicker } from './components/molecules/DatePicker';\nexport { DateTimePicker } from './components/molecules/DateTimePicker';\nexport { Avatar } from './components/atoms/Avatar';\nexport { Calendar } from './components/molecules/Calendar';\nexport { DateTimeSelector } from './components/molecules/DateTimeSelector';\nexport { ModalGroupManager, ModalView, ModalLifecycleHandler, useModalManager, IBaseModal } from './components/atoms/Modal';\n"],"file":"index.js"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tecsinapse/react-native-kit",
|
|
3
3
|
"description": "TecSinapse React Native components",
|
|
4
|
-
"version": "1.12.
|
|
4
|
+
"version": "1.12.8",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "MIT",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@emotion/native": "^11.0.0",
|
|
15
15
|
"@emotion/react": "^11.4.1",
|
|
16
|
-
"@tecsinapse/react-core": "^1.12.
|
|
16
|
+
"@tecsinapse/react-core": "^1.12.5"
|
|
17
17
|
},
|
|
18
18
|
"repository": {
|
|
19
19
|
"type": "git",
|
|
@@ -27,7 +27,12 @@
|
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": ">=16.8.0",
|
|
29
29
|
"react-native": ">=0.64.0",
|
|
30
|
-
"react-native-
|
|
30
|
+
"react-native-safe-area-context": "^3.1.9",
|
|
31
|
+
"react-native-vector-icons": ">=8.1.0",
|
|
32
|
+
"uuid": "^8.3.2"
|
|
31
33
|
},
|
|
32
|
-
"
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/uuid": "^8.3.3"
|
|
36
|
+
},
|
|
37
|
+
"gitHead": "ce86b8c8b3e7c09e0fd86689418b540010f1419b"
|
|
33
38
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import styled from '@emotion/native';
|
|
2
|
-
import { StyleProps } from '@tecsinapse/react-core';
|
|
2
|
+
import { RFValueStr, StyleProps } from '@tecsinapse/react-core';
|
|
3
3
|
import { PressableProps, ViewProps } from 'react-native';
|
|
4
4
|
|
|
5
5
|
export const StyledView = styled.View<ViewProps & Partial<StyleProps>>`
|
|
@@ -16,7 +16,7 @@ export const TabContainer = styled.Pressable<
|
|
|
16
16
|
flex: 1;
|
|
17
17
|
margin-horizontal: ${({ theme }) => theme.spacing.mili};
|
|
18
18
|
padding-top: ${({ theme }) => theme.spacing.deca};
|
|
19
|
-
border-top-width: ${({ selected }) => (selected ? '2px' : 0)};
|
|
19
|
+
border-top-width: ${({ selected }) => (selected ? RFValueStr('2px') : 0)};
|
|
20
20
|
border-color: ${({ theme }) => theme.color.primary.medium};
|
|
21
21
|
align-items: center;
|
|
22
22
|
justify-content: flex-end;
|
|
@@ -26,7 +26,7 @@ export const TabContent = styled.View<ViewProps & Partial<StyleProps>>`
|
|
|
26
26
|
aspect-ratio: 1;
|
|
27
27
|
justify-content: center;
|
|
28
28
|
align-items: center;
|
|
29
|
-
min-height: 48px;
|
|
29
|
+
min-height: ${RFValueStr('48px')};
|
|
30
30
|
background-color: ${({ theme }) => theme.color.primary.xlight};
|
|
31
31
|
border-radius: ${({ theme }) => theme.borderRadius['mili']};
|
|
32
32
|
`;
|
|
@@ -2,13 +2,14 @@ import styled from '@emotion/native';
|
|
|
2
2
|
import {
|
|
3
3
|
InputContainer,
|
|
4
4
|
InputElement,
|
|
5
|
-
|
|
5
|
+
RFValueStr,
|
|
6
|
+
StyleProps
|
|
6
7
|
} from '@tecsinapse/react-core';
|
|
7
8
|
import { Font, fontStyles } from '../Text/styled';
|
|
8
9
|
import { InputNativeProps } from './Input';
|
|
9
10
|
|
|
10
11
|
export const StyledInputContainer = styled(InputContainer)<Partial<StyleProps>>`
|
|
11
|
-
min-height: 50px;
|
|
12
|
+
min-height: ${RFValueStr('50px')};
|
|
12
13
|
`;
|
|
13
14
|
|
|
14
15
|
const StyledNativeInputBase = styled(InputElement)<
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { FC, ReactElement, useState } from 'react';
|
|
2
|
+
import { Modal as RNModal, ModalProps } from 'react-native';
|
|
3
|
+
import { createModalLifecycleHandler } from './ModalLifecycleHandler';
|
|
4
|
+
import { IBaseModal } from './ui/types';
|
|
5
|
+
|
|
6
|
+
export const modalLifecycle = createModalLifecycleHandler()
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* It's responsable for rendering all the modal components.
|
|
10
|
+
*
|
|
11
|
+
* @param param0
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
export const ModalGroupManager: FC<ModalProps> = ({ children, ...others }) => {
|
|
15
|
+
|
|
16
|
+
modalLifecycle.attach(useState<ReactElement<IBaseModal>[]>([]))
|
|
17
|
+
const _render = modalLifecycle.render()
|
|
18
|
+
const hasModals = _render.length > 0
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
{children}
|
|
23
|
+
<RNModal transparent statusBarTranslucent animationType='none' visible={hasModals} {...others}>
|
|
24
|
+
{_render}
|
|
25
|
+
</RNModal>
|
|
26
|
+
</>
|
|
27
|
+
)
|
|
28
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import React, { Dispatch, ReactElement } from "react"
|
|
2
|
+
import { IBaseModal } from "./ui/types"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* It Represents a node (usually a modal component) in the modal's lifecycle handler.
|
|
6
|
+
*/
|
|
7
|
+
interface ModalNode {
|
|
8
|
+
id: string
|
|
9
|
+
visible?: boolean
|
|
10
|
+
lastVisualization?: Date
|
|
11
|
+
modal: () => ReactElement<IBaseModal>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Manage all modal's lifecycle.
|
|
16
|
+
*/
|
|
17
|
+
export class ModalLifecycleHandler {
|
|
18
|
+
|
|
19
|
+
nodeGroup: Map<string, ModalNode>
|
|
20
|
+
state: [ReactElement<IBaseModal>[], Dispatch<ReactElement<IBaseModal>[]>] | undefined
|
|
21
|
+
|
|
22
|
+
constructor() {
|
|
23
|
+
this.nodeGroup = new Map()
|
|
24
|
+
this.state = undefined
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Holds the ModalGroupManager state.
|
|
29
|
+
*
|
|
30
|
+
* @param state
|
|
31
|
+
*/
|
|
32
|
+
public attach = (state: [ReactElement<IBaseModal>[], Dispatch<ReactElement<IBaseModal>[]>]) => {
|
|
33
|
+
this.state = state
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Updates all the modal components.
|
|
38
|
+
*/
|
|
39
|
+
public update = () => {
|
|
40
|
+
const nodes = Array.from(this.nodeGroup.values())
|
|
41
|
+
.filter(node => node.visible || !!node.lastVisualization)
|
|
42
|
+
.sort((nodeA, nodeB) => (nodeA.lastVisualization?.getTime() || 0) - (nodeB.lastVisualization?.getTime() || 0))
|
|
43
|
+
.map((node, index, filteredNodes) => {
|
|
44
|
+
let modalElement = node.modal()
|
|
45
|
+
let { props } = modalElement
|
|
46
|
+
return React.cloneElement(modalElement, {
|
|
47
|
+
...props,
|
|
48
|
+
key: node.id,
|
|
49
|
+
visible: node.visible,
|
|
50
|
+
isLastShown: filteredNodes.length - 1 === index,
|
|
51
|
+
close: () => this.close(node.id),
|
|
52
|
+
onClose: () => {
|
|
53
|
+
this.remove(node.id)
|
|
54
|
+
props.onClose?.()
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const [, updateState ] = this.state || []
|
|
60
|
+
updateState?.(nodes)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Renders all selected modals.
|
|
65
|
+
*
|
|
66
|
+
* @returns
|
|
67
|
+
*/
|
|
68
|
+
public render = (): ReactElement<IBaseModal>[] => {
|
|
69
|
+
const [ modals ] = this.state || []
|
|
70
|
+
return modals || []
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Tells to the lifecycle handler that a modal component needs to be handled.
|
|
75
|
+
*
|
|
76
|
+
* @param id
|
|
77
|
+
* @param modal
|
|
78
|
+
* @returns
|
|
79
|
+
*/
|
|
80
|
+
public sync = (id: string, modal: () => ReactElement<IBaseModal>) => {
|
|
81
|
+
if (this.nodeGroup.has(id)) {
|
|
82
|
+
const savedNode = this.nodeGroup.get(id)
|
|
83
|
+
savedNode && this.nodeGroup.set(id, { ...savedNode, modal })
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
this.nodeGroup.set(id, { id, modal })
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Destroy a modal from the lifecycle handler.
|
|
91
|
+
*
|
|
92
|
+
* @param id
|
|
93
|
+
*/
|
|
94
|
+
public destroy = (id: string) => {
|
|
95
|
+
this.nodeGroup.delete(id)
|
|
96
|
+
this.update()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Removes a modal from the rendering stack. It tells to the lifecycle handler that a modal
|
|
101
|
+
* component is no longer used by the application.
|
|
102
|
+
*
|
|
103
|
+
* @param id
|
|
104
|
+
*/
|
|
105
|
+
private remove = (id: string) => {
|
|
106
|
+
const savedNode = this.nodeGroup.get(id)
|
|
107
|
+
savedNode && this.nodeGroup.set(id, { ...savedNode, lastVisualization: undefined })
|
|
108
|
+
this.update()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Makes a modal appears.
|
|
113
|
+
*
|
|
114
|
+
* @param id
|
|
115
|
+
*/
|
|
116
|
+
public show = (id: string) => {
|
|
117
|
+
const savedNode = this.nodeGroup.get(id)
|
|
118
|
+
savedNode && this.nodeGroup.set(id, { ...savedNode, visible: true, lastVisualization: new Date() })
|
|
119
|
+
this.update()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Makes a modal disappears.
|
|
124
|
+
*
|
|
125
|
+
* @param id
|
|
126
|
+
*/
|
|
127
|
+
public close = (id: string) => {
|
|
128
|
+
const savedNode = this.nodeGroup.get(id)
|
|
129
|
+
savedNode && this.nodeGroup.set(id, { ...savedNode, visible: false })
|
|
130
|
+
this.update()
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Creates a new ModalLifecycleHandlere instance.
|
|
136
|
+
*
|
|
137
|
+
* @returns
|
|
138
|
+
*/
|
|
139
|
+
export const createModalLifecycleHandler = () => {
|
|
140
|
+
return new ModalLifecycleHandler()
|
|
141
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { BoxContent } from "@tecsinapse/react-core";
|
|
2
|
+
import React, { FC, useCallback, useEffect, useRef, useState } from "react";
|
|
3
|
+
import { Animated, Easing, Keyboard, KeyboardAvoidingView, LayoutChangeEvent, Pressable } from "react-native";
|
|
4
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
5
|
+
import { BackDropView, CloseBar, StyledPressableBackDrop } from "./styled";
|
|
6
|
+
import { IBaseModal } from "./types";
|
|
7
|
+
|
|
8
|
+
const BACKDROP_ALPHA = .65
|
|
9
|
+
const INTERPOLATION_STEPS = 10
|
|
10
|
+
const INTERPOLATION_DURATION = 195 //ms
|
|
11
|
+
const OPACITY_DURATION = 25 //ms
|
|
12
|
+
|
|
13
|
+
export const ModalView: FC<IBaseModal> = ({
|
|
14
|
+
children,
|
|
15
|
+
visible,
|
|
16
|
+
BoxComponent = BoxContent,
|
|
17
|
+
frozen,
|
|
18
|
+
isLastShown,
|
|
19
|
+
close,
|
|
20
|
+
onClose
|
|
21
|
+
}) => {
|
|
22
|
+
|
|
23
|
+
const { bottom } = useSafeAreaInsets()
|
|
24
|
+
const [ ready, setReady ] = useState(false)
|
|
25
|
+
const [ keyboardOpened, setKeyboardOpened ] = useState(false)
|
|
26
|
+
const [ boxHeight, setBoxHeight ] = useState(0)
|
|
27
|
+
const backgroundCarrier = useRef(new Animated.Value(0)).current
|
|
28
|
+
const translationCarrier = useRef(new Animated.Value(0)).current
|
|
29
|
+
const opacityCarrier = useRef(new Animated.Value(0)).current
|
|
30
|
+
const offset = isLastShown && keyboardOpened ? 0 : bottom
|
|
31
|
+
|
|
32
|
+
const show = useCallback(() => {
|
|
33
|
+
Animated.sequence([
|
|
34
|
+
Animated.timing(backgroundCarrier, {
|
|
35
|
+
toValue: INTERPOLATION_STEPS,
|
|
36
|
+
duration: INTERPOLATION_DURATION,
|
|
37
|
+
easing: Easing.out(Easing.circle),
|
|
38
|
+
useNativeDriver: false
|
|
39
|
+
}),
|
|
40
|
+
Animated.timing(opacityCarrier, {
|
|
41
|
+
toValue: 1,
|
|
42
|
+
duration: OPACITY_DURATION,
|
|
43
|
+
useNativeDriver: true
|
|
44
|
+
}),
|
|
45
|
+
Animated.timing(translationCarrier, {
|
|
46
|
+
toValue: 0,
|
|
47
|
+
duration: INTERPOLATION_DURATION,
|
|
48
|
+
easing: Easing.out(Easing.circle),
|
|
49
|
+
useNativeDriver: true
|
|
50
|
+
})
|
|
51
|
+
]).start()
|
|
52
|
+
}, [])
|
|
53
|
+
|
|
54
|
+
const hide = useCallback((to: number) => {
|
|
55
|
+
Animated.sequence([
|
|
56
|
+
Animated.parallel([
|
|
57
|
+
Animated.timing(translationCarrier, {
|
|
58
|
+
toValue: to,
|
|
59
|
+
duration: INTERPOLATION_DURATION,
|
|
60
|
+
easing: Easing.out(Easing.circle),
|
|
61
|
+
useNativeDriver: true
|
|
62
|
+
}),
|
|
63
|
+
Animated.timing(opacityCarrier, {
|
|
64
|
+
toValue: 0,
|
|
65
|
+
duration: INTERPOLATION_DURATION,
|
|
66
|
+
useNativeDriver: true
|
|
67
|
+
})
|
|
68
|
+
]),
|
|
69
|
+
Animated.timing(backgroundCarrier, {
|
|
70
|
+
toValue: 0,
|
|
71
|
+
duration: INTERPOLATION_DURATION,
|
|
72
|
+
easing: Easing.out(Easing.circle),
|
|
73
|
+
useNativeDriver: false
|
|
74
|
+
}),
|
|
75
|
+
]).start(onClose)
|
|
76
|
+
}, [onClose])
|
|
77
|
+
|
|
78
|
+
const backgroundInterpolation = backgroundCarrier.interpolate({
|
|
79
|
+
inputRange: [0, INTERPOLATION_STEPS],
|
|
80
|
+
outputRange: ['rgba(0, 0, 0, 0)', `rgba(0, 0, 0, ${BACKDROP_ALPHA})`]
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const handleBoxLayoutChanges = useCallback((lce: LayoutChangeEvent) => {
|
|
84
|
+
let boxHeightEvent = lce.nativeEvent.layout.height
|
|
85
|
+
setBoxHeight(boxHeightEvent)
|
|
86
|
+
|
|
87
|
+
if (visible && !ready) {
|
|
88
|
+
translationCarrier.setValue(boxHeightEvent)
|
|
89
|
+
setReady(true)
|
|
90
|
+
}
|
|
91
|
+
}, [show, ready, visible, setReady])
|
|
92
|
+
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (visible && ready) requestAnimationFrame(() => show())
|
|
95
|
+
if (!visible && !ready) {
|
|
96
|
+
Keyboard.dismiss()
|
|
97
|
+
requestAnimationFrame(() => hide(boxHeight))
|
|
98
|
+
}
|
|
99
|
+
if (!visible && ready) setReady(false)
|
|
100
|
+
}, [ready, visible])
|
|
101
|
+
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
const showEvent = Keyboard.addListener('keyboardDidShow', () => setKeyboardOpened(true))
|
|
104
|
+
const hideEvent = Keyboard.addListener('keyboardDidHide', () => setKeyboardOpened(false))
|
|
105
|
+
return () => {
|
|
106
|
+
showEvent.remove()
|
|
107
|
+
hideEvent.remove()
|
|
108
|
+
}
|
|
109
|
+
}, [])
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<StyledPressableBackDrop onPress={!frozen ? close : undefined}>
|
|
113
|
+
<BackDropView style={{ backgroundColor: backgroundInterpolation }}>
|
|
114
|
+
<KeyboardAvoidingView enabled={isLastShown} behavior="padding">
|
|
115
|
+
<Animated.View style={{ opacity: opacityCarrier, transform: [{ translateY: translationCarrier }]}}>
|
|
116
|
+
<Pressable>
|
|
117
|
+
<BoxComponent onLayout={handleBoxLayoutChanges} style={{ paddingBottom: offset }} variant="bottom">
|
|
118
|
+
<CloseBar/>
|
|
119
|
+
{children}
|
|
120
|
+
</BoxComponent>
|
|
121
|
+
</Pressable>
|
|
122
|
+
</Animated.View>
|
|
123
|
+
</KeyboardAvoidingView>
|
|
124
|
+
</BackDropView>
|
|
125
|
+
</StyledPressableBackDrop>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import styled from "@emotion/native";
|
|
2
|
+
import { RFValueStr, StyleProps } from "@tecsinapse/react-core";
|
|
3
|
+
import { Animated } from "react-native";
|
|
4
|
+
|
|
5
|
+
export const StyledPressableBackDrop = styled.Pressable<Partial<StyleProps>>`
|
|
6
|
+
flex: 1;
|
|
7
|
+
position: absolute;
|
|
8
|
+
width: 100%;
|
|
9
|
+
height: 100%;
|
|
10
|
+
`
|
|
11
|
+
|
|
12
|
+
export const BackDropView = styled(Animated.View)<Partial<StyleProps>>`
|
|
13
|
+
justify-content: flex-end;
|
|
14
|
+
flex: 1;
|
|
15
|
+
`
|
|
16
|
+
|
|
17
|
+
export const CloseBar = styled.View<Partial<StyleProps>>`
|
|
18
|
+
background-color: ${({ theme }) => theme.color.secondary.light};
|
|
19
|
+
border-radius: ${RFValueStr('10px')};
|
|
20
|
+
margin: ${`${RFValueStr('5px')} auto`};
|
|
21
|
+
width: ${RFValueStr('42px')};
|
|
22
|
+
height: ${RFValueStr('5px')};
|
|
23
|
+
`
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Defines a modal interface and allows you implement your own modal component.
|
|
4
|
+
*/
|
|
5
|
+
export interface IBaseModal {
|
|
6
|
+
visible?: boolean
|
|
7
|
+
BoxComponent?: React.FC<any>
|
|
8
|
+
frozen?: boolean
|
|
9
|
+
isLastShown?: boolean
|
|
10
|
+
close?: () => void
|
|
11
|
+
onClose?: () => void
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ReactElement, useCallback, useEffect, useState } from "react"
|
|
2
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
3
|
+
import { modalLifecycle } from "./ModalGroupManager"
|
|
4
|
+
import { IBaseModal } from "./ui/types"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Use this hook to tell the modal lifecycle handler that you want to add
|
|
8
|
+
* a new modal component.
|
|
9
|
+
*
|
|
10
|
+
* @param id
|
|
11
|
+
* @param modal
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
export const useModalManager = (modal: () => ReactElement<IBaseModal>) => {
|
|
15
|
+
|
|
16
|
+
const [id] = useState(uuidv4())
|
|
17
|
+
modalLifecycle.sync(id, modal)
|
|
18
|
+
|
|
19
|
+
const show = useCallback(() => {
|
|
20
|
+
modalLifecycle.show(id)
|
|
21
|
+
}, [id])
|
|
22
|
+
|
|
23
|
+
const close = useCallback(() => {
|
|
24
|
+
modalLifecycle.close(id)
|
|
25
|
+
}, [id])
|
|
26
|
+
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
return () => modalLifecycle.destroy(id)
|
|
29
|
+
}, [])
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
show,
|
|
33
|
+
close
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -7,7 +7,8 @@ import {
|
|
|
7
7
|
InputContainerProps,
|
|
8
8
|
PressableSurface,
|
|
9
9
|
PressableSurfaceProps,
|
|
10
|
-
|
|
10
|
+
RFValueStr,
|
|
11
|
+
StyleProps
|
|
11
12
|
} from '@tecsinapse/react-core';
|
|
12
13
|
import { ActivityIndicator, ModalProps, View, ViewProps } from 'react-native';
|
|
13
14
|
import { Input, InputNativeProps } from '../Input';
|
|
@@ -46,7 +47,7 @@ export const Header = styled(View)<ViewProps & Partial<StyleProps>>`
|
|
|
46
47
|
align-items: center;
|
|
47
48
|
justify-content: space-between;
|
|
48
49
|
padding: ${({ theme }) => theme.spacing.deca};
|
|
49
|
-
height: 75px;
|
|
50
|
+
height: ${RFValueStr('75px')};
|
|
50
51
|
`;
|
|
51
52
|
|
|
52
53
|
export const CloseButton = styled(Button)<ButtonProps & Partial<StyleProps>>`
|
|
@@ -66,7 +67,7 @@ export const SearchBar = styled(Input)<InputNativeProps & Partial<StyleProps>>`
|
|
|
66
67
|
export const ListItem = styled(PressableSurface)<
|
|
67
68
|
PressableSurfaceProps & Partial<StyleProps>
|
|
68
69
|
>`
|
|
69
|
-
border-bottom-width: 1px;
|
|
70
|
+
border-bottom-width: ${RFValueStr('1px')};
|
|
70
71
|
border-color: ${({ theme }) => theme.color.secondary.light};
|
|
71
72
|
padding-vertical: ${({ theme }) => theme.spacing.mili};
|
|
72
73
|
padding-horizontal: ${({ theme }) => theme.spacing.deca};
|
package/src/index.ts
CHANGED
|
@@ -26,3 +26,4 @@ export { DateTimePicker } from './components/molecules/DateTimePicker';
|
|
|
26
26
|
export { Avatar } from './components/atoms/Avatar';
|
|
27
27
|
export { Calendar } from './components/molecules/Calendar';
|
|
28
28
|
export { DateTimeSelector } from './components/molecules/DateTimeSelector';
|
|
29
|
+
export { ModalGroupManager, ModalView, ModalLifecycleHandler, useModalManager, IBaseModal } from './components/atoms/Modal';
|