From a29d12ba6604c052921564e303c1e6ec8e809e7d Mon Sep 17 00:00:00 2001 From: Xavier Carpentier Date: Tue, 29 Jan 2019 17:16:17 +0100 Subject: [PATCH 01/19] chore add typescript dep --- package.json | 3 ++- yarn.lock | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index bea1920c8..654c1b0b9 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,8 @@ "prop-types": "15.6.2", "react": "16.8.1", "react-native": "0.51.0", - "react-test-renderer": "16.8.1" + "react-test-renderer": "16.8.1", + "typescript": "3.2.4" }, "dependencies": { "@expo/react-native-action-sheet": "^2.0.1", diff --git a/yarn.lock b/yarn.lock index 1374045ca..7a078e389 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6390,6 +6390,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.2.4.tgz#c585cb952912263d915b462726ce244ba510ef3d" + integrity sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg== + ua-parser-js@^0.7.9: version "0.7.17" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" From 2f88e42e96dd758c555ed9bb1f5572e52f49fb52 Mon Sep 17 00:00:00 2001 From: Xavier Carpentier Date: Fri, 5 Apr 2019 18:14:24 +0200 Subject: [PATCH 02/19] init TS --- .eslintignore | 7 - .eslintrc | 22 - circle.yml | 24 +- index.d.ts | 397 ------------ lib/Actions.d.ts | 33 + lib/Actions.js | 79 +++ lib/Actions.js.map | 1 + lib/Avatar.d.ts | 52 ++ lib/Avatar.js | 123 ++++ lib/Avatar.js.map | 1 + lib/Bubble.d.ts | 128 ++++ lib/Bubble.js | 327 ++++++++++ lib/Bubble.js.map | 1 + lib/Color.d.ts | 18 + lib/Color.js | 18 + lib/Color.js.map | 1 + lib/Composer.d.ts | 55 ++ lib/Composer.js | 78 +++ lib/Composer.js.map | 1 + lib/Constant.d.ts | 5 + lib/Constant.js | 10 + lib/Constant.js.map | 1 + lib/Day.d.ts | 41 ++ lib/Day.js | 64 ++ lib/Day.js.map | 1 + lib/GiftedAvatar.d.ts | 32 + lib/GiftedAvatar.js | 137 ++++ lib/GiftedAvatar.js.map | 1 + lib/GiftedChat.d.ts | 283 +++++++++ lib/GiftedChat.js | 512 +++++++++++++++ lib/GiftedChat.js.map | 1 + lib/InputToolbar.d.ts | 59 ++ lib/InputToolbar.js | 134 ++++ lib/InputToolbar.js.map | 1 + lib/LoadEarlier.d.ts | 41 ++ lib/LoadEarlier.js | 80 +++ lib/LoadEarlier.js.map | 1 + lib/Message.d.ts | 63 ++ lib/Message.js | 144 +++++ lib/Message.js.map | 1 + lib/MessageContainer.d.ts | 82 +++ lib/MessageContainer.js | 215 +++++++ lib/MessageContainer.js.map | 1 + lib/MessageImage.d.ts | 30 + lib/MessageImage.js | 48 ++ lib/MessageImage.js.map | 1 + lib/MessageText.d.ts | 56 ++ lib/MessageText.js | 139 +++++ lib/MessageText.js.map | 1 + lib/MessageVideo.d.ts | 36 ++ lib/MessageVideo.js | 38 ++ lib/MessageVideo.js.map | 1 + lib/Send.d.ts | 39 ++ lib/Send.js | 54 ++ lib/Send.js.map | 1 + lib/SystemMessage.d.ts | 27 + lib/SystemMessage.js | 44 ++ lib/SystemMessage.js.map | 1 + lib/Time.d.ts | 44 ++ lib/Time.js | 75 +++ lib/Time.js.map | 1 + lib/index.d.ts | 1 + lib/index.js | 2 + lib/index.js.map | 1 + lib/types.d.ts | 26 + lib/types.js | 1 + lib/types.js.map | 1 + lib/utils.d.ts | 3 + lib/utils.js | 18 + lib/utils.js.map | 1 + package.json | 31 +- src/.prettierrc | 11 + src/Actions.js | 103 --- src/Actions.tsx | 110 ++++ src/Avatar.js | 129 ---- src/Avatar.tsx | 175 ++++++ src/Bubble.js | 332 ---------- src/Bubble.tsx | 428 +++++++++++++ src/{Color.js => Color.ts} | 2 +- src/Composer.js | 100 --- src/Composer.tsx | 127 ++++ src/{Constant.js => Constant.ts} | 0 src/{Day.js => Day.tsx} | 65 +- src/GiftedAvatar.js | 130 ---- src/GiftedAvatar.tsx | 191 ++++++ src/GiftedChat.js | 648 ------------------- src/GiftedChat.tsx | 796 ++++++++++++++++++++++++ src/GiftedChatInteractionManager.js | 19 - src/InputToolbar.js | 137 ---- src/InputToolbar.tsx | 173 +++++ src/{LoadEarlier.js => LoadEarlier.tsx} | 144 +++-- src/Message.js | 161 ----- src/Message.tsx | 176 ++++++ src/MessageContainer.js | 253 -------- src/MessageContainer.tsx | 333 ++++++++++ src/MessageImage.js | 64 -- src/MessageImage.tsx | 83 +++ src/MessageText.js | 163 ----- src/MessageText.tsx | 186 ++++++ src/MessageVideo.js | 51 -- src/MessageVideo.tsx | 67 ++ src/Send.js | 65 -- src/Send.tsx | 95 +++ src/SystemMessage.js | 48 -- src/SystemMessage.tsx | 69 ++ src/Time.js | 91 --- src/Time.tsx | 126 ++++ src/index.ts | 1 + src/types.ts | 30 + src/utils.js | 24 - src/utils.ts | 25 + tsconfig.json | 21 + tslint.json | 14 + yarn.lock | 730 ++++------------------ 114 files changed, 7027 insertions(+), 3666 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc delete mode 100644 index.d.ts create mode 100644 lib/Actions.d.ts create mode 100644 lib/Actions.js create mode 100644 lib/Actions.js.map create mode 100644 lib/Avatar.d.ts create mode 100644 lib/Avatar.js create mode 100644 lib/Avatar.js.map create mode 100644 lib/Bubble.d.ts create mode 100644 lib/Bubble.js create mode 100644 lib/Bubble.js.map create mode 100644 lib/Color.d.ts create mode 100644 lib/Color.js create mode 100644 lib/Color.js.map create mode 100644 lib/Composer.d.ts create mode 100644 lib/Composer.js create mode 100644 lib/Composer.js.map create mode 100644 lib/Constant.d.ts create mode 100644 lib/Constant.js create mode 100644 lib/Constant.js.map create mode 100644 lib/Day.d.ts create mode 100644 lib/Day.js create mode 100644 lib/Day.js.map create mode 100644 lib/GiftedAvatar.d.ts create mode 100644 lib/GiftedAvatar.js create mode 100644 lib/GiftedAvatar.js.map create mode 100644 lib/GiftedChat.d.ts create mode 100644 lib/GiftedChat.js create mode 100644 lib/GiftedChat.js.map create mode 100644 lib/InputToolbar.d.ts create mode 100644 lib/InputToolbar.js create mode 100644 lib/InputToolbar.js.map create mode 100644 lib/LoadEarlier.d.ts create mode 100644 lib/LoadEarlier.js create mode 100644 lib/LoadEarlier.js.map create mode 100644 lib/Message.d.ts create mode 100644 lib/Message.js create mode 100644 lib/Message.js.map create mode 100644 lib/MessageContainer.d.ts create mode 100644 lib/MessageContainer.js create mode 100644 lib/MessageContainer.js.map create mode 100644 lib/MessageImage.d.ts create mode 100644 lib/MessageImage.js create mode 100644 lib/MessageImage.js.map create mode 100644 lib/MessageText.d.ts create mode 100644 lib/MessageText.js create mode 100644 lib/MessageText.js.map create mode 100644 lib/MessageVideo.d.ts create mode 100644 lib/MessageVideo.js create mode 100644 lib/MessageVideo.js.map create mode 100644 lib/Send.d.ts create mode 100644 lib/Send.js create mode 100644 lib/Send.js.map create mode 100644 lib/SystemMessage.d.ts create mode 100644 lib/SystemMessage.js create mode 100644 lib/SystemMessage.js.map create mode 100644 lib/Time.d.ts create mode 100644 lib/Time.js create mode 100644 lib/Time.js.map create mode 100644 lib/index.d.ts create mode 100644 lib/index.js create mode 100644 lib/index.js.map create mode 100644 lib/types.d.ts create mode 100644 lib/types.js create mode 100644 lib/types.js.map create mode 100644 lib/utils.d.ts create mode 100644 lib/utils.js create mode 100644 lib/utils.js.map create mode 100644 src/.prettierrc delete mode 100644 src/Actions.js create mode 100644 src/Actions.tsx delete mode 100644 src/Avatar.js create mode 100644 src/Avatar.tsx delete mode 100644 src/Bubble.js create mode 100644 src/Bubble.tsx rename src/{Color.js => Color.ts} (99%) delete mode 100644 src/Composer.js create mode 100644 src/Composer.tsx rename src/{Constant.js => Constant.ts} (100%) rename src/{Day.js => Day.tsx} (58%) delete mode 100644 src/GiftedAvatar.js create mode 100644 src/GiftedAvatar.tsx delete mode 100644 src/GiftedChat.js create mode 100644 src/GiftedChat.tsx delete mode 100644 src/GiftedChatInteractionManager.js delete mode 100644 src/InputToolbar.js create mode 100644 src/InputToolbar.tsx rename src/{LoadEarlier.js => LoadEarlier.tsx} (52%) delete mode 100644 src/Message.js create mode 100644 src/Message.tsx delete mode 100644 src/MessageContainer.js create mode 100644 src/MessageContainer.tsx delete mode 100644 src/MessageImage.js create mode 100644 src/MessageImage.tsx delete mode 100644 src/MessageText.js create mode 100644 src/MessageText.tsx delete mode 100644 src/MessageVideo.js create mode 100644 src/MessageVideo.tsx delete mode 100644 src/Send.js create mode 100644 src/Send.tsx delete mode 100644 src/SystemMessage.js create mode 100644 src/SystemMessage.tsx delete mode 100644 src/Time.js create mode 100644 src/Time.tsx create mode 100644 src/index.ts create mode 100644 src/types.ts delete mode 100644 src/utils.js create mode 100644 src/utils.ts create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index be20f4653..000000000 --- a/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -android -ios -example -example-slack-message -example-pusher-chatkit -example-expo \ No newline at end of file diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index e717fdbb9..000000000 --- a/.eslintrc +++ /dev/null @@ -1,22 +0,0 @@ -{ - "extends": "cooperka/react-native", - "parser": "babel-eslint", - "env": { - "browser": true, - "jest": true - }, - "rules": { - "no-underscore-dangle": 0, - "import/no-unresolved": [ - 2, - { - "ignore": ["react", "react-native"] - } - ], - "import/no-extraneous-dependencies": 0, - "import/extensions": 0, - "react/no-unused-prop-types": 0, - "react/no-typos": 0, - "jsx-a11y/accessible-emoji": 0 - } -} diff --git a/circle.yml b/circle.yml index fd01fd22e..3a5d703e0 100644 --- a/circle.yml +++ b/circle.yml @@ -1,7 +1,7 @@ --- machine: environment: - PATH: "${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin" + PATH: '${PATH}:${HOME}/${CIRCLE_PROJECT_REPONAME}/node_modules/.bin' node: version: 8.2.0 dependencies: @@ -9,27 +9,13 @@ dependencies: - yarn global add codecov - yarn install --no-progress --no-emoji --ignore-engines cache_directories: - - "node_modules" + - 'node_modules' - ~/.yarn - ~/.cache/yarn test: override: - - yarn run lint - - yarn run test:coverage + - yarn lint + - yarn tsc + - yarn test:coverage - codecov - -# TODO: deployment: -# release: -# tag: /v[0-9]+(\.[0-9]+)*/ -# commands: -# - echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" >> ~/.npmrc -# - yarn publish --new-version `./scripts/version.js` - -#deployment: -# appr: -# branch: /.*/ -# commands: -# - 'export BRANCH="$CIRCLE_PROJECT_REPONAME/$CIRCLE_PROJECT_USERNAME#$CIRCLE_BRANCH"' -# - 'echo $BRANCH' -# - yarn appr diff --git a/index.d.ts b/index.d.ts deleted file mode 100644 index 5eb49ca48..000000000 --- a/index.d.ts +++ /dev/null @@ -1,397 +0,0 @@ -import * as React from 'react'; -import * as RN from 'react-native'; - -type Omit = Pick> - -type ViewStyle = RN.StyleProp; -type TextStyle = RN.StyleProp; -type ImageStyle = RN.StyleProp; - -export interface LeftRightStyle { - left: T; - right: T; -} - -export interface User { - _id: any; - name?: string; - avatar?: string; -} - -export interface IMessage { - _id: any; - text: string; - createdAt: Date | number; - user: User; - image?: string; - system?: boolean; -} - -export type IChatMessage = IMessage; - -interface ActionsProps { - // todo: onSend is not used - onSend?(): void; - options?: any; - optionTintColor?: string; - icon?(): void; - wrapperStyle?: ViewStyle; - containerStyle?: ViewStyle; - iconTextStyle?: ViewStyle; - onPressActionButton(): void; -} - -export class Actions extends React.Component {} - -interface AvatarProps { - renderAvatarOnTop: boolean; - position: 'left' | 'right'; - currentMessage: TMessage; - previousMessage: TMessage; - nextMessage: TMessage; - onPressAvatar(): void; - renderAvatar(props: AvatarProps): JSX.Element; - containerStyle: { - left: any; - right: any; - }; - imageStyle: { - left: any; - right: any; - }; - // TODO: remove in next major release - isSameDay(currentMessage: TMessage, message: TMessage): boolean; - isSameUser(currentMessage: TMessage, message: TMessage): boolean; -} - -export class Avatar extends React.Component {} - -interface BubbleProps { - user: User; - touchableProps?: object; - onLongPress?(context?: any, message?: any): void; - renderMessageImage?( - messageImageProps: RenderMessageImageProps, - ): React.ReactNode; - renderMessageText?(messageTextProps: MessageTextProps): React.ReactNode; - renderCustomView?(bubbleProps: BubbleProps): React.ReactNode; - renderTime?(timeProps: TimeProps): React.ReactNode; - renderTicks?(currentMessage: TMessage): React.ReactNode; - renderUsername?(): React.ReactNode; - renderUsernameOnMessage?: boolean - position?: "left" | "right"; - currentMessage?: TMessage; - nextMessage?: TMessage; - previousMessage?: TMessage; - containerStyle?: LeftRightStyle; - wrapperStyle?: LeftRightStyle; - textStyle?: LeftRightStyle; - bottomContainerStyle: LeftRightStyle; - tickStyle: TextStyle; - containerToNextStyle: LeftRightStyle; - containerToPreviousStyle: LeftRightStyle; - // TODO: remove in next major release - isSameDay?(currentMessage: TMessage, nextMessage: TMessage): boolean; - isSameUser?(currentMessage: TMessage, nextMessage: TMessage): boolean; -} - -export class Bubble extends React.Component {} - -interface ComposerProps { - composerHeight?: number; - text?: string; - placeholder?: string; - placeholderTextColor?: string; - textInputProps?: Partial; - onTextChanged?(text: string): void; - onInputSizeChanged?(contentSize: { width: number; height: number }): void; - multiline?: boolean; - textInputStyle?: RN.TextInputProps['style']; - textInputAutoFocus?: boolean; - keyboardAppearance?: RN.TextInputProps['keyboardAppearance']; -} - -export class Composer extends React.Component {} - -interface DayProps { - currentMessage?: TMessage; - previousMessage?: TMessage; - containerStyle?: ViewStyle; - wrapperStyle?: ViewStyle; - textStyle?: TextStyle; - // TODO: remove in next major release - isSameDay?(currentMessage: TMessage, nextMessage: TMessage): boolean; - isSameUser?(currentMessage: TMessage, nextMessage: TMessage): boolean; - dateFormat?: string; -} - -export class Day extends React.Component {} - -interface GiftedAvatarProps { - user?: User; - onPress?(): void; - avatarStyle?: ImageStyle; - textStyle?: TextStyle; -} - -export class GiftedAvatar extends React.Component {} - -export interface GiftedChatProps { - /* Messages to display */ - messages?: TMessage[]; - /* Input text; default is undefined, but if specified, it will override GiftedChat's internal state */ - text?: string; - /* Placeholder when text is empty; default is 'Type a message...' */ - placeholder?: string; - /* Generate an id for new messages. Defaults to UUID v4, generated by uuid */ - messageIdGenerator?(message: TMessage): string; - /* User sending the messages: { _id, name, avatar } */ - user?: User; - /* Callback when sending a message */ - onSend?(messages: TMessage[]): void; - /* Locale to localize the dates */ - locale?: string; - /* Format to use for rendering times; default is 'LT' */ - timeFormat?: string; - /* Format to use for rendering dates; default is 'll' */ - dateFormat?: string; - /* Animates the view when the keyboard appears */ - isAnimated?: boolean; - /* Enables the "Load earlier messages" button */ - loadEarlier?: boolean; - /*Callback when loading earlier messages*/ - onLoadEarlier?(): void; - /*Display an ActivityIndicator when loading earlier messages*/ - isLoadingEarlier?: boolean; - /* Render a loading view when initializing */ - renderLoading?(): React.ReactNode; - /* Custom "Load earlier messages" button */ - renderLoadEarlier?(props: LoadEarlierProps): React.ReactNode; - /* Custom message avatar; set to null to not render any avatar for the message */ - renderAvatar?(props: AvatarProps): React.ReactNode; - /* Whether to render an avatar for the current user; default is false, only show avatars for other users */ - showUserAvatar?: boolean; - /* When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is false */ - showAvatarForEveryMessage?: boolean; - /* Callback when a message avatar is tapped */ - onPressAvatar?(user: User): void; - /* Render the message avatar at the top of consecutive messages, rather than the bottom; default is false */ - renderAvatarOnTop?: boolean; - /* Custom message bubble */ - renderBubble?(props: BubbleProps): React.ReactNode; - /*Custom system message */ - renderSystemMessage?(props: SystemMessageProps): React.ReactNode; - /* Callback when a message bubble is long-pressed; default is to show an ActionSheet with "Copy Text" (see example using showActionSheetWithOptions()) */ - onLongPress?(context: any, message: any): void; - /* Reverses display order of messages; default is true */ - inverted?: boolean; - /*Custom message container */ - renderMessage?(message: MessageProps): React.ReactNode; - /* Custom message text */ - renderMessageText?(messageText: MessageTextProps): React.ReactNode; - /* Custom message image */ - renderMessageImage?(props: RenderMessageImageProps): React.ReactNode; - /* Extra props to be passed to the component created by the default renderMessageImage */ - imageProps?: MessageProps; - /*Extra props to be passed to the MessageImage's Lightbox */ - lightboxProps?: any; - /* Custom view inside the bubble */ - renderCustomView?(): React.ReactNode; - /*Custom day above a message*/ - renderDay?(props: DayProps): React.ReactNode; - /* Custom time inside a message */ - renderTime?(props: TimeProps): React.ReactNode; - /* Custom footer component on the ListView, e.g. 'User is typing...' */ - renderFooter?(): React.ReactNode; - /* Custom component to render below the MessageContainer (separate from the ListView) */ - renderChatFooter?(): React.ReactNode; - /* Custom message composer container */ - renderInputToolbar?(props: InputToolbarProps): React.ReactNode; - /* Custom text input message composer */ - renderComposer?(props: ComposerProps): React.ReactNode; - /* Custom action button on the left of the message composer */ - renderActions?(props: ActionsProps): React.ReactNode; - /* Custom send button; you can pass children to the original Send component quite easily, for example to use a custom icon (example) */ - renderSend?(props: SendProps): React.ReactNode; - /*Custom second line of actions below the message composer */ - renderAccessory?(props: InputToolbarProps): React.ReactNode; - /*Callback when the Action button is pressed (if set, the default actionSheet will not be used) */ - onPressActionButton?(): void; - /*Distance of the chat from the bottom of the screen (e.g. useful if you display a tab bar) */ - bottomOffset?: number; - /* Minimum height of the input toolbar; default is 44 */ - minInputToolbarHeight?: number; - /*Extra props to be passed to the messages ; some props can't be overridden, see the code in MessageContainer.render() for details */ - listViewProps?: any; - /* Extra props to be passed to the */ - textInputProps?: any; - /*Determines whether the keyboard should stay visible after a tap; see docs */ - keyboardShouldPersistTaps?: any; - /* Callback when the input text changes */ - onInputTextChanged?(text: string): void; - /*Max message composer TextInput length */ - maxInputLength?: number; - /* Custom parse patterns for react-native-parsed-text used to linkify message content (like URLs and phone numbers) */ - parsePatterns?(): React.ReactNode; - /* Force getting keyboard height to fix some display issues */ - forceGetKeyboardHeight?: boolean; - /* Force send button */ - alwaysShowSend?: boolean; - /* Image style */ - imageStyle?: ViewStyle; - /* This can be used to pass any data which needs to be re-rendered */ - extraData?: any; - /* composer min Height */ - minComposerHeight?: number; - /* composer min Height */ - maxComposerHeight?: number; -} - -export class GiftedChat extends React.Component { - static defaultProps: GiftedChatProps; - static append( - currentMessages: TMessage[], - messages: TMessage[], - inverted?: boolean, - ): TMessage[]; - static prepend( - currentMessages: TMessage[], - messages: TMessage[], - inverted?: boolean, - ): TMessage[]; -} - -interface InputToolbarProps { - renderAccessory?(props: InputToolbarProps): React.ReactNode; - renderActions?(props: ActionsProps): React.ReactNode; - renderSend?(props: SendProps): React.ReactNode; - renderComposer?(props: ComposerProps): React.ReactNode; - onPressActionButton?(): void; - containerStyle?: ViewStyle; - primaryStyle?: ViewStyle; - accessoryStyle?: ViewStyle; -} -export class InputToolbar extends React.Component {} - -interface LoadEarlierProps { - onLoadEarlier?(): void; - isLoadingEarlier: boolean; - label?: string; - containerStyle?: ViewStyle; - wrapperStyle?: ViewStyle; - textStyle?: TextStyle; - activityIndicatorStyle?: ViewStyle; -} - -export class LoadEarlier extends React.Component {} - -interface MessageProps { - // TODO: this is not used - renderAvatar(props: AvatarProps): React.ReactNode; - showUserAvatar?: boolean; - renderBubble(props: BubbleProps): React.ReactNode; - renderDay(props: DayProps): React.ReactNode; - renderSystemMessage(props: SystemMessageProps): React.ReactNode; - position?: 'left' | 'right'; - currentMessage?: TMessage; - nextMessage?: TMessage; - previousMessage?: TMessage; - user?: User; - inverted?: boolean; - containerStyle: LeftRightStyle; -} - -export class Message extends React.Component {} - -interface MessageContainerProps { - messages?: TMessage[]; - user?: User; - renderFooter?(props: MessageContainerProps): React.ReactNode; - renderMessage?(props: MessageProps): React.ReactNode; - renderLoadEarlier?(props: LoadEarlierProps): React.ReactNode; - // todo: not used - onLoadEarlier?(): void; - listViewProps: Partial; - inverted?: boolean; - loadEarlier?: boolean; - // todo: should be InvertibleScrollView props - invertibleScrollViewProps?: object; -} - -export class MessageContainer extends React.Component< - MessageContainerProps -> {} - -interface MessageImageProps { - currentMessage?: TMessage; - containerStyle?: ViewStyle; - imageStyle?: ImageStyle; - imageProps?: Partial; - // todo: should be LightBox properties - lightboxProps?: object; -} - -export class MessageImage extends React.Component {} - -export type RenderMessageImageProps< - TMessage extends IMessage = IMessage -> = MessageImageProps & - Omit, 'wrapperStyle' | 'containerStyle'>; - -interface MessageTextProps { - position: 'left' | 'right'; - currentMessage?: TMessage; - containerStyle?: LeftRightStyle; - textStyle?: LeftRightStyle; - linkStyle?: LeftRightStyle; - parsePatterns?(linkStyle: TextStyle): any; - textProps?: RN.TextProps; - customTextStyle?: TextStyle; -} - -export class MessageText extends React.Component {} - -export type RenderMessageTextProps< - TMessage extends IMessage = IMessage -> = MessageTextProps & - Omit, 'wrapperStyle' | 'containerStyle'>; - -interface SendProps { - text?: string; - onSend?({ text }: { text: string }, b: boolean): void; - label?: string; - containerStyle?: ViewStyle; - textStyle?: TextStyle; - children?: React.ReactNode; - alwaysShowSend?: boolean; - disabled?: boolean; -} - -export class Send extends React.Component {} - -interface SystemMessageProps { - currentMessage?: TMessage; - containerStyle?: ViewStyle; - wrapperStyle?: ViewStyle; - textStyle?: TextStyle; -} - -export class SystemMessage extends React.Component {} - -interface TimeProps { - position?: 'left' | 'right'; - currentMessage?: TMessage; - containerStyle?: LeftRightStyle; - textStyle?: LeftRightStyle; - timeFormat?: string; -} - -export class Time extends React.Component {} - -export type utils = { - isSameUser(currentMessage?: TMessage, message?: TMessage): boolean; - isSameDay(currentMessage?: TMessage, message?: TMessage): boolean; - isSameTime(currentMessage?: TMessage, message?: TMessage): boolean; -}; - -export const utils: utils; diff --git a/lib/Actions.d.ts b/lib/Actions.d.ts new file mode 100644 index 000000000..cae3319ad --- /dev/null +++ b/lib/Actions.d.ts @@ -0,0 +1,33 @@ +import PropTypes from 'prop-types'; +import React, { ReactNode } from 'react'; +import { ViewStyle, TextStyle } from 'react-native'; +interface ActionsProps { + options?: { + [key: string]: any; + }; + optionTintColor?: string; + icon?: () => ReactNode; + wrapperStyle?: ViewStyle; + iconTextStyle?: TextStyle; + containerStyle?: ViewStyle; + onPressActionButton?(): void; +} +export default class Actions extends React.Component { + static defaultProps: ActionsProps; + static propTypes: { + onSend: PropTypes.Requireable<(...args: any[]) => any>; + options: PropTypes.Requireable; + optionTintColor: PropTypes.Requireable; + icon: PropTypes.Requireable<(...args: any[]) => any>; + onPressActionButton: PropTypes.Requireable<(...args: any[]) => any>; + wrapperStyle: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + containerStyle: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + }; + static contextTypes: { + actionSheet: PropTypes.Requireable<(...args: any[]) => any>; + }; + onActionsPress: () => void; + renderIcon(): {} | null | undefined; + render(): JSX.Element; +} +export {}; diff --git a/lib/Actions.js b/lib/Actions.js new file mode 100644 index 000000000..00067123f --- /dev/null +++ b/lib/Actions.js @@ -0,0 +1,79 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { StyleSheet, Text, TouchableOpacity, View, ViewPropTypes, } from 'react-native'; +import Color from './Color'; +export default class Actions extends React.Component { + constructor() { + super(...arguments); + this.onActionsPress = () => { + const { options } = this.props; + const optionKeys = Object.keys(options); + const cancelButtonIndex = optionKeys.indexOf('Cancel'); + this.context.actionSheet().showActionSheetWithOptions({ + options: optionKeys, + cancelButtonIndex, + tintColor: this.props.optionTintColor, + }, (buttonIndex) => { + const key = optionKeys[buttonIndex]; + if (key) { + options[key](this.props); + } + }); + }; + } + renderIcon() { + if (this.props.icon) { + return this.props.icon(); + } + return ( + + + ); + } + render() { + return ( + {this.renderIcon()} + ); + } +} +Actions.defaultProps = { + options: {}, + optionTintColor: Color.optionTintColor, + icon: undefined, + containerStyle: {}, + iconTextStyle: {}, + wrapperStyle: {}, +}; +Actions.propTypes = { + onSend: PropTypes.func, + options: PropTypes.object, + optionTintColor: PropTypes.string, + icon: PropTypes.func, + onPressActionButton: PropTypes.func, + wrapperStyle: ViewPropTypes.style, + containerStyle: ViewPropTypes.style, +}; +Actions.contextTypes = { + actionSheet: PropTypes.func, +}; +const styles = StyleSheet.create({ + container: { + width: 26, + height: 26, + marginLeft: 10, + marginBottom: 10, + }, + wrapper: { + borderRadius: 13, + borderColor: Color.defaultColor, + borderWidth: 2, + flex: 1, + }, + iconText: { + color: Color.defaultColor, + fontWeight: 'bold', + fontSize: 16, + backgroundColor: Color.backgroundTransparent, + textAlign: 'center', + }, +}); +//# sourceMappingURL=Actions.js.map \ No newline at end of file diff --git a/lib/Actions.js.map b/lib/Actions.js.map new file mode 100644 index 000000000..4d02c0bc0 --- /dev/null +++ b/lib/Actions.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Actions.js","sourceRoot":"","sources":["../src/Actions.tsx"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,YAAY,CAAA;AAClC,OAAO,KAAoB,MAAM,OAAO,CAAA;AACxC,OAAO,EACL,UAAU,EACV,IAAI,EACJ,gBAAgB,EAChB,IAAI,EACJ,aAAa,GAGd,MAAM,cAAc,CAAA;AACrB,OAAO,KAAK,MAAM,SAAS,CAAA;AAY3B,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,KAAK,CAAC,SAAuB;IAAlE;;QAwBE,mBAAc,GAAG,GAAG,EAAE;YACpB,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;YAC9B,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,OAAQ,CAAC,CAAA;YACxC,MAAM,iBAAiB,GAAG,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;YACtD,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,0BAA0B,CACnD;gBACE,OAAO,EAAE,UAAU;gBACnB,iBAAiB;gBACjB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe;aACtC,EACD,CAAC,WAAmB,EAAE,EAAE;gBACtB,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;gBACnC,IAAI,GAAG,EAAE;oBACP,OAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;iBAC1B;YACH,CAAC,CACF,CAAA;QACH,CAAC,CAAA;IAuBH,CAAC;IArBC,UAAU;QACR,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;YACnB,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAA;SACzB;QACD,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CACrD;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,CACnE;MAAA,EAAE,IAAI,CAAC,CACR,CAAA;IACH,CAAC;IAED,MAAM;QACJ,OAAO,CACL,CAAC,gBAAgB,CACf,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CACrD,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,mBAAmB,IAAI,IAAI,CAAC,cAAc,CAAC,CAE/D;QAAA,CAAC,IAAI,CAAC,UAAU,EAAE,CACpB;MAAA,EAAE,gBAAgB,CAAC,CACpB,CAAA;IACH,CAAC;;AA9DM,oBAAY,GAAiB;IAClC,OAAO,EAAE,EAAE;IACX,eAAe,EAAE,KAAK,CAAC,eAAe;IACtC,IAAI,EAAE,SAAS;IACf,cAAc,EAAE,EAAE;IAClB,aAAa,EAAE,EAAE;IACjB,YAAY,EAAE,EAAE;CACjB,CAAA;AAEM,iBAAS,GAAG;IACjB,MAAM,EAAE,SAAS,CAAC,IAAI;IACtB,OAAO,EAAE,SAAS,CAAC,MAAM;IACzB,eAAe,EAAE,SAAS,CAAC,MAAM;IACjC,IAAI,EAAE,SAAS,CAAC,IAAI;IACpB,mBAAmB,EAAE,SAAS,CAAC,IAAI;IACnC,YAAY,EAAE,aAAa,CAAC,KAAK;IACjC,cAAc,EAAE,aAAa,CAAC,KAAK;CACpC,CAAA;AAEM,oBAAY,GAAG;IACpB,WAAW,EAAE,SAAS,CAAC,IAAI;CAC5B,CAAA;AA4CH,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC;IAC/B,SAAS,EAAE;QACT,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,UAAU,EAAE,EAAE;QACd,YAAY,EAAE,EAAE;KACjB;IACD,OAAO,EAAE;QACP,YAAY,EAAE,EAAE;QAChB,WAAW,EAAE,KAAK,CAAC,YAAY;QAC/B,WAAW,EAAE,CAAC;QACd,IAAI,EAAE,CAAC;KACR;IACD,QAAQ,EAAE;QACR,KAAK,EAAE,KAAK,CAAC,YAAY;QACzB,UAAU,EAAE,MAAM;QAClB,QAAQ,EAAE,EAAE;QACZ,eAAe,EAAE,KAAK,CAAC,qBAAqB;QAC5C,SAAS,EAAE,QAAQ;KACpB;CACF,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/Avatar.d.ts b/lib/Avatar.d.ts new file mode 100644 index 000000000..55d10dd81 --- /dev/null +++ b/lib/Avatar.d.ts @@ -0,0 +1,52 @@ +import PropTypes from 'prop-types'; +import React, { ReactNode } from 'react'; +import { ImageStyle, ViewStyle } from 'react-native'; +import { Omit, IMessage, User, LeftRightStyle } from './types'; +interface AvatarProps { + currentMessage?: IMessage; + previousMessage?: IMessage; + nextMessage?: IMessage; + position: 'left' | 'right'; + renderAvatarOnTop?: boolean; + showAvatarForEveryMessage?: boolean; + imageStyle?: LeftRightStyle; + containerStyle?: LeftRightStyle; + renderAvatar?(props: Omit): ReactNode; + onPressAvatar?(user: User): void; +} +export default class Avatar extends React.Component { + static defaultProps: { + renderAvatarOnTop: boolean; + showAvatarForEveryMessage: boolean; + position: string; + currentMessage: { + user: null; + }; + previousMessage: {}; + nextMessage: {}; + containerStyle: {}; + imageStyle: {}; + onPressAvatar: () => void; + }; + static propTypes: { + renderAvatarOnTop: PropTypes.Requireable; + showAvatarForEveryMessage: PropTypes.Requireable; + position: PropTypes.Requireable; + currentMessage: PropTypes.Requireable; + previousMessage: PropTypes.Requireable; + nextMessage: PropTypes.Requireable; + onPressAvatar: PropTypes.Requireable<(...args: any[]) => any>; + renderAvatar: PropTypes.Requireable<(...args: any[]) => any>; + containerStyle: PropTypes.Requireable Error | null) | undefined; + right: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + }>>; + imageStyle: PropTypes.Requireable Error | null) | undefined; + right: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + }>>; + }; + renderAvatar(): {} | null | undefined; + render(): JSX.Element | null; +} +export {}; diff --git a/lib/Avatar.js b/lib/Avatar.js new file mode 100644 index 000000000..4b5f41568 --- /dev/null +++ b/lib/Avatar.js @@ -0,0 +1,123 @@ +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +import PropTypes from 'prop-types'; +import React from 'react'; +import { StyleSheet, View, ViewPropTypes, } from 'react-native'; +import GiftedAvatar from './GiftedAvatar'; +import { isSameUser, isSameDay } from './utils'; +const styles = { + left: StyleSheet.create({ + container: { + marginRight: 8, + }, + onTop: { + alignSelf: 'flex-start', + }, + onBottom: {}, + image: { + height: 36, + width: 36, + borderRadius: 18, + }, + }), + right: StyleSheet.create({ + container: { + marginLeft: 8, + }, + onTop: { + alignSelf: 'flex-start', + }, + onBottom: {}, + image: { + height: 36, + width: 36, + borderRadius: 18, + }, + }), +}; +export default class Avatar extends React.Component { + renderAvatar() { + if (this.props.renderAvatar) { + const _a = this.props, { renderAvatar } = _a, avatarProps = __rest(_a, ["renderAvatar"]); + return this.props.renderAvatar(avatarProps); + } + if (this.props.currentMessage) { + return ( this.props.onPressAvatar && + this.props.onPressAvatar(this.props.currentMessage.user)}/>); + } + return null; + } + render() { + const { renderAvatarOnTop, showAvatarForEveryMessage, containerStyle, position, currentMessage, renderAvatar, previousMessage, nextMessage, imageStyle, } = this.props; + const messageToCompare = renderAvatarOnTop ? previousMessage : nextMessage; + const computedStyle = renderAvatarOnTop ? 'onTop' : 'onBottom'; + if (renderAvatar === null) { + return null; + } + if (!showAvatarForEveryMessage && + currentMessage && + messageToCompare && + isSameUser(currentMessage, messageToCompare) && + isSameDay(currentMessage, messageToCompare)) { + return ( + + ); + } + return ( + {this.renderAvatar()} + ); + } +} +Avatar.defaultProps = { + renderAvatarOnTop: false, + showAvatarForEveryMessage: false, + position: 'left', + currentMessage: { + user: null, + }, + previousMessage: {}, + nextMessage: {}, + containerStyle: {}, + imageStyle: {}, + onPressAvatar: () => { }, +}; +Avatar.propTypes = { + renderAvatarOnTop: PropTypes.bool, + showAvatarForEveryMessage: PropTypes.bool, + position: PropTypes.oneOf(['left', 'right']), + currentMessage: PropTypes.object, + previousMessage: PropTypes.object, + nextMessage: PropTypes.object, + onPressAvatar: PropTypes.func, + renderAvatar: PropTypes.func, + containerStyle: PropTypes.shape({ + left: ViewPropTypes.style, + right: ViewPropTypes.style, + }), + imageStyle: PropTypes.shape({ + left: ViewPropTypes.style, + right: ViewPropTypes.style, + }), +}; +//# sourceMappingURL=Avatar.js.map \ No newline at end of file diff --git a/lib/Avatar.js.map b/lib/Avatar.js.map new file mode 100644 index 000000000..ba6468882 --- /dev/null +++ b/lib/Avatar.js.map @@ -0,0 +1 @@ +{"version":3,"file":"Avatar.js","sourceRoot":"","sources":["../src/Avatar.tsx"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/Bubble.d.ts b/lib/Bubble.d.ts new file mode 100644 index 000000000..663274fcc --- /dev/null +++ b/lib/Bubble.d.ts @@ -0,0 +1,128 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { ViewStyle, TextStyle } from 'react-native'; +import MessageText from './MessageText'; +import MessageImage from './MessageImage'; +import MessageVideo from './MessageVideo'; +import Time from './Time'; +import { User, IMessage, LeftRightStyle } from './types'; +interface BubbleProps { + user?: User; + touchableProps?: object; + renderUsernameOnMessage?: boolean; + position: 'left' | 'right'; + currentMessage?: TMessage; + nextMessage?: TMessage; + previousMessage?: TMessage; + optionTitles?: string; + containerStyle?: LeftRightStyle; + wrapperStyle?: LeftRightStyle; + textStyle?: LeftRightStyle; + bottomContainerStyle?: LeftRightStyle; + tickStyle?: TextStyle; + containerToNextStyle?: LeftRightStyle; + containerToPreviousStyle?: LeftRightStyle; + usernameStyle?: LeftRightStyle; + onLongPress?(context?: any, message?: any): void; + renderMessageImage?(messageImageProps: MessageImage['props']): React.ReactNode; + renderMessageVideo?(messageVideoProps: MessageVideo['props']): React.ReactNode; + renderMessageText?(messageTextProps: MessageText['props']): React.ReactNode; + renderCustomView?(bubbleProps: BubbleProps): React.ReactNode; + renderTime?(timeProps: Time['props']): React.ReactNode; + renderTicks?(currentMessage: TMessage): React.ReactNode; + renderUsername?(): React.ReactNode; + isSameDay?(currentMessage: TMessage, nextMessage: TMessage): boolean; + isSameUser?(currentMessage: TMessage, nextMessage: TMessage): boolean; +} +export default class Bubble extends React.Component { + static contextTypes: { + actionSheet: PropTypes.Requireable<(...args: any[]) => any>; + }; + static defaultProps: { + touchableProps: {}; + onLongPress: null; + renderMessageImage: null; + renderMessageVideo: null; + renderMessageText: null; + renderCustomView: null; + renderUsername: null; + renderTicks: null; + renderTime: null; + position: string; + optionTitles: string[]; + currentMessage: { + text: null; + createdAt: null; + image: null; + }; + nextMessage: {}; + previousMessage: {}; + containerStyle: {}; + wrapperStyle: {}; + bottomContainerStyle: {}; + tickStyle: {}; + usernameStyle: {}; + containerToNextStyle: {}; + containerToPreviousStyle: {}; + }; + static propTypes: { + user: PropTypes.Validator; + touchableProps: PropTypes.Requireable; + onLongPress: PropTypes.Requireable<(...args: any[]) => any>; + renderMessageImage: PropTypes.Requireable<(...args: any[]) => any>; + renderMessageVideo: PropTypes.Requireable<(...args: any[]) => any>; + renderMessageText: PropTypes.Requireable<(...args: any[]) => any>; + renderCustomView: PropTypes.Requireable<(...args: any[]) => any>; + renderUsernameOnMessage: PropTypes.Requireable; + renderUsername: PropTypes.Requireable<(...args: any[]) => any>; + renderTime: PropTypes.Requireable<(...args: any[]) => any>; + renderTicks: PropTypes.Requireable<(...args: any[]) => any>; + position: PropTypes.Requireable; + optionTitles: PropTypes.Requireable<(string | null)[]>; + currentMessage: PropTypes.Requireable; + nextMessage: PropTypes.Requireable; + previousMessage: PropTypes.Requireable; + containerStyle: PropTypes.Requireable Error | null) | undefined; + right: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + }>>; + wrapperStyle: PropTypes.Requireable Error | null) | undefined; + right: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + }>>; + bottomContainerStyle: PropTypes.Requireable Error | null) | undefined; + right: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + }>>; + tickStyle: PropTypes.Requireable; + usernameStyle: PropTypes.Requireable; + containerToNextStyle: PropTypes.Requireable Error | null) | undefined; + right: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + }>>; + containerToPreviousStyle: PropTypes.Requireable Error | null) | undefined; + right: ((object: import("react-native").ViewProps, key: string, componentName: string, ...rest: any[]) => Error | null) | undefined; + }>>; + }; + onLongPress: () => void; + handleBubbleToNext(): (ViewStyle | { + borderBottomLeftRadius: number; + } | { + borderBottomRightRadius: number; + } | undefined)[] | null; + handleBubbleToPrevious(): (ViewStyle | { + borderTopLeftRadius: number; + } | { + borderTopRightRadius: number; + } | undefined)[] | null; + renderMessageText(): {} | null | undefined; + renderMessageImage(): {} | null | undefined; + renderMessageVideo(): {} | null | undefined; + renderTicks(): {} | null | undefined; + renderTime(): {} | null | undefined; + renderUsername(): JSX.Element | null; + renderCustomView(): {} | null | undefined; + render(): JSX.Element; +} +export {}; diff --git a/lib/Bubble.js b/lib/Bubble.js new file mode 100644 index 000000000..f3dc2a752 --- /dev/null +++ b/lib/Bubble.js @@ -0,0 +1,327 @@ +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +import PropTypes from 'prop-types'; +import React from 'react'; +import { Text, Clipboard, StyleSheet, TouchableWithoutFeedback, View, ViewPropTypes, } from 'react-native'; +import MessageText from './MessageText'; +import MessageImage from './MessageImage'; +import MessageVideo from './MessageVideo'; +import Time from './Time'; +import Color from './Color'; +import { isSameUser, isSameDay } from './utils'; +const styles = { + left: StyleSheet.create({ + container: { + flex: 1, + alignItems: 'flex-start', + }, + wrapper: { + borderRadius: 15, + backgroundColor: Color.leftBubbleBackground, + marginRight: 60, + minHeight: 20, + justifyContent: 'flex-end', + }, + containerToNext: { + borderBottomLeftRadius: 3, + }, + containerToPrevious: { + borderTopLeftRadius: 3, + }, + bottom: { + flexDirection: 'row', + justifyContent: 'flex-start', + }, + }), + right: StyleSheet.create({ + container: { + flex: 1, + alignItems: 'flex-end', + }, + wrapper: { + borderRadius: 15, + backgroundColor: Color.defaultBlue, + marginLeft: 60, + minHeight: 20, + justifyContent: 'flex-end', + }, + containerToNext: { + borderBottomRightRadius: 3, + }, + containerToPrevious: { + borderTopRightRadius: 3, + }, + bottom: { + flexDirection: 'row', + justifyContent: 'flex-end', + }, + }), + content: StyleSheet.create({ + tick: { + fontSize: 10, + backgroundColor: Color.backgroundTransparent, + color: Color.white, + }, + tickView: { + flexDirection: 'row', + marginRight: 10, + }, + username: { + top: -3, + left: 0, + fontSize: 12, + backgroundColor: 'transparent', + color: '#aaa', + }, + usernameView: { + flexDirection: 'row', + marginHorizontal: 10, + }, + }), +}; +const DEFAULT_OPTION_TITLES = ['Copy Text', 'Cancel']; +export default class Bubble extends React.Component { + constructor() { + super(...arguments); + this.onLongPress = () => { + const { currentMessage } = this.props; + if (this.props.onLongPress) { + this.props.onLongPress(this.context, this.props.currentMessage); + } + else if (currentMessage && currentMessage.text) { + const { optionTitles } = this.props; + const options = optionTitles && optionTitles.length > 0 + ? optionTitles.slice(0, 2) + : DEFAULT_OPTION_TITLES; + const cancelButtonIndex = options.length - 1; + this.context.actionSheet().showActionSheetWithOptions({ + options, + cancelButtonIndex, + }, (buttonIndex) => { + switch (buttonIndex) { + case 0: + Clipboard.setString(currentMessage.text); + break; + default: + break; + } + }); + } + }; + } + handleBubbleToNext() { + const { currentMessage, nextMessage, position, containerToNextStyle, } = this.props; + if (currentMessage && + nextMessage && + position && + isSameUser(currentMessage, nextMessage) && + isSameDay(currentMessage, nextMessage)) { + return [ + styles[position].containerToNext, + containerToNextStyle && containerToNextStyle[position], + ]; + } + return null; + } + handleBubbleToPrevious() { + const { currentMessage, previousMessage, position, containerToPreviousStyle, } = this.props; + if (currentMessage && + previousMessage && + position && + isSameUser(currentMessage, previousMessage) && + isSameDay(currentMessage, previousMessage)) { + return [ + styles[position].containerToPrevious, + containerToPreviousStyle && containerToPreviousStyle[position], + ]; + } + return null; + } + renderMessageText() { + if (this.props.currentMessage && this.props.currentMessage.text) { + const _a = this.props, { containerStyle, wrapperStyle } = _a, messageTextProps = __rest(_a, ["containerStyle", "wrapperStyle"]); + if (this.props.renderMessageText) { + return this.props.renderMessageText(messageTextProps); + } + return ; + } + return null; + } + renderMessageImage() { + if (this.props.currentMessage && this.props.currentMessage.image) { + const _a = this.props, { containerStyle, wrapperStyle } = _a, messageImageProps = __rest(_a, ["containerStyle", "wrapperStyle"]); + if (this.props.renderMessageImage) { + return this.props.renderMessageImage(messageImageProps); + } + return ; + } + return null; + } + renderMessageVideo() { + if (this.props.currentMessage && this.props.currentMessage.video) { + const _a = this.props, { containerStyle, wrapperStyle } = _a, messageVideoProps = __rest(_a, ["containerStyle", "wrapperStyle"]); + if (this.props.renderMessageVideo) { + return this.props.renderMessageVideo(messageVideoProps); + } + return ; + } + return null; + } + renderTicks() { + const { currentMessage, renderTicks, user } = this.props; + if (renderTicks && currentMessage) { + return renderTicks(currentMessage); + } + if (currentMessage && user && currentMessage.user._id !== user._id) { + return null; + } + if (currentMessage && + (currentMessage.sent || currentMessage.received || currentMessage.pending)) { + return ( + {!!currentMessage.sent && ()} + {!!currentMessage.received && ()} + {!!currentMessage.pending && (🕓)} + ); + } + return null; + } + renderTime() { + if (this.props.currentMessage && this.props.currentMessage.createdAt) { + const _a = this.props, { containerStyle, wrapperStyle, textStyle } = _a, timeProps = __rest(_a, ["containerStyle", "wrapperStyle", "textStyle"]); + if (this.props.renderTime) { + return this.props.renderTime(timeProps); + } + return