Merged PR 686347: Align the render rule with other platforms and enhance extensibility

Related work items: #1292147, #1300851, #1300852, #1300853, #1300854, #1300855, #1300856, #1307932
This commit is contained in:
Dongyu Zhao 2018-06-29 09:01:24 +00:00
Родитель fe552d5317
Коммит 8b9dc5a947
248 изменённых файлов: 7017 добавлений и 5481 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -57,3 +57,5 @@ typings/
# dotenv environment variables file # dotenv environment variables file
.env .env
# VSCode
.vscode

Просмотреть файл

127
dist/Components/Basic/FlexBox.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,127 @@
import * as React from 'react';
import { TouchableOpacity, View } from 'react-native';
export class FlexBox extends React.Component {
constructor(props) {
super(props);
this.renderChildren = () => {
if (this.props.children) {
return React.Children.map(this.props.children, (child, index) => {
if (child) {
if (typeof child !== 'string' && typeof child !== 'number') {
if (this.props.width === 'auto') {
return React.cloneElement(child, {
containerWidth: this.props.containerWidth,
containerHeight: this.props.containerHeight
});
}
else {
return React.cloneElement(child, {
containerWidth: this.state.width,
containerHeight: this.state.height
});
}
}
}
});
}
return undefined;
};
this.onLayoutChange = (event) => {
let width = event.nativeEvent.layout.width;
let height = event.nativeEvent.layout.height;
this.setState({
width: width,
height: height
}, () => {
console.log(`FlexBox: width: ${width} height: ${height}`);
if (this.props.onLayoutChange) {
this.props.onLayoutChange(width, height);
}
});
};
this.getFlexStyle = () => {
if (this.props.flex) {
return {
flex: this.props.flex
};
}
return {};
};
this.getChildrenFlexStyle = () => {
let result = {
flexDirection: this.props.flexDirection,
alignItems: this.props.wrap === 'wrap' ? 'flex-start' : this.props.alignItems,
justifyContent: this.props.justifyContent,
height: this.props.height,
flexWrap: this.props.wrap,
};
return result;
};
this.getSizeStyle = () => {
if (this.props.width === 'auto') {
return {
flex: 0
};
}
if (this.props.width === 'stretch') {
return {
flex: 1
};
}
if (this.props.relativeWidth && typeof this.props.width === 'number') {
return {
flex: this.props.width
};
}
return {
width: this.props.width
};
};
this.getVerticalMarginStyle = () => {
if (this.props.vIndex > 0) {
return {
marginTop: this.props.vSpace,
};
}
return {};
};
this.getHorizontalMarginStyle = () => {
if (this.props.hIndex > 0) {
return {
marginLeft: this.props.hSpace,
};
}
return {};
};
this.state = {
width: 0,
height: 0,
};
}
render() {
if (this.props.onPress) {
return this.renderTouchableBox();
}
return this.renderBox();
}
renderBox() {
return (React.createElement(View, { style: [
this.getChildrenFlexStyle(),
this.getFlexStyle(),
this.getSizeStyle(),
this.getVerticalMarginStyle(),
this.getHorizontalMarginStyle(),
this.props.style,
], onLayout: this.onLayoutChange }, this.renderChildren()));
}
renderTouchableBox() {
return (React.createElement(TouchableOpacity, { style: [
this.getChildrenFlexStyle(),
this.getFlexStyle(),
this.getSizeStyle(),
this.getVerticalMarginStyle(),
this.getHorizontalMarginStyle(),
this.props.style,
], onLayout: this.onLayoutChange, onPress: this.props.onPress }, this.renderChildren()));
}
}

Просмотреть файл

156
dist/Components/Basic/ImageBlock.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,156 @@
import * as React from 'react';
import { Image, Text, View } from 'react-native';
import { FlexBox } from './FlexBox';
export class ImageBlock extends React.Component {
constructor(props) {
super(props);
this.renderPlaceholder = () => {
if (!this.state.loaded) {
return (React.createElement(View, { style: [
{
alignItems: 'center',
justifyContent: 'center'
}
] },
React.createElement(Text, { style: {
fontSize: 32,
color: 'rgba(0, 0, 0, 0.5)',
textAlign: 'center'
} }, '\uE601')));
}
return undefined;
};
this.onLayoutChange = (width, height) => {
Image.getSize(this.props.url, this.onImageSize, this.onImageSizeError);
};
this.onImageSizeUpdate = (event) => {
let width = event.nativeEvent.layout.width;
let height = event.nativeEvent.layout.height;
console.log(`Image at url:${this.props.url} size updated. Width: ${width}, height: ${height}`);
if (this.props.onImageSize) {
this.props.onImageSize(width, height);
}
};
this.onImageSize = (width, height) => {
console.log(`Image at url:${this.props.url} get size succeed. Width: ${width}, height: ${height}`);
let ratio = width > 0 ? height / width : height;
if (this.props.width === 'auto') {
this.applyAutoSize(width, ratio);
}
else if (this.props.width === 'stretch') {
this.applyStretchSize(width, height, ratio);
}
else {
this.applyFixSize(ratio);
}
};
this.onImageSizeError = () => {
console.log(`Image at url:${this.props.url} get size failed.`);
this.setState({
loaded: false
});
};
this.onImageLoad = () => {
console.log(`Image at url:${this.props.url} load succeed.`);
this.setState({
loaded: true
});
Image.getSize(this.props.url, this.onImageSize, this.onImageSizeError);
};
this.onImageError = () => {
console.log(`Image at url:${this.props.url} load failed.`);
this.setState({
loaded: false
});
};
this.state = {
loaded: true,
width: undefined,
height: undefined,
ratio: 1,
};
}
render() {
return (React.createElement(FlexBox, Object.assign({}, this.props, { style: [
this.props.boxStyle,
{
alignSelf: this.props.alignSelf,
}
], onLayoutChange: this.onLayoutChange, onPress: this.props.onPress, width: 'auto' }),
this.renderPlaceholder(),
React.createElement(Image, { accessible: !!this.props.alt, accessibilityLabel: this.props.alt, source: { uri: this.props.url }, style: [
this.getSize(),
this.props.imgStyle
], onLoad: this.onImageLoad, onError: this.onImageError, onLayout: this.onImageSizeUpdate })));
}
applyFixSize(ratio) {
if (typeof this.props.width === 'number') {
this.setState({
width: this.props.width,
height: this.props.width * ratio,
ratio: ratio,
});
}
}
applyStretchSize(width, height, ratio) {
if (this.props.containerWidth) {
let finalWidth = this.props.containerWidth;
let finalHeight = finalWidth * ratio;
console.log(`Image at url:${this.props.url} get size succeed. Final width: ${finalWidth}, final height: ${finalHeight}`);
this.setState({
width: finalWidth,
height: finalHeight,
ratio: ratio
});
}
else {
this.setState({
width: width,
height: height,
ratio: ratio
});
}
}
applyAutoSize(width, ratio) {
let finalWidth = width;
if (finalWidth > this.props.containerWidth) {
finalWidth = this.props.containerWidth;
}
let finalHeight = finalWidth * ratio;
console.log(`Image at url:${this.props.url} get size succeed. Final width: ${finalWidth}, final height: ${finalHeight}`);
this.setState({
width: finalWidth,
height: finalHeight,
ratio: ratio
});
}
getSize() {
let finalWidth = this.state.width;
let finalHeight = this.state.height;
if (this.state.width && this.state.height) {
if (this.state.ratio <= 1) {
if (this.props.maxWidth && finalWidth > this.props.maxWidth) {
finalWidth = this.props.maxWidth;
}
finalHeight = finalWidth * this.state.ratio;
if (this.props.maxHeight && finalHeight > this.props.maxHeight) {
finalHeight = this.props.maxHeight;
finalWidth = this.state.ratio > 0 ? finalHeight / this.state.ratio : finalWidth;
}
}
else {
if (this.props.maxHeight && finalHeight > this.props.maxHeight) {
finalHeight = this.props.maxHeight;
}
finalWidth = this.state.ratio > 0 ? finalHeight / this.state.ratio : finalWidth;
if (this.props.maxWidth && finalWidth > this.props.maxWidth) {
finalWidth = this.props.maxWidth;
}
}
}
return {
width: finalWidth,
height: finalHeight,
};
}
}

22
dist/Components/Basic/SeparateLine.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,22 @@
import React from 'react';
import { PixelRatio, Platform, View, } from 'react-native';
export class SeparateLine extends React.PureComponent {
render() {
const { color, margin } = this.props;
const thickness = (Platform.OS === 'ios') ?
parseFloat((1 / PixelRatio.get()).toFixed(2)) :
1;
const style = {
height: thickness,
marginHorizontal: 0,
marginVertical: margin
};
return (React.createElement(View, Object.assign({}, this.props, { style: [
{
flex: 0,
backgroundColor: color,
},
style
] })));
}
}

14
dist/Components/Basic/TextBlock.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,14 @@
import React from 'react';
import { Text, } from 'react-native';
import { FlexBox } from './FlexBox';
export class TextBlock extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, flexDirection: 'row', relativeWidth: false, width: this.props.width, vSpace: this.props.spacing, alignSelf: 'stretch', alignItems: 'stretch', alignContent: 'stretch', justifyContent: this.props.horizontalAlign, style: this.props.boxStyle },
React.createElement(Text, { style: [
this.props.textStyle,
], numberOfLines: this.props.numberOfLines }, this.props.children)));
}
}

10
dist/Components/Containers/Column.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,10 @@
import * as React from 'react';
import { FlexBox } from '../Basic/FlexBox';
export class Column extends React.Component {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { flexDirection: 'column', relativeWidth: true, alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', justifyContent: 'space-between', width: this.props.width, vIndex: this.props.vIndex, hIndex: this.props.hIndex, style: this.props.style, vSpace: this.props.spacing, onPress: this.props.onPress }, this.props.children));
}
}

10
dist/Components/Containers/Row.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,10 @@
import * as React from 'react';
import { FlexBox } from '../Basic/FlexBox';
export class Row extends React.Component {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { flexDirection: 'row', relativeWidth: false, alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', wrap: this.props.wrap, justifyContent: 'space-between', width: this.props.width ? this.props.width : 'stretch', vIndex: this.props.vIndex, hIndex: this.props.hIndex, style: this.props.style, vSpace: this.props.spacing, onPress: this.props.onPress }, this.props.children));
}
}

26
dist/Components/Inputs/Button.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,26 @@
import * as React from 'react';
import { FlexBox } from '../Basic/FlexBox';
import { TextBlock } from '../Basic/TextBlock';
export class Button extends React.Component {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, flexDirection: 'row', relativeWidth: false, flex: 1, alignSelf: 'stretch', alignItems: 'center', alignContent: 'center', justifyContent: 'center', width: 'stretch', hSpace: 10, style: [
{
paddingVertical: 10,
paddingHorizontal: 10,
borderRadius: 4,
backgroundColor: '#277BDF',
},
this.props.boxStyle
], onPress: this.props.onPress },
React.createElement(TextBlock, { vIndex: 0, hIndex: 0, width: 'stretch', horizontalAlign: 'center', textStyle: [
{
textAlign: 'center',
color: 'white',
},
this.props.textStyle,
], numberOfLines: 1 }, this.props.title)));
}
}

107
dist/Components/Inputs/DateInput.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,107 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as React from 'react';
import { DatePickerAndroid, DatePickerIOS, Platform, Text, TouchableOpacity, View } from 'react-native';
import { Utils } from '../../Shared/Utils';
import { FlexBox } from '../Basic/FlexBox';
export class DateInput extends React.Component {
constructor(props) {
super(props);
this.renderBtn = () => {
if (!this.state.showDatePicker) {
return (React.createElement(TouchableOpacity, { style: { flex: 1 }, onPress: this.showDatePicker },
React.createElement(View, { style: {
flex: 1,
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38,
} },
React.createElement(Text, null, this.props.value))));
}
return undefined;
};
this.renderInlineDatePicker = () => {
if (Platform.OS === 'ios') {
if (this.state.showDatePicker) {
let date = Utils.extractDate(this.props.value);
console.log(date);
return (React.createElement(DatePickerIOS, { date: date, mode: 'date', onDateChange: this.onDateChange, style: { flex: 1 } }));
}
}
return undefined;
};
this.onPickerClose = () => {
if (this.props.validateInput) {
if (this.props.validateInput(this.props.value)) {
console.log('DateInput: valid');
}
else {
console.log('DateInput: invalid');
}
}
};
this.onDateChange = (date) => {
if (this.props.onValueChange) {
let timeString = Utils.getDateString(date);
console.log(timeString);
this.setState({
showDatePicker: false,
}, () => this.props.onValueChange(timeString));
}
};
this.showDatePickerAndroid = this.showDatePickerAndroid.bind(this);
this.showDatePicker = this.showDatePicker.bind(this);
this.state = {
showDatePicker: false,
};
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, relativeWidth: false, flexDirection: 'row', alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', justifyContent: 'space-between', width: 'stretch' },
this.renderBtn(),
this.renderInlineDatePicker()));
}
showDatePickerAndroid() {
return __awaiter(this, void 0, void 0, function* () {
if (Platform.OS === 'android') {
const today = new Date();
try {
const { action, year, month, day } = yield DatePickerAndroid.open({
date: today,
});
if (action === DatePickerAndroid.dateSetAction) {
let newDate = new Date(year, month, day);
this.onDateChange(newDate);
}
}
catch ({ code, message }) {
console.warn('Cannot open date picker', message);
}
}
});
}
showDatePicker() {
return __awaiter(this, void 0, void 0, function* () {
if (this.state.showDatePicker) {
this.setState({
showDatePicker: false
}, this.onPickerClose);
}
else {
this.setState({
showDatePicker: true
});
yield this.showDatePickerAndroid();
}
});
}
}

24
dist/Components/Inputs/InputBox.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,24 @@
import * as React from 'react';
import { TextInput } from 'react-native';
import { FlexBox } from '../Basic/FlexBox';
export class InputBox extends React.Component {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, relativeWidth: false, flexDirection: 'row', alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', justifyContent: 'space-between', width: 'stretch' },
React.createElement(TextInput, { style: [
{
flex: 1,
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38,
},
this.props.style
], multiline: this.props.multiline, keyboardType: this.props.keyboardType, blurOnSubmit: true, placeholder: this.props.placeholder, value: this.props.value, returnKeyType: this.props.returnKeyType, underlineColorAndroid: 'transparent', importantForAccessibility: 'no-hide-descendants', onChangeText: this.props.onValueChange, onBlur: this.props.onBlur })));
}
}

33
dist/Components/Inputs/NumberInput.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,33 @@
import * as React from 'react';
import { Platform } from 'react-native';
import { Utils } from '../../Shared/Utils';
import { InputBox } from './InputBox';
export class NumberInput extends React.Component {
constructor(props) {
super(props);
this.onChangeText = (input) => {
if (this.props.onValueChange) {
if (Utils.isSymbol(input) || Utils.isNumber(input)) {
console.log('change text');
this.props.onValueChange(input);
}
}
};
this.onBlur = () => {
if (this.props.validateInput) {
if (this.props.validateInput(this.props.value)) {
console.log('NumberInput: valid');
}
else {
console.log('NumberInput: invalid');
}
}
if (this.props.onBlur) {
this.props.onBlur();
}
};
}
render() {
return (React.createElement(InputBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, multiline: false, keyboardType: Platform.OS === 'ios' ? 'numbers-and-punctuation' : 'numeric', placeholder: this.props.placeholder, value: this.props.value, returnKeyType: 'done', onValueChange: this.onChangeText, onBlur: this.onBlur }));
}
}

