diff --git a/docs/src/articles/guides/code-autocompletion.md b/docs/src/articles/guides/code-autocompletion.md new file mode 100644 index 000000000..542f11842 --- /dev/null +++ b/docs/src/articles/guides/code-autocompletion.md @@ -0,0 +1,47 @@ +# Code Autocompletion + +UI Kitten provides code autocompletion functionality for code editors such as Visual Studio Code, WebStorm, or Sublime Text. The feature provides code suggestions, syntax highlighting, and other code editing aids to help developers write code more efficiently and with fewer errors. +
+ +## Components + +The code completion feature for components is working "out of the box" for predefined mapping types. + +![image](assets/images/articles/guides/autocompletion-button-standard.gif) + +Also, it is possible to use the code completion feature with user components types added with [custom mapping](design-system/customize-mapping). +To do that, just setup UI Kitten [metro bundler config](guides/improving-performance). After starting metro server, it will parse the file and add new types to declaration. + +![image](assets/images/articles/guides/autocompletion-button-custom.gif) + +If necessary, you can use the generated types in props definition for your custom components created using UI Kitten. The generated types file is located in `node_modules/@eva-design/eva/mapping.types.ts` + +## Theme + +It is also possible to use autocompletion with style definitions. In order to get it worked, it is necessary to use [declaration merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html) typescript feature. +To do that, just create a `ts` file in your project with the merging declaration: + +```js +import {ColorValue} from 'react-native/Libraries/StyleSheet/StyleSheet'; +import {ThemeColors} from '@eva-design/eva/theme.types'; + +declare global { + interface ViewStyle { + backgroundColor?: ColorValue | undefined | ThemeColors; + borderColor?: ColorValue | undefined | ThemeColors; + } +} +``` +The declaration extends standard react-native interface with `ThemeColors` which is base theme autogenerated type (there are only `backgroundColor` and `borderColor` props are redefined in the example, but you can add additional props if needed). +If you have your own theme, it is possible to add your keys into that `ThemeColors` type either. It can be done with the [metro bundler config customization](guides/improving-performance) feature already used in the case above. The only additional step is adding path to your theme to appropriate `EvaConfig` property: + +```js +const evaConfig = { + evaPackage: '@eva-design/eva', + customMappingPath: './myMapping.json', + customThemePath: './myTheme.json', +}; +``` +After starting metro, it will regenerate `ThemeColors` type by adding your theme values. + +![image](assets/images/articles/guides/autocompletion-stylesheet.gif) diff --git a/docs/src/assets/images/articles/guides/autocompletion-button-custom.gif b/docs/src/assets/images/articles/guides/autocompletion-button-custom.gif new file mode 100644 index 000000000..1ca9758d5 Binary files /dev/null and b/docs/src/assets/images/articles/guides/autocompletion-button-custom.gif differ diff --git a/docs/src/assets/images/articles/guides/autocompletion-button-standard.gif b/docs/src/assets/images/articles/guides/autocompletion-button-standard.gif new file mode 100644 index 000000000..ad49f85fb Binary files /dev/null and b/docs/src/assets/images/articles/guides/autocompletion-button-standard.gif differ diff --git a/docs/src/assets/images/articles/guides/autocompletion-stylesheet.gif b/docs/src/assets/images/articles/guides/autocompletion-stylesheet.gif new file mode 100644 index 000000000..84bdf04ca Binary files /dev/null and b/docs/src/assets/images/articles/guides/autocompletion-stylesheet.gif differ diff --git a/docs/src/structure.ts b/docs/src/structure.ts index 3994d579d..d57c864c3 100644 --- a/docs/src/structure.ts +++ b/docs/src/structure.ts @@ -135,6 +135,20 @@ export const structure = [ description: 'How to get rid of performance issues in UI Kitten when using mapping customization or React Native Navigation by Wix', keywords: 'ui kitten, react native apps, custom mapping path, evaConfig, evaPackage', }, + { + type: 'page', + name: 'Code Autocompletion', + children: [ + { + type: 'block', + block: 'markdown', + source: 'guides/code-autocompletion.md', + }, + ], + title: 'Code Autocompletion', + description: 'How to use code autocompletion feature with UI Kitten', + keywords: 'ui kitten, react native apps, custom mapping path, evaConfig, evaPackage, code autocompletion', + }, ], }, { diff --git a/src/components/ui/avatar/avatar.component.tsx b/src/components/ui/avatar/avatar.component.tsx index 3d0af8cc5..10732cadd 100644 --- a/src/components/ui/avatar/avatar.component.tsx +++ b/src/components/ui/avatar/avatar.component.tsx @@ -11,24 +11,20 @@ import { ImageStyle, StyleSheet, } from 'react-native'; -import { - EvaSize, - Overwrite, - LiteralUnion, -} from '../../devsupport'; import { styled, StyledComponentProps, StyleType, } from '../../theme'; +import { AvatarAppearance, AvatarShape, AvatarSize } from '@eva-design/eva/mapping.types'; -type AvatarStyledProps = Overwrite; -}>; +interface AvatarStyledProps extends StyledComponentProps { + appearance?: AvatarAppearance; +} export type AvatarProps

= AvatarStyledProps & P & { - shape?: 'round' | 'rounded' | 'square' | string; - size?: EvaSize; + shape?: AvatarShape; + size?: AvatarSize; /** * We use `any` here to prevent ts complains for most of the libraries that use * React.ComponentType & SomeType to describe static / instance methods for the components. @@ -44,12 +40,19 @@ export type AvatarElement = React.ReactElement; * * @extends React.Component * + * @property {string} appearance - Appearance of the component. + * The predefined one is `default`. + * Can be extended with custom mapping feature. + * Defaults to *default*. + * * @property {string} shape - Shape of the component. - * Can be `round`, `rounded` or `square`. + * The predefined ones are `round`, `rounded` or `square`. + * Can be extended with custom mapping feature. * Defaults to *round*. * * @property {string} size - Size of the component. - * Can be `tiny`, `small`, `medium`, `large`, or `giant`. + * The predefined ones are `tiny`, `small`, `medium`, `large`, or `giant`. + * Can be extended with custom mapping feature. * Defaults to *medium*. * * @property {React.ComponentType} ImageComponent - A component to render. diff --git a/src/components/ui/bottomNavigation/bottomNavigation.component.tsx b/src/components/ui/bottomNavigation/bottomNavigation.component.tsx index d8ae8fa21..750fd2512 100644 --- a/src/components/ui/bottomNavigation/bottomNavigation.component.tsx +++ b/src/components/ui/bottomNavigation/bottomNavigation.component.tsx @@ -14,8 +14,6 @@ import { } from 'react-native'; import { ChildrenWithProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { styled, @@ -30,10 +28,11 @@ import { TabIndicator, TabIndicatorElement, } from '../shared/tabIndicator.component'; +import { BottomNavigationAppearance } from '@eva-design/eva/mapping.types'; -type BottomNavigationStyledProps = Overwrite; -}>; +interface BottomNavigationStyledProps extends StyledComponentProps { + appearance?: BottomNavigationAppearance; +} export interface BottomNavigationProps extends ViewProps, BottomNavigationStyledProps { children?: ChildrenWithProps; @@ -57,7 +56,7 @@ export type BottomNavigationElement = React.ReactElement; * @property {(number) => void} onSelect - Called when tab is pressed. * * @property {string} appearance - Appearance of the component. - * Can be `default` or `noIndicator`. + * The predefined ones are `default` or `noIndicator`. Can be extended with custom mapping feature. * * @property {StyleProp} indicatorStyle - Styles of the indicator. * diff --git a/src/components/ui/bottomNavigation/bottomNavigationTab.component.tsx b/src/components/ui/bottomNavigation/bottomNavigationTab.component.tsx index f5b930d0b..1af30d23f 100644 --- a/src/components/ui/bottomNavigation/bottomNavigationTab.component.tsx +++ b/src/components/ui/bottomNavigation/bottomNavigationTab.component.tsx @@ -18,8 +18,6 @@ import { TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -28,10 +26,11 @@ import { StyleType, } from '../../theme'; import { TextProps } from '../text/text.component'; +import { BottomNavigationTabAppearance } from '@eva-design/eva/mapping.types'; -type BottomNavigationTabStyledProps = Overwrite; -}>; +interface BottomNavigationTabStyledProps extends StyledComponentProps { + appearance?: BottomNavigationTabAppearance; +} export interface BottomNavigationTabProps extends TouchableWebProps, BottomNavigationTabStyledProps { title?: RenderProp | React.ReactText; diff --git a/src/components/ui/button/button.component.tsx b/src/components/ui/button/button.component.tsx index cf609d9a5..553f5eca2 100644 --- a/src/components/ui/button/button.component.tsx +++ b/src/components/ui/button/button.component.tsx @@ -13,16 +13,12 @@ import { TargetedEvent, } from 'react-native'; import { - EvaSize, - EvaStatus, FalsyFC, FalsyText, RenderProp, TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -31,10 +27,11 @@ import { StyleType, } from '../../theme'; import { TextProps } from '../text/text.component'; +import { ButtonAppearance, ButtonSize, ButtonStatus } from '@eva-design/eva/mapping.types'; -type ButtonStyledProps = Overwrite; -}>; +interface ButtonStyledProps extends StyledComponentProps { + appearance?: ButtonAppearance; +} type TouchableWebPropsWithoutChildren = Omit; @@ -42,8 +39,8 @@ export interface ButtonProps extends TouchableWebPropsWithoutChildren, ButtonSty children?: RenderProp | React.ReactText; accessoryLeft?: RenderProp>; accessoryRight?: RenderProp>; - status?: EvaStatus; - size?: EvaSize; + status?: ButtonStatus; + size?: ButtonSize; } export type ButtonElement = React.ReactElement; @@ -66,16 +63,19 @@ export type ButtonElement = React.ReactElement; * Expected to return an Image. * * @property {string} appearance - Appearance of the component. - * Can be `filled`, `outline` or `ghost`. + * The predefined ones are `filled`, `outline` or `ghost`. + * Can be extended with custom mapping feature. * Defaults to *filled*. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. * Defaults to *primary*. * Use *control* status when needed to display within a contrast container. * * @property {string} size - Size of the component. - * Can be `tiny`, `small`, `medium`, `large`, or `giant`. + * The predefined ones are `tiny`, `small`, `medium`, `large`, or `giant`. + * Can be extended with custom mapping feature. * Defaults to *medium*. * * @property {TouchableOpacityProps} ...TouchableOpacityProps - Any props applied to TouchableOpacity component. @@ -87,7 +87,7 @@ export type ButtonElement = React.ReactElement; * Button can be disabled with `disabled` property. * * @overview-example ButtonAppearances - * Within Eva Design System, it can be `filled`, `outline` or `ghost`. + * The predefined appearances are `filled`, `outline` or `ghost`. * * @overview-example ButtonAccessories * Also, it may contain inner views configured with `accessoryLeft` and `accessoryRight` properties. diff --git a/src/components/ui/buttonGroup/buttonGroup.component.tsx b/src/components/ui/buttonGroup/buttonGroup.component.tsx index 05c5e4df8..d259c1d25 100644 --- a/src/components/ui/buttonGroup/buttonGroup.component.tsx +++ b/src/components/ui/buttonGroup/buttonGroup.component.tsx @@ -13,10 +13,6 @@ import { } from 'react-native'; import { ChildrenWithProps, - EvaSize, - EvaStatus, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { styled, @@ -27,15 +23,16 @@ import { ButtonElement, ButtonProps, } from '../button/button.component'; +import { ButtonGroupAppearance, ButtonGroupSize, ButtonGroupStatus } from '@eva-design/eva/mapping.types'; -type ButtonGroupStyledProps = Overwrite; -}>; +interface ButtonGroupStyledProps extends StyledComponentProps { + appearance?: ButtonGroupAppearance; +} export interface ButtonGroupProps extends ViewProps, ButtonGroupStyledProps { children: ChildrenWithProps; - status?: EvaStatus; - size?: EvaSize; + status?: ButtonGroupStatus; + size?: ButtonGroupSize; } export type ButtonGroupElement = React.ReactElement; diff --git a/src/components/ui/card/card.component.tsx b/src/components/ui/card/card.component.tsx index 37c579dc7..fc72fa004 100644 --- a/src/components/ui/card/card.component.tsx +++ b/src/components/ui/card/card.component.tsx @@ -12,14 +12,11 @@ import { ViewProps, } from 'react-native'; import { - EvaStatus, FalsyFC, RenderProp, TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -28,17 +25,18 @@ import { StyleType, } from '../../theme'; import { Divider } from '../divider/divider.component'; +import { CardAppearance, CardStatus } from '@eva-design/eva/mapping.types'; -type CardStyledProps = Overwrite; -}>; +interface CardStyledProps extends StyledComponentProps { + appearance?: CardAppearance; +} export interface CardProps extends TouchableWebProps, CardStyledProps { children?: React.ReactNode; header?: RenderProp; footer?: RenderProp; accent?: RenderProp; - status?: EvaStatus; + status?: CardStatus; } export type CardElement = React.ReactElement; @@ -61,11 +59,12 @@ export type CardElement = React.ReactElement; * Accents may change it's color depending on *status* property. * * @property {string} appearance - Appearance of the component. - * Can be `filled` or `outline`. + * The predefined ones are `filled` or `outline`. Can be extended with custom mapping feature. * Defaults to *outline*. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. * Defaults to *basic*. * * @property {TouchableOpacityProps} ...TouchableOpacityProps - Any props applied to TouchableOpacity component. diff --git a/src/components/ui/checkbox/checkbox.component.tsx b/src/components/ui/checkbox/checkbox.component.tsx index bfa0e2a12..7b630a4a2 100644 --- a/src/components/ui/checkbox/checkbox.component.tsx +++ b/src/components/ui/checkbox/checkbox.component.tsx @@ -14,14 +14,11 @@ import { View, } from 'react-native'; import { - EvaStatus, FalsyText, RenderProp, TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -38,10 +35,11 @@ import { Minus, MinusProps, } from '../shared/minus.component'; +import { CheckBoxAppearance, CheckBoxStatus } from '@eva-design/eva/mapping.types'; -type CheckBoxStyledProps = Overwrite; -}>; +interface CheckBoxStyledProps extends StyledComponentProps { + appearance?: CheckBoxAppearance; +} type TouchableWebPropsWithoutChildren = Omit; @@ -50,7 +48,7 @@ export interface CheckBoxProps extends TouchableWebPropsWithoutChildren, CheckBo checked?: boolean; onChange?: (checked: boolean, indeterminate: boolean) => void; indeterminate?: boolean; - status?: EvaStatus; + status?: CheckBoxStatus; } export type CheckBoxElement = React.ReactElement; @@ -77,8 +75,8 @@ export type CheckBoxElement = React.ReactElement; * If it is a function, expected to return a Text. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *basic*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *basic*. * Use *control* status when needed to display within a contrast container. * * @property {TouchableOpacityProps} ...TouchableOpacityProps - Any props applied to TouchableOpacity component. diff --git a/src/components/ui/circularProgressBar/circularProgressBar.component.tsx b/src/components/ui/circularProgressBar/circularProgressBar.component.tsx index fb42e267a..ca89d10cd 100644 --- a/src/components/ui/circularProgressBar/circularProgressBar.component.tsx +++ b/src/components/ui/circularProgressBar/circularProgressBar.component.tsx @@ -15,11 +15,8 @@ import { ViewStyle, } from 'react-native'; import { - EvaSize, LiteralUnion, - Overwrite, Size, - EvaStatus, RenderProp, FalsyFC, } from '@ui-kitten/components/devsupport'; @@ -31,10 +28,15 @@ import { Text, } from '@ui-kitten/components'; import { CircularProgressBarAnimation, CircularProgressBarAnimationConfig } from './animation'; +import { + CircularProgressBarAppearance, + CircularProgressBarSize, + CircularProgressBarStatus, +} from '@eva-design/eva/mapping.types'; -type CircularProgressBarStyledProps = Overwrite; -}>; +interface CircularProgressBarStyledProps extends StyledComponentProps { + appearance?: CircularProgressBarAppearance; +} interface IndicatorStyle { width: number; @@ -62,8 +64,8 @@ export interface CircularProgressBarProps extends ViewProps, CircularProgressBar progress?: number; animating?: boolean; renderIcon?: RenderProp>; - size?: EvaSize; - status?: EvaStatus; + size?: CircularProgressBarSize; + status?: CircularProgressBarStatus; textStyle?: TextStyle; iconStyle?: IconStyle; animationConfig?: Partial; @@ -83,12 +85,12 @@ export type CircularProgressBarElement = React.ReactElement ReactElement} renderIcon - Function component @@ -326,7 +328,7 @@ export class CircularProgressBar extends React.PureComponent => { const showIcon = this.props.renderIcon; diff --git a/src/components/ui/datepicker/baseDatepicker.component.tsx b/src/components/ui/datepicker/baseDatepicker.component.tsx index c6a99f37e..3d9e041eb 100644 --- a/src/components/ui/datepicker/baseDatepicker.component.tsx +++ b/src/components/ui/datepicker/baseDatepicker.component.tsx @@ -16,8 +16,6 @@ import { ViewStyle, } from 'react-native'; import { - EvaInputSize, - EvaStatus, FalsyFC, FalsyText, RenderProp, @@ -38,6 +36,7 @@ import { PopoverPlacements, } from '../popover/type'; import { TextProps } from '../text/text.component'; +import { DatepickerSize, DatepickerStatus } from '@eva-design/eva/mapping.types'; export interface BaseDatepickerProps extends StyledComponentProps, TouchableOpacityProps, @@ -48,8 +47,8 @@ export interface BaseDatepickerProps extends StyledComponentProps, caption?: RenderProp | React.ReactText; accessoryLeft?: RenderProp>; accessoryRight?: RenderProp>; - status?: EvaStatus; - size?: EvaInputSize; + status?: DatepickerStatus; + size?: DatepickerSize; placeholder?: RenderProp | React.ReactText; placement?: PopoverPlacement | string; backdropStyle?: StyleProp; diff --git a/src/components/ui/datepicker/datepicker.component.tsx b/src/components/ui/datepicker/datepicker.component.tsx index 40b1ddae2..dd0b6f18a 100644 --- a/src/components/ui/datepicker/datepicker.component.tsx +++ b/src/components/ui/datepicker/datepicker.component.tsx @@ -87,14 +87,14 @@ export type DatepickerElement = React.ReactElement> * @property {(date: D) => boolean} filter - A function to determine whether particular date cells should be disabled. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *basic*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *basic*. * Useful for giving user a hint on the input validity. * Use *control* status when needed to display within a contrast container. * * @property {string} size - Size of the component. - * Can be `small`, `medium` or `large`. - * Defaults to *medium*. + * The predefined ones are `small`, `medium` or `large`. + * Can be extended with custom mapping feature. Defaults to *medium*. * * @property {ReactText | ReactElement | (TextProps) => ReactElement} placeholder - String, number or a function * component to render when input field is empty. diff --git a/src/components/ui/drawer/drawer.component.tsx b/src/components/ui/drawer/drawer.component.tsx index ad6a1abb9..e62714a98 100644 --- a/src/components/ui/drawer/drawer.component.tsx +++ b/src/components/ui/drawer/drawer.component.tsx @@ -18,8 +18,10 @@ import { Menu, MenuProps, } from '../menu/menu.component'; +import { DrawerAppearance } from '@eva-design/eva/mapping.types'; export interface DrawerProps extends MenuProps { + appearance?: DrawerAppearance; header?: RenderProp; footer?: RenderProp; } @@ -52,7 +54,8 @@ export type DrawerElement = React.ReactElement; * where row - index of item in group, section - index of group in list. * * @property {string} appearance - Appearance of the component. - * Can be `default` or `noDivider`. + * The predefined ones are `default` or `noDivider`. + * Can be extended with custom mapping feature. * * @property {ListProps} ...ListProps - Any props applied to List component, * excluding `renderItem` and `data`. diff --git a/src/components/ui/input/input.component.tsx b/src/components/ui/input/input.component.tsx index b1c3894c1..f68210da8 100644 --- a/src/components/ui/input/input.component.tsx +++ b/src/components/ui/input/input.component.tsx @@ -20,8 +20,6 @@ import { ViewStyle, } from 'react-native'; import { - EvaSize, - EvaStatus, FalsyFC, FalsyText, FlexViewCrossStyleProps, @@ -30,8 +28,6 @@ import { WebEventResponder, WebEventResponderCallbacks, WebEventResponderInstance, - Overwrite, - LiteralUnion, TouchableWithoutFeedback, } from '../../devsupport'; import { @@ -41,14 +37,15 @@ import { StyleType, } from '../../theme'; import { TextProps } from '../text/text.component'; +import { InputAppearance, InputSize, InputStatus } from '@eva-design/eva/mapping.types'; -type InputStyledProps = Overwrite; -}>; +interface InputStyledProps extends StyledComponentProps { + appearance?: InputAppearance; +} export interface InputProps extends TextInputProps, InputStyledProps { - status?: EvaStatus; - size?: EvaSize; + status?: InputStatus; + size?: InputSize; disabled?: boolean; label?: RenderProp | React.ReactText; caption?: RenderProp | React.ReactText; @@ -94,14 +91,14 @@ export type InputElement = React.ReactElement; * Expected to return an Image. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *basic*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *basic*. * Useful for giving user a hint on the input validity. * Use *control* status when needed to display within a contrast container. * * @property {string} size - Size of the component. - * Can be `small`, `medium` or `large`. - * Defaults to *medium*. + * The predefined ones are `small`, `medium` or `large`. + * Can be extended with custom mapping feature. Defaults to *medium*. * * @property {StyleProp} textStyle - Customizes the style of the text field. * diff --git a/src/components/ui/layout/layout.component.tsx b/src/components/ui/layout/layout.component.tsx index e66e3ffb6..eecc9d864 100644 --- a/src/components/ui/layout/layout.component.tsx +++ b/src/components/ui/layout/layout.component.tsx @@ -9,19 +9,19 @@ import { View, ViewProps, } from 'react-native'; -import { Overwrite, LiteralUnion } from '../../devsupport'; import { styled, StyledComponentProps, } from '../../theme'; +import { LayoutAppearance, LayoutLevel } from '@eva-design/eva/mapping.types'; -type LayoutStyledProps = Overwrite; -}>; +interface LayoutStyledProps extends StyledComponentProps { + appearance?: LayoutAppearance; +} export interface LayoutProps extends ViewProps, LayoutStyledProps { children?: React.ReactNode; - level?: LiteralUnion<'1' | '2' | '3' | '4'>; + level?: LayoutLevel; } export type LayoutElement = React.ReactElement; @@ -34,8 +34,8 @@ export type LayoutElement = React.ReactElement; * @property {ReactNode} children - Component to render within the layout. * * @property {string} level - Background color level of component. - * Can be `1`, `2`, `3` or `4`. - * Defaults to *1*. + * The predefined ones are `1`, `2`, `3` or `4`. + * Can be extended with custom mapping feature. Defaults to *1*. * * @property {ViewProps} ...ViewProps - Any props applied to View component. * diff --git a/src/components/ui/list/list.component.tsx b/src/components/ui/list/list.component.tsx index 5584c1ebc..3f78c60bd 100644 --- a/src/components/ui/list/list.component.tsx +++ b/src/components/ui/list/list.component.tsx @@ -9,15 +9,15 @@ import { FlatList, FlatListProps, } from 'react-native'; -import { Overwrite, LiteralUnion } from '../../devsupport'; import { styled, StyledComponentProps, } from '../../theme'; +import { ListAppearance } from '@eva-design/eva/mapping.types'; -type ListStyledProps = Overwrite; -}>; +interface ListStyledProps extends StyledComponentProps { + appearance?: ListAppearance; +} // eslint-disable-next-line @typescript-eslint/no-explicit-any export type ListProps = FlatListProps & ListStyledProps; diff --git a/src/components/ui/list/listItem.component.tsx b/src/components/ui/list/listItem.component.tsx index 865906973..38c6ebefc 100644 --- a/src/components/ui/list/listItem.component.tsx +++ b/src/components/ui/list/listItem.component.tsx @@ -20,8 +20,6 @@ import { TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -30,10 +28,11 @@ import { StyleType, } from '../../theme'; import { TextProps } from '../text/text.component'; +import { ListItemAppearance } from '@eva-design/eva/mapping.types'; -type ListItemStyledProps = Overwrite; -}>; +interface ListItemStyledProps extends StyledComponentProps { + appearance?: ListItemAppearance; +} export interface ListItemProps extends TouchableWebProps, ListItemStyledProps { title?: RenderProp | React.ReactText; diff --git a/src/components/ui/menu/menu.component.tsx b/src/components/ui/menu/menu.component.tsx index dcee8591c..8c600ffbf 100644 --- a/src/components/ui/menu/menu.component.tsx +++ b/src/components/ui/menu/menu.component.tsx @@ -10,7 +10,6 @@ import { ChildrenWithProps, IndexPath, Overwrite, - LiteralUnion, } from '../../devsupport'; import { styled } from '../../theme'; import { Divider } from '../divider/divider.component'; @@ -27,9 +26,10 @@ import { MenuItemDescriptor, MenuService, } from './menu.service'; +import { MenuAppearance } from '@eva-design/eva/mapping.types'; type MenuStyledProps = Overwrite; + appearance?: MenuAppearance; }>; type MenuListProps = Omit; @@ -49,7 +49,7 @@ export type MenuElement = React.ReactElement; * @extends React.Component * * @property {string} appearance - Appearance of the component. - * Can be `default` or `noDivider`. + * The predefined ones are `default` or `noDivider`. Can be extended with custom mapping feature. * * @property {ReactElement | ReactElement[]} children - * Items to be rendered within menu. diff --git a/src/components/ui/menu/menuItem.component.tsx b/src/components/ui/menu/menuItem.component.tsx index 13cadce7b..4b1cf3d25 100644 --- a/src/components/ui/menu/menuItem.component.tsx +++ b/src/components/ui/menu/menuItem.component.tsx @@ -21,7 +21,6 @@ import { TouchableWeb, TouchableWebProps, Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -31,10 +30,11 @@ import { } from '../../theme'; import { TextProps } from '../text/text.component'; import { MenuItemDescriptor } from './menu.service'; +import { MenuItemAppearance } from '@eva-design/eva/mapping.types'; -type MenuItemStyledProps = Overwrite; -}>; +interface MenuItemStyledProps extends StyledComponentProps { + appearance?: MenuItemAppearance; +} type TouchableMenuItemProps = Overwrite void; diff --git a/src/components/ui/progressBar/progressBar.component.tsx b/src/components/ui/progressBar/progressBar.component.tsx index 799fef1da..6a4289efc 100644 --- a/src/components/ui/progressBar/progressBar.component.tsx +++ b/src/components/ui/progressBar/progressBar.component.tsx @@ -13,22 +13,17 @@ import { ViewProps, ViewStyle, } from 'react-native'; -import { - EvaSize, - EvaStatus, - LiteralUnion, - Overwrite, -} from '@ui-kitten/components/devsupport'; import { styled, StyledComponentProps, StyleType, } from '@ui-kitten/components'; import { ProgressBarAnimation, ProgressBarAnimationConfig } from './animation'; +import { ProgressBarAppearance, ProgressBarSize, ProgressBarStatus } from '@eva-design/eva/mapping.types'; -type ProgressBarStyledProps = Overwrite; -}>; +interface ProgressBarStyledProps extends StyledComponentProps { + appearance?: ProgressBarAppearance; +} interface ComponentStyles { track: ViewStyle; @@ -39,8 +34,8 @@ export interface ProgressBarProps extends ViewProps, ProgressBarStyledProps { progress?: number; animating?: boolean; animationConfig?: Partial; - status?: EvaStatus; - size?: EvaSize; + status?: ProgressBarStatus; + size?: ProgressBarSize; } export type ProgressBarElement = React.ReactElement; @@ -61,12 +56,12 @@ interface State { * Can be from 0 to 1. * * @property {string} size - Size of the component. - * Can be `tiny`, `small`, `medium`, `large`, or `giant`. - * Defaults to *small*. + * CThe predefined ones are `tiny`, `small`, `medium`, `large`, or `giant`. + * Can be extended with custom mapping feature. Defaults to *small*. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *primary*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *primary*. * Use *control* status when needed to display within a contrast container. * * @property {Partial} animationConfig - Animation configuration. diff --git a/src/components/ui/radio/radio.component.tsx b/src/components/ui/radio/radio.component.tsx index a99dcaa3c..f2387f593 100644 --- a/src/components/ui/radio/radio.component.tsx +++ b/src/components/ui/radio/radio.component.tsx @@ -13,14 +13,11 @@ import { View, } from 'react-native'; import { - EvaStatus, FalsyText, RenderProp, TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -29,10 +26,11 @@ import { StyleType, } from '../../theme'; import { TextProps } from '../text/text.component'; +import { RadioAppearance, RadioStatus } from '@eva-design/eva/mapping.types'; -type RadioStyledProps = Overwrite; -}>; +interface RadioStyledProps extends StyledComponentProps { + appearance?: RadioAppearance; +} type TouchableWebPropsWithoutChildren = Omit; @@ -40,7 +38,7 @@ export interface RadioProps extends TouchableWebPropsWithoutChildren, RadioStyle children?: RenderProp | React.ReactText; checked?: boolean; onChange?: (checked: boolean) => void; - status?: EvaStatus; + status?: RadioStatus; } export type RadioElement = React.ReactElement; @@ -61,8 +59,8 @@ export type RadioElement = React.ReactElement; * If it is a function, expected to return a Text. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *basic*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *basic*. * Use *control* status when needed to display within a contrast container. * * @property {TouchableOpacityProps} ...TouchableOpacityProps - Any props applied to TouchableOpacity component. diff --git a/src/components/ui/radioGroup/radioGroup.component.tsx b/src/components/ui/radioGroup/radioGroup.component.tsx index 8ff285e2d..ed4bd92b0 100644 --- a/src/components/ui/radioGroup/radioGroup.component.tsx +++ b/src/components/ui/radioGroup/radioGroup.component.tsx @@ -11,8 +11,6 @@ import { } from 'react-native'; import { ChildrenWithProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { styled, @@ -23,10 +21,11 @@ import { RadioElement, RadioProps, } from '../radio/radio.component'; +import { RadioGroupAppearance } from '@eva-design/eva/mapping.types'; -type RadioGroupStyledProps = Overwrite; -}>; +interface RadioGroupStyledProps extends StyledComponentProps { + appearance?: RadioGroupAppearance; +} export interface RadioGroupProps extends ViewProps, RadioGroupStyledProps { children?: ChildrenWithProps; diff --git a/src/components/ui/select/select.component.tsx b/src/components/ui/select/select.component.tsx index 51a26a17e..1cb8fe367 100644 --- a/src/components/ui/select/select.component.tsx +++ b/src/components/ui/select/select.component.tsx @@ -21,8 +21,6 @@ import { } from 'react-native'; import { ChildrenWithProps, - EvaInputSize, - EvaStatus, FalsyFC, FalsyText, IndexPath, @@ -30,8 +28,6 @@ import { TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -51,10 +47,11 @@ import { SelectItemDescriptor, SelectService, } from './select.service'; +import { SelectAppearance, SelectSize, SelectStatus } from '@eva-design/eva/mapping.types'; -type SelectStyledProps = Overwrite; -}>; +interface SelectStyledProps extends StyledComponentProps { + appearance?: SelectAppearance; +} export interface SelectProps extends TouchableWebProps, SelectStyledProps { children?: ChildrenWithProps; @@ -67,8 +64,8 @@ export interface SelectProps extends TouchableWebProps, SelectStyledProps { caption?: RenderProp | React.ReactText; accessoryLeft?: RenderProp>; accessoryRight?: RenderProp>; - status?: EvaStatus; - size?: EvaInputSize; + status?: SelectStatus; + size?: SelectSize; } export type SelectElement = React.ReactElement; @@ -138,13 +135,13 @@ const CHEVRON_ANIM_DURATION = 200; * Expected to return an Image. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *basic*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *basic*. * Use *control* status when needed to display within a contrast container. * * @property {string} size - Size of the component. - * Can be `small`, `medium` or `large`. - * Defaults to *medium*. + * The predefined ones are `small`, `medium` or `large`. + * Can be extended with custom mapping feature. Defaults to *medium*. * * @property {() => void} onFocus - Called when options list becomes visible. * diff --git a/src/components/ui/spinner/spinner.component.tsx b/src/components/ui/spinner/spinner.component.tsx index ce159bd1f..aeaaf2189 100644 --- a/src/components/ui/spinner/spinner.component.tsx +++ b/src/components/ui/spinner/spinner.component.tsx @@ -13,11 +13,7 @@ import { ViewStyle, } from 'react-native'; import { - EvaSize, - EvaStatus, Size, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { styled, @@ -27,15 +23,16 @@ import { SpinnerAnimation, SpinnerAnimationStyle, } from './animation'; +import { SpinnerAppearance, SpinnerSize, SpinnerStatus } from '@eva-design/eva/mapping.types'; -type SpinnerStyledProps = Overwrite; -}>; +interface SpinnerStyledProps extends StyledComponentProps { + appearance?: SpinnerAppearance; +} export interface SpinnerProps extends ViewProps, SpinnerStyledProps { animating?: boolean; - status?: EvaStatus; - size?: EvaSize; + status?: SpinnerStatus; + size?: SpinnerSize; } export type SpinnerElement = React.ReactElement; @@ -55,13 +52,13 @@ interface ArcElementStyle { * Default is *true*. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *primary*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *primary*. * Use *control* status when needed to display within a contrast container. * * @property {string} size - Size of the component. - * Can be `tiny`, `small`, `medium`, `large`, or `giant`. - * Defaults to *medium*. + * The predefined ones are `tiny`, `small`, `medium`, `large`, or `giant`. + * Can be extended with custom mapping feature. Defaults to *medium*. * * @overview-example SpinnerSimpleUsage * Default Spinner status is `primary` and size is `medium`. diff --git a/src/components/ui/tab/tab.component.tsx b/src/components/ui/tab/tab.component.tsx index 1dc0a6e6a..a16babf16 100644 --- a/src/components/ui/tab/tab.component.tsx +++ b/src/components/ui/tab/tab.component.tsx @@ -18,8 +18,6 @@ import { TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -28,10 +26,11 @@ import { StyleType, } from '../../theme'; import { TextProps } from '../text/text.component'; +import { TabAppearance } from '@eva-design/eva/mapping.types'; -type TabStyledProps = Overwrite; -}>; +interface TabStyledProps extends StyledComponentProps { + appearance?: TabAppearance; +} export interface TabProps extends TouchableWebProps, TabStyledProps { children?: React.ReactElement; diff --git a/src/components/ui/tab/tabBar.component.tsx b/src/components/ui/tab/tabBar.component.tsx index aeae85cc4..caa500ebe 100644 --- a/src/components/ui/tab/tabBar.component.tsx +++ b/src/components/ui/tab/tabBar.component.tsx @@ -14,8 +14,6 @@ import { } from 'react-native'; import { ChildrenWithProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { styled, @@ -27,10 +25,11 @@ import { TabProps, } from './tab.component'; import { TabIndicator } from '../shared/tabIndicator.component'; +import { TabBarAppearance } from '@eva-design/eva/mapping.types'; -type TabBarStyledProps = Overwrite; -}>; +interface TabBarStyledProps extends StyledComponentProps { + appearance?: TabBarAppearance; +} export interface TabBarProps extends ViewProps, TabBarStyledProps { children?: ChildrenWithProps; diff --git a/src/components/ui/text/text.component.tsx b/src/components/ui/text/text.component.tsx index bdb6b9c12..4ff3d052c 100644 --- a/src/components/ui/text/text.component.tsx +++ b/src/components/ui/text/text.component.tsx @@ -9,26 +9,22 @@ import { Text as RNText, TextProps as RNTextProps, } from 'react-native'; -import { - EvaStatus, - Overwrite, - LiteralUnion, -} from '../../devsupport'; import { styled, StyledComponentProps, } from '../../theme'; +import { TextAppearance, TextCategory, TextStatus } from '@eva-design/eva/mapping.types'; -type TextStyledProps = Overwrite; -}>; +interface TextStyledProps extends StyledComponentProps { + appearance?: TextAppearance; +} type ChildElement = React.ReactText | TextElement; export interface TextProps extends RNTextProps, TextStyledProps { children?: ChildElement | ChildElement[]; - category?: LiteralUnion<'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 's1' | 's2' | 'p1' | 'p2' | 'c1' | 'c2' | 'label'>; - status?: EvaStatus; + category?: TextCategory; + status?: TextStatus; } export type TextElement = React.ReactElement; @@ -41,20 +37,22 @@ export type TextElement = React.ReactElement; * @property {ReactText | ReactElement} children - String or number to be rendered as text. * Also can be ReactElement - nested Text component. * - * @property {string} appearance - Can be `default`, `alternative` or `hint`. + * @property {string} appearance - The predefined ones are `default`, `alternative` or `hint`. + * Can be extended with custom mapping feature. * Use `alternative` for displaying light text on a dark content and vice versa. * Use `hint` for giving user a hint on something. * - * @property {string} category - Can be `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `s1`, `s2`, `p1`, `p2`, `c1`, `c2`, `label`. - * Defaults to *p1*. + * @property {string} category - The predefined ones are + * `h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `s1`, `s2`, `p1`, `p2`, `c1`, `c2`, `label`. + * Can be extended with custom mapping feature. Defaults to *p1*. * Use *h* categories when needed to display headings. * Use *s* categories when needed to display subtitles. * Use *p* categories when needed to display regular text. * Use *c* and *label* categories when needed to give user a hint on something. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *basic*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *basic*. * Use *control* status when needed to display within a contrast container. * * @property {TextProps} ...TextProps - Any props applied to Text component. diff --git a/src/components/ui/toggle/toggle.component.tsx b/src/components/ui/toggle/toggle.component.tsx index 0257ce294..ae1393de7 100644 --- a/src/components/ui/toggle/toggle.component.tsx +++ b/src/components/ui/toggle/toggle.component.tsx @@ -20,14 +20,11 @@ import { ViewProps, } from 'react-native'; import { - EvaStatus, FalsyText, RenderProp, RTLService, TouchableWeb, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -37,10 +34,11 @@ import { } from '../../theme'; import { TextProps } from '../text/text.component'; import { CheckMark } from '../shared/checkmark.component'; +import { ToggleAppearance, ToggleStatus } from '@eva-design/eva/mapping.types'; -type ToggleStyledProps = Overwrite; -}>; +interface ToggleStyledProps extends StyledComponentProps { + appearance?: ToggleAppearance; +} type TouchableWebPropsWithoutChildren = Omit; @@ -48,7 +46,7 @@ export interface ToggleProps extends TouchableWebPropsWithoutChildren, ToggleSty children?: RenderProp | React.ReactText; checked?: boolean; onChange?: (checked: boolean) => void; - status?: EvaStatus; + status?: ToggleStatus; } export type ToggleElement = React.ReactElement; @@ -69,8 +67,8 @@ export type ToggleElement = React.ReactElement; * If it is a function, expected to return a Text. * * @property {string} status - Status of the component. - * Can be `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. - * Defaults to *basic*. + * The predefined ones are `basic`, `primary`, `success`, `info`, `warning`, `danger` or `control`. + * Can be extended with custom mapping feature. Defaults to *basic*. * Use *control* status when needed to display within a contrast container. * * @property {TouchableOpacityProps} ...TouchableOpacityProps - Any props applied to TouchableOpacity component. diff --git a/src/components/ui/topNavigation/topNavigation.component.tsx b/src/components/ui/topNavigation/topNavigation.component.tsx index 1a6dc4c00..beb6643ba 100644 --- a/src/components/ui/topNavigation/topNavigation.component.tsx +++ b/src/components/ui/topNavigation/topNavigation.component.tsx @@ -14,8 +14,6 @@ import { FalsyFC, FalsyText, RenderProp, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { styled, @@ -23,23 +21,22 @@ import { StyleType, } from '../../theme'; import { TextProps } from '../text/text.component'; +import { TopNavigationAlignment, TopNavigationAppearance } from '@eva-design/eva/mapping.types'; -type TopNavigationStyledProps = Overwrite; -}>; +interface TopNavigationStyledProps extends StyledComponentProps { + appearance?: TopNavigationAppearance; +} export interface TopNavigationProps extends ViewProps, TopNavigationStyledProps { title?: RenderProp | React.ReactText; subtitle?: RenderProp | React.ReactText; accessoryLeft?: () => React.ReactElement; accessoryRight?: () => React.ReactElement; - alignment?: AlignmentProp; + alignment?: TopNavigationAlignment; } export type TopNavigationElement = React.ReactElement; -type AlignmentProp = 'start' | 'center'; - /** * TopNavigation provides a heading component for the entire page. * @@ -60,12 +57,12 @@ type AlignmentProp = 'start' | 'center'; * to render to the right edge the top navigation. * * @property {string} appearance - Appearance of the component. - * Can be `default`, `control`. + * The predefined ones are `default`, `control`. Can be extended with custom mapping feature. * Use *control* appearance when needed to display within a contrast container. * * @property {string} alignment - Alignment of nested components. - * Can be `center` or `start`. - * Defaults to *start*. + * The predefined ones are `center` or `start`. + * Can be extended with custom mapping feature. Defaults to *start*. * * @property {ViewProps} ...ViewProps - Any props applied to View component. * @@ -99,7 +96,7 @@ type AlignmentProp = 'start' | 'center'; @styled('TopNavigation') export class TopNavigation extends React.Component { - private getAlignmentDependentStyles = (alignment: AlignmentProp): StyleType => { + private getAlignmentDependentStyles = (alignment: TopNavigationAlignment): StyleType => { if (alignment === 'center') { return { container: styles.containerCentered, diff --git a/src/components/ui/topNavigation/topNavigationAction.component.tsx b/src/components/ui/topNavigation/topNavigationAction.component.tsx index 5de531748..e8239e73a 100644 --- a/src/components/ui/topNavigation/topNavigationAction.component.tsx +++ b/src/components/ui/topNavigation/topNavigationAction.component.tsx @@ -17,8 +17,6 @@ import { TouchableWeb, TouchableWebElement, TouchableWebProps, - Overwrite, - LiteralUnion, } from '../../devsupport'; import { Interaction, @@ -26,10 +24,11 @@ import { StyledComponentProps, StyleType, } from '../../theme'; +import { TopNavigationActionAppearance } from '@eva-design/eva/mapping.types'; -type TopNavigationActionStyledProps = Overwrite; -}>; +interface TopNavigationActionStyledProps extends StyledComponentProps { + appearance?: TopNavigationActionAppearance; +} export interface TopNavigationActionProps extends TouchableWebProps, TopNavigationActionStyledProps { icon?: RenderProp>; @@ -49,7 +48,7 @@ export type TopNavigationActionElement = React.ReactElement { return `node_modules/${evaPackage}/${CACHE_FILE_NAME}`; }, + mappingTypes: (evaPackage: string): string => { + return `node_modules/${evaPackage}/${MAPPING_TYPES_FILE_NAME}`; + }, + themeTypes: (evaPackage: string): string => { + return `node_modules/${evaPackage}/${THEME_TYPES_FILE_NAME}`; + }, }; const schemaProcessor = new SchemaProcessor(); @@ -58,13 +67,42 @@ interface EvaCache { */ // eslint-disable-next-line no-restricted-syntax export default class BootstrapService { - static run = (config: EvaConfig): void => { const hasAtLeastOneEvaPackage: boolean = BootstrapService.ensureEvaPackagesInstalledOrWarn(); const isValidConfig: boolean = EvaConfigService.validateConfigOrWarn(config); + const evaMappingPath: string = RELATIVE_PATHS.evaMapping(config.evaPackage); + const evaMapping: SchemaType = ProjectService.requireModule(evaMappingPath); if (hasAtLeastOneEvaPackage && isValidConfig) { - BootstrapService.processMappingIfNeeded(config); + if (!BootstrapService.isBootstrappedBefore(config) || BootstrapService.isRebootstrapNeeded(config)) { + let customMapping = {}; + let customTheme = {}; + let nextChecksum = DEFAULT_CHECKSUM; + if (config.customMappingPath) { + const customMappingString: string = ProjectService.requireActualModule(config.customMappingPath); + customMapping = JSON.parse(customMappingString); + nextChecksum = BootstrapService.createChecksum(customMappingString); + } + if (config.customThemePath) { + const customThemeString: string = ProjectService.requireActualModule(config.customThemePath); + customTheme = JSON.parse(customThemeString); + } + const combinedMapping: SchemaType = LodashMerge({}, evaMapping, customMapping); + const combinedTheme: Record = LodashMerge({}, light, customTheme); + const styles: ThemeStyleType = schemaProcessor.process(combinedMapping); + const writableCache: string = BootstrapService.createWritableCache(nextChecksum, styles); + const outputCachePath: string = RELATIVE_PATHS.cache(config.evaPackage); + Fs.writeFileSync(outputCachePath, writableCache); + Fs.appendFileSync(RELATIVE_PATHS.evaIndex(config.evaPackage), CACHE_EXPORT_SIGNATURE); + + const mappingFileContent = generateMappingTypes(combinedMapping); + Fs.writeFileSync(RELATIVE_PATHS.mappingTypes(config.evaPackage), mappingFileContent); + + const themeFileContent = generateThemeTypes(combinedTheme); + Fs.writeFileSync(RELATIVE_PATHS.themeTypes(config.evaPackage), themeFileContent); + + LogService.success(`Successfully bootstrapped ${config.evaPackage}`); + } } }; @@ -90,65 +128,26 @@ export default class BootstrapService { return true; }; - private static processMappingIfNeeded = (config: EvaConfig): void => { - const evaMappingPath: string = RELATIVE_PATHS.evaMapping(config.evaPackage); + private static isRebootstrapNeeded(config: EvaConfig): boolean { const outputCachePath: string = RELATIVE_PATHS.cache(config.evaPackage); - - /* - * Use `require` for eva mapping as it is static module and should not be changed. - * Require actual cache by reading file at cache file as it may change by file system. - */ - const evaMapping: SchemaType = ProjectService.requireModule(evaMappingPath); const actualCacheString: string = ProjectService.requireActualModule(outputCachePath); const actualCache: EvaCache = JSON.parse(actualCacheString); - - let customMapping: CustomSchemaType; - let actualChecksum: string = DEFAULT_CHECKSUM; + const actualChecksum: string = actualCache?.checksum || DEFAULT_CHECKSUM; let nextChecksum: string = DEFAULT_CHECKSUM; - - if (actualCache?.checksum) { - actualChecksum = actualCache.checksum; - } - if (config.customMappingPath) { - - /* - * Require custom mapping by reading file at `customMappingPath` as it may change by user. - */ const customMappingString: string = ProjectService.requireActualModule(config.customMappingPath); - customMapping = JSON.parse(customMappingString); - /* - * Calculate checksum only for custom mapping, - * but not for styles we generate because eva mapping is a static module. - */ nextChecksum = BootstrapService.createChecksum(customMappingString); } + return actualChecksum !== nextChecksum; + } - /* - * Write if it is the first call - * Or re-write if custom mapping was changed - */ - if (actualChecksum === DEFAULT_CHECKSUM || actualChecksum !== nextChecksum) { - const mapping: SchemaType = LodashMerge({}, evaMapping, customMapping); - const styles: ThemeStyleType = schemaProcessor.process(mapping); - const writableCache: string = BootstrapService.createWritableCache(nextChecksum, styles); - - Fs.writeFileSync(outputCachePath, writableCache); - } - - const hasCacheExports: boolean = BootstrapService.hasCacheExports(config); - if (!hasCacheExports) { - const evaIndexPath: string = RELATIVE_PATHS.evaIndex(config.evaPackage); - - Fs.appendFileSync(evaIndexPath, CACHE_EXPORT_SIGNATURE); - LogService.success(`Successfully bootstrapped ${config.evaPackage}`); - } - }; + private static isBootstrappedBefore(config: EvaConfig): boolean { + return BootstrapService.hasCacheExports(config); + } private static hasCacheExports = (config: EvaConfig): boolean => { const evaIndexPath: string = RELATIVE_PATHS.evaIndex(config.evaPackage); const evaIndexString = ProjectService.requireActualModule(evaIndexPath); - return evaIndexString.includes(CACHE_EXPORT_SIGNATURE); }; diff --git a/src/metro-config/services/eva-config.service.ts b/src/metro-config/services/eva-config.service.ts index e06542605..ecbafc6cb 100644 --- a/src/metro-config/services/eva-config.service.ts +++ b/src/metro-config/services/eva-config.service.ts @@ -19,6 +19,7 @@ import ProjectService from './project.service'; export interface EvaConfig { evaPackage: EvaMappingPackageName; customMappingPath?: string; + customThemePath?: string; watch?: boolean; }