From b7d4d592cc84bd5b3cce84ac192d7fef1e7cd494 Mon Sep 17 00:00:00 2001 From: Mattermost Build Date: Tue, 19 Nov 2019 20:32:12 +0100 Subject: [PATCH] Automated cherry pick of #3571 (#3577) * Preview markdown table as 5x5 max * Make linter happy * Determine max columns from device width * Add snapshot test * Use Dimensions and update unit tests * Remove async --- .../__snapshots__/markdown_table.test.js.snap | 177 ++++++++++++++++++ .../markdown/markdown_table/markdown_table.js | 50 ++++- .../markdown_table/markdown_table.test.js | 55 ++++++ 3 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 app/components/markdown/markdown_table/__snapshots__/markdown_table.test.js.snap create mode 100644 app/components/markdown/markdown_table/markdown_table.test.js diff --git a/app/components/markdown/markdown_table/__snapshots__/markdown_table.test.js.snap b/app/components/markdown/markdown_table/__snapshots__/markdown_table.test.js.snap new file mode 100644 index 000000000..f47e327e9 --- /dev/null +++ b/app/components/markdown/markdown_table/__snapshots__/markdown_table.test.js.snap @@ -0,0 +1,177 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MarkdownTable should match snapshot 1`] = ` + + + + < + className="row" + > + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + + < + className="row" + > + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + + < + className="row" + > + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + + < + className="row" + > + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + + < + className="row" + isLastRow={true} + > + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + < + className="col" + /> + + + + + + + +`; diff --git a/app/components/markdown/markdown_table/markdown_table.js b/app/components/markdown/markdown_table/markdown_table.js index a288a1d3d..a6f1cac18 100644 --- a/app/components/markdown/markdown_table/markdown_table.js +++ b/app/components/markdown/markdown_table/markdown_table.js @@ -7,6 +7,7 @@ import {intlShape} from 'react-intl'; import { ScrollView, View, + Dimensions, } from 'react-native'; import LinearGradient from 'react-native-linear-gradient'; import Icon from 'react-native-vector-icons/FontAwesome'; @@ -19,6 +20,7 @@ import {changeOpacity, makeStyleSheetFromTheme} from 'app/utils/theme'; import {goToScreen} from 'app/actions/navigation'; const MAX_HEIGHT = 300; +const MAX_PREVIEW_COLUMNS = 5; export default class MarkdownTable extends React.PureComponent { static propTypes = { @@ -38,9 +40,23 @@ export default class MarkdownTable extends React.PureComponent { containerWidth: 0, contentHeight: 0, contentWidth: 0, + maxPreviewColumns: MAX_PREVIEW_COLUMNS, }; } + componentDidMount() { + Dimensions.addEventListener('change', this.setMaxPreviewColumns); + } + + componentWillUnmount() { + Dimensions.removeEventListener('change', this.setMaxPreviewColumns); + } + + setMaxPreviewColumns = ({window}) => { + const maxPreviewColumns = Math.floor(window.width / CELL_WIDTH); + this.setState({maxPreviewColumns}); + } + getTableWidth = () => { return this.props.numColumns * CELL_WIDTH; }; @@ -73,6 +89,38 @@ export default class MarkdownTable extends React.PureComponent { }); }; + renderPreviewRows = (drawExtraBorders = true) => { + const {maxPreviewColumns} = this.state; + const style = getStyleSheet(this.props.theme); + + const tableStyle = [style.table]; + if (drawExtraBorders) { + tableStyle.push(style.tableExtraBorders); + } + + // Add an extra prop to the last row of the table so that it knows not to render a bottom border + // since the container should be rendering that + const rows = React.Children.toArray(this.props.children).slice(0, maxPreviewColumns).map((row) => { + const children = React.Children.toArray(row.props.children).slice(0, maxPreviewColumns); + return { + ...row, + props: { + ...row.props, + children, + }, + }; + }); + rows[rows.length - 1] = React.cloneElement(rows[rows.length - 1], { + isLastRow: true, + }); + + return ( + + {rows} + + ); + } + renderRows = (drawExtraBorders = true) => { const style = getStyleSheet(this.props.theme); @@ -152,7 +200,7 @@ export default class MarkdownTable extends React.PureComponent { showsVerticalScrollIndicator={false} style={[style.container, {maxWidth: this.getTableWidth()}]} > - {this.renderRows(false)} + {this.renderPreviewRows(false)} {moreRight} {moreBelow} diff --git a/app/components/markdown/markdown_table/markdown_table.test.js b/app/components/markdown/markdown_table/markdown_table.test.js new file mode 100644 index 000000000..afda3bed2 --- /dev/null +++ b/app/components/markdown/markdown_table/markdown_table.test.js @@ -0,0 +1,55 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +import React from 'react'; +import {shallowWithIntl} from 'test/intl-test-helper'; + +import Preferences from 'mattermost-redux/constants/preferences'; + +import MarkdownTable from './markdown_table'; + +describe('MarkdownTable', () => { + const createCell = (type, children = null) => { + return React.createElement('', {key: Date.now(), className: type}, children); + }; + + const numColumns = 10; + const children = []; + for (let i = 0; i <= numColumns; i++) { + const cols = []; + for (let j = 0; j <= numColumns; j++) { + cols.push(createCell('col')); + } + + children.push(createCell('row', cols)); + } + + const baseProps = { + children, + numColumns, + theme: Preferences.THEMES.default, + }; + + test('should match snapshot', () => { + const wrapper = shallowWithIntl( + + ); + + expect(wrapper.getElement()).toMatchSnapshot(); + }); + + test('should slice rows and columns', () => { + const wrapper = shallowWithIntl( + + ); + + const {maxPreviewColumns} = wrapper.state(); + expect(wrapper.find('.row')).toHaveLength(maxPreviewColumns); + expect(wrapper.find('.col')).toHaveLength(Math.pow(maxPreviewColumns, 2)); + + const newMaxPreviewColumns = maxPreviewColumns - 1; + wrapper.setState({maxPreviewColumns: newMaxPreviewColumns}); + expect(wrapper.find('.row')).toHaveLength(newMaxPreviewColumns); + expect(wrapper.find('.col')).toHaveLength(Math.pow(newMaxPreviewColumns, 2)); + }); +});