112
dist/Components/Inputs/TimeInput.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,112 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as React from 'react';
import { DatePickerIOS, Platform, Text, TimePickerAndroid, TouchableOpacity, View } from 'react-native';
import { Utils } from '../../Shared/Utils';
import { FlexBox } from '../Basic/FlexBox';
export class TimeInput extends React.Component {
constructor(props) {
super(props);
this.renderBtn = () => {
if (!this.state.showTimePicker) {
return (React.createElement(TouchableOpacity, { style: { flex: 1 }, onPress: this.showDatePicker },
React.createElement(View, { style: [
{
flex: 1,
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38,
}
] },
React.createElement(Text, null, this.props.value))));
}
return undefined;
};
this.showTimePickerIOS = () => {
if (Platform.OS === 'ios') {
if (this.state.showTimePicker) {
let time = Utils.extractTime(this.props.value);
console.log(time);
return (React.createElement(DatePickerIOS, { date: time, mode: 'time', onDateChange: this.onTimeChangeIOS, style: { flex: 1 } }));
}
}
return undefined;
};
this.onPickerClose = () => {
if (this.props.validateInput) {
if (this.props.validateInput(this.props.value)) {
console.log('TimeInput: valid');
}
else {
console.log('TimeInput: invalid');
}
}
};
this.onTimeChangeIOS = (date) => {
this.onTimeChange(date.getHours(), date.getMinutes());
};
this.onTimeChange = (hour, minute) => {
if (this.props.onValueChange) {
let timeString = Utils.composeTimeString(hour, minute);
console.log(timeString);
this.setState({
showTimePicker: false,
}, () => this.props.onValueChange(timeString));
}
};
this.showTimePickerAndroid = this.showTimePickerAndroid.bind(this);
this.showDatePicker = this.showDatePicker.bind(this);
this.state = {
showTimePicker: false,
};
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, relativeWidth: false, flexDirection: 'row', alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', justifyContent: 'space-between', width: 'stretch' },
this.renderBtn(),
this.showTimePickerIOS()));
}
showTimePickerAndroid() {
return __awaiter(this, void 0, void 0, function* () {
if (Platform.OS === 'android') {
const now = new Date();
try {
const { action, hour, minute } = yield TimePickerAndroid.open({
hour: now.getHours(),
minute: now.getMinutes(),
is24Hour: true
});
if (action === TimePickerAndroid.timeSetAction) {
this.onTimeChange(hour, minute);
}
}
catch ({ code, message }) {
console.warn('Cannot open date picker', message);
}
}
});
}
showDatePicker() {
return __awaiter(this, void 0, void 0, function* () {
if (this.state.showTimePicker) {
this.setState({
showTimePicker: false
}, this.onPickerClose);
}
else {
this.setState({
showTimePicker: true
}, this.showTimePickerAndroid);
}
});
}
}

Просмотреть файл

@ -50,7 +50,7 @@ export class ActionContext {
formValidate: false, formValidate: false,
target: target, target: target,
}; };
let hookFuncs = this.getExcuteFuncs(action.type, externalHooks); let hookFuncs = this.getExecuteFuncs(action.type, externalHooks);
args = hookFuncs.reduce((prev, current) => { args = hookFuncs.reduce((prev, current) => {
return current(prev); return current(prev);
}, args); }, args);
@ -75,7 +75,7 @@ export class ActionContext {
} }
return callback; return callback;
} }
getExcuteFuncs(actionType, externalHooks) { getExecuteFuncs(actionType, externalHooks) {
let hookFuncs = []; let hookFuncs = [];
if (this.hooks) { if (this.hooks) {
let hookArrays = this.hooks[actionType]; let hookArrays = this.hooks[actionType];

Просмотреть файл

5
dist/Schema/Base/ActionElement.js поставляемый
Просмотреть файл

@ -1,4 +1,4 @@
import { AbstractElement } from '../Base/AbstractElement'; import { AbstractElement } from './AbstractElement';
export var ActionType; export var ActionType;
(function (ActionType) { (function (ActionType) {
ActionType["OpenUrl"] = "Action.OpenUrl"; ActionType["OpenUrl"] = "Action.OpenUrl";
@ -27,6 +27,9 @@ export class ActionElement extends AbstractElement {
getData() { getData() {
return {}; return {};
} }
getStyleConfig() {
return {};
}
isAction() { isAction() {
return true; return true;
} }

7
dist/Schema/Base/ContentElement.js поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
import { Spacing } from '../../Shared/Enums'; import { Spacing } from '../../Shared/Enums';
import { Utils } from '../../Shared/Utils'; import { Utils } from '../../Shared/Utils';
import { AbstractElement } from '../Base/AbstractElement'; import { AbstractElement } from './AbstractElement';
export var ContentElementType; export var ContentElementType;
(function (ContentElementType) { (function (ContentElementType) {
ContentElementType["Column"] = "Column"; ContentElementType["Column"] = "Column";
@ -31,6 +31,11 @@ export class ContentElement extends AbstractElement {
getId() { getId() {
return this.id; return this.id;
} }
getStyleConfig() {
return {
spacing: this.spacing
};
}
isContent() { isContent() {
return true; return true;
} }

4
dist/Schema/Base/FormElement.js поставляемый
Просмотреть файл

@ -1,6 +1,6 @@
import { FormContext } from '../../Context/FormContext'; import { FormContext } from '../../Contexts/FormContext';
import { ContentElement } from '../Base/ContentElement';
import { ActionFactory } from '../Factories/ActionFactory'; import { ActionFactory } from '../Factories/ActionFactory';
import { ContentElement } from './ContentElement';
export var FormElementType; export var FormElementType;
(function (FormElementType) { (function (FormElementType) {
FormElementType["Column"] = "Column"; FormElementType["Column"] = "Column";

2
dist/Schema/Base/InputElement.js поставляемый
Просмотреть файл

@ -1,4 +1,4 @@
import { ContentElement } from '../Base/ContentElement'; import { ContentElement } from './ContentElement';
export var InputElementType; export var InputElementType;
(function (InputElementType) { (function (InputElementType) {
InputElementType["TextInput"] = "Input.Text"; InputElementType["TextInput"] = "Input.Text";

5
dist/Schema/Base/ValueElement.js поставляемый
Просмотреть файл

@ -1,4 +1,4 @@
import { AbstractElement } from '../Base/AbstractElement'; import { AbstractElement } from './AbstractElement';
export var ValueElementType; export var ValueElementType;
(function (ValueElementType) { (function (ValueElementType) {
ValueElementType["Fact"] = "Fact"; ValueElementType["Fact"] = "Fact";
@ -18,4 +18,7 @@ export class ValueElement extends AbstractElement {
isValue() { isValue() {
return true; return true;
} }
getStyleConfig() {
return {};
}
} }

8
dist/Schema/CardElements/Image.js поставляемый
Просмотреть файл

@ -30,6 +30,14 @@ export class ImageElement extends FormElement {
getChildren() { getChildren() {
return []; return [];
} }
getStyleConfig() {
return {
horizontalAlignment: this.horizontalAlignment,
imgSize: this.size,
style: this.style,
spacing: this.spacing,
};
}
setSize(size) { setSize(size) {
this.size = Utils.getStringEnumValueOrDefault(ImageSize, size, ImageSize.Auto); this.size = Utils.getStringEnumValueOrDefault(ImageSize, size, ImageSize.Auto);
} }

11
dist/Schema/CardElements/TextBlock.js поставляемый
Просмотреть файл

@ -16,6 +16,17 @@ export class TextBlockElement extends ContentElement {
this.wrap = json.wrap || false; this.wrap = json.wrap || false;
} }
} }
getStyleConfig() {
return {
color: this.color,
horizontalAlignment: this.horizontalAlignment,
isSubtle: this.isSubtle,
fontSize: this.size,
fontWeight: this.weight,
wrap: this.wrap,
spacing: this.spacing,
};
}
getTypeName() { getTypeName() {
return ContentElementType.TextBlock; return ContentElementType.TextBlock;
} }

6
dist/Schema/Containers/Column.js поставляемый
Просмотреть файл

@ -34,6 +34,12 @@ export class ColumnElement extends FormElement {
getChildren() { getChildren() {
return this.items; return this.items;
} }
getStyleConfig() {
return {
spacing: this.spacing,
columnWidth: this.width,
};
}
hasItems() { hasItems() {
return this.items && this.items.length > 0; return this.items && this.items.length > 0;
} }

5
dist/Schema/Containers/ColumnSet.js поставляемый
Просмотреть файл

@ -17,6 +17,11 @@ export class ColumnSetElement extends FormElement {
getChildren() { getChildren() {
return this.columns; return this.columns;
} }
getStyleConfig() {
return {
spacing: this.spacing,
};
}
hasColumns() { hasColumns() {
return this.columns && this.columns.length > 0; return this.columns && this.columns.length > 0;
} }

5
dist/Schema/Containers/Container.js поставляемый
Просмотреть файл

@ -21,6 +21,11 @@ export class ContainerElement extends FormElement {
getChildren() { getChildren() {
return this.items; return this.items;
} }
getStyleConfig() {
return {
spacing: this.spacing,
};
}
hasItems() { hasItems() {
return this.items && this.items.length > 0; return this.items && this.items.length > 0;
} }

5
dist/Schema/Containers/FactSet.js поставляемый
Просмотреть файл

@ -14,6 +14,11 @@ export class FactSetElement extends ContentElement {
getRequiredProperties() { getRequiredProperties() {
return ['facts']; return ['facts'];
} }
getStyleConfig() {
return {
spacing: this.spacing,
};
}
hasFacts() { hasFacts() {
return this.facts && this.facts.length > 0; return this.facts && this.facts.length > 0;
} }

5
dist/Schema/Containers/ImageSet.js поставляемый
Просмотреть файл

@ -18,6 +18,11 @@ export class ImageSetElement extends ContentElement {
getRequiredProperties() { getRequiredProperties() {
return ['images']; return ['images'];
} }
getStyleConfig() {
return {
spacing: this.spacing,
};
}
hasImages() { hasImages() {
return this.images && this.images.length > 0; return this.images && this.images.length > 0;
} }

190
dist/Styles/HostConfig.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,190 @@
import { ColumnWidth, FontSize, FontWeight, HorizontalAlignment, ImageSize, Spacing, TextColor } from '../Shared/Enums';
export var SizeModeCode;
(function (SizeModeCode) {
SizeModeCode[SizeModeCode["Auto"] = -1] = "Auto";
SizeModeCode[SizeModeCode["Stretch"] = -2] = "Stretch";
})(SizeModeCode || (SizeModeCode = {}));
export class HostConfigManager {
constructor() {
}
static getInstance() {
if (HostConfigManager.sharedInstance === undefined) {
HostConfigManager.sharedInstance = new HostConfigManager();
}
return HostConfigManager.sharedInstance;
}
getDefaultStyle() {
return {
textAlign: this.getTextAlignment(HorizontalAlignment.Center),
alignSelf: this.getSelfAlignment(HorizontalAlignment.Center),
color: this.getColor(TextColor.Default),
flex: 1,
fontSize: this.getFontSize(FontSize.Default),
imgSize: this.getImgSize(ImageSize.Auto),
fontWeight: this.getFontWeight(FontWeight.Default),
marginTop: this.getSpacing(Spacing.Default),
columnWidth: this.getColumnWidth(ColumnWidth.Auto),
wrap: true,
};
}
getColor(color) {
switch (color) {
case TextColor.Accent:
return '#2E89FC';
case TextColor.Attention:
return '#FF0000';
case TextColor.Dark:
return '#000000';
case TextColor.Default:
return '#333333';
case TextColor.Good:
return '#54a254';
case TextColor.Light:
return '#FFFFFF';
case TextColor.Warning:
return '#c3ab23';
default:
return this.getColor(TextColor.Default);
}
}
getSubtleColor(color) {
switch (color) {
case TextColor.Accent:
return '#2E89FC88';
case TextColor.Attention:
return '#FF0000DD';
case TextColor.Dark:
return '#00000066';
case TextColor.Default:
return '#333333EE';
case TextColor.Good:
return '#54a254DD';
case TextColor.Light:
return '#00000033';
case TextColor.Warning:
return '#c3ab23dd';
default:
return this.getSubtleColor(TextColor.Default);
}
}
getFontSize(size) {
switch (size) {
case FontSize.Default:
return 14;
case FontSize.ExtraLarge:
return 26;
case FontSize.Large:
return 21;
case FontSize.Medium:
return 17;
case FontSize.Small:
return 12;
default:
return this.getFontSize(FontSize.Default);
}
}
getFontWeight(weight) {
switch (weight) {
case FontWeight.Bolder:
return '600';
case FontWeight.Default:
return '400';
case FontWeight.Lighter:
return '200';
default:
return this.getFontWeight(FontWeight.Default);
}
}
getImgSize(size) {
switch (size) {
case ImageSize.Auto:
return 'auto';
case ImageSize.Large:
return 160;
case ImageSize.Medium:
return 80;
case ImageSize.Small:
return 40;
case ImageSize.Stretch:
return 'stretch';
default:
return this.getImgSize(ImageSize.Auto);
}
}
getSpacing(spacing) {
switch (spacing) {
case Spacing.Default:
return 8;
case Spacing.ExtraLarge:
return 40;
case Spacing.Large:
return 30;
case Spacing.Medium:
return 20;
case Spacing.None:
return 0;
case Spacing.Padding:
return 10;
case Spacing.Small:
return 3;
default:
return this.getSpacing(Spacing.Default);
}
}
getTextAlignment(align) {
switch (align) {
case HorizontalAlignment.Center:
return 'center';
case HorizontalAlignment.Left:
return 'left';
case HorizontalAlignment.Right:
return 'right';
default:
return this.getTextAlignment(HorizontalAlignment.Center);
}
}
getInboxTextAlignment(align) {
switch (align) {
case HorizontalAlignment.Center:
return 'center';
case HorizontalAlignment.Left:
return 'flex-start';
case HorizontalAlignment.Right:
return 'flex-end';
case ImageSize.Stretch:
return 'space-between';
default:
return this.getInboxTextAlignment(HorizontalAlignment.Left);
}
}
getSelfAlignment(align) {
switch (align) {
case HorizontalAlignment.Center:
return 'center';
case HorizontalAlignment.Left:
return 'flex-start';
case HorizontalAlignment.Right:
return 'flex-end';
case ImageSize.Stretch:
return 'stretch';
default:
return this.getSelfAlignment(HorizontalAlignment.Center);
}
}
getColumnWidth(width) {
if (typeof width === 'number') {
return width;
}
switch (width) {
case ColumnWidth.Auto:
return 'auto';
case ColumnWidth.Stretch:
return 'stretch';
default:
return this.getColumnWidth(ColumnWidth.Auto);
}
}
getWrap(wrap) {
return wrap ? 'wrap' : 'nowrap';
}
}

37
dist/Styles/StyleManager.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,37 @@
import { ImageSize } from '../Shared/Enums';
import { HostConfigManager } from './HostConfig';
export class StyleManager {
constructor() { }
static getInstance() {
if (StyleManager.sharedInstance === undefined) {
StyleManager.sharedInstance = new StyleManager();
}
return StyleManager.sharedInstance;
}
getStyle(element) {
let elementConfig = element.getStyleConfig();
let style = {
textAlign: HostConfigManager.getInstance().getTextAlignment(elementConfig.horizontalAlignment),
inboxTextAlign: HostConfigManager.getInstance().getInboxTextAlignment(elementConfig.horizontalAlignment),
alignSelf: HostConfigManager.getInstance().getSelfAlignment(elementConfig.horizontalAlignment),
color: this.getColor(elementConfig.color, elementConfig.isSubtle),
flex: 1,
fontSize: HostConfigManager.getInstance().getFontSize(elementConfig.fontSize),
imgSize: HostConfigManager.getInstance().getImgSize(elementConfig.imgSize),
fontWeight: HostConfigManager.getInstance().getFontWeight(elementConfig.fontWeight),
spacing: HostConfigManager.getInstance().getSpacing(elementConfig.spacing),
columnWidth: HostConfigManager.getInstance().getColumnWidth(elementConfig.columnWidth),
wrap: HostConfigManager.getInstance().getWrap(elementConfig.wrap),
};
if (elementConfig.imgSize === ImageSize.Stretch) {
style.alignSelf = HostConfigManager.getInstance().getSelfAlignment(ImageSize.Stretch);
}
return style;
}
getColor(color, isSubtle) {
if (isSubtle) {
return HostConfigManager.getInstance().getSubtleColor(color);
}
return HostConfigManager.getInstance().getColor(color);
}
}

45
dist/View/Actions/OpenUrlAction.js поставляемый
Просмотреть файл

@ -1,45 +0,0 @@
import React from 'react';
import { TouchableOpacity, } from 'react-native';
import { ActionContext } from '../../Context/ActionContext';
import { CardText } from '../Basic/CardText';
import { StyleManager } from '../Styles/StyleManager';
export class OpenUrlActionView extends React.Component {
constructor(props) {
super(props);
this.onPress = () => {
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element);
if (callback) {
if (this.props.actionHooks) {
callback(...this.props.actionHooks);
}
else {
callback();
}
}
};
this.styleConfig = StyleManager.getInstance().getStyle();
}
render() {
const { element, index } = this.props;
if (!element || !element.isValid()) {
return;
}
return (React.createElement(TouchableOpacity, { style: [
{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingVertical: this.styleConfig.action.button.paddingVertical,
paddingHorizontal: this.styleConfig.action.button.paddingHorizontal,
borderRadius: this.styleConfig.action.button.borderRadius,
backgroundColor: this.styleConfig.action.button.backgroundColor,
},
StyleManager.getInstance().getActionButtonSpacingStyle(index)
], onPress: this.onPress },
React.createElement(CardText, { style: {
fontSize: this.styleConfig.action.button.fontSize,
color: this.styleConfig.action.button.textColor,
}, numberOfLines: 1 }, element.title)));
}
}

45
dist/View/Actions/ShowCardAction.js поставляемый
Просмотреть файл

@ -1,45 +0,0 @@
import React from 'react';
import { TouchableOpacity, } from 'react-native';
import { ActionContext } from '../../Context/ActionContext';
import { CardText } from '../Basic/CardText';
import { StyleManager } from '../Styles/StyleManager';
export class ShowCardActionView extends React.Component {
constructor(props) {
super(props);
this.onPress = () => {
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element);
if (callback) {
if (this.props.actionHooks) {
callback(...this.props.actionHooks);
}
else {
callback();
}
}
};
this.styleConfig = StyleManager.getInstance().getStyle();
}
render() {
const { element, index } = this.props;
if (!element || !element.isValid()) {
return;
}
return (React.createElement(TouchableOpacity, { style: [
{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingVertical: this.styleConfig.action.button.paddingVertical,
paddingHorizontal: this.styleConfig.action.button.paddingHorizontal,
borderRadius: this.styleConfig.action.button.borderRadius,
backgroundColor: this.styleConfig.action.button.backgroundColor,
},
StyleManager.getInstance().getActionButtonSpacingStyle(index)
], onPress: this.onPress },
React.createElement(CardText, { style: {
fontSize: this.styleConfig.action.button.fontSize,
color: this.styleConfig.action.button.textColor,
}, numberOfLines: 1 }, element.title)));
}
}

45
dist/View/Actions/SubmitAction.js поставляемый
Просмотреть файл

@ -1,45 +0,0 @@
import React from 'react';
import { TouchableOpacity, } from 'react-native';
import { ActionContext } from '../../Context/ActionContext';
import { CardText } from '../Basic/CardText';
import { StyleManager } from '../Styles/StyleManager';
export class SubmitActionView extends React.Component {
constructor(props) {
super(props);
this.onPress = () => {
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element);
if (callback) {
if (this.props.actionHooks) {
callback(...this.props.actionHooks);
}
else {
callback();
}
}
};
this.styleConfig = StyleManager.getInstance().getStyle();
}
render() {
const { element, index } = this.props;
if (!element || !element.isValid()) {
return;
}
return (React.createElement(TouchableOpacity, { style: [
{
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
paddingVertical: this.styleConfig.action.button.paddingVertical,
paddingHorizontal: this.styleConfig.action.button.paddingHorizontal,
borderRadius: this.styleConfig.action.button.borderRadius,
backgroundColor: this.styleConfig.action.button.backgroundColor,
},
StyleManager.getInstance().getActionButtonSpacingStyle(index)
], onPress: this.onPress },
React.createElement(CardText, { style: {
fontSize: this.styleConfig.action.button.fontSize,
color: this.styleConfig.action.button.textColor,
}, numberOfLines: 1 }, element.title)));
}
}

18
dist/View/Basic/CardText.js поставляемый
Просмотреть файл

@ -1,18 +0,0 @@
import React from 'react';
import { Text, } from 'react-native';
import { StyleManager } from '../Styles/StyleManager';
export class CardText extends React.PureComponent {
constructor(props) {
super(props);
this.fontFamily = StyleManager.getInstance().getFontFamily();
}
render() {
const { style, children } = this.props;
return (React.createElement(Text, Object.assign({}, this.props, { style: [
{
fontFamily: this.fontFamily || undefined,
},
style
] }), children));
}
}

47
dist/View/Basic/DecCardElementView.js поставляемый
Просмотреть файл

@ -1,47 +0,0 @@
import React from 'react';
import { ContentElementType } from '../../Schema/Base/ContentElement';
import { ImageView } from '../CardElements/ImageView';
import { TextBlockView } from '../CardElements/TextBlockView';
import { ColumnSetView } from '../Containers/ColumnSetView';
import { ColumnView } from '../Containers/ColumnView';
import { ContainerView } from '../Containers/ContainerView';
import { FactSetView } from '../Containers/FactSetView';
import { ImageSetView } from '../Containers/ImageSetView';
import { DateInputView } from '../Inputs/DateInputView';
import { NumberInputView } from '../Inputs/NumberInputView';
import { TextInputView } from '../Inputs/TextInputView';
import { TimeInputView } from '../Inputs/TimeInputView';
export class DecCardElementView extends React.PureComponent {
render() {
const { element, index, containerWidth } = this.props;
if (!element || !element.isValid()) {
return null;
}
switch (element.type) {
case ContentElementType.TextBlock:
return (React.createElement(TextBlockView, { element: element, index: index }));
case ContentElementType.Image:
return (React.createElement(ImageView, { element: element, index: index }));
case ContentElementType.ImageSet:
return (React.createElement(ImageSetView, { element: element, index: index }));
case ContentElementType.Container:
return (React.createElement(ContainerView, { element: element, index: index }));
case ContentElementType.Column:
return (React.createElement(ColumnView, { element: element, containerWidth: containerWidth, index: index }));
case ContentElementType.ColumnSet:
return (React.createElement(ColumnSetView, { element: element, index: index }));
case ContentElementType.FactSet:
return (React.createElement(FactSetView, { element: element, index: index }));
case ContentElementType.TextInput:
return (React.createElement(TextInputView, { element: element, index: index }));
case ContentElementType.DateInput:
return (React.createElement(DateInputView, { element: element, index: index }));
case ContentElementType.TimeInput:
return (React.createElement(TimeInputView, { element: element, index: index }));
case ContentElementType.NumberInput:
return (React.createElement(NumberInputView, { element: element, index: index }));
default:
return null;
}
}
}

71
dist/View/Basic/DecCardElementWrapper.js поставляемый
Просмотреть файл

@ -1,71 +0,0 @@
import React from 'react';
import { TouchableOpacity, View, } from 'react-native';
import { ActionContext } from '../../Context/ActionContext';
import { SeparateLine } from '../Basic/SeparateLine';
import { StyleManager } from '../Styles/StyleManager';
export class DecCardElementWrapper extends React.PureComponent {
constructor(props) {
super(props);
this.styleConfig = StyleManager.getInstance().getStyle();
this.onClick = this.onClick.bind(this);
}
render() {
if (!this.props.element || !this.props.element.isValid()) {
return null;
}
if (this.props.element.isForm() && this.props.element.getAction() !== undefined) {
return this.renderActionView();
}
return this.renderNonActionView();
}
renderActionView() {
const isHorizontalLayout = StyleManager.getInstance().isHorizontalCardElement(this.props.element.type);
if (this.props.element.separator) {
return (React.createElement(TouchableOpacity, { style: this.props.style, onPress: this.onClick },
this.renderSeparator(this.props.element.spacing, isHorizontalLayout),
this.renderWrapper(this.props.element.spacing, 0, isHorizontalLayout, { flex: 1 })));
}
else {
return this.renderTouchableWrapper(this.props.element.spacing, this.props.index, isHorizontalLayout, this.props.style);
}
}
renderNonActionView() {
const isHorizontalLayout = StyleManager.getInstance().isHorizontalCardElement(this.props.element.type);
if (this.props.element.separator) {
return (React.createElement(View, { style: this.props.style },
this.renderSeparator(this.props.element.spacing, isHorizontalLayout),
this.renderWrapper(this.props.element.spacing, 0, isHorizontalLayout, { flex: 1 })));
}
else {
return this.renderWrapper(this.props.element.spacing, this.props.index, isHorizontalLayout, this.props.style);
}
}
renderTouchableWrapper(spacing, index, isHorizontalLayout, wrapperStyle) {
return (React.createElement(TouchableOpacity, { style: [
wrapperStyle,
StyleManager.getInstance().getCardElementSpacingStyle(spacing, index, isHorizontalLayout)
], onPress: this.onClick }, this.props.children));
}
renderWrapper(spacing, index, isHorizontalLayout, wrapperStyle) {
return (React.createElement(View, { style: [
wrapperStyle,
StyleManager.getInstance().getCardElementSpacingStyle(spacing, index, isHorizontalLayout)
] }, this.props.children));
}
renderSeparator(spacing, isHorizontalLayout) {
return (React.createElement(SeparateLine, { isHorizontal: isHorizontalLayout, margin: StyleManager.getInstance().getCardElementMargin(spacing), color: this.styleConfig.element.separateLineColor }));
}
onClick() {
let actionContext = ActionContext.getGlobalInstance();
let callback = actionContext.getActionEventHandler(this.props.element.getAction());
if (callback) {
const element = this.props.element;
if (element.isForm()) {
let action = element.getAction();
if (action) {
callback();
}
}
}
}
}

32
dist/View/Basic/SeparateLine.js поставляемый
Просмотреть файл

@ -1,32 +0,0 @@
import React from 'react';
import { PixelRatio, Platform, View, } from 'react-native';
export class SeparateLine extends React.PureComponent {
render() {
const { color, isHorizontal, margin } = this.props;
const thickness = (Platform.OS === 'ios') ?
parseFloat((1 / PixelRatio.get()).toFixed(2)) :
1;
const style = isHorizontal ?
{
width: thickness,
marginLeft: margin,
marginRight: margin,
marginTop: 0,
marginBottom: 0,
} :
{
height: thickness,
marginLeft: 0,
marginRight: 0,
marginTop: margin,
marginBottom: margin,
};
return (React.createElement(View, Object.assign({}, this.props, { style: [
{
flex: 1,
backgroundColor: color,
},
style
] })));
}
}

156
dist/View/CardElements/ImageView.js поставляемый
Просмотреть файл

@ -1,156 +0,0 @@
import React from 'react';
import { Image, StyleSheet, Text, View, } from 'react-native';
import { FlexImageAlignment, HorizontalAlignment, ImageSize, ImageStyle, } from '../../Shared/Enums';
import { DecCardElementWrapper } from '../Basic/DecCardElementWrapper';
import { StyleManager } from '../Styles/StyleManager';
const IMAGEMINSIZE = 18;
var ImageFit;
(function (ImageFit) {
ImageFit[ImageFit["FlexibleWidth"] = 0] = "FlexibleWidth";
ImageFit[ImageFit["FlexibleHeight"] = 1] = "FlexibleHeight";
})(ImageFit || (ImageFit = {}));
export class ImageView extends React.PureComponent {
constructor(props) {
super(props);
this.onLayout = (event) => {
const { element } = this.props;
if (element.isFixedSize()) {
return;
}
let width = event.nativeEvent.layout.width;
let height = event.nativeEvent.layout.height;
console.log('AdaptiveCard Image onLayout', width, height);
if (!this.fitStyle) {
this.fitStyle = width !== 0 && height === 0 ? 1 : 0;
}
this.setState({
viewWidth: width,
viewHeight: height
});
};
this.onLoad = () => {
const { element } = this.props;
Image.getSize(element.url, (width, height) => {
console.log('AdaptiveCard Image getSize', width, height);
if (!this.isComponentUnmounted && width) {
this.setState({
imageAspectRatio: height / width
});
}
}, (error) => {
console.error('failed to get image size of commute url, error');
});
};
this.onError = () => {
if (!this.isComponentUnmounted) {
this.setState({
imageLoadSuccess: false,
});
}
};
this.getDimensionsForBestFit = () => {
if (this.state.imageAspectRatio) {
switch (this.fitStyle) {
case 1:
if (this.state.viewWidth) {
return {
height: Math.floor(this.state.viewWidth * this.state.imageAspectRatio),
width: this.state.viewWidth
};
}
break;
case 0:
if (this.state.viewHeight) {
let dimensions = {
width: Math.floor(this.state.viewHeight / this.state.imageAspectRatio),
height: this.state.viewHeight
};
if (this.state.viewWidth && dimensions.width > this.state.viewWidth) {
dimensions.width = this.state.viewWidth;
}
return dimensions;
}
break;
}
}
else if (this.fitStyle !== undefined) {
return {
width: this.state.viewWidth || IMAGEMINSIZE,
height: this.state.viewHeight || IMAGEMINSIZE
};
}
return undefined;
};
this.state = {
viewWidth: 0,
viewHeight: 0,
imageAspectRatio: 1,
imageLoadSuccess: true,
};
}
componentWillUnmount() {
this.isComponentUnmounted = true;
}
render() {
const { element, index } = this.props;
if (!element || !element.isValid()) {
return null;
}
const dimensions = element.isFixedSize() ?
{
width: StyleManager.getInstance().getImageSize(element.size),
height: StyleManager.getInstance().getImageSize(element.size),
} :
this.getDimensionsForBestFit();
const borderRadius = element.style === ImageStyle.Person && dimensions ?
dimensions.width / 2 :
undefined;
return (React.createElement(DecCardElementWrapper, { element: element, index: index, style: StyleManager.getInstance().isHorizontalImageSet() ? undefined : { flex: 1 } },
React.createElement(View, { style: { flex: 1 }, onLayout: this.onLayout },
this.state.imageLoadSuccess ?
undefined :
this.renderPlaceholder(),
React.createElement(Image, { accessible: !!element.altText, accessibilityLabel: element.altText || undefined, style: {
overflow: 'hidden',
width: dimensions ? dimensions.width : undefined,
height: dimensions ? dimensions.height : undefined,
alignSelf: this.getImageAlignment(element.horizontalAlignment, element.size),
borderRadius: borderRadius
}, source: { uri: element.url }, onLoad: this.onLoad, onError: this.onError, resizeMode: 'cover', resizeMethod: 'auto' }))));
}
renderPlaceholder() {
return (React.createElement(View, { style: [
StyleSheet.absoluteFill,
{
alignItems: 'center',
justifyContent: 'center'
}
] },
React.createElement(Text, { style: {
fontSize: 32,
color: 'rgba(0, 0, 0, 0.5)',
textAlign: 'center'
} }, '\uE601')));
}
getImageAlignment(alignment, imageSize) {
let imageAlignment;
if (imageSize === ImageSize.Stretch) {
imageAlignment = FlexImageAlignment.Stretch;
}
else {
switch (alignment) {
case HorizontalAlignment.Left:
imageAlignment = FlexImageAlignment.FlexStart;
break;
case HorizontalAlignment.Right:
imageAlignment = FlexImageAlignment.FlexEnd;
break;
case HorizontalAlignment.Center:
default:
imageAlignment = FlexImageAlignment.Center;
break;
}
}
return imageAlignment;
}
}

29
dist/View/CardElements/TextBlockView.js поставляемый
Просмотреть файл

@ -1,29 +0,0 @@
import React from 'react';
import { View, } from 'react-native';
import { CardText } from '../Basic/CardText';
import { DecCardElementWrapper } from '../Basic/DecCardElementWrapper';
import { StyleManager } from '../Styles/StyleManager';
export class TextBlockView extends React.PureComponent {
render() {
const { element, index } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(DecCardElementWrapper, { element: element, index: index, style: {
flex: 1,
} },
React.createElement(View, { style: {
flex: 1,
} },
React.createElement(CardText, { style: {
backgroundColor: 'transparent',
fontSize: StyleManager.getInstance().getFontSize(element.size),
fontWeight: StyleManager.getInstance().getFontWeight(element.weight),
color: element.isSubtle ?
StyleManager.getInstance().getSubtleColor(element.color) :
StyleManager.getInstance().getColor(element.color),
textAlign: element.horizontalAlignment,
flexWrap: StyleManager.getInstance().getWrapStyle(element.wrap),
}, numberOfLines: element.maxLines || undefined }, element.text))));
}
}

42
dist/View/Containers/ColumnSetView.js поставляемый
Просмотреть файл

@ -1,42 +0,0 @@
import React from 'react';
import { View, } from 'react-native';
import { DecCardElementView } from '../Basic/DecCardElementView';
import { DecCardElementWrapper } from '../Basic/DecCardElementWrapper';
export class ColumnSetView extends React.PureComponent {
constructor(props) {
super(props);
this.renderColumn = (column, index) => {
return (React.createElement(DecCardElementView, { key: 'column' + index, index: index, containerWidth: this.state.viewWidth, element: column }));
};
this.onLayout = (event) => {
if (!this.isComponentUnmounted && !this.state.viewWidth && this.hasFixedWidthColumns) {
this.setState({
viewWidth: event.nativeEvent.layout.width,
});
}
};
this.state = {
viewWidth: 0,
};
const { element } = props;
this.hasFixedWidthColumns = element.columns.some(item => item.isFixedWidth());
this.isEqualDistribution = element.columns.every(item => item.isFixedWidth());
}
componentWillUnmount() {
this.isComponentUnmounted = true;
}
render() {
const { element, index } = this.props;
if (!element || !element.isValid() || !element.hasColumns()) {
return null;
}
return (React.createElement(DecCardElementWrapper, { element: element, index: index, style: {
flex: 1,
} },
React.createElement(View, { style: {
flex: 1,
flexDirection: 'row',
justifyContent: this.isEqualDistribution ? 'space-between' : 'flex-start',
}, onLayout: this.onLayout }, element.columns.map(this.renderColumn))));
}
}

39
dist/View/Containers/ColumnView.js поставляемый
Просмотреть файл

@ -1,39 +0,0 @@
import React from 'react';
import { View, } from 'react-native';
import { ColumnWidth } from '../../Shared/Enums';
import { DecCardElementView } from '../Basic/DecCardElementView';
import { DecCardElementWrapper } from '../Basic/DecCardElementWrapper';
export class ColumnView extends React.PureComponent {
render() {
const { element, index } = this.props;
if (!element || !element.isValid() || !element.hasItems()) {
return null;
}
return (React.createElement(DecCardElementWrapper, { element: element, index: index, style: this.getViewStyle() },
React.createElement(View, { style: { flex: 1 } }, element.items.map((cardElement, index) => React.createElement(DecCardElementView, { key: 'containerItems' + index, index: index, element: cardElement })))));
}
getViewStyle() {
const { element, containerWidth } = this.props;
if (element.isFixedWidth()) {
if (element.width < 10) {
return {
flex: element.width,
};
}
else if (containerWidth) {
return {
width: containerWidth * (element.width / 100),
};
}
else {
return;
}
}
else {
return {
flex: element.width === ColumnWidth.Auto ? 0 : 1,
alignSelf: element.width,
};
}
}
}

40
dist/View/Containers/ContainerView.js поставляемый
Просмотреть файл

@ -1,40 +0,0 @@
import React from 'react';
import { View, } from 'react-native';
import { ContainerStyle } from '../../Shared/Enums';
import { DecCardElementView } from '../Basic/DecCardElementView';
import { DecCardElementWrapper } from '../Basic/DecCardElementWrapper';
import { StyleManager } from '../Styles/StyleManager';
export class ContainerView extends React.PureComponent {
constructor(props) {
super(props);
this.styleConfig = StyleManager.getInstance().getStyle();
}
render() {
const { element, index } = this.props;
if (!element || !element.isValid() || !element.hasItems()) {
return null;
}
return (React.createElement(DecCardElementWrapper, { element: element, index: index, style: {
flex: 1,
} },
React.createElement(View, { style: [{
flex: 1,
},
this.getContainerStyle(element.style)
] }, element.items.map((cardElement, index) => React.createElement(DecCardElementView, { key: 'containerItems' + index, index: index, element: cardElement })))));
}
getContainerStyle(style) {
let containerStyle;
switch (style) {
case ContainerStyle.Emphasis:
containerStyle = {
backgroundColor: this.styleConfig.container.backgroundColor,
};
break;
case ContainerStyle.Default:
default:
break;
}
return containerStyle;
}
}

18
dist/View/Containers/FactSetView.js поставляемый
Просмотреть файл

@ -1,18 +0,0 @@
import React from 'react';
import { View } from 'react-native';
import { DecCardElementWrapper } from '../Basic/DecCardElementWrapper';
import { FactView } from './FactView';
export class FactSetView extends React.PureComponent {
render() {
const { element, index } = this.props;
if (!element || !element.isValid() || !element.hasFacts()) {
return null;
}
return (React.createElement(DecCardElementWrapper, { element: element, index: index, style: {
flex: 1,
} },
React.createElement(View, { style: {
flex: 1,
} }, element.facts.map((fact, index) => React.createElement(FactView, { key: 'fact' + index, element: fact })))));
}
}

29
dist/View/Containers/FactView.js поставляемый
Просмотреть файл

@ -1,29 +0,0 @@
import React from 'react';
import { View } from 'react-native';
import { CardText } from '../Basic/CardText';
import { StyleManager } from '../Styles/StyleManager';
export class FactView extends React.PureComponent {
constructor(props) {
super(props);
this.styleConfig = StyleManager.getInstance().getStyle();
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(View, { style: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-start'
} },
React.createElement(CardText, { style: {
color: this.styleConfig.fact.titleColor,
marginRight: this.styleConfig.fact.spacing,
} }, element.title),
React.createElement(CardText, { style: {
color: this.styleConfig.fact.valueColor,
marginLeft: this.styleConfig.fact.spacing,
} }, element.value)));
}
}

30
dist/View/Containers/ImageSetView.js поставляемый
Просмотреть файл

@ -1,30 +0,0 @@
import React from 'react';
import { FlatList, View, } from 'react-native';
import { DecCardElementView } from '../Basic/DecCardElementView';
import { DecCardElementWrapper } from '../Basic/DecCardElementWrapper';
import { StyleManager } from '../Styles/StyleManager';
export class ImageSetView extends React.PureComponent {
constructor() {
super(...arguments);
this.renderImage = (image, index) => {
const { element } = this.props;
image.setSize(element.imageSize);
return (React.createElement(DecCardElementView, { key: 'image' + index, index: index, element: image }));
};
}
render() {
const { element, index } = this.props;
if (!element || !element.isValid() || !element.hasImages()) {
return null;
}
return (React.createElement(DecCardElementWrapper, { element: element, index: index, style: {
flex: 1,
} }, StyleManager.getInstance().isHorizontalImageSet() ?
React.createElement(FlatList, { style: { flex: 1 }, horizontal: true, data: element.images, renderItem: ({ item, index }) => this.renderImage(item, index), keyExtractor: (item, index) => 'image' + index, showsHorizontalScrollIndicator: false })
:
React.createElement(View, { style: {
flex: 1,
flexWrap: 'wrap',
} }, element.images.map(this.renderImage))));
}
}

32
dist/View/Factories/ActionElementView.js поставляемый
Просмотреть файл

@ -1,32 +0,0 @@
import React from 'react';
import { ActionType } from '../../Schema/Base/ActionElement';
import { OpenUrlActionView } from '../Actions/OpenUrlAction';
import { ShowCardActionView } from '../Actions/ShowCardAction';
import { SubmitActionView } from '../Actions/SubmitAction';
export class ActionElementView extends React.Component {
constructor(props) {
super(props);
this.getHooks = this.getHooks.bind(this);
}
render() {
console.log('Render Action: ' + this.props.element.getActionType());
switch (this.props.element.getActionType()) {
case ActionType.OpenUrl:
return (React.createElement(OpenUrlActionView, { element: this.props.element, index: this.props.index, actionHooks: this.getHooks(ActionType.OpenUrl) }));
case ActionType.ShowCard:
return (React.createElement(ShowCardActionView, { element: this.props.element, index: this.props.index, actionHooks: this.getHooks(ActionType.ShowCard) }));
case ActionType.Submit:
return (React.createElement(SubmitActionView, { element: this.props.element, index: this.props.index, actionHooks: this.getHooks(ActionType.Submit) }));
default:
return undefined;
}
}
getHooks(actionType) {
if (this.props.actionContext) {
let result = this.props.actionContext.getHooks(actionType);
console.log('Attach hook:' + result);
return result;
}
return undefined;
}
}

49
dist/View/Factories/ContentElementView.js поставляемый
Просмотреть файл

@ -1,49 +0,0 @@
import * as React from 'react';
import { ContentElementType } from '../../Schema/Base/ContentElement';
import { SeparateLine } from '../Basic/SeparateLine';
import { TextBlockView } from '../CardElements/TextBlockView';
import { FactSetView } from '../Containers/FactSetView';
import { ImageSetView } from '../Containers/ImageSetView';
import { StyleManager } from '../Styles/StyleManager';
import { FormElementView } from './FormElementView';
import { InputElementView } from './InputElementView';
export class ContentElementView extends React.Component {
constructor(props) {
super(props);
}
render() {
return [
this.renderSeperator(),
this.renderELement()
];
}
renderELement() {
if (this.props.element) {
if (this.props.element.isForm()) {
return (React.createElement(FormElementView, { index: this.props.index, element: this.props.element }));
}
else if (this.props.element.isInput()) {
return (React.createElement(InputElementView, { index: this.props.index, element: this.props.element }));
}
else {
switch (this.props.element.type) {
case ContentElementType.TextBlock:
return (React.createElement(TextBlockView, { element: this.props.element, index: this.props.index }));
case ContentElementType.ImageSet:
return (React.createElement(ImageSetView, { element: this.props.element, index: this.props.index }));
case ContentElementType.FactSet:
return (React.createElement(FactSetView, { element: this.props.element, index: this.props.index }));
default:
return null;
}
return undefined;
}
}
return undefined;
}
renderSeperator() {
if (this.props.element.separator) {
return (React.createElement(SeparateLine, { isHorizontal: StyleManager.getInstance().isHorizontalCardElement(this.props.element.type), margin: StyleManager.getInstance().getCardElementMargin(this.props.element.spacing), color: StyleManager.getInstance().getStyle().element.separateLineColor }));
}
}
}

19
dist/View/Factories/ElementView.js поставляемый
Просмотреть файл

@ -1,19 +0,0 @@
import * as React from 'react';
import { ContentElementView } from './ContentElementView';
import { ValueElementView } from './ValueElementView';
export class ElementView extends React.Component {
constructor(props) {
super(props);
}
render() {
if (this.props.element) {
if (this.props.element.isContent()) {
return (React.createElement(ContentElementView, { index: this.props.index, element: this.props.element }));
}
else if (this.props.element.isContent()) {
return (React.createElement(ValueElementView, { index: this.props.index, element: this.props.element }));
}
}
return undefined;
}
}

31
dist/View/Factories/FormElementView.js поставляемый
Просмотреть файл

@ -1,31 +0,0 @@
import * as React from 'react';
import { FormElementType } from 'Schema/Base/FormElement';
import { ImageView } from '../CardElements/ImageView';
import { CardView } from '../Cards/CardView';
import { ColumnSetView } from '../Containers/ColumnSetView';
import { ColumnView } from '../Containers/ColumnView';
import { ContainerView } from '../Containers/ContainerView';
export class FormElementView extends React.Component {
constructor(props) {
super(props);
}
render() {
if (this.props.element) {
switch (this.props.element.type) {
case FormElementType.Image:
return (React.createElement(ImageView, { element: this.props.element, index: this.props.index }));
case FormElementType.Container:
return (React.createElement(ContainerView, { element: this.props.element, index: this.props.index }));
case FormElementType.Column:
return (React.createElement(ColumnView, { element: this.props.element, containerWidth: this.props.containerWidth, index: this.props.index }));
case FormElementType.ColumnSet:
return (React.createElement(ColumnSetView, { element: this.props.element, index: this.props.index }));
case FormElementType.AdaptiveCard:
return (React.createElement(CardView, { element: this.props.element, index: this.props.index }));
default:
return undefined;
}
}
return undefined;
}
}

25
dist/View/Factories/InputElementView.js поставляемый
Просмотреть файл

@ -1,25 +0,0 @@
import * as React from 'react';
import { InputElementType } from '../../Schema/Base/InputElement';
import { DateInputView } from '../Inputs/DateInputView';
import { NumberInputView } from '../Inputs/NumberInputView';
import { TextInputView } from '../Inputs/TextInputView';
export class InputElementView extends React.Component {
constructor(props) {
super(props);
}
render() {
if (this.props.element) {
switch (this.props.element.type) {
case InputElementType.TextInput:
return (React.createElement(TextInputView, { element: this.props.element, index: this.props.index }));
case InputElementType.NumberInput:
return (React.createElement(NumberInputView, { element: this.props.element, index: this.props.index }));
case InputElementType.DateInput:
return (React.createElement(DateInputView, { element: this.props.element, index: this.props.index }));
default:
return undefined;
}
}
return undefined;
}
}

19
dist/View/Factories/ValueElementView.js поставляемый
Просмотреть файл

@ -1,19 +0,0 @@
import * as React from 'react';
import { ValueElementType } from '../../Schema/Base/ValueElement';
import { FactView } from '../Containers/FactView';
export class ValueElementView extends React.Component {
constructor(props) {
super(props);
}
render() {
if (this.props.element) {
switch (this.props.element.type) {
case ValueElementType.Fact:
return (React.createElement(FactView, { element: this.props.element, index: this.props.index }));
default:
return undefined;
}
}
return undefined;
}
}

106
dist/View/Inputs/DateInputView.js поставляемый
Просмотреть файл

@ -1,106 +0,0 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import React from 'react';
import { DatePickerAndroid, DatePickerIOS, Platform, Text, TouchableOpacity, View } from 'react-native';
import { FormContext } from '../../Context/FormContext';
import { Utils } from '../../Shared/Utils';
export class DateInputView extends React.PureComponent {
constructor(props) {
super(props);
this.showDatePicker = this.showDatePicker.bind(this);
this.onDateChange = this.onDateChange.bind(this);
this.onPickerClose = this.onPickerClose.bind(this);
this.state = {
dateString: this.props.element.value,
showDatePicker: false,
};
this.updateStore();
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(View, null,
React.createElement(TouchableOpacity, { onPress: this.showDatePicker },
React.createElement(View, { style: {
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38
} },
React.createElement(Text, null, this.state.dateString))),
this.renderInlineTimePicker()));
}
renderInlineTimePicker() {
if (Platform.OS === 'ios') {
if (this.state.showDatePicker) {
let date = Utils.extractDate(this.state.dateString);
console.log(date);
return (React.createElement(DatePickerIOS, { date: date, mode: 'date', onDateChange: this.onDateChange }));
}
}
return undefined;
}
showDatePickerAndroid() {
return __awaiter(this, void 0, void 0, function* () {
if (Platform.OS === 'android') {
const today = new Date();
try {
const { action, year, month, day } = yield DatePickerAndroid.open({
date: today,
});
if (action === DatePickerAndroid.dateSetAction) {
let newDate = new Date(year, month, day);
this.onDateChange(newDate);
}
}
catch ({ code, message }) {
console.warn('Cannot open date picker', message);
}
}
});
}
showDatePicker() {
return __awaiter(this, void 0, void 0, function* () {
if (this.state.showDatePicker) {
this.setState({
showDatePicker: false
}, this.onPickerClose);
}
else {
this.setState({
showDatePicker: true
});
yield this.showDatePickerAndroid();
}
});
}
onPickerClose() {
if (this.props.element.validateForm(this.state.dateString)) {
console.log('DateInput: valide');
}
else {
console.log('DateInput: invalide');
}
}
onDateChange(date) {
let timeString = Utils.getDateString(date);
console.log(timeString);
this.setState({
dateString: timeString,
}, this.updateStore);
}
updateStore() {
FormContext.getInstance().updateField(this.props.element.id, this.state.dateString, this.props.element.validateForm(this.state.dateString));
}
}

55
dist/View/Inputs/NumberInputView.js поставляемый
Просмотреть файл

@ -1,55 +0,0 @@
import React from 'react';
import { Platform, TextInput, } from 'react-native';
import { FormContext } from '../../Context/FormContext';
import { Utils } from '../../Shared/Utils';
export class NumberInputView extends React.PureComponent {
constructor(props) {
super(props);
this.onChangeText = this.onChangeText.bind(this);
this.onBlur = this.onBlur.bind(this);
let defaultValue = this.props.element.value;
if (defaultValue === undefined) {
defaultValue = '';
}
if (Utils.isNumber(this.props.element.value.toString())) {
this.state = {
value: this.props.element.value.toString(),
};
this.updateStore();
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(TextInput, { style: {
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38
}, multiline: false, keyboardType: Platform.OS === 'ios' ? 'numbers-and-punctuation' : 'numeric', blurOnSubmit: true, placeholder: element.placeholder, value: this.state.value, returnKeyType: 'done', underlineColorAndroid: 'transparent', importantForAccessibility: 'no-hide-descendants', onChangeText: this.onChangeText, onBlur: this.onBlur }));
}
onChangeText(input) {
if (Utils.isSymbol(input) || Utils.isNumber(input)) {
console.log('change text');
this.setState({
value: input
}, this.updateStore);
}
}
onBlur() {
if (this.props.element.validateForm(this.state.value)) {
console.log('NumberInput: valide');
}
else {
console.log('NumberInput: invalide');
}
}
updateStore() {
FormContext.getInstance().updateField(this.props.element.id, this.state.value, this.props.element.validateForm(this.state.value));
}
}

41
dist/View/Inputs/TextInputView.js поставляемый
Просмотреть файл

@ -1,41 +0,0 @@
import React from 'react';
import { TextInput, } from 'react-native';
import { FormContext } from '../../Context/FormContext';
export class TextInputView extends React.PureComponent {
constructor(props) {
super(props);
this.onChangeText = this.onChangeText.bind(this);
let defaultValue = this.props.element.value;
if (defaultValue === undefined) {
defaultValue = '';
}
this.state = {
value: defaultValue,
};
this.updateStore();
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(TextInput, { style: {
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
fontSize: 16,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: element.isMultiline ? 116 : 38
}, multiline: element.isMultiline, blurOnSubmit: true, placeholder: element.placeholder, value: this.state.value, returnKeyType: 'done', underlineColorAndroid: 'transparent', importantForAccessibility: 'no-hide-descendants', onChangeText: this.onChangeText }));
}
onChangeText(input) {
this.setState({
value: input
}, this.updateStore);
}
updateStore() {
FormContext.getInstance().updateField(this.props.element.id, this.state.value, this.props.element.validateForm(this.state.value));
}
}

111
dist/View/Inputs/TimeInputView.js поставляемый
Просмотреть файл

@ -1,111 +0,0 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import React from 'react';
import { DatePickerIOS, Platform, Text, TimePickerAndroid, TouchableOpacity, View } from 'react-native';
import { FormContext } from '../../Context/FormContext';
import { Utils } from '../../Shared/Utils';
export class TimeInputView extends React.PureComponent {
constructor(props) {
super(props);
this.showDatePicker = this.showDatePicker.bind(this);
this.onTimeChangeIOS = this.onTimeChangeIOS.bind(this);
this.onTimeChange = this.onTimeChange.bind(this);
this.onPickerClose = this.onPickerClose.bind(this);
this.state = {
timeString: this.props.element.value,
showTimePicker: false,
};
this.updateStore();
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(View, null,
React.createElement(TouchableOpacity, { onPress: this.showDatePicker },
React.createElement(View, { style: {
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38
} },
React.createElement(Text, null, this.state.timeString))),
this.showTimePickerIOS()));
}
showTimePickerIOS() {
if (Platform.OS === 'ios') {
if (this.state.showTimePicker) {
let time = Utils.extractTime(this.state.timeString);
console.log(time);
return (React.createElement(DatePickerIOS, { date: time, mode: 'time', onDateChange: this.onTimeChangeIOS }));
}
}
return undefined;
}
showTimePickerAndroid() {
return __awaiter(this, void 0, void 0, function* () {
if (Platform.OS === 'android') {
const now = new Date();
try {
const { action, hour, minute } = yield TimePickerAndroid.open({
hour: now.getHours(),
minute: now.getMinutes(),
is24Hour: true
});
if (action === TimePickerAndroid.timeSetAction) {
this.onTimeChange(hour, minute);
}
}
catch ({ code, message }) {
console.warn('Cannot open date picker', message);
}
}
});
}
showDatePicker() {
return __awaiter(this, void 0, void 0, function* () {
if (this.state.showTimePicker) {
this.setState({
showTimePicker: false
}, this.onPickerClose);
}
else {
this.setState({
showTimePicker: true
}, this.showTimePickerAndroid);
}
});
}
onPickerClose() {
if (this.props.element.validateForm(this.state.timeString)) {
console.log('TimeInput: valide');
}
else {
console.log('TimeInput: invalide');
}
}
onTimeChangeIOS(date) {
this.onTimeChange(date.getHours(), date.getMinutes());
}
onTimeChange(hour, minute) {
let timeString = Utils.composeTimeString(hour, minute);
console.log(timeString);
this.setState({
timeString: timeString,
showTimePicker: false,
}, this.updateStore);
}
updateStore() {
FormContext.getInstance().updateField(this.props.element.id, this.state.timeString, this.props.element.validateForm(this.state.timeString));
}
}

91
dist/View/Styles/DefaultStyle.json поставляемый
Просмотреть файл

@ -1,91 +0,0 @@
{
"card": {
"backgroundColor": "#FFF",
"borderWidth": 1,
"borderColor": "#EEE",
"borderRadius": 4,
"padding": 20,
"spacing": 10
},
"element": {
"separateLineColor": "#EEE",
"spacing": {
"none": 0,
"small": 2,
"default": 6,
"medium": 16,
"large": 24,
"extraLarge": 34,
"padding": 10
}
},
"textBlock": {
"fontFamily": {
"ios": "",
"android": ""
},
"fontSize": {
"small": 12,
"default": 13,
"medium": 16,
"large": 18,
"extraLarge": 20
},
"fontWeight": {
"lighter": "100",
"default": "normal",
"bolder": "bold"
},
"textColor": {
"default": "#2B2C33",
"dark": "#000",
"light": "#FFF",
"accent": "#1686D9",
"good": "#4CAF50",
"warning": "#F0C01E",
"attention": "#F44336"
},
"subtleTextColor": {
"default": "#8A8D91",
"dark": "#000",
"light": "#FFF",
"accent": "rgba(22, 134, 217, 0.5)",
"good": "rgba(76, 175, 80, 0.8)",
"warning": "rgba(240, 192, 30, 0.8)",
"attention": "rgba(244, 67, 54, 0.8)"
}
},
"image": {
"imageSet": {
"direction": "row"
},
"imageSize": {
"small": 25,
"medium": 50,
"large": 100
}
},
"container": {
"backgroundColor": "#F5F5F5"
},
"fact": {
"titleColor": "#8A8D91",
"valueColor": "#000",
"spacing": 5
},
"action": {
"actionSet": {
"direction": "row",
"spacing": 10
},
"button": {
"borderRadius": 4,
"backgroundColor": "#277BDF",
"spacing": 10,
"paddingVertical": 10,
"paddingHorizontal": 10,
"textColor": "#FFF",
"fontSize": 13
}
}
}

128
dist/View/Styles/StyleManager.js поставляемый
Просмотреть файл

@ -1,128 +0,0 @@
import merge from 'lodash/merge';
import { Platform, } from 'react-native';
import { ContentElementType } from '../../Schema/Base/ContentElement';
import { FlexDirection, FlexWrap, FontSize, FontWeight, Spacing, TextColor, } from '../../Shared/Enums';
import { Utils } from '../../Shared/Utils';
const defaultStyle = require('./DefaultStyle.json');
export class StyleManager {
constructor(style = {}) {
this.style = style;
}
static getInstance() {
if (StyleManager.sharedInstance === undefined) {
StyleManager.sharedInstance = new StyleManager(defaultStyle);
}
return StyleManager.sharedInstance;
}
addStyle(overrideStyle) {
return merge(this.style, overrideStyle);
}
getStyle() {
return this.style;
}
getFontFamily() {
return Platform.OS === 'ios' ?
this.style.textBlock.fontFamily.ios :
this.style.textBlock.fontFamily.android;
}
getImageSetFlexDirectionValue() {
return this.getFlexDirectionValue(this.style.image.imageSet.direction);
}
getActionSetFlexDirectionValue() {
return this.getFlexDirectionValue(this.style.action.actionSet.direction);
}
isHorizontalImageSet() {
return this.isHorizontalSet(this.style.image.imageSet.direction);
}
isHorizontalActionSet() {
return this.isHorizontalSet(this.style.action.actionSet.direction);
}
getImageSize(size) {
return this.style.image.imageSize[size] || this.style.image.imageSize.medium;
}
getFontSize(size) {
return this.style.textBlock.fontSize[size] || this.style.textBlock.fontSize[FontSize.Default];
}
getFontWeight(weight) {
return (this.style.textBlock.fontWeight[weight] || this.style.textBlock.fontWeight[FontWeight.Default]);
}
getColor(colorName) {
return this.style.textBlock.textColor[colorName] || this.style.textBlock.textColor[TextColor.Default];
}
getSubtleColor(colorName) {
return this.style.textBlock.subtleTextColor[colorName] || this.style.textBlock.subtleTextColor[TextColor.Default];
}
getWrapStyle(wrap) {
return (wrap ? FlexWrap.Wrap : FlexWrap.NoWrap);
}
isHorizontalCardElement(type) {
return type === ContentElementType.Column ||
(type === ContentElementType.Image && this.isHorizontalImageSet());
}
getCardElementMargin(spacing) {
let margin = 0;
if (spacing.toLowerCase() !== Spacing.Padding.toLowerCase()) {
margin = Utils.isValidValue(this.style.element.spacing[spacing]) ?
this.style.element.spacing[spacing] :
this.style.element.spacing[Spacing.Default];
}
return margin;
}
getCardElementSpacingStyle(spacing, index, isHorizontalLayout) {
if (spacing === Spacing.Padding) {
return {
padding: this.style.element.spacing.padding
};
}
else {
let margin = 0;
if (index > 0) {
margin = this.getCardElementMargin(spacing);
}
if (isHorizontalLayout) {
return {
marginLeft: margin
};
}
else {
return {
marginTop: margin
};
}
}
}
getActionButtonSpacingStyle(index) {
if (index > 0) {
if (this.isHorizontalActionSet()) {
return {
marginLeft: this.style.action.button.spacing,
};
}
else {
return {
marginTop: this.style.action.button.spacing,
};
}
}
return;
}
getFlexDirectionValue(direction) {
let directionStyle;
switch (direction.toLowerCase()) {
case FlexDirection.Row:
default:
directionStyle = FlexDirection.Row;
break;
case FlexDirection.Column:
directionStyle = FlexDirection.Column;
break;
}
return directionStyle;
}
isHorizontalSet(direction) {
if (direction.toLowerCase() === FlexDirection.Column.toLowerCase()) {
return false;
}
return true;
}
}

27
dist/Views/Actions/OpenUrlAction.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,27 @@
import * as React from 'react';
import { Button } from '../../Components/Inputs/Button';
import { ActionContext } from '../../Contexts/ActionContext';
export class OpenUrlActionView extends React.Component {
constructor(props) {
super(props);
this.onPress = () => {
console.log('OpenUrlAction pressed');
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element);
if (callback) {
if (this.props.actionHooks) {
callback(...this.props.actionHooks);
}
else {
callback();
}
}
};
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Button, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, title: this.props.element.title, onPress: this.onPress }));
}
}

27
dist/Views/Actions/ShowCardAction.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,27 @@
import * as React from 'react';
import { Button } from '../../Components/Inputs/Button';
import { ActionContext } from '../../Contexts/ActionContext';
export class ShowCardActionView extends React.Component {
constructor(props) {
super(props);
this.onPress = () => {
console.log('ShowCardAction pressed');
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element);
if (callback) {
if (this.props.actionHooks) {
callback(...this.props.actionHooks);
}
else {
callback();
}
}
};
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Button, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, title: this.props.element.title, onPress: this.onPress }));
}
}

27
dist/Views/Actions/SubmitAction.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,27 @@
import * as React from 'react';
import { Button } from '../../Components/Inputs/Button';
import { ActionContext } from '../../Contexts/ActionContext';
export class SubmitActionView extends React.Component {
constructor(props) {
super(props);
this.onPress = () => {
console.log('SubmitAction pressed');
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element);
if (callback) {
if (this.props.actionHooks) {
callback(...this.props.actionHooks);
}
else {
callback();
}
}
};
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Button, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, title: this.props.element.title, onPress: this.onPress }));
}
}

58
dist/Views/CardElements/Image.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,58 @@
import * as React from 'react';
import { ImageBlock } from '../../Components/Basic/ImageBlock';
import { ActionContext } from '../../Contexts/ActionContext';
import { HostConfigManager } from '../../Styles/HostConfig';
import { StyleManager } from '../../Styles/StyleManager';
export class ImageView extends React.Component {
constructor(props) {
super(props);
this.getBorderRadius = () => {
const { element } = this.props;
if (element && element.isValid() && element.style === 'person') {
return {
borderRadius: this.state.width / 2,
};
}
return {};
};
this.onImageSize = (width, height) => {
this.setState({
width: width,
height: height
}, () => {
console.log(`ImageView onImageSize width: ${width} height: ${height}`);
const { element } = this.props;
if (element && element.isValid()) {
if (this.props.onImageSize) {
this.props.onImageSize(width, height, element.url);
}
}
});
};
this.onPress = () => {
console.log('ImageView pressed');
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element.selectAction);
if (callback) {
callback();
}
};
const { element } = this.props;
if (element && element.isValid()) {
this.styleConfig = StyleManager.getInstance().getStyle(element);
if (this.props.size) {
this.styleConfig.imgSize = HostConfigManager.getInstance().getImgSize(this.props.size);
}
this.state = {
width: 0,
height: 0,
};
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(ImageBlock, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, relativeWidth: false, url: element.url, alt: element.altText, flexDirection: 'row', alignSelf: this.styleConfig.alignSelf, alignItems: this.styleConfig.alignSelf, alignContent: 'center', justifyContent: 'center', width: this.styleConfig.imgSize, vSpace: this.styleConfig.spacing || this.props.vSpace, hSpace: this.props.hSpace, containerWidth: this.props.containerWidth, containerHeight: this.props.containerHeight, maxWidth: this.props.maxWidth, maxHeight: this.props.maxHeight, imgStyle: this.getBorderRadius(), onPress: element.selectAction ? this.onPress : undefined, onImageSize: this.onImageSize }));
}
}

32
dist/Views/CardElements/TextBlock.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,32 @@
import * as React from 'react';
import { TextBlock } from '../../Components/Basic/TextBlock';
import { StyleManager } from '../../Styles/StyleManager';
export class TextBlockView extends React.Component {
constructor(props) {
super(props);
const { element } = this.props;
if (element && element.isValid()) {
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(TextBlock, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, width: 'stretch', boxStyle: [
{
backgroundColor: 'transparent'
}
], textStyle: [
{
backgroundColor: 'transparent',
fontSize: this.styleConfig.fontSize,
fontWeight: this.styleConfig.fontWeight,
color: this.styleConfig.color,
textAlign: this.styleConfig.textAlign,
flexWrap: this.styleConfig.wrap,
}
], horizontalAlign: this.styleConfig.inboxTextAlign, spacing: this.styleConfig.spacing, numberOfLines: element.maxLines }, element.text));
}
}

Просмотреть файл

@ -1,12 +1,13 @@
import React from 'react'; import React from 'react';
import { View, } from 'react-native'; import { View, } from 'react-native';
import { ActionContext } from '../../Context/ActionContext'; import { ImageBackground } from '../../Components/Basic/ImageBackground';
import { Column } from '../../Components/Containers/Column';
import { Row } from '../../Components/Containers/Row';
import { ActionContext } from '../../Contexts/ActionContext';
import { ActionType } from '../../Schema/Base/ActionElement'; import { ActionType } from '../../Schema/Base/ActionElement';
import { DecCardElementView } from '../Basic/DecCardElementView'; import { ActionFactory } from '../Factories/ActionFactory';
import { ImageBackground } from '../Basic/ImageBackground'; import { ContentFactory } from '../Factories/ContentFactory';
import { ActionElementView } from '../Factories/ActionElementView'; export class AdaptiveCardView extends React.Component {
import { StyleManager } from '../Styles/StyleManager';
export class CardView extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.showSubCard = (args) => { this.showSubCard = (args) => {
@ -32,7 +33,6 @@ export class CardView extends React.Component {
name: 'showSubCard', name: 'showSubCard',
actionType: ActionType.ShowCard actionType: ActionType.ShowCard
}); });
this.styleConfig = StyleManager.getInstance().getStyle();
} }
render() { render() {
if (!this.props.element.isValid()) { if (!this.props.element.isValid()) {
@ -40,24 +40,27 @@ export class CardView extends React.Component {
} }
const cardStyle = Object.assign({ const cardStyle = Object.assign({
flex: 1, flex: 1,
backgroundColor: this.styleConfig.card.backgroundColor, backgroundColor: 'white',
borderWidth: this.styleConfig.card.borderWidth, borderWidth: 1,
borderColor: this.styleConfig.card.borderColor, borderColor: '#777777',
borderRadius: this.styleConfig.card.borderRadius, borderRadius: 4,
}, this.props.style); }, this.props.style);
if (this.props.element.backgroundImage) { if (this.props.element.backgroundImage) {
return (React.createElement(ImageBackground, { containerStyle: cardStyle, imageStyle: { return (React.createElement(ImageBackground, { containerStyle: cardStyle, imageStyle: {
borderRadius: this.styleConfig.card.borderRadius, borderRadius: 4,
}, source: { uri: this.props.element.backgroundImage } }, }, source: { uri: this.props.element.backgroundImage } },
React.createElement(View, { style: { flex: 1, padding: this.styleConfig.card.padding } }, React.createElement(View, { style: { flex: 1, padding: 10 } },
this.renderBody(), this.renderBody(),
this.renderActions(), this.renderActions(),
this.renderSubCard()))); this.renderSubCard())));
} }
else { else {
return (React.createElement(View, { style: [cardStyle, { return (React.createElement(View, { style: [
padding: this.styleConfig.card.padding, cardStyle,
}] }, {
padding: 20,
}
] },
this.renderBody(), this.renderBody(),
this.renderActions(), this.renderActions(),
this.renderSubCard())); this.renderSubCard()));
@ -67,23 +70,18 @@ export class CardView extends React.Component {
if (!this.props.element.hasBody()) { if (!this.props.element.hasBody()) {
return null; return null;
} }
return (React.createElement(View, { style: { flex: 1 } }, this.props.element.body.map((cardElement, index) => React.createElement(DecCardElementView, { key: 'body' + index, index: index, element: cardElement })))); return (React.createElement(Column, { vIndex: 0, hIndex: 0, width: 'stretch' }, this.props.element.body.map((contentElement, index) => ContentFactory.createView(contentElement, index))));
} }
renderActions() { renderActions() {
if (!this.props.element.hasActions()) { if (!this.props.element.hasActions()) {
return null; return null;
} }
return (React.createElement(View, { style: { return (React.createElement(Row, { vIndex: 1, hIndex: 0, spacing: 10 }, this.props.element.actions.map((action, index) => ActionFactory.createAction(action, index, this.actionContext))));
flex: 1,
flexDirection: StyleManager.getInstance().getActionSetFlexDirectionValue(),
alignItems: 'stretch',
marginTop: this.styleConfig.action.actionSet.spacing,
} }, this.props.element.actions.map((action, index) => React.createElement(ActionElementView, { key: index, element: action, index: index, actionContext: this.actionContext }))));
} }
renderSubCard() { renderSubCard() {
if (this.state.subCard) { if (this.state.subCard) {
return (React.createElement(CardView, { element: this.state.subCard, style: { return (React.createElement(AdaptiveCardView, { vIndex: 2, hIndex: 0, element: this.state.subCard, style: {
marginTop: this.styleConfig.card.spacing, marginTop: 10,
} })); } }));
} }
return undefined; return undefined;

38
dist/Views/Containers/Column.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,38 @@
import * as React from 'react';
import { Column } from '../../Components/Containers/Column';
import { ActionContext } from '../../Contexts/ActionContext';
import { StyleManager } from '../../Styles/StyleManager';
import { ContentFactory } from '../Factories/ContentFactory';
export class ColumnView extends React.Component {
constructor(props) {
super(props);
this.renderContents = () => {
const { element } = this.props;
if (!element || !element.isValid()) {
return undefined;
}
if (element.hasItems()) {
return element.items.map((content, index) => ContentFactory.createView(content, index));
}
return undefined;
};
this.onPress = () => {
console.log('ColumnView onPress');
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element.selectAction);
if (callback) {
callback();
}
};
const { element } = this.props;
if (element && element.isValid()) {
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Column, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, width: this.styleConfig.columnWidth, onPress: element.selectAction ? this.onPress : undefined, spacing: this.styleConfig.spacing }, this.renderContents()));
}
}

29
dist/Views/Containers/ColumnSet.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,29 @@
import * as React from 'react';
import { Row } from '../../Components/Containers/Row';
import { StyleManager } from '../../Styles/StyleManager';
import { ColumnView } from './Column';
export class ColumnSetView extends React.Component {
constructor(props) {
super(props);
this.renderColumns = () => {
const { element } = this.props;
if (!element || !element.isValid()) {
return undefined;
}
if (element.hasColumns()) {
return element.columns.map((column, index) => (React.createElement(ColumnView, { key: index, vIndex: 0, hIndex: index, element: column })));
}
};
const { element } = this.props;
if (element && element.isValid()) {
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Row, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, spacing: this.styleConfig.spacing }, this.renderColumns()));
}
}

38
dist/Views/Containers/Container.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,38 @@
import * as React from 'react';
import { Column } from '../../Components/Containers/Column';
import { ActionContext } from '../../Contexts/ActionContext';
import { StyleManager } from '../../Styles/StyleManager';
import { ContentFactory } from '../Factories/ContentFactory';
export class ContainerView extends React.Component {
constructor(props) {
super(props);
this.renderContents = () => {
const { element } = this.props;
if (!element || !element.isValid()) {
return undefined;
}
if (element.hasItems()) {
return element.items.map((content, index) => ContentFactory.createView(content, index));
}
return undefined;
};
this.onPress = () => {
console.log('ContainerView onPress');
let callback = ActionContext.getGlobalInstance().getActionEventHandler(this.props.element.selectAction);
if (callback) {
callback();
}
};
const { element } = this.props;
if (element && element.isValid()) {
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Column, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, width: 'stretch', onPress: element.selectAction ? this.onPress : undefined, spacing: this.styleConfig.spacing }, this.renderContents()));
}
}

21
dist/Views/Containers/Fact.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,21 @@
import * as React from 'react';
import { TextBlock } from '../../Components/Basic/TextBlock';
import { Row } from '../../Components/Containers/Row';
export class FactView extends React.Component {
constructor(props) {
super(props);
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Row, { vIndex: this.props.vIndex, hIndex: this.props.hIndex },
React.createElement(TextBlock, { vIndex: 0, hIndex: 0, width: 'auto', textStyle: {
color: '#333333',
} }, element.title),
React.createElement(TextBlock, { vIndex: 0, hIndex: 1, width: 'auto', textStyle: {
color: '#777777',
} }, element.value)));
}
}

29
dist/Views/Containers/FactSet.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,29 @@
import * as React from 'react';
import { Column } from '../../Components/Containers/Column';
import { StyleManager } from '../../Styles/StyleManager';
import { FactView } from './Fact';
export class FactSetView extends React.Component {
constructor(props) {
super(props);
this.renderFacts = () => {
const { element } = this.props;
if (!element || !element.isValue()) {
return undefined;
}
if (element.facts) {
return element.facts.map((fact, index) => (React.createElement(FactView, { key: index, vIndex: 0, hIndex: index, element: fact })));
}
};
const { element } = this.props;
if (element && element.isValid()) {
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Column, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, width: 'stretch', spacing: this.styleConfig.spacing }, this.renderFacts()));
}
}

49
dist/Views/Containers/ImageSet.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,49 @@
import * as React from 'react';
import { ScrollView } from 'react-native';
import { Row } from '../../Components/Containers/Row';
import { StyleManager } from '../../Styles/StyleManager';
import { ImageView } from '../CardElements/Image';
export class ImageSetView extends React.Component {
constructor(props) {
super(props);
this.renderImages = () => {
const { element } = this.props;
if (!element || !element.isValid()) {
return undefined;
}
return element.images.map((img, index) => (React.createElement(ImageView, { key: index, vIndex: 1, hIndex: index, element: img, size: element.imageSize, maxWidth: this.state.maxWidth, maxHeight: this.state.maxHeight, onImageSize: this.onImageSize, hSpace: 10 })));
};
this.onImageSize = (width, height, url) => {
console.log(`ImageSet adjust height: ${height}`);
let maxWidth = width;
let maxHeight = height;
let ratio = width > 0 ? height / width : height;
if (maxWidth > this.props.containerWidth) {
maxWidth = this.props.containerWidth;
}
maxHeight = maxWidth * ratio;
if (this.state.maxHeight !== undefined && this.state.maxHeight !== 0 && maxHeight > this.state.maxHeight) {
maxHeight = this.state.maxHeight;
}
this.setState({
maxHeight: maxHeight
});
};
const { element } = this.props;
if (element && element.isValid()) {
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
this.state = {
maxWidth: undefined,
maxHeight: undefined,
};
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(ScrollView, { flex: 1, horizontal: true, minHeight: this.state.maxHeight },
React.createElement(Row, { vIndex: 0, hIndex: 0, spacing: this.styleConfig.spacing, wrap: 'nowrap' }, this.renderImages())));
}
}

28
dist/Views/Factories/ActionFactory.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,28 @@
import React from 'react';
import { ActionType } from '../../Schema/Base/ActionElement';
import { OpenUrlActionView } from '../Actions/OpenUrlAction';
import { ShowCardActionView } from '../Actions/ShowCardAction';
import { SubmitActionView } from '../Actions/SubmitAction';
export class ActionFactory {
static createAction(element, index, context) {
if (element) {
switch (element.type) {
case ActionType.OpenUrl:
return (React.createElement(OpenUrlActionView, { key: 'OpenUrlActionView' + index, vIndex: 0, hIndex: index, element: element, actionHooks: this.getHooks(context, element.getActionType()) }));
case ActionType.ShowCard:
return (React.createElement(ShowCardActionView, { key: 'ShowCardActionView' + index, vIndex: 0, hIndex: index, element: element, actionHooks: this.getHooks(context, element.getActionType()) }));
case ActionType.Submit:
return (React.createElement(SubmitActionView, { key: 'SubmitActionView' + index, vIndex: 0, hIndex: index, element: element, actionHooks: this.getHooks(context, element.getActionType()) }));
default:
return null;
}
}
return null;
}
static getHooks(context, actionType) {
if (context) {
return context.getHooks(actionType);
}
return undefined;
}
}

58
dist/Views/Factories/ContentFactory.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,58 @@
import * as React from 'react';
import { SeparateLine } from '../../Components/Basic/SeparateLine';
import { ContentElementType } from '../../Schema/Base/ContentElement';
import { HostConfigManager } from '../../Styles/HostConfig';
import { ImageView } from '../CardElements/Image';
import { TextBlockView } from '../CardElements/TextBlock';
import { ColumnSetView } from '../Containers/ColumnSet';
import { ContainerView } from '../Containers/Container';
import { FactSetView } from '../Containers/FactSet';
import { ImageSetView } from '../Containers/ImageSet';
import { DateInputView } from '../Inputs/DateInput';
import { NumberInputView } from '../Inputs/NumberInput';
import { TextInputView } from '../Inputs/TextInput';
import { TimeInputView } from '../Inputs/TimeInput';
export class ContentFactory {
static createView(element, index) {
if (element) {
let elementView = ContentFactory.createElement(element, index);
if (index > 0 && element.separator) {
return [
React.createElement(SeparateLine, { key: 'SeparateLine' + index, color: '#777777', margin: HostConfigManager.getInstance().getSpacing(element.spacing) }),
elementView
];
}
return [elementView];
}
return null;
}
static createElement(element, index) {
if (element) {
switch (element.type) {
case ContentElementType.TextInput:
return (React.createElement(TextInputView, { key: 'TextInputView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.NumberInput:
return (React.createElement(NumberInputView, { key: 'NumberInputView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.DateInput:
return (React.createElement(DateInputView, { key: 'DateInputView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.TimeInput:
return (React.createElement(TimeInputView, { key: 'TimeInputView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.Container:
return (React.createElement(ContainerView, { key: 'ContainerView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.ColumnSet:
return (React.createElement(ColumnSetView, { key: 'ColumnSetView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.TextBlock:
return (React.createElement(TextBlockView, { key: 'TextBlockView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.Image:
return (React.createElement(ImageView, { key: 'ImageView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.ImageSet:
return (React.createElement(ImageSetView, { key: 'ImageSetView' + index, element: element, vIndex: index, hIndex: 0 }));
case ContentElementType.FactSet:
return (React.createElement(FactSetView, { key: 'FactSetView' + index, element: element, vIndex: index, hIndex: 0 }));
default:
return null;
}
}
return null;
}
}

33
dist/Views/Inputs/DateInput.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,33 @@
import * as React from 'react';
import { Row } from '../../Components/Containers/Row';
import { DateInput } from '../../Components/Inputs/DateInput';
import { FormContext } from '../../Contexts/FormContext';
import { StyleManager } from '../../Styles/StyleManager';
export class DateInputView extends React.Component {
constructor(props) {
super(props);
this.onValueChange = (value) => {
this.setState({
value: value
}, this.updateStore);
};
const { element } = this.props;
if (element && element.isValid()) {
this.state = {
value: this.props.element.value,
};
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Row, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, spacing: this.styleConfig.spacing },
React.createElement(DateInput, { vIndex: 0, hIndex: 0, value: this.state.value, onValueChange: this.onValueChange, validateInput: element.validateForm })));
}
updateStore() {
FormContext.getInstance().updateField(this.props.element.id, this.state.value, this.props.element.validateForm(this.state.value));
}
}

43
dist/Views/Inputs/NumberInput.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,43 @@
import * as React from 'react';
import { Row } from '../../Components/Containers/Row';
import { NumberInput } from '../../Components/Inputs/NumberInput';
import { FormContext } from '../../Contexts/FormContext';
import { Utils } from '../../Shared/Utils';
import { StyleManager } from '../../Styles/StyleManager';
export class NumberInputView extends React.Component {
constructor(props) {
super(props);
this.onBlur = () => {
console.log('NumberInputView onBlur');
};
this.onValueChange = (value) => {
this.setState({
value: value
}, this.updateStore);
};
const { element } = this.props;
if (element && element.isValid()) {
let defaultValue = this.props.element.value;
if (defaultValue === undefined) {
defaultValue = '';
}
if (Utils.isNumber(this.props.element.value.toString())) {
this.state = {
value: this.props.element.value.toString(),
};
}
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Row, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, spacing: this.styleConfig.spacing },
React.createElement(NumberInput, { vIndex: 0, hIndex: 0, placeholder: element.placeholder, value: this.state.value, onValueChange: this.onValueChange, onBlur: this.onBlur, validateInput: element.validateForm })));
}
updateStore() {
FormContext.getInstance().updateField(this.props.element.id, this.state.value, this.props.element.validateForm(this.state.value));
}
}

36
dist/Views/Inputs/TextInput.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,36 @@
import * as React from 'react';
import { Row } from '../../Components/Containers/Row';
import { InputBox } from '../../Components/Inputs/InputBox';
import { FormContext } from '../../Contexts/FormContext';
import { StyleManager } from '../../Styles/StyleManager';
export class TextInputView extends React.Component {
constructor(props) {
super(props);
this.onBlur = () => {
console.log('TextInputView onBlur');
};
this.onValueChange = (value) => {
this.setState({
value: value
}, this.updateStore);
};
const { element } = this.props;
if (element && element.isValid()) {
this.state = {
value: this.props.element.value,
};
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Row, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, spacing: this.styleConfig.spacing },
React.createElement(InputBox, { vIndex: 0, hIndex: 0, placeholder: element.placeholder, value: this.state.value, onValueChange: this.onValueChange, onBlur: this.onBlur })));
}
updateStore() {
FormContext.getInstance().updateField(this.props.element.id, this.state.value, this.props.element.validateForm(this.state.value));
}
}

33
dist/Views/Inputs/TimeInput.js поставляемый Normal file
Просмотреть файл

@ -0,0 +1,33 @@
import * as React from 'react';
import { Row } from '../../Components/Containers/Row';
import { TimeInput } from '../../Components/Inputs/TimeInput';
import { FormContext } from '../../Contexts/FormContext';
import { StyleManager } from '../../Styles/StyleManager';
export class TimeInputView extends React.Component {
constructor(props) {
super(props);
this.onValueChange = (value) => {
this.setState({
value: value
}, this.updateStore);
};
const { element } = this.props;
if (element && element.isValid()) {
this.state = {
value: this.props.element.value,
};
this.styleConfig = StyleManager.getInstance().getStyle(element);
}
}
render() {
const { element } = this.props;
if (!element || !element.isValid()) {
return null;
}
return (React.createElement(Row, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, spacing: this.styleConfig.spacing },
React.createElement(TimeInput, { vIndex: 0, hIndex: 0, value: this.state.value, onValueChange: this.onValueChange, validateInput: element.validateForm })));
}
updateStore() {
FormContext.getInstance().updateField(this.props.element.id, this.state.value, this.props.element.validateForm(this.state.value));
}
}

Просмотреть файл

@ -1,10 +1,10 @@
import React from 'react'; import React from 'react';
import { Linking, View, } from 'react-native'; import { Linking, View, } from 'react-native';
import { ActionContext } from '../Context/ActionContext'; import { ActionContext } from '../Contexts/ActionContext';
import { FormContext } from '../Context/FormContext'; import { FormContext } from '../Contexts/FormContext';
import { ActionType } from '../Schema/Base/ActionElement'; import { ActionType } from '../Schema/Base/ActionElement';
import { CardElement } from '../Schema/Cards/Card'; import { CardElement } from '../Schema/Cards/Card';
import { CardView } from './Cards/CardView'; import { AdaptiveCardView } from './Cards/AdaptiveCard';
export class CardRootView extends React.PureComponent { export class CardRootView extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
@ -65,6 +65,6 @@ export class CardRootView extends React.PureComponent {
} }
render() { render() {
return (React.createElement(View, { style: { flex: 1 } }, return (React.createElement(View, { style: { flex: 1 } },
React.createElement(CardView, { element: this.state.rootCard }))); React.createElement(AdaptiveCardView, { vIndex: 0, hIndex: 0, element: this.state.rootCard })));
} }
} }

Просмотреть файл

2
dist/index.js поставляемый
Просмотреть файл

@ -1,2 +1,2 @@
import { CardRootView } from './View/CardRootView'; import { CardRootView } from './Views/Root';
export default CardRootView; export default CardRootView;

Просмотреть файл

Просмотреть файл

@ -0,0 +1,127 @@
import * as React from 'react';
import { TouchableOpacity, View } from 'react-native';
export class FlexBox extends React.Component {
constructor(props) {
super(props);
this.renderChildren = () => {
if (this.props.children) {
return React.Children.map(this.props.children, (child, index) => {
if (child) {
if (typeof child !== 'string' && typeof child !== 'number') {
if (this.props.width === 'auto') {
return React.cloneElement(child, {
containerWidth: this.props.containerWidth,
containerHeight: this.props.containerHeight
});
}
else {
return React.cloneElement(child, {
containerWidth: this.state.width,
containerHeight: this.state.height
});
}
}
}
});
}
return undefined;
};
this.onLayoutChange = (event) => {
let width = event.nativeEvent.layout.width;
let height = event.nativeEvent.layout.height;
this.setState({
width: width,
height: height
}, () => {
console.log(`FlexBox: width: ${width} height: ${height}`);
if (this.props.onLayoutChange) {
this.props.onLayoutChange(width, height);
}
});
};
this.getFlexStyle = () => {
if (this.props.flex) {
return {
flex: this.props.flex
};
}
return {};
};
this.getChildrenFlexStyle = () => {
let result = {
flexDirection: this.props.flexDirection,
alignItems: this.props.wrap === 'wrap' ? 'flex-start' : this.props.alignItems,
justifyContent: this.props.justifyContent,
height: this.props.height,
flexWrap: this.props.wrap,
};
return result;
};
this.getSizeStyle = () => {
if (this.props.width === 'auto') {
return {
flex: 0
};
}
if (this.props.width === 'stretch') {
return {
flex: 1
};
}
if (this.props.relativeWidth && typeof this.props.width === 'number') {
return {
flex: this.props.width
};
}
return {
width: this.props.width
};
};
this.getVerticalMarginStyle = () => {
if (this.props.vIndex > 0) {
return {
marginTop: this.props.vSpace,
};
}
return {};
};
this.getHorizontalMarginStyle = () => {
if (this.props.hIndex > 0) {
return {
marginLeft: this.props.hSpace,
};
}
return {};
};
this.state = {
width: 0,
height: 0,
};
}
render() {
if (this.props.onPress) {
return this.renderTouchableBox();
}
return this.renderBox();
}
renderBox() {
return (React.createElement(View, { style: [
this.getChildrenFlexStyle(),
this.getFlexStyle(),
this.getSizeStyle(),
this.getVerticalMarginStyle(),
this.getHorizontalMarginStyle(),
this.props.style,
], onLayout: this.onLayoutChange }, this.renderChildren()));
}
renderTouchableBox() {
return (React.createElement(TouchableOpacity, { style: [
this.getChildrenFlexStyle(),
this.getFlexStyle(),
this.getSizeStyle(),
this.getVerticalMarginStyle(),
this.getHorizontalMarginStyle(),
this.props.style,
], onLayout: this.onLayoutChange, onPress: this.props.onPress }, this.renderChildren()));
}
}

Просмотреть файл

@ -0,0 +1,156 @@
import * as React from 'react';
import { Image, Text, View } from 'react-native';
import { FlexBox } from './FlexBox';
export class ImageBlock extends React.Component {
constructor(props) {
super(props);
this.renderPlaceholder = () => {
if (!this.state.loaded) {
return (React.createElement(View, { style: [
{
alignItems: 'center',
justifyContent: 'center'
}
] },
React.createElement(Text, { style: {
fontSize: 32,
color: 'rgba(0, 0, 0, 0.5)',
textAlign: 'center'
} }, '\uE601')));
}
return undefined;
};
this.onLayoutChange = (width, height) => {
Image.getSize(this.props.url, this.onImageSize, this.onImageSizeError);
};
this.onImageSizeUpdate = (event) => {
let width = event.nativeEvent.layout.width;
let height = event.nativeEvent.layout.height;
console.log(`Image at url:${this.props.url} size updated. Width: ${width}, height: ${height}`);
if (this.props.onImageSize) {
this.props.onImageSize(width, height);
}
};
this.onImageSize = (width, height) => {
console.log(`Image at url:${this.props.url} get size succeed. Width: ${width}, height: ${height}`);
let ratio = width > 0 ? height / width : height;
if (this.props.width === 'auto') {
this.applyAutoSize(width, ratio);
}
else if (this.props.width === 'stretch') {
this.applyStretchSize(width, height, ratio);
}
else {
this.applyFixSize(ratio);
}
};
this.onImageSizeError = () => {
console.log(`Image at url:${this.props.url} get size failed.`);
this.setState({
loaded: false
});
};
this.onImageLoad = () => {
console.log(`Image at url:${this.props.url} load succeed.`);
this.setState({
loaded: true
});
Image.getSize(this.props.url, this.onImageSize, this.onImageSizeError);
};
this.onImageError = () => {
console.log(`Image at url:${this.props.url} load failed.`);
this.setState({
loaded: false
});
};
this.state = {
loaded: true,
width: undefined,
height: undefined,
ratio: 1,
};
}
render() {
return (React.createElement(FlexBox, Object.assign({}, this.props, { style: [
this.props.boxStyle,
{
alignSelf: this.props.alignSelf,
}
], onLayoutChange: this.onLayoutChange, onPress: this.props.onPress, width: 'auto' }),
this.renderPlaceholder(),
React.createElement(Image, { accessible: !!this.props.alt, accessibilityLabel: this.props.alt, source: { uri: this.props.url }, style: [
this.getSize(),
this.props.imgStyle
], onLoad: this.onImageLoad, onError: this.onImageError, onLayout: this.onImageSizeUpdate })));
}
applyFixSize(ratio) {
if (typeof this.props.width === 'number') {
this.setState({
width: this.props.width,
height: this.props.width * ratio,
ratio: ratio,
});
}
}
applyStretchSize(width, height, ratio) {
if (this.props.containerWidth) {
let finalWidth = this.props.containerWidth;
let finalHeight = finalWidth * ratio;
console.log(`Image at url:${this.props.url} get size succeed. Final width: ${finalWidth}, final height: ${finalHeight}`);
this.setState({
width: finalWidth,
height: finalHeight,
ratio: ratio
});
}
else {
this.setState({
width: width,
height: height,
ratio: ratio
});
}
}
applyAutoSize(width, ratio) {
let finalWidth = width;
if (finalWidth > this.props.containerWidth) {
finalWidth = this.props.containerWidth;
}
let finalHeight = finalWidth * ratio;
console.log(`Image at url:${this.props.url} get size succeed. Final width: ${finalWidth}, final height: ${finalHeight}`);
this.setState({
width: finalWidth,
height: finalHeight,
ratio: ratio
});
}
getSize() {
let finalWidth = this.state.width;
let finalHeight = this.state.height;
if (this.state.width && this.state.height) {
if (this.state.ratio <= 1) {
if (this.props.maxWidth && finalWidth > this.props.maxWidth) {
finalWidth = this.props.maxWidth;
}
finalHeight = finalWidth * this.state.ratio;
if (this.props.maxHeight && finalHeight > this.props.maxHeight) {
finalHeight = this.props.maxHeight;
finalWidth = this.state.ratio > 0 ? finalHeight / this.state.ratio : finalWidth;
}
}
else {
if (this.props.maxHeight && finalHeight > this.props.maxHeight) {
finalHeight = this.props.maxHeight;
}
finalWidth = this.state.ratio > 0 ? finalHeight / this.state.ratio : finalWidth;
if (this.props.maxWidth && finalWidth > this.props.maxWidth) {
finalWidth = this.props.maxWidth;
}
}
}
return {
width: finalWidth,
height: finalHeight,
};
}
}

Просмотреть файл

@ -0,0 +1,22 @@
import React from 'react';
import { PixelRatio, Platform, View, } from 'react-native';
export class SeparateLine extends React.PureComponent {
render() {
const { color, margin } = this.props;
const thickness = (Platform.OS === 'ios') ?
parseFloat((1 / PixelRatio.get()).toFixed(2)) :
1;
const style = {
height: thickness,
marginHorizontal: 0,
marginVertical: margin
};
return (React.createElement(View, Object.assign({}, this.props, { style: [
{
flex: 0,
backgroundColor: color,
},
style
] })));
}
}

Просмотреть файл

@ -0,0 +1,14 @@
import React from 'react';
import { Text, } from 'react-native';
import { FlexBox } from './FlexBox';
export class TextBlock extends React.PureComponent {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, flexDirection: 'row', relativeWidth: false, width: this.props.width, vSpace: this.props.spacing, alignSelf: 'stretch', alignItems: 'stretch', alignContent: 'stretch', justifyContent: this.props.horizontalAlign, style: this.props.boxStyle },
React.createElement(Text, { style: [
this.props.textStyle,
], numberOfLines: this.props.numberOfLines }, this.props.children)));
}
}

Просмотреть файл

@ -0,0 +1,10 @@
import * as React from 'react';
import { FlexBox } from '../Basic/FlexBox';
export class Column extends React.Component {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { flexDirection: 'column', relativeWidth: true, alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', justifyContent: 'space-between', width: this.props.width, vIndex: this.props.vIndex, hIndex: this.props.hIndex, style: this.props.style, vSpace: this.props.spacing, onPress: this.props.onPress }, this.props.children));
}
}

Просмотреть файл

@ -0,0 +1,10 @@
import * as React from 'react';
import { FlexBox } from '../Basic/FlexBox';
export class Row extends React.Component {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { flexDirection: 'row', relativeWidth: false, alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', wrap: this.props.wrap, justifyContent: 'space-between', width: this.props.width ? this.props.width : 'stretch', vIndex: this.props.vIndex, hIndex: this.props.hIndex, style: this.props.style, vSpace: this.props.spacing, onPress: this.props.onPress }, this.props.children));
}
}

Просмотреть файл

@ -0,0 +1,26 @@
import * as React from 'react';
import { FlexBox } from '../Basic/FlexBox';
import { TextBlock } from '../Basic/TextBlock';
export class Button extends React.Component {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, flexDirection: 'row', relativeWidth: false, flex: 1, alignSelf: 'stretch', alignItems: 'center', alignContent: 'center', justifyContent: 'center', width: 'stretch', hSpace: 10, style: [
{
paddingVertical: 10,
paddingHorizontal: 10,
borderRadius: 4,
backgroundColor: '#277BDF',
},
this.props.boxStyle
], onPress: this.props.onPress },
React.createElement(TextBlock, { vIndex: 0, hIndex: 0, width: 'stretch', horizontalAlign: 'center', textStyle: [
{
textAlign: 'center',
color: 'white',
},
this.props.textStyle,
], numberOfLines: 1 }, this.props.title)));
}
}

Просмотреть файл

@ -0,0 +1,107 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as React from 'react';
import { DatePickerAndroid, DatePickerIOS, Platform, Text, TouchableOpacity, View } from 'react-native';
import { Utils } from '../../Shared/Utils';
import { FlexBox } from '../Basic/FlexBox';
export class DateInput extends React.Component {
constructor(props) {
super(props);
this.renderBtn = () => {
if (!this.state.showDatePicker) {
return (React.createElement(TouchableOpacity, { style: { flex: 1 }, onPress: this.showDatePicker },
React.createElement(View, { style: {
flex: 1,
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38,
} },
React.createElement(Text, null, this.props.value))));
}
return undefined;
};
this.renderInlineDatePicker = () => {
if (Platform.OS === 'ios') {
if (this.state.showDatePicker) {
let date = Utils.extractDate(this.props.value);
console.log(date);
return (React.createElement(DatePickerIOS, { date: date, mode: 'date', onDateChange: this.onDateChange, style: { flex: 1 } }));
}
}
return undefined;
};
this.onPickerClose = () => {
if (this.props.validateInput) {
if (this.props.validateInput(this.props.value)) {
console.log('DateInput: valid');
}
else {
console.log('DateInput: invalid');
}
}
};
this.onDateChange = (date) => {
if (this.props.onValueChange) {
let timeString = Utils.getDateString(date);
console.log(timeString);
this.setState({
showDatePicker: false,
}, () => this.props.onValueChange(timeString));
}
};
this.showDatePickerAndroid = this.showDatePickerAndroid.bind(this);
this.showDatePicker = this.showDatePicker.bind(this);
this.state = {
showDatePicker: false,
};
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, relativeWidth: false, flexDirection: 'row', alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', justifyContent: 'space-between', width: 'stretch' },
this.renderBtn(),
this.renderInlineDatePicker()));
}
showDatePickerAndroid() {
return __awaiter(this, void 0, void 0, function* () {
if (Platform.OS === 'android') {
const today = new Date();
try {
const { action, year, month, day } = yield DatePickerAndroid.open({
date: today,
});
if (action === DatePickerAndroid.dateSetAction) {
let newDate = new Date(year, month, day);
this.onDateChange(newDate);
}
}
catch ({ code, message }) {
console.warn('Cannot open date picker', message);
}
}
});
}
showDatePicker() {
return __awaiter(this, void 0, void 0, function* () {
if (this.state.showDatePicker) {
this.setState({
showDatePicker: false
}, this.onPickerClose);
}
else {
this.setState({
showDatePicker: true
});
yield this.showDatePickerAndroid();
}
});
}
}

Просмотреть файл

@ -0,0 +1,24 @@
import * as React from 'react';
import { TextInput } from 'react-native';
import { FlexBox } from '../Basic/FlexBox';
export class InputBox extends React.Component {
constructor(props) {
super(props);
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, relativeWidth: false, flexDirection: 'row', alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', justifyContent: 'space-between', width: 'stretch' },
React.createElement(TextInput, { style: [
{
flex: 1,
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38,
},
this.props.style
], multiline: this.props.multiline, keyboardType: this.props.keyboardType, blurOnSubmit: true, placeholder: this.props.placeholder, value: this.props.value, returnKeyType: this.props.returnKeyType, underlineColorAndroid: 'transparent', importantForAccessibility: 'no-hide-descendants', onChangeText: this.props.onValueChange, onBlur: this.props.onBlur })));
}
}

Просмотреть файл

@ -0,0 +1,33 @@
import * as React from 'react';
import { Platform } from 'react-native';
import { Utils } from '../../Shared/Utils';
import { InputBox } from './InputBox';
export class NumberInput extends React.Component {
constructor(props) {
super(props);
this.onChangeText = (input) => {
if (this.props.onValueChange) {
if (Utils.isSymbol(input) || Utils.isNumber(input)) {
console.log('change text');
this.props.onValueChange(input);
}
}
};
this.onBlur = () => {
if (this.props.validateInput) {
if (this.props.validateInput(this.props.value)) {
console.log('NumberInput: valid');
}
else {
console.log('NumberInput: invalid');
}
}
if (this.props.onBlur) {
this.props.onBlur();
}
};
}
render() {
return (React.createElement(InputBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, multiline: false, keyboardType: Platform.OS === 'ios' ? 'numbers-and-punctuation' : 'numeric', placeholder: this.props.placeholder, value: this.props.value, returnKeyType: 'done', onValueChange: this.onChangeText, onBlur: this.onBlur }));
}
}

Просмотреть файл

@ -0,0 +1,112 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import * as React from 'react';
import { DatePickerIOS, Platform, Text, TimePickerAndroid, TouchableOpacity, View } from 'react-native';
import { Utils } from '../../Shared/Utils';
import { FlexBox } from '../Basic/FlexBox';
export class TimeInput extends React.Component {
constructor(props) {
super(props);
this.renderBtn = () => {
if (!this.state.showTimePicker) {
return (React.createElement(TouchableOpacity, { style: { flex: 1 }, onPress: this.showDatePicker },
React.createElement(View, { style: [
{
flex: 1,
borderColor: 'gray',
borderWidth: 1,
borderRadius: 4,
paddingHorizontal: 10,
paddingVertical: 6,
marginVertical: 6,
height: 38,
}
] },
React.createElement(Text, null, this.props.value))));
}
return undefined;
};
this.showTimePickerIOS = () => {
if (Platform.OS === 'ios') {
if (this.state.showTimePicker) {
let time = Utils.extractTime(this.props.value);
console.log(time);
return (React.createElement(DatePickerIOS, { date: time, mode: 'time', onDateChange: this.onTimeChangeIOS, style: { flex: 1 } }));
}
}
return undefined;
};
this.onPickerClose = () => {
if (this.props.validateInput) {
if (this.props.validateInput(this.props.value)) {
console.log('TimeInput: valid');
}
else {
console.log('TimeInput: invalid');
}
}
};
this.onTimeChangeIOS = (date) => {
this.onTimeChange(date.getHours(), date.getMinutes());
};
this.onTimeChange = (hour, minute) => {
if (this.props.onValueChange) {
let timeString = Utils.composeTimeString(hour, minute);
console.log(timeString);
this.setState({
showTimePicker: false,
}, () => this.props.onValueChange(timeString));
}
};
this.showTimePickerAndroid = this.showTimePickerAndroid.bind(this);
this.showDatePicker = this.showDatePicker.bind(this);
this.state = {
showTimePicker: false,
};
}
render() {
return (React.createElement(FlexBox, { vIndex: this.props.vIndex, hIndex: this.props.hIndex, relativeWidth: false, flexDirection: 'row', alignSelf: 'stretch', alignContent: 'flex-start', alignItems: 'stretch', justifyContent: 'space-between', width: 'stretch' },
this.renderBtn(),
this.showTimePickerIOS()));
}
showTimePickerAndroid() {
return __awaiter(this, void 0, void 0, function* () {
if (Platform.OS === 'android') {
const now = new Date();
try {
const { action, hour, minute } = yield TimePickerAndroid.open({
hour: now.getHours(),
minute: now.getMinutes(),
is24Hour: true
});
if (action === TimePickerAndroid.timeSetAction) {
this.onTimeChange(hour, minute);
}
}
catch ({ code, message }) {
console.warn('Cannot open date picker', message);
}
}
});
}
showDatePicker() {
return __awaiter(this, void 0, void 0, function* () {
if (this.state.showTimePicker) {
this.setState({
showTimePicker: false
}, this.onPickerClose);
}
else {
this.setState({
showTimePicker: true
}, this.showTimePickerAndroid);
}
});
}
}

Просмотреть файл

@ -50,7 +50,7 @@ export class ActionContext {
formValidate: false, formValidate: false,
target: target, target: target,
}; };
let hookFuncs = this.getExcuteFuncs(action.type, externalHooks); let hookFuncs = this.getExecuteFuncs(action.type, externalHooks);
args = hookFuncs.reduce((prev, current) => { args = hookFuncs.reduce((prev, current) => {
return current(prev); return current(prev);
}, args); }, args);
@ -75,7 +75,7 @@ export class ActionContext {
} }
return callback; return callback;
} }
getExcuteFuncs(actionType, externalHooks) { getExecuteFuncs(actionType, externalHooks) {
let hookFuncs = []; let hookFuncs = [];
if (this.hooks) { if (this.hooks) {
let hookArrays = this.hooks[actionType]; let hookArrays = this.hooks[actionType];

Просмотреть файл

@ -1,4 +1,4 @@
import { AbstractElement } from '../Base/AbstractElement'; import { AbstractElement } from './AbstractElement';
export var ActionType; export var ActionType;
(function (ActionType) { (function (ActionType) {
ActionType["OpenUrl"] = "Action.OpenUrl"; ActionType["OpenUrl"] = "Action.OpenUrl";
@ -27,6 +27,9 @@ export class ActionElement extends AbstractElement {
getData() { getData() {
return {}; return {};
} }
getStyleConfig() {
return {};
}
isAction() { isAction() {
return true; return true;
} }

Просмотреть файл

@ -1,6 +1,6 @@
import { Spacing } from '../../Shared/Enums'; import { Spacing } from '../../Shared/Enums';
import { Utils } from '../../Shared/Utils'; import { Utils } from '../../Shared/Utils';
import { AbstractElement } from '../Base/AbstractElement'; import { AbstractElement } from './AbstractElement';
export var ContentElementType; export var ContentElementType;
(function (ContentElementType) { (function (ContentElementType) {
ContentElementType["Column"] = "Column"; ContentElementType["Column"] = "Column";
@ -31,6 +31,11 @@ export class ContentElement extends AbstractElement {
getId() { getId() {
return this.id; return this.id;
} }
getStyleConfig() {
return {
spacing: this.spacing
};
}
isContent() { isContent() {
return true; return true;
} }

Просмотреть файл

@ -1,6 +1,6 @@
import { FormContext } from '../../Context/FormContext'; import { FormContext } from '../../Contexts/FormContext';
import { ContentElement } from '../Base/ContentElement';
import { ActionFactory } from '../Factories/ActionFactory'; import { ActionFactory } from '../Factories/ActionFactory';
import { ContentElement } from './ContentElement';
export var FormElementType; export var FormElementType;
(function (FormElementType) { (function (FormElementType) {
FormElementType["Column"] = "Column"; FormElementType["Column"] = "Column";

Просмотреть файл

@ -1,4 +1,4 @@
import { ContentElement } from '../Base/ContentElement'; import { ContentElement } from './ContentElement';
export var InputElementType; export var InputElementType;
(function (InputElementType) { (function (InputElementType) {
InputElementType["TextInput"] = "Input.Text"; InputElementType["TextInput"] = "Input.Text";

Просмотреть файл

@ -1,4 +1,4 @@
import { AbstractElement } from '../Base/AbstractElement'; import { AbstractElement } from './AbstractElement';
export var ValueElementType; export var ValueElementType;
(function (ValueElementType) { (function (ValueElementType) {
ValueElementType["Fact"] = "Fact"; ValueElementType["Fact"] = "Fact";
@ -18,4 +18,7 @@ export class ValueElement extends AbstractElement {
isValue() { isValue() {
return true; return true;
} }
getStyleConfig() {
return {};
}
} }

Просмотреть файл

@ -30,6 +30,14 @@ export class ImageElement extends FormElement {
getChildren() { getChildren() {
return []; return [];
} }
getStyleConfig() {
return {
horizontalAlignment: this.horizontalAlignment,
imgSize: this.size,
style: this.style,
spacing: this.spacing,
};
}
setSize(size) { setSize(size) {
this.size = Utils.getStringEnumValueOrDefault(ImageSize, size, ImageSize.Auto); this.size = Utils.getStringEnumValueOrDefault(ImageSize, size, ImageSize.Auto);
} }

Просмотреть файл

@ -16,6 +16,17 @@ export class TextBlockElement extends ContentElement {
this.wrap = json.wrap || false; this.wrap = json.wrap || false;
} }
} }
getStyleConfig() {
return {
color: this.color,
horizontalAlignment: this.horizontalAlignment,
isSubtle: this.isSubtle,
fontSize: this.size,
fontWeight: this.weight,
wrap: this.wrap,
spacing: this.spacing,
};
}
getTypeName() { getTypeName() {
return ContentElementType.TextBlock; return ContentElementType.TextBlock;
} }

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше