@fountain-ui/core 2.0.0-beta.82 → 2.0.0-beta.83

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.
Files changed (38) hide show
  1. package/build/commonjs/Accordion/Accordion.js +9 -15
  2. package/build/commonjs/Accordion/Accordion.js.map +1 -1
  3. package/build/commonjs/Dialog/Dialog.js +59 -31
  4. package/build/commonjs/Dialog/Dialog.js.map +1 -1
  5. package/build/commonjs/Dialog/DialogProps.js.map +1 -1
  6. package/build/commonjs/Modal/AnimatedContainer/index.js +153 -0
  7. package/build/commonjs/Modal/AnimatedContainer/index.js.map +1 -0
  8. package/build/commonjs/Modal/Modal.js +41 -15
  9. package/build/commonjs/Modal/Modal.js.map +1 -1
  10. package/build/commonjs/Modal/ModalProps.js +12 -0
  11. package/build/commonjs/Modal/ModalProps.js.map +1 -1
  12. package/build/commonjs/Modal/index.js +8 -0
  13. package/build/commonjs/Modal/index.js.map +1 -1
  14. package/build/module/Accordion/Accordion.js +9 -15
  15. package/build/module/Accordion/Accordion.js.map +1 -1
  16. package/build/module/Dialog/Dialog.js +61 -31
  17. package/build/module/Dialog/Dialog.js.map +1 -1
  18. package/build/module/Dialog/DialogProps.js.map +1 -1
  19. package/build/module/Modal/AnimatedContainer/index.js +131 -0
  20. package/build/module/Modal/AnimatedContainer/index.js.map +1 -0
  21. package/build/module/Modal/Modal.js +41 -14
  22. package/build/module/Modal/Modal.js.map +1 -1
  23. package/build/module/Modal/ModalProps.js +5 -0
  24. package/build/module/Modal/ModalProps.js.map +1 -1
  25. package/build/module/Modal/index.js +1 -0
  26. package/build/module/Modal/index.js.map +1 -1
  27. package/build/typescript/Dialog/DialogProps.d.ts +6 -0
  28. package/build/typescript/Modal/AnimatedContainer/index.d.ts +5 -0
  29. package/build/typescript/Modal/ModalProps.d.ts +41 -8
  30. package/build/typescript/Modal/index.d.ts +2 -1
  31. package/package.json +2 -2
  32. package/src/Accordion/Accordion.tsx +6 -11
  33. package/src/Dialog/Dialog.tsx +70 -32
  34. package/src/Dialog/DialogProps.ts +7 -0
  35. package/src/Modal/AnimatedContainer/index.tsx +156 -0
  36. package/src/Modal/Modal.tsx +42 -18
  37. package/src/Modal/ModalProps.ts +51 -10
  38. package/src/Modal/index.ts +2 -1
@@ -1 +1 @@
1
- {"version":3,"names":["React","View","css","StyleSheet","useElevationStyle","Slide","SimpleBackdrop","defaultEnterDuration","defaultExitDuration","createModalCloseEvent","reason","metadata","Modal","props","animationStyle","backdropOpacity","children","disableAnimation","enterDuration","exitDuration","hideBackdrop","onClose","style","visible","otherProps","handleBackdropPress","exited","setExited","useState","elevationStyle","absoluteFill"],"sources":["Modal.tsx"],"sourcesContent":["import React from 'react';\nimport { View } from 'react-native';\nimport { css, StyleSheet } from '../styles';\nimport { useElevationStyle } from '../hooks';\nimport Slide from '../Slide';\nimport SimpleBackdrop from './SimpleBackdrop';\nimport type ModalProps from './ModalProps';\n\nexport type ModalCloseReasonType = 'OUTSIDE_PRESS' | 'HARDWARE_BACK_PRESS' | 'CLOSE_BUTTON_PRESS' | 'UNKNOWN';\n\nexport interface ModalCloseEvent {\n metadata: {\n reason: ModalCloseReasonType\n };\n}\n\nconst defaultEnterDuration = 300;\nconst defaultExitDuration = 150;\n\nexport const createModalCloseEvent = (reason: ModalCloseReasonType) => ({\n metadata: {\n reason,\n },\n});\n\nexport default function Modal(props: ModalProps) {\n const {\n animationStyle,\n backdropOpacity = 0.5,\n children,\n disableAnimation = false,\n enterDuration = defaultEnterDuration,\n exitDuration = defaultExitDuration,\n hideBackdrop = false,\n onClose,\n style,\n visible,\n ...otherProps\n } = props;\n\n const handleBackdropPress = () => {\n if (onClose) {\n onClose(createModalCloseEvent('OUTSIDE_PRESS'));\n }\n };\n\n const [exited, setExited] = React.useState(true);\n\n const elevationStyle = useElevationStyle(6);\n\n if (!visible) {\n if (disableAnimation || exited) {\n return null;\n }\n }\n\n return (\n <View\n style={css([\n StyleSheet.absoluteFill,\n elevationStyle,\n style,\n ])}\n {...otherProps}\n >\n {(hideBackdrop || !visible) ? null : (\n <SimpleBackdrop\n onPress={handleBackdropPress}\n opacity={backdropOpacity}\n />\n )}\n\n {!disableAnimation ? (\n <Slide\n appear={visible}\n enterDuration={enterDuration}\n exitDuration={exitDuration}\n onEnter={() => setExited(false)}\n onExited={() => setExited(true)}\n style={animationStyle}\n >\n {children}\n </Slide>\n ) : children}\n </View>\n );\n};\n"],"mappings":";;AAAA,OAAOA,KAAP,MAAkB,OAAlB;AACA,SAASC,IAAT,QAAqB,cAArB;AACA,SAASC,GAAT,EAAcC,UAAd,QAAgC,WAAhC;AACA,SAASC,iBAAT,QAAkC,UAAlC;AACA,OAAOC,KAAP,MAAkB,UAAlB;AACA,OAAOC,cAAP,MAA2B,kBAA3B;AAWA,MAAMC,oBAAoB,GAAG,GAA7B;AACA,MAAMC,mBAAmB,GAAG,GAA5B;AAEA,OAAO,MAAMC,qBAAqB,GAAIC,MAAD,KAAmC;EACpEC,QAAQ,EAAE;IACND;EADM;AAD0D,CAAnC,CAA9B;AAMP,eAAe,SAASE,KAAT,CAAeC,KAAf,EAAkC;EAC7C,MAAM;IACFC,cADE;IAEFC,eAAe,GAAG,GAFhB;IAGFC,QAHE;IAIFC,gBAAgB,GAAG,KAJjB;IAKFC,aAAa,GAAGX,oBALd;IAMFY,YAAY,GAAGX,mBANb;IAOFY,YAAY,GAAG,KAPb;IAQFC,OARE;IASFC,KATE;IAUFC,OAVE;IAWF,GAAGC;EAXD,IAYFX,KAZJ;;EAcA,MAAMY,mBAAmB,GAAG,MAAM;IAC9B,IAAIJ,OAAJ,EAAa;MACTA,OAAO,CAACZ,qBAAqB,CAAC,eAAD,CAAtB,CAAP;IACH;EACJ,CAJD;;EAMA,MAAM,CAACiB,MAAD,EAASC,SAAT,IAAsB3B,KAAK,CAAC4B,QAAN,CAAe,IAAf,CAA5B;EAEA,MAAMC,cAAc,GAAGzB,iBAAiB,CAAC,CAAD,CAAxC;;EAEA,IAAI,CAACmB,OAAL,EAAc;IACV,IAAIN,gBAAgB,IAAIS,MAAxB,EAAgC;MAC5B,OAAO,IAAP;IACH;EACJ;;EAED,oBACI,oBAAC,IAAD;IACI,KAAK,EAAExB,GAAG,CAAC,CACPC,UAAU,CAAC2B,YADJ,EAEPD,cAFO,EAGPP,KAHO,CAAD;EADd,GAMQE,UANR,GAQMJ,YAAY,IAAI,CAACG,OAAlB,GAA6B,IAA7B,gBACG,oBAAC,cAAD;IACI,OAAO,EAAEE,mBADb;IAEI,OAAO,EAAEV;EAFb,EATR,EAeK,CAACE,gBAAD,gBACG,oBAAC,KAAD;IACI,MAAM,EAAEM,OADZ;IAEI,aAAa,EAAEL,aAFnB;IAGI,YAAY,EAAEC,YAHlB;IAII,OAAO,EAAE,MAAMQ,SAAS,CAAC,KAAD,CAJ5B;IAKI,QAAQ,EAAE,MAAMA,SAAS,CAAC,IAAD,CAL7B;IAMI,KAAK,EAAEb;EANX,GAQKE,QARL,CADH,GAWGA,QA1BR,CADJ;AA8BH;AAAA"}
1
+ {"version":3,"names":["React","View","css","StyleSheet","useElevationStyle","AnimatedContainer","SimpleBackdrop","createModalCloseEvent","reason","metadata","Modal","props","animationStyle","backdropOpacity","children","closeAnimation","disableAnimation","hideBackdrop","initialOpacity","initialTranslateY","onClose","onEnter","onEnterProp","onEntered","onEnteredProp","onExit","onExitProp","onExited","onExitedProp","openAnimation","style","visible","otherProps","handleBackdropPress","exited","setExited","useState","elevationStyle","absoluteFill"],"sources":["Modal.tsx"],"sourcesContent":["import React from 'react';\nimport { View } from 'react-native';\nimport { css, StyleSheet } from '../styles';\nimport { useElevationStyle } from '../hooks';\nimport type ModalProps from './ModalProps';\nimport AnimatedContainer from './AnimatedContainer';\nimport SimpleBackdrop from './SimpleBackdrop';\n\nexport type ModalCloseReasonType = 'OUTSIDE_PRESS' | 'HARDWARE_BACK_PRESS' | 'CLOSE_BUTTON_PRESS' | 'UNKNOWN';\n\nexport interface ModalCloseEvent {\n metadata: {\n reason: ModalCloseReasonType\n };\n}\n\nexport const createModalCloseEvent = (reason: ModalCloseReasonType) => ({\n metadata: {\n reason,\n },\n});\n\nexport default function Modal(props: ModalProps) {\n const {\n animationStyle,\n backdropOpacity = 0.5,\n children,\n closeAnimation,\n disableAnimation = false,\n hideBackdrop = false,\n initialOpacity,\n initialTranslateY,\n onClose,\n onEnter: onEnterProp,\n onEntered: onEnteredProp,\n onExit: onExitProp,\n onExited: onExitedProp,\n openAnimation,\n style,\n visible,\n ...otherProps\n } = props;\n\n const handleBackdropPress = () => {\n if (onClose) {\n onClose(createModalCloseEvent('OUTSIDE_PRESS'));\n }\n };\n\n const [exited, setExited] = React.useState(true);\n\n const elevationStyle = useElevationStyle(6);\n\n const onEnter = () => {\n setExited(false);\n onEnterProp?.();\n };\n\n const onEntered = () => {\n onEnteredProp?.();\n };\n\n const onExit = () => {\n onExitProp?.();\n };\n\n const onExited = () => {\n setExited(true);\n onExitedProp?.();\n };\n\n if (!visible) {\n if (disableAnimation || exited) {\n return null;\n }\n }\n\n return (\n <View\n style={css([\n StyleSheet.absoluteFill,\n elevationStyle,\n style,\n ])}\n {...otherProps}\n >\n {(!hideBackdrop && visible) ? (\n <SimpleBackdrop\n onPress={handleBackdropPress}\n opacity={backdropOpacity}\n />\n ) : null}\n\n {!disableAnimation ? (\n <AnimatedContainer\n children={children}\n closeAnimation={closeAnimation}\n initialOpacity={initialOpacity}\n initialTranslateY={initialTranslateY}\n onEnter={onEnter}\n onEntered={onEntered}\n onExit={onExit}\n onExited={onExited}\n openAnimation={openAnimation}\n style={animationStyle}\n visible={visible}\n />\n ) : children}\n </View>\n );\n};\n"],"mappings":";;AAAA,OAAOA,KAAP,MAAkB,OAAlB;AACA,SAASC,IAAT,QAAqB,cAArB;AACA,SAASC,GAAT,EAAcC,UAAd,QAAgC,WAAhC;AACA,SAASC,iBAAT,QAAkC,UAAlC;AAEA,OAAOC,iBAAP,MAA8B,qBAA9B;AACA,OAAOC,cAAP,MAA2B,kBAA3B;AAUA,OAAO,MAAMC,qBAAqB,GAAIC,MAAD,KAAmC;EACpEC,QAAQ,EAAE;IACND;EADM;AAD0D,CAAnC,CAA9B;AAMP,eAAe,SAASE,KAAT,CAAeC,KAAf,EAAkC;EAC7C,MAAM;IACFC,cADE;IAEFC,eAAe,GAAG,GAFhB;IAGFC,QAHE;IAIFC,cAJE;IAKFC,gBAAgB,GAAG,KALjB;IAMFC,YAAY,GAAG,KANb;IAOFC,cAPE;IAQFC,iBARE;IASFC,OATE;IAUFC,OAAO,EAAEC,WAVP;IAWFC,SAAS,EAAEC,aAXT;IAYFC,MAAM,EAAEC,UAZN;IAaFC,QAAQ,EAAEC,YAbR;IAcFC,aAdE;IAeFC,KAfE;IAgBFC,OAhBE;IAiBF,GAAGC;EAjBD,IAkBFrB,KAlBJ;;EAoBA,MAAMsB,mBAAmB,GAAG,MAAM;IAC9B,IAAIb,OAAJ,EAAa;MACTA,OAAO,CAACb,qBAAqB,CAAC,eAAD,CAAtB,CAAP;IACH;EACJ,CAJD;;EAMA,MAAM,CAAC2B,MAAD,EAASC,SAAT,IAAsBnC,KAAK,CAACoC,QAAN,CAAe,IAAf,CAA5B;EAEA,MAAMC,cAAc,GAAGjC,iBAAiB,CAAC,CAAD,CAAxC;;EAEA,MAAMiB,OAAO,GAAG,MAAM;IAClBc,SAAS,CAAC,KAAD,CAAT;IACAb,WAAW,SAAX,IAAAA,WAAW,WAAX,YAAAA,WAAW;EACd,CAHD;;EAKA,MAAMC,SAAS,GAAG,MAAM;IACpBC,aAAa,SAAb,IAAAA,aAAa,WAAb,YAAAA,aAAa;EAChB,CAFD;;EAIA,MAAMC,MAAM,GAAG,MAAM;IACjBC,UAAU,SAAV,IAAAA,UAAU,WAAV,YAAAA,UAAU;EACb,CAFD;;EAIA,MAAMC,QAAQ,GAAG,MAAM;IACnBQ,SAAS,CAAC,IAAD,CAAT;IACAP,YAAY,SAAZ,IAAAA,YAAY,WAAZ,YAAAA,YAAY;EACf,CAHD;;EAKA,IAAI,CAACG,OAAL,EAAc;IACV,IAAIf,gBAAgB,IAAIkB,MAAxB,EAAgC;MAC5B,OAAO,IAAP;IACH;EACJ;;EAED,oBACI,oBAAC,IAAD;IACI,KAAK,EAAEhC,GAAG,CAAC,CACPC,UAAU,CAACmC,YADJ,EAEPD,cAFO,EAGPP,KAHO,CAAD;EADd,GAMQE,UANR,GAQM,CAACf,YAAD,IAAiBc,OAAlB,gBACG,oBAAC,cAAD;IACI,OAAO,EAAEE,mBADb;IAEI,OAAO,EAAEpB;EAFb,EADH,GAKG,IAbR,EAeK,CAACG,gBAAD,gBACG,oBAAC,iBAAD;IACI,QAAQ,EAAEF,QADd;IAEI,cAAc,EAAEC,cAFpB;IAGI,cAAc,EAAEG,cAHpB;IAII,iBAAiB,EAAEC,iBAJvB;IAKI,OAAO,EAAEE,OALb;IAMI,SAAS,EAAEE,SANf;IAOI,MAAM,EAAEE,MAPZ;IAQI,QAAQ,EAAEE,QARd;IASI,aAAa,EAAEE,aATnB;IAUI,KAAK,EAAEjB,cAVX;IAWI,OAAO,EAAEmB;EAXb,EADH,GAcGjB,QA7BR,CADJ;AAiCH;AAAA"}
@@ -1,2 +1,7 @@
1
+ export let ANIMATION_TYPE;
1
2
 
3
+ (function (ANIMATION_TYPE) {
4
+ ANIMATION_TYPE["SLIDE"] = "slide";
5
+ ANIMATION_TYPE["FADE"] = "fade";
6
+ })(ANIMATION_TYPE || (ANIMATION_TYPE = {}));
2
7
  //# sourceMappingURL=ModalProps.js.map
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["ModalProps.ts"],"sourcesContent":["import React from 'react';\nimport type { ViewProps } from 'react-native';\nimport type { ComponentProps, OverridableComponentProps } from '../types';\nimport { ModalCloseEvent } from './Modal';\n\nexport default interface ModalProps extends OverridableComponentProps<ViewProps, {\n /**\n * Style object provided to animation component.\n */\n animationStyle?: ComponentProps['style'];\n\n /**\n * Opacity for backdrop.\n * @default 0.5\n */\n backdropOpacity?: number;\n\n /**\n * A single child content element.\n */\n children: React.ReactElement;\n\n /**\n * If `true`, the animation is disabled.\n * @default false\n */\n disableAnimation?: boolean;\n\n /**\n * The number of milliseconds to enter animation.\n * @default 300\n */\n enterDuration?: number;\n\n /**\n * The number of milliseconds to exit animation.\n * @default 150\n */\n exitDuration?: number;\n\n /**\n * If `true`, the backdrop is not rendered.\n * @default false\n */\n hideBackdrop?: boolean;\n\n /**\n * Callback fired when the component requests to be closed.\n */\n onClose?: (event?: ModalCloseEvent) => void,\n\n /**\n * If `true`, the modal is visible.\n */\n visible: boolean;\n}> {}\n"],"mappings":""}
1
+ {"version":3,"names":["ANIMATION_TYPE"],"sources":["ModalProps.ts"],"sourcesContent":["import React from 'react';\nimport type { ViewProps } from 'react-native';\nimport { Animated } from 'react-native';\nimport type { ComponentProps, OverridableComponentProps } from '../types';\nimport { ModalCloseEvent } from './Modal';\n\nexport const enum ANIMATION_TYPE {\n SLIDE = 'slide',\n FADE = 'fade',\n}\n\nexport type AnimationUnit = Omit<Animated.TimingAnimationConfig, 'useNativeDriver'> & {\n /**\n * Type of animation used when the dialog opens and closes.\n */\n type: ANIMATION_TYPE;\n}\n\nexport default interface ModalProps extends OverridableComponentProps<ViewProps, {\n /**\n * Style object provided to animation component.\n */\n animationStyle?: ComponentProps['style'];\n\n /**\n * Opacity for backdrop.\n * @default 0.5\n */\n backdropOpacity?: number;\n\n /**\n * A single child content element.\n */\n children: React.ReactElement;\n\n /**\n * If `true`, the animation is disabled.\n * @default false\n */\n disableAnimation?: boolean;\n\n /**\n * Animation used when the modal closes.\n */\n closeAnimation?: AnimationUnit[] | undefined;\n\n /**\n * If `true`, the backdrop is not rendered.\n * @default false\n */\n hideBackdrop?: boolean;\n\n /**\n * Set the initial value of opacity for animating.\n */\n initialOpacity?: number | undefined;\n\n /**\n * Set the initial value of transition y for animating.\n */\n initialTranslateY?: number | undefined;\n\n /**\n * Callback fired when the component requests to be closed.\n */\n onClose?: (event?: ModalCloseEvent) => void;\n\n /**\n * Callback fired when the enter animation will start.\n */\n onEnter?: () => void | undefined;\n\n /**\n * Callback fired when the enter animation is completed.\n */\n onEntered?: () => void | undefined;\n\n /**\n * Callback fired when the exit animation will start.\n */\n onExit?: () => void | undefined;\n\n /**\n * Callback fired when the exit animation is completed.\n */\n onExited?: () => void | undefined;\n\n /**\n * Animation used when the modal opens.\n */\n openAnimation?: AnimationUnit[] | undefined;\n\n /**\n * If `true`, the modal is visible.\n */\n visible: boolean;\n}> {}\n"],"mappings":"AAMA,WAAkBA,cAAlB;;WAAkBA,c;EAAAA,c;EAAAA,c;GAAAA,c,KAAAA,c"}
@@ -1,2 +1,3 @@
1
1
  export { default, createModalCloseEvent } from './Modal';
