[RN] Add branded dialog component
This commit is contained in:
parent
3ebad112a2
commit
22a602768c
|
@ -266,6 +266,8 @@
|
|||
},
|
||||
"allow": "Allow",
|
||||
"confirm": "Confirm",
|
||||
"confirmNo": "No",
|
||||
"confirmYes": "Yes",
|
||||
"kickMessage": "Ouch! You have been kicked out of the meet!",
|
||||
"kickTitle": "Kicked from meeting",
|
||||
"popupErrorTitle": "Pop-up blocked",
|
||||
|
|
|
@ -4,7 +4,7 @@ import React, { Component } from 'react';
|
|||
|
||||
import { Container, Text } from '../../react';
|
||||
|
||||
import { dialog as styles } from './styles';
|
||||
import styles from './styles';
|
||||
|
||||
type Props = {
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
export * from './native';
|
|
@ -0,0 +1,3 @@
|
|||
// @flow
|
||||
|
||||
export * from './web';
|
|
@ -1,10 +1,6 @@
|
|||
// @flow
|
||||
|
||||
export { default as BottomSheet } from './BottomSheet';
|
||||
export { default as Dialog } from './Dialog';
|
||||
export * from './_';
|
||||
|
||||
export { default as DialogContainer } from './DialogContainer';
|
||||
export { default as DialogContent } from './DialogContent';
|
||||
export { default as StatelessDialog } from './StatelessDialog';
|
||||
export { default as DialogWithTabs } from './DialogWithTabs';
|
||||
export { default as AbstractDialogTab } from './AbstractDialogTab';
|
||||
export type { Props as AbstractDialogTabProps } from './AbstractDialogTab';
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
import { Icon } from '../../../font-icons';
|
||||
|
||||
import AbstractDialog, {
|
||||
type Props as AbstractProps,
|
||||
type State
|
||||
} from '../AbstractDialog';
|
||||
import { brandedDialog as styles } from './styles';
|
||||
|
||||
export type Props = {
|
||||
...AbstractProps,
|
||||
|
||||
t: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* Component to render a custom dialog.
|
||||
*/
|
||||
class BaseDialog<P: Props, S: State> extends AbstractDialog<P, S> {
|
||||
/**
|
||||
* Initializes a new {@code FeedbackDialog} instance.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: P) {
|
||||
super(props);
|
||||
|
||||
this._onSubmit = this._onSubmit.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements React's {@link Component#render()}.
|
||||
*
|
||||
* @inheritdoc
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
render() {
|
||||
const { style } = this.props;
|
||||
|
||||
return (
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { [
|
||||
styles.overlay,
|
||||
style
|
||||
] }>
|
||||
<View
|
||||
pointerEvents = 'box-none'
|
||||
style = { [
|
||||
styles.dialog,
|
||||
this.props.style
|
||||
] }>
|
||||
<TouchableOpacity
|
||||
onPress = { this._onCancel }
|
||||
style = { styles.closeWrapper }>
|
||||
<Icon
|
||||
name = 'close'
|
||||
style = { styles.closeStyle } />
|
||||
</TouchableOpacity>
|
||||
{ this._renderContent() }
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
|
||||
_onSubmit: () => boolean;
|
||||
|
||||
/**
|
||||
* Renders the content of the dialog.
|
||||
*
|
||||
* @returns {ReactElement}
|
||||
*/
|
||||
_renderContent: () => Object
|
||||
|
||||
/**
|
||||
* Renders a specific {@code string} which may contain HTML.
|
||||
*
|
||||
* @param {string|undefined} html - The {@code string} which may
|
||||
* contain HTML to render.
|
||||
* @returns {ReactElement[]|string}
|
||||
*/
|
||||
_renderHTML(html: ?string) {
|
||||
if (typeof html === 'string') {
|
||||
// At the time of this writing, the specified HTML contains a couple
|
||||
// of spaces one after the other. They do not cause a visible
|
||||
// problem on Web, because the specified HTML is rendered as, well,
|
||||
// HTML. However, we're not rendering HTML here.
|
||||
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
html = html.replace(/\s{2,}/gi, ' ');
|
||||
|
||||
// Render text in <b>text</b> in bold.
|
||||
const opening = /<\s*b\s*>/gi;
|
||||
const closing = /<\s*\/\s*b\s*>/gi;
|
||||
let o;
|
||||
let c;
|
||||
let prevClosingLastIndex = 0;
|
||||
const r = [];
|
||||
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
while (o = opening.exec(html)) {
|
||||
closing.lastIndex = opening.lastIndex;
|
||||
|
||||
// eslint-disable-next-line no-cond-assign
|
||||
if (c = closing.exec(html)) {
|
||||
r.push(html.substring(prevClosingLastIndex, o.index));
|
||||
r.push(
|
||||
<Text style = { styles.boldDialogText }>
|
||||
{ html.substring(opening.lastIndex, c.index) }
|
||||
</Text>);
|
||||
opening.lastIndex
|
||||
= prevClosingLastIndex
|
||||
= closing.lastIndex;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prevClosingLastIndex < html.length) {
|
||||
r.push(html.substring(prevClosingLastIndex));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
|
||||
export default BaseDialog;
|
|
@ -0,0 +1,93 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View, Text, TouchableOpacity } from 'react-native';
|
||||
|
||||
import BaseDialog, { type Props as BaseProps } from './BaseDialog';
|
||||
import {
|
||||
brandedDialog
|
||||
} from './styles';
|
||||
|
||||
type Props = {
|
||||
...BaseProps,
|
||||
|
||||
t: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract dialog to submit something. E.g. a confirmation or a form.
|
||||
*/
|
||||
class BaseSubmitDialog<P: Props, S: *> extends BaseDialog<P, S> {
|
||||
/**
|
||||
* Returns the title key of the submit button.
|
||||
*
|
||||
* NOTE: Please do not change this, this should be consistent accross the
|
||||
* application. This method is here to be able to be overriden ONLY by the
|
||||
* {@code ConfirmDialog}.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
_getSubmitButtonKey() {
|
||||
return 'dialog.Ok';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders additional buttons, if any - may be overwritten by children.
|
||||
*
|
||||
* @returns {?ReactElement}
|
||||
*/
|
||||
_renderAdditionalButtons() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code BaseDialog._renderContent}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
_renderContent() {
|
||||
const { t } = this.props;
|
||||
const additionalButtons = this._renderAdditionalButtons();
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View style = { brandedDialog.mainWrapper }>
|
||||
{ this._renderSubmittable() }
|
||||
</View>
|
||||
<View style = { brandedDialog.buttonWrapper }>
|
||||
{ additionalButtons }
|
||||
<TouchableOpacity
|
||||
disabled = { this.props.okDisabled }
|
||||
onPress = { this._onSubmit }
|
||||
style = { [
|
||||
brandedDialog.button,
|
||||
additionalButtons
|
||||
? null : brandedDialog.buttonFarLeft,
|
||||
brandedDialog.buttonFarRight
|
||||
] }>
|
||||
<Text style = { brandedDialog.text }>
|
||||
{ t(this._getSubmitButtonKey()) }
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
|
||||
_onSubmit: ?string => boolean;
|
||||
|
||||
_renderHTML: string => Object | string
|
||||
|
||||
/**
|
||||
* Renders the actual content of the dialog defining what is about to be
|
||||
* submitted. E.g. a simple confirmation (text, properly wrapped) or a
|
||||
* complex form.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
_renderSubmittable: () => Object
|
||||
}
|
||||
|
||||
export default BaseSubmitDialog;
|
|
@ -0,0 +1,91 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { Text, TouchableOpacity } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../i18n';
|
||||
|
||||
import { type Props as BaseProps } from './BaseDialog';
|
||||
import BaseSubmitDialog from './BaseSubmitDialog';
|
||||
import { brandedDialog } from './styles';
|
||||
|
||||
type Props = {
|
||||
...BaseProps,
|
||||
|
||||
/**
|
||||
* Untranslated i18n key of the content to be displayed.
|
||||
*
|
||||
* NOTE: This dialog also adds support to Object type keys that will be
|
||||
* translated using the provided params. See i18n function
|
||||
* {@code translate(string, Object)} for more details.
|
||||
*/
|
||||
contentKey: string | { key: string, params: Object},
|
||||
|
||||
t: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a confirm dialog component.
|
||||
*/
|
||||
class ConfirmDialog extends BaseSubmitDialog<Props, *> {
|
||||
/**
|
||||
* Returns the title key of the submit button.
|
||||
*
|
||||
* @returns {string}
|
||||
*/
|
||||
_getSubmitButtonKey() {
|
||||
return 'dialog.confirmYes';
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
|
||||
/**
|
||||
* Renders the 'No' button.
|
||||
*
|
||||
* NOTE: The {@code ConfirmDialog} is the only dialog right now that
|
||||
* renders 2 buttons, mainly for clarity.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
_renderAdditionalButtons() {
|
||||
const { t } = this.props;
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress = { this._onCancel }
|
||||
style = { [
|
||||
brandedDialog.button,
|
||||
brandedDialog.buttonFarLeft,
|
||||
brandedDialog.buttonSeparator
|
||||
] }>
|
||||
<Text style = { brandedDialog.text }>
|
||||
{ t('dialog.confirmNo') }
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code BaseSubmitDialog._renderSubmittable}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
_renderSubmittable() {
|
||||
const { contentKey, t } = this.props;
|
||||
const content
|
||||
= typeof contentKey === 'string'
|
||||
? t(contentKey)
|
||||
: this._renderHTML(t(contentKey.key, contentKey.params));
|
||||
|
||||
return (
|
||||
<Text style = { brandedDialog.text }>
|
||||
{ content }
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
_renderHTML: string => Object | string
|
||||
}
|
||||
|
||||
export default translate(connect()(ConfirmDialog));
|
|
@ -0,0 +1,22 @@
|
|||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import BaseDialog, { type Props } from './BaseDialog';
|
||||
|
||||
/**
|
||||
* Implements a custom dialog component, where the content can freely be
|
||||
* rendered.
|
||||
*/
|
||||
class CustomDialog extends BaseDialog<Props, *> {
|
||||
/**
|
||||
* Implements {@code BaseDialog._renderContent}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
_renderContent() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default connect()(CustomDialog);
|
|
@ -0,0 +1,30 @@
|
|||
// @flow
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../i18n';
|
||||
|
||||
import { type Props as BaseProps } from './BaseDialog';
|
||||
import BaseSubmitDialog from './BaseSubmitDialog';
|
||||
|
||||
type Props = {
|
||||
...BaseProps,
|
||||
|
||||
t: Function
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements a submit dialog component that can have free content.
|
||||
*/
|
||||
class CustomSubmitDialog extends BaseSubmitDialog<Props, *> {
|
||||
/**
|
||||
* Implements {@code BaseSubmitDialog._renderSubmittable}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
_renderSubmittable() {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect()(CustomSubmitDialog));
|
|
@ -6,15 +6,15 @@ import { Modal, StyleSheet, TextInput } from 'react-native';
|
|||
import Prompt from 'react-native-prompt';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../i18n';
|
||||
import { LoadingIndicator } from '../../react';
|
||||
import { set } from '../../redux';
|
||||
import { translate } from '../../../i18n';
|
||||
import { LoadingIndicator } from '../../../react';
|
||||
import { set } from '../../../redux';
|
||||
|
||||
import AbstractDialog from './AbstractDialog';
|
||||
import AbstractDialog from '../AbstractDialog';
|
||||
import type {
|
||||
Props as AbstractDialogProps,
|
||||
State as AbstractDialogState
|
||||
} from './AbstractDialog';
|
||||
} from '../AbstractDialog';
|
||||
import { dialog as styles } from './styles';
|
||||
|
||||
/**
|
||||
|
@ -44,6 +44,11 @@ type Props = {
|
|||
*/
|
||||
bodyKey: string,
|
||||
|
||||
/**
|
||||
* Function to be used to retreive translated i18n labels.
|
||||
*/
|
||||
t: Function,
|
||||
|
||||
textInputProps: Object
|
||||
};
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
// @flow
|
||||
|
||||
import React from 'react';
|
||||
import { View, Text, TextInput, TouchableOpacity } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { translate } from '../../../i18n';
|
||||
|
||||
import { type State as AbstractState } from '../AbstractDialog';
|
||||
|
||||
import BaseDialog, { type Props as BaseProps } from './BaseDialog';
|
||||
import {
|
||||
FIELD_UNDERLINE,
|
||||
brandedDialog,
|
||||
inputDialog as styles
|
||||
} from './styles';
|
||||
|
||||
type Props = {
|
||||
...BaseProps,
|
||||
|
||||
/**
|
||||
* The untranslated i18n key for the field label on the dialog.
|
||||
*/
|
||||
contentKey: string,
|
||||
|
||||
t: Function,
|
||||
|
||||
textInputProps: ?Object
|
||||
}
|
||||
|
||||
type State = {
|
||||
...AbstractState,
|
||||
|
||||
/**
|
||||
* The current value of the field.
|
||||
*/
|
||||
fieldValue: ?string
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements a single field input dialog component.
|
||||
*/
|
||||
class InputDialog extends BaseDialog<Props, State> {
|
||||
/**
|
||||
* Instantiates a new {@code InputDialog}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
fieldValue: undefined
|
||||
};
|
||||
|
||||
this._onChangeText = this._onChangeText.bind(this);
|
||||
this._onSubmitValue = this._onSubmitValue.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@code BaseDialog._renderContent}.
|
||||
*
|
||||
* @inheritdoc
|
||||
*/
|
||||
_renderContent() {
|
||||
const { okDisabled, t } = this.props;
|
||||
|
||||
return (
|
||||
<View>
|
||||
<View
|
||||
style = { [
|
||||
brandedDialog.mainWrapper,
|
||||
styles.fieldWrapper
|
||||
] }>
|
||||
<Text style = { styles.fieldLabel }>
|
||||
{ t(this.props.contentKey) }
|
||||
</Text>
|
||||
<TextInput
|
||||
onChangeText = { this._onChangeText }
|
||||
style = { styles.field }
|
||||
underlineColorAndroid = { FIELD_UNDERLINE }
|
||||
value = { this.state.fieldValue }
|
||||
{ ...this.props.textInputProps } />
|
||||
</View>
|
||||
<View style = { brandedDialog.buttonWrapper }>
|
||||
<TouchableOpacity
|
||||
disabled = { okDisabled }
|
||||
onPress = { this._onSubmit }
|
||||
style = { [
|
||||
brandedDialog.button,
|
||||
brandedDialog.buttonFarLeft,
|
||||
brandedDialog.buttonFarRight
|
||||
] }>
|
||||
<Text style = { brandedDialog.text }>
|
||||
{ t('dialog.Ok') }
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_onCancel: () => void;
|
||||
|
||||
_onChangeText: string => void;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the text in the field changes.
|
||||
*
|
||||
* @param {string} fieldValue - The updated field value.
|
||||
* @returns {void}
|
||||
*/
|
||||
_onChangeText(fieldValue) {
|
||||
this.setState({
|
||||
fieldValue
|
||||
});
|
||||
}
|
||||
|
||||
_onSubmit: ?string => boolean;
|
||||
|
||||
_onSubmitValue: () => boolean;
|
||||
|
||||
/**
|
||||
* Callback to be invoked when the value of this dialog is submitted.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_onSubmitValue() {
|
||||
return this._onSubmit(this.state.fieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(connect()(InputDialog));
|
|
@ -0,0 +1,12 @@
|
|||
// @flow
|
||||
|
||||
export { default as BottomSheet } from './BottomSheet';
|
||||
export { default as ConfirmDialog } from './ConfirmDialog';
|
||||
export { default as CustomDialog } from './CustomDialog';
|
||||
export { default as Dialog } from './Dialog';
|
||||
export { default as InputDialog } from './InputDialog';
|
||||
export { default as CustomSubmitDialog } from './CustomSubmitDialog';
|
||||
|
||||
// NOTE: Some dialogs reuse the style of these base classes for consistency
|
||||
// and as we're in a /native namespace, it's safe to export the styles.
|
||||
export * from './styles';
|
|
@ -0,0 +1,183 @@
|
|||
// @flow
|
||||
|
||||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import { BoxModel, ColorPalette, createStyleSheet } from '../../../styles';
|
||||
|
||||
import { PREFERRED_DIALOG_SIZE } from '../../constants';
|
||||
|
||||
const BORDER_RADIUS = 5;
|
||||
const DIALOG_BORDER_COLOR = 'rgba(255, 255, 255, 0.2)';
|
||||
|
||||
export const FIELD_UNDERLINE = ColorPalette.transparent;
|
||||
export const PLACEHOLDER_COLOR = ColorPalette.lightGrey;
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code BottomSheet}. These have
|
||||
* been implemented as per the Material Design guidelines:
|
||||
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
||||
*/
|
||||
export const bottomSheetStyles = createStyleSheet({
|
||||
/**
|
||||
* Style for a backdrop which dims the view in the background. This view
|
||||
* will also be clickable. The backgroundColor is applied to the overlay
|
||||
* view instead, so the modal animation doesn't affect the backdrop.
|
||||
*/
|
||||
backdrop: {
|
||||
...StyleSheet.absoluteFillObject
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the container of the sheet.
|
||||
*/
|
||||
container: {
|
||||
alignItems: 'flex-end',
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for an overlay on top of which the sheet will be displayed.
|
||||
*/
|
||||
overlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.8)'
|
||||
},
|
||||
|
||||
/**
|
||||
* Bottom sheet's base style.
|
||||
*/
|
||||
sheet: {
|
||||
backgroundColor: ColorPalette.white,
|
||||
flex: 1,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8
|
||||
}
|
||||
});
|
||||
|
||||
export const brandedDialog = createStyleSheet({
|
||||
|
||||
/**
|
||||
* The style of bold {@code Text} rendered by the {@code Dialog}s of the
|
||||
* feature authentication.
|
||||
*/
|
||||
boldDialogText: {
|
||||
fontWeight: 'bold'
|
||||
},
|
||||
|
||||
button: {
|
||||
backgroundColor: ColorPalette.blue,
|
||||
flex: 1,
|
||||
padding: BoxModel.padding * 1.5
|
||||
},
|
||||
|
||||
buttonFarLeft: {
|
||||
borderBottomLeftRadius: BORDER_RADIUS
|
||||
},
|
||||
|
||||
buttonFarRight: {
|
||||
borderBottomRightRadius: BORDER_RADIUS
|
||||
},
|
||||
|
||||
buttonSeparator: {
|
||||
borderRightColor: DIALOG_BORDER_COLOR,
|
||||
borderRightWidth: 1
|
||||
},
|
||||
|
||||
buttonWrapper: {
|
||||
alignItems: 'stretch',
|
||||
borderRadius: BORDER_RADIUS,
|
||||
flexDirection: 'row'
|
||||
},
|
||||
|
||||
closeStyle: {
|
||||
color: ColorPalette.white,
|
||||
fontSize: 16
|
||||
},
|
||||
|
||||
closeWrapper: {
|
||||
alignSelf: 'flex-end',
|
||||
padding: BoxModel.padding
|
||||
},
|
||||
|
||||
dialog: {
|
||||
alignItems: 'stretch',
|
||||
backgroundColor: 'rgb(0, 3, 6)',
|
||||
borderColor: DIALOG_BORDER_COLOR,
|
||||
borderRadius: BORDER_RADIUS,
|
||||
borderWidth: 1,
|
||||
flex: 1,
|
||||
flexDirection: 'column',
|
||||
maxWidth: PREFERRED_DIALOG_SIZE
|
||||
},
|
||||
|
||||
mainWrapper: {
|
||||
alignSelf: 'stretch',
|
||||
padding: BoxModel.padding * 2,
|
||||
|
||||
// The added bottom padding is to compensate the empty space around the
|
||||
// close icon.
|
||||
paddingBottom: BoxModel.padding * 3
|
||||
},
|
||||
|
||||
overlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(127, 127, 127, 0.6)',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center',
|
||||
padding: 30
|
||||
},
|
||||
|
||||
text: {
|
||||
color: ColorPalette.white,
|
||||
fontSize: 16,
|
||||
textAlign: 'center'
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code Dialog}.
|
||||
*/
|
||||
export const dialog = createStyleSheet({
|
||||
/**
|
||||
* The style of the {@code Text} in a {@code Dialog} button.
|
||||
*/
|
||||
buttonText: {
|
||||
color: ColorPalette.blue
|
||||
},
|
||||
|
||||
/**
|
||||
* The style of the {@code Text} in a {@code Dialog} button which is
|
||||
* disabled.
|
||||
*/
|
||||
disabledButtonText: {
|
||||
color: ColorPalette.darkGrey
|
||||
}
|
||||
});
|
||||
|
||||
export const inputDialog = createStyleSheet({
|
||||
bottomField: {
|
||||
marginBottom: 0
|
||||
},
|
||||
|
||||
field: {
|
||||
...brandedDialog.text,
|
||||
borderBottomWidth: 1,
|
||||
borderColor: DIALOG_BORDER_COLOR,
|
||||
margin: BoxModel.margin,
|
||||
textAlign: 'left'
|
||||
},
|
||||
|
||||
fieldLabel: {
|
||||
...brandedDialog.text,
|
||||
margin: BoxModel.margin,
|
||||
textAlign: 'left'
|
||||
},
|
||||
|
||||
fieldWrapper: {
|
||||
...brandedDialog.mainWrapper,
|
||||
paddingBottom: BoxModel.padding * 2
|
||||
}
|
||||
});
|
|
@ -1,75 +1,14 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import { BoxModel, ColorPalette, createStyleSheet } from '../../styles';
|
||||
import { BoxModel, createStyleSheet } from '../../styles';
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code Dialog}.
|
||||
*/
|
||||
export const dialog = createStyleSheet({
|
||||
/**
|
||||
* The style of the {@code Text} in a {@code Dialog} button.
|
||||
*/
|
||||
buttonText: {
|
||||
color: ColorPalette.blue
|
||||
},
|
||||
|
||||
export default createStyleSheet({
|
||||
/**
|
||||
* Unified container for a consistent Dialog style.
|
||||
*/
|
||||
dialogContainer: {
|
||||
paddingHorizontal: BoxModel.padding,
|
||||
paddingVertical: 1.5 * BoxModel.padding
|
||||
},
|
||||
|
||||
/**
|
||||
* The style of the {@code Text} in a {@code Dialog} button which is
|
||||
* disabled.
|
||||
*/
|
||||
disabledButtonText: {
|
||||
color: ColorPalette.darkGrey
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The React {@code Component} styles of {@code BottomSheet}. These have
|
||||
* been implemented as per the Material Design guidelines:
|
||||
* {@link https://material.io/guidelines/components/bottom-sheets.html}.
|
||||
*/
|
||||
export const bottomSheetStyles = createStyleSheet({
|
||||
/**
|
||||
* Style for a backdrop which dims the view in the background. This view
|
||||
* will also be clickable. The backgroundColor is applied to the overlay
|
||||
* view instead, so the modal animation doesn't affect the backdrop.
|
||||
*/
|
||||
backdrop: {
|
||||
...StyleSheet.absoluteFillObject
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for the container of the sheet.
|
||||
*/
|
||||
container: {
|
||||
alignItems: 'flex-end',
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
|
||||
/**
|
||||
* Style for an overlay on top of which the sheet will be displayed.
|
||||
*/
|
||||
overlay: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
backgroundColor: 'rgba(0, 0, 0, 0.8)'
|
||||
},
|
||||
|
||||
/**
|
||||
* Bottom sheet's base style.
|
||||
*/
|
||||
sheet: {
|
||||
flex: 1,
|
||||
backgroundColor: ColorPalette.white,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 8
|
||||
}
|
||||
});
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
* Placeholder styles for web to be able to use cross platform components
|
||||
* unmodified such as {@code DialogContent}.
|
||||
*/
|
||||
export const dialog = {};
|
||||
export default {};
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import AbstractDialog from './AbstractDialog';
|
||||
import type { Props as AbstractDialogProps, State } from './AbstractDialog';
|
||||
import AbstractDialog from '../AbstractDialog';
|
||||
import type { Props as AbstractDialogProps, State } from '../AbstractDialog';
|
||||
import StatelessDialog from './StatelessDialog';
|
||||
|
||||
/**
|
|
@ -3,8 +3,8 @@
|
|||
import Tabs from '@atlaskit/tabs';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { StatelessDialog } from '../../../base/dialog';
|
||||
import { translate } from '../../../base/i18n';
|
||||
import { StatelessDialog } from '../../../dialog';
|
||||
import { translate } from '../../../i18n';
|
||||
|
||||
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||
|
|
@ -7,9 +7,9 @@ import _ from 'lodash';
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { translate } from '../../i18n';
|
||||
import { translate } from '../../../i18n';
|
||||
|
||||
import type { DialogProps } from '../constants';
|
||||
import type { DialogProps } from '../../constants';
|
||||
|
||||
/**
|
||||
* The ID to be used for the cancel button if enabled.
|
||||
|
@ -56,6 +56,11 @@ type Props = {
|
|||
*/
|
||||
submitDisabled: boolean,
|
||||
|
||||
/**
|
||||
* Function to be used to retreive translated i18n labels.
|
||||
*/
|
||||
t: Function,
|
||||
|
||||
/**
|
||||
* Width of the dialog, can be:
|
||||
* - 'small' (400px), 'medium' (600px), 'large' (800px),
|
|
@ -0,0 +1,7 @@
|
|||
// @flow
|
||||
|
||||
export { default as AbstractDialogTab } from './AbstractDialogTab';
|
||||
export type { Props as AbstractDialogTabProps } from './AbstractDialogTab';
|
||||
export { default as Dialog } from './Dialog';
|
||||
export { default as DialogWithTabs } from './DialogWithTabs';
|
||||
export { default as StatelessDialog } from './StatelessDialog';
|
|
@ -38,9 +38,11 @@ export type DialogProps = {
|
|||
onSubmit: Function,
|
||||
|
||||
/**
|
||||
* Used to obtain translations in children classes.
|
||||
* Additional style to be applied on the dialog.
|
||||
*
|
||||
* NOTE: Not all dialog types support this!
|
||||
*/
|
||||
t: Function,
|
||||
style?: Object,
|
||||
|
||||
/**
|
||||
* Key to use for showing a title.
|
||||
|
@ -54,3 +56,13 @@ export type DialogProps = {
|
|||
*/
|
||||
titleString: string
|
||||
};
|
||||
|
||||
/**
|
||||
* A preferred (or optimal) dialog size. This constant is reused in many
|
||||
* components, where dialog size optimization is suggested.
|
||||
*
|
||||
* NOTE: Even though we support valious devices, including tablets, we don't
|
||||
* want the dialogs to be oversized even on larger devices. This number seems
|
||||
* to be a good compromise, but also easy to update.
|
||||
*/
|
||||
export const PREFERRED_DIALOG_SIZE = 300;
|
||||
|
|
|
@ -12,10 +12,7 @@ import {
|
|||
} from '../../../modules/transport';
|
||||
import { parseURLParams } from '../base/config';
|
||||
import { DeviceSelection } from '../device-selection';
|
||||
|
||||
// Using the full path to the file to prevent adding unnecessary code into the
|
||||
// dialog popup bundle.
|
||||
import DialogWithTabs from '../base/dialog/components/DialogWithTabs';
|
||||
import { DialogWithTabs } from '../base/dialog';
|
||||
|
||||
const logger = Logger.getLogger(__filename);
|
||||
|
||||
|
|
Loading…
Reference in New Issue