2
+ export { ANIMATION_TYPE } from './ModalProps';
2
3
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["default","createModalCloseEvent"],"sources":["index.ts"],"sourcesContent":["export { default, createModalCloseEvent } from './Modal';\nexport type { ModalCloseEvent } from './Modal';\nexport type { default as ModalProps } from './ModalProps';\n"],"mappings":"AAAA,SAASA,OAAT,EAAkBC,qBAAlB,QAA+C,SAA/C"}
1
+ {"version":3,"names":["default","createModalCloseEvent","ANIMATION_TYPE"],"sources":["index.ts"],"sourcesContent":["export { default, createModalCloseEvent } from './Modal';\nexport type { ModalCloseEvent } from './Modal';\nexport type { default as ModalProps, AnimationUnit } from './ModalProps';\nexport { ANIMATION_TYPE } from './ModalProps';\n"],"mappings":"AAAA,SAASA,OAAT,EAAkBC,qBAAlB,QAA+C,SAA/C;AAGA,SAASC,cAAT,QAA+B,cAA/B"}
@@ -1,7 +1,13 @@
1
1
  import React from 'react';
2
2
  import type { ModalProps } from '../Modal';
3
3
  import type { OverridableComponentProps } from '../types';
4
+ import { ANIMATION_TYPE } from '../Modal';
4
5
  export default interface DialogProps extends OverridableComponentProps<ModalProps, {
6
+ /**
7
+ * Type of animation used when the dialog opens and closes.
8
+ * @default 'slide'
9
+ */
10
+ animationType?: ANIMATION_TYPE;
5
11
  /**
6
12
  * Dialog children, usually the included sub-components.
7
13
  */
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import type ModalProps from '../ModalProps';
3
+ declare type AnimatedContainerProps = Pick<ModalProps, 'children' | 'closeAnimation' | 'initialOpacity' | 'initialTranslateY' | 'onEnter' | 'onEntered' | 'onExit' | 'onExited' | 'openAnimation' | 'style' | 'visible'>;
4
+ export default function AnimatedContainer(props: AnimatedContainerProps): JSX.Element;
5
+ export {};
@@ -1,7 +1,18 @@
1
1
  import React from 'react';
2
2
  import type { ViewProps } from 'react-native';
3
+ import { Animated } from 'react-native';
3
4
  import type { ComponentProps, OverridableComponentProps } from '../types';
4
5
  import { ModalCloseEvent } from './Modal';
6
+ export declare const enum ANIMATION_TYPE {
7
+ SLIDE = "slide",
8
+ FADE = "fade"
9
+ }
10
+ export declare type AnimationUnit = Omit<Animated.TimingAnimationConfig, 'useNativeDriver'> & {
11
+ /**
12
+ * Type of animation used when the dialog opens and closes.
13
+ */
14
+ type: ANIMATION_TYPE;
15
+ };
5
16
  export default interface ModalProps extends OverridableComponentProps<ViewProps, {
6
17
  /**
7
18
  * Style object provided to animation component.
@@ -22,24 +33,46 @@ export default interface ModalProps extends OverridableComponentProps<ViewProps,
22
33
  */
23
34
  disableAnimation?: boolean;
24
35
  /**
25
- * The number of milliseconds to enter animation.
26
- * @default 300
27
- */
28
- enterDuration?: number;
29
- /**
30
- * The number of milliseconds to exit animation.
31
- * @default 150
36
+ * Animation used when the modal closes.
32
37
  */
33
- exitDuration?: number;
38
+ closeAnimation?: AnimationUnit[] | undefined;
34
39
  /**
35
40
  * If `true`, the backdrop is not rendered.
36
41
  * @default false
37
42
  */
38
43
  hideBackdrop?: boolean;
44
+ /**
45
+ * Set the initial value of opacity for animating.
46
+ */
47
+ initialOpacity?: number | undefined;
48
+ /**
49
+ * Set the initial value of transition y for animating.
50
+ */
51
+ initialTranslateY?: number | undefined;
39
52
  /**
40
53
  * Callback fired when the component requests to be closed.
41
54
  */
42
55
  onClose?: (event?: ModalCloseEvent) => void;
56
+ /**
57
+ * Callback fired when the enter animation will start.
58
+ */
59
+ onEnter?: () => void | undefined;
60
+ /**
61
+ * Callback fired when the enter animation is completed.
62
+ */
63
+ onEntered?: () => void | undefined;
64
+ /**
65
+ * Callback fired when the exit animation will start.
66
+ */
67
+ onExit?: () => void | undefined;
68
+ /**
69
+ * Callback fired when the exit animation is completed.
70
+ */
71
+ onExited?: () => void | undefined;
72
+ /**
73
+ * Animation used when the modal opens.
74
+ */
75
+ openAnimation?: AnimationUnit[] | undefined;
43
76
  /**
44
77
  * If `true`, the modal is visible.
45
78
  */
@@ -1,3 +1,4 @@
1
1
  export { default, createModalCloseEvent } from './Modal';
2
2
  export type { ModalCloseEvent } from './Modal';
3
- export type { default as ModalProps } from './ModalProps';
3
+ export type { default as ModalProps, AnimationUnit } from './ModalProps';
4
+ export { ANIMATION_TYPE } from './ModalProps';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fountain-ui/core",
3
- "version": "2.0.0-beta.82",
3
+ "version": "2.0.0-beta.83",
4
4
  "author": "Fountain-UI Team",
5
5
  "description": "React components that implement Tappytoon's Fountain Design.",
6
6
  "license": "MIT",
@@ -67,5 +67,5 @@
67
67
  "publishConfig": {
68
68
  "access": "public"
69
69
  },
70
- "gitHead": "f07255eea37343ebe04cff31bd0db4dd0a0d08e9"
70
+ "gitHead": "ade918bdbf6082ea7d61be5749d28ff0c6c3300b"
71
71
  }
@@ -26,14 +26,10 @@ type AccordionStyles = NamedStylesStringUnion<
26
26
  | 'contentView'
27
27
  >;
28
28
 
29
- const CONTENT_Y_START = 10;
30
- const CONTENT_Y_END = 0;
31
-
32
29
  const ROTATE_HIDE_DEGREE = 0;
33
30
  const ROTATE_SHOW_DEGREE = 180;
34
- const ANIMATION_CONFIG: Readonly<WithTimingConfig> = { duration: 300 };
35
- const INITIAL_EXPANDED_DELAY_MILLIS = 400;
36
- const CONTENT_TRANSLATEY_DELAY_MILLIS = 300;
31
+ const ANIMATION_CONFIG: Readonly<WithTimingConfig> = { duration: 200 };
32
+ const INITIAL_EXPANDED_DELAY_MILLIS = 100;
37
33
  const CONTENT_OPACITY_DELAY_MILLIS = 200;
38
34
 
39
35
  const useStyles: UseStyles<AccordionStyles> = function (): AccordionStyles {
@@ -47,6 +43,7 @@ const useStyles: UseStyles<AccordionStyles> = function (): AccordionStyles {
47
43
  paddingHorizontal: theme.spacing(4),
48
44
  paddingVertical: theme.spacing(3.5),
49
45
  alignItems: 'center',
46
+ height: 64,
50
47
  },
51
48
  titleColumn: { flexShrink: 1 },
52
49
  subtitle: {
@@ -85,7 +82,6 @@ export default function Accordion(props: AccordionProps) {
85
82
 
86
83
  const rotate = useSharedValue(ROTATE_HIDE_DEGREE);
87
84
  const animatedOpacity = useSharedValue(0);
88
- const animatedContentY = useSharedValue(CONTENT_Y_START);
89
85
 
90
86
  const animatedHeight = useSharedValue(0);
91
87
  const [contentHeight, setContentHeight] = useState(0);
@@ -100,7 +96,6 @@ export default function Accordion(props: AccordionProps) {
100
96
  }), []);
101
97
 
102
98
  const animatedContentStyle = useAnimatedStyle(() => ({
103
- transform: [{ translateY: animatedContentY.value }],
104
99
  opacity: animatedOpacity.value,
105
100
  }), []);
106
101
 
@@ -126,9 +121,6 @@ export default function Accordion(props: AccordionProps) {
126
121
  animatedOpacity.value = isExpanded
127
122
  ? withDelay(CONTENT_OPACITY_DELAY_MILLIS, withTiming(1, ANIMATION_CONFIG))
128
123
  : withTiming(0, ANIMATION_CONFIG);
129
- animatedContentY.value = isExpanded
130
- ? withDelay(CONTENT_TRANSLATEY_DELAY_MILLIS, withTiming(CONTENT_Y_END, ANIMATION_CONFIG))
131
- : withDelay(ANIMATION_CONFIG.duration as number, withTiming(CONTENT_Y_START, { duration: 0 }));
132
124
  }, [isExpanded, contentHeight]);
133
125
 
134
126
  return (
@@ -143,6 +135,7 @@ export default function Accordion(props: AccordionProps) {
143
135
  children={title}
144
136
  color={'textPrimary'}
145
137
  numberOfLines={1}
138
+ disableFontScaling={true}
146
139
  />
147
140
 
148
141
  {subTitle ? (
@@ -153,6 +146,8 @@ export default function Accordion(props: AccordionProps) {
153
146
  style={styles.subtitle}
154
147
  color={'tertiary'}
155
148
  children={subTitle}
149
+ numberOfLines={1}
150
+ disableFontScaling={true}
156
151
  />
157
152
  </React.Fragment>
158
153
  ) : null}
@@ -1,11 +1,9 @@
1
- import React, { useEffect } from 'react';
2
- import { useWindowDimensions, Animated, Easing } from 'react-native';
1
+ import React, { useMemo } from 'react';
2
+ import { useWindowDimensions } from 'react-native';
3
3
  import { css, NamedStylesStringUnion, UseStyles } from '@fountain-ui/styles';
4
4
  import Column from '../Column';
5
- import Modal from '../Modal';
5
+ import Modal, { ANIMATION_TYPE, AnimationUnit } from '../Modal';
6
6
  import Paper from '../Paper';
7
- import { useAnimatedValue } from '../hooks';
8
- import { isNotAndroid12 } from '../utils';
9
7
  import { useTheme } from '../styles';
10
8
  import type DialogProps from './DialogProps';
11
9
 
@@ -22,9 +20,6 @@ type DialogStyles = NamedStylesStringUnion<DialogStyleKeys>;
22
20
 
23
21
  const DIALOG_MAX_WIDTH = 328;
24
22
 
25
- const fadeDuration = 300;
26
- const fadeAnimationDelay = 50;
27
-
28
23
  const useStyles: UseStyles<DialogStyles> = function (): DialogStyles {
29
24
  const theme = useTheme();
30
25
 
@@ -40,6 +35,7 @@ const useStyles: UseStyles<DialogStyles> = function (): DialogStyles {
40
35
  zIndex: theme.zIndex.dialog,
41
36
  },
42
37
  paper: {
38
+ borderRadius: theme.shape.roundnessExtra,
43
39
  margin,
44
40
  maxWidth: DIALOG_MAX_WIDTH,
45
41
  overflow: 'hidden',
@@ -68,6 +64,7 @@ const useStyles: UseStyles<DialogStyles> = function (): DialogStyles {
68
64
 
69
65
  export default function Dialog(props: DialogProps) {
70
66
  const {
67
+ animationType = ANIMATION_TYPE.SLIDE,
71
68
  children,
72
69
  fullScreen = false,
73
70
  onClose,
@@ -78,38 +75,80 @@ export default function Dialog(props: DialogProps) {
78
75
  } = props;
79
76
 
80
77
  const styles = useStyles();
81
- const theme = useTheme();
82
- const animatedOpacity = useAnimatedValue(0);
83
-
84
- useEffect(() => {
85
- if(!fullScreen){
86
- Animated.timing(animatedOpacity, {
87
- toValue: visible ? 1 : 0,
88
- duration: fadeDuration,
89
- delay: visible ? fadeAnimationDelay : 0,
90
- easing: Easing.out(Easing.exp),
91
- useNativeDriver: isNotAndroid12,
92
- }).start();
78
+
79
+ const { height: screenHeight } = useWindowDimensions();
80
+
81
+ const closeAnimation = useMemo<AnimationUnit[]>(() => {
82
+ if (animationType === ANIMATION_TYPE.FADE) {
83
+ return [{
84
+ toValue: 0,
85
+ type: ANIMATION_TYPE.FADE,
86
+ }];
87
+ } else if (animationType === ANIMATION_TYPE.SLIDE && !fullScreen) {
88
+ return [
89
+ {
90
+ toValue: screenHeight,
91
+ type: ANIMATION_TYPE.SLIDE,
92
+ },
93
+ {
94
+ duration: 150,
95
+ toValue: 0,
96
+ type: ANIMATION_TYPE.FADE,
97
+ },
98
+ ];
99
+ }
100
+
101
+ return [{
102
+ duration: 150,
103
+ toValue: screenHeight,
104
+ type: ANIMATION_TYPE.SLIDE,
105
+ }];
106
+ }, [animationType, fullScreen, screenHeight]);
107
+
108
+ const openAnimation = useMemo<AnimationUnit[]>(() => {
109
+ if (animationType === ANIMATION_TYPE.FADE) {
110
+ return [{
111
+ toValue: 1,
112
+ type: ANIMATION_TYPE.FADE,
113
+ }];
114
+ } else if (animationType === ANIMATION_TYPE.SLIDE && !fullScreen) {
115
+ return [
116
+ {
117
+ toValue: 0,
118
+ type: ANIMATION_TYPE.SLIDE,
119
+ },
120
+ {
121
+ delay: 50,
122
+ duration: 150,
123
+ toValue: 1,
124
+ type: ANIMATION_TYPE.FADE,
125
+ },
126
+ ];
93
127
  }
94
- }, [fullScreen, visible]);
128
+
129
+ return [{
130
+ toValue: 0,
131
+ type: ANIMATION_TYPE.SLIDE,
132
+ }];
133
+ }, [animationType, fullScreen]);
134
+
135
+ const initialOpacity = animationType === ANIMATION_TYPE.SLIDE && fullScreen ? 1 : undefined;
136
+
137
+ const initialTranslateY = animationType === ANIMATION_TYPE.FADE ? 0 : undefined;
95
138
 
96
139
  return (
97
140
  <Modal
98
141
  animationStyle={fullScreen ? styles.animationFullScreen : styles.animation}
142
+ closeAnimation={closeAnimation}
143
+ initialOpacity={initialOpacity}
144
+ initialTranslateY={initialTranslateY}
99
145
  onClose={onClose}
100
- exitDuration={fullScreen ? 150 : 300}
146
+ openAnimation={openAnimation}
101
147
  visible={visible}
102
148
  style={styles.root}
103
149
  {...otherProps}
104
150
  >
105
- <Animated.View
106
- needsOffscreenAlphaCompositing={true}
107
- style={{
108
- height: fullScreen ? '100%' : 'auto',
109
- width: fullScreen ? '100%' : 'auto',
110
- opacity: fullScreen ? 1 : animatedOpacity,
111
- }}
112
- >
151
+ <React.Fragment>
113
152
  {topElement ? (
114
153
  <Column style={fullScreen ? undefined : styles.topElementSize}>
115
154
  <Column style={styles.topElementPosition}>
@@ -122,14 +161,13 @@ export default function Dialog(props: DialogProps) {
122
161
  elevation={6}
123
162
  square={fullScreen}
124
163
  style={css([
125
- { borderRadius: fullScreen ? undefined : theme.shape.roundnessExtra },
126
164
  fullScreen ? styles.paperFullScreen : styles.paper,
127
165
  style,
128
166
  ])}
129
167
  >
130
168
  {children}
131
169
  </Paper>
132
- </Animated.View>
170
+ </React.Fragment>
133
171
  </Modal>
134
172
  );
135
173
  };
@@ -1,8 +1,15 @@
1
1
  import React from 'react';
2
2
  import type { ModalProps } from '../Modal';
3
3
  import type { OverridableComponentProps } from '../types';
4
+ import { ANIMATION_TYPE } from '../Modal';
4
5
 
5
6
  export default interface DialogProps extends OverridableComponentProps<ModalProps, {
7
+ /**
8
+ * Type of animation used when the dialog opens and closes.
9
+ * @default 'slide'
10
+ */
11
+ animationType?: ANIMATION_TYPE;
12
+
6
13
  /**
7
14
  * Dialog children, usually the included sub-components.
8
15
  */
@@ -0,0 +1,156 @@
1
+ import React, { useCallback, useEffect } from 'react';
2
+ import { Animated, Easing, Platform, useWindowDimensions } from 'react-native';
3
+ import * as R from 'ramda';
4
+ import { useAnimatedValue } from '../../hooks';
5
+ import { isNotAndroid12 } from '../../utils';
6
+ import type ModalProps from '../ModalProps';
7
+ import { ANIMATION_TYPE, AnimationUnit } from '../ModalProps';
8
+
9
+ type AnimatedContainerProps = Pick<ModalProps,
10
+ | 'children'
11
+ | 'closeAnimation'
12
+ | 'initialOpacity'
13
+ | 'initialTranslateY'
14
+ | 'onEnter'
15
+ | 'onEntered'
16
+ | 'onExit'
17
+ | 'onExited'
18
+ | 'openAnimation'
19
+ | 'style'
20
+ | 'visible'>
21
+
22
+ const DEFAULT_ANIMATION_CONFIG = {
23
+ duration: 300,
24
+ useNativeDriver: isNotAndroid12,
25
+ };
26
+
27
+ export default function AnimatedContainer(props: AnimatedContainerProps) {
28
+ const {
29
+ children,
30
+ closeAnimation,
31
+ initialOpacity,
32
+ initialTranslateY,
33
+ onEnter,
34
+ onEntered,
35
+ onExit,
36
+ onExited,
37
+ openAnimation,
38
+ style,
39
+ visible,
40
+ } = props;
41
+
42
+ const { height: screenHeight } = useWindowDimensions();
43
+
44
+ const opacity = useAnimatedValue(initialOpacity ?? 0);
45
+
46
+ const translateY = useAnimatedValue(initialTranslateY ?? screenHeight);
47
+
48
+ const convertToCompositeAnimation = useCallback((animationUnit: AnimationUnit) => {
49
+ const {
50
+ type,
51
+ ...others
52
+ } = animationUnit;
53
+
54
+ switch (type) {
55
+ case ANIMATION_TYPE.FADE:
56
+ return Animated.timing(opacity, {
57
+ ...others,
58
+ useNativeDriver: isNotAndroid12,
59
+ });
60
+ case ANIMATION_TYPE.SLIDE:
61
+ default:
62
+ const easing = others.toValue === screenHeight
63
+ ? Easing.in(Easing.ease)
64
+ : Platform.OS === 'web'
65
+ ? Easing.bezier(0.16, 1, 0.3, 1)
66
+ : Easing.out(Easing.exp);
67
+
68
+ return Animated.timing(translateY, {
69
+ ...others,
70
+ easing,
71
+ useNativeDriver: isNotAndroid12,
72
+ });
73
+ }
74
+ }, [screenHeight]);
75
+
76
+ useEffect(() => {
77
+ if (visible) {
78
+ onEnter?.();
79
+
80
+ if (R.isNil(openAnimation)) {
81
+ opacity.setValue(1);
82
+
83
+ Animated.timing(translateY, {
84
+ ...DEFAULT_ANIMATION_CONFIG,
85
+ easing: Platform.OS === 'web'
86
+ ? Easing.bezier(0.16, 1, 0.3, 1)
87
+ : Easing.out(Easing.exp),
88
+ toValue: 0,
89
+ }).start(({ finished }) => {
90
+ if (finished) {
91
+ onEntered?.();
92
+ }
93
+ });
94
+ } else {
95
+ const convertedAnimation = openAnimation.map((animationUnit) => {
96
+ return convertToCompositeAnimation({
97
+ ...DEFAULT_ANIMATION_CONFIG,
98
+ ...animationUnit,
99
+ });
100
+ });
101
+
102
+ Animated.parallel(convertedAnimation).start(({ finished }) => {
103
+ if (finished) {
104
+ onEntered?.();
105
+ }
106
+ });
107
+ }
108
+ } else {
109
+ onExit?.();
110
+
111
+ if (R.isNil(closeAnimation)) {
112
+ opacity.setValue(1);
113
+
114
+ Animated.timing(translateY, {
115
+ ...DEFAULT_ANIMATION_CONFIG,
116
+ easing: Easing.in(Easing.ease),
117
+ toValue: screenHeight,
118
+ }).start(({ finished }) => {
119
+ if (finished) {
120
+ onExited?.();
121
+ }
122
+ });
123
+ } else {
124
+ const convertedAnimation = closeAnimation.map((animationUnit) => {
125
+ return convertToCompositeAnimation({
126
+ ...DEFAULT_ANIMATION_CONFIG,
127
+ ...animationUnit,
128
+ });
129
+ });
130
+
131
+ Animated.parallel(convertedAnimation).start(({ finished }) => {
132
+ if (finished) {
133
+ onExited?.();
134
+ }
135
+ });
136
+ }
137
+ }
138
+ }, [convertToCompositeAnimation, visible]);
139
+
140
+ const animatedStyle = {
141
+ opacity,
142
+ transform: [{ translateY }],
143
+ };
144
+
145
+ return (
146
+ <Animated.View
147
+ pointerEvents={'box-none'}
148
+ style={[
149
+ animatedStyle,
150
+ style,
151
+ ]}
152
+ >
153
+ {children}
154
+ </Animated.View>
155
+ );
156
+ }