diff --git a/html/elements/Br.js b/html/elements/Br.js new file mode 100644 index 00000000..57e79d35 --- /dev/null +++ b/html/elements/Br.js @@ -0,0 +1,12 @@ +import React from 'react'; +import { Text } from '@shoutem/ui'; + +function Br() { + return ( + + {"\n"} + + ); +} + +export default Br; diff --git a/html/elements/Inline.js b/html/elements/Inline.js index f13bbf12..323e033c 100644 --- a/html/elements/Inline.js +++ b/html/elements/Inline.js @@ -3,6 +3,7 @@ import _ from 'lodash'; import { View } from '../../components/View'; import { Text } from '../../components/Text'; +import { removeWhiteSpace } from './Text'; import { TouchableOpacity } from '../../components/TouchableOpacity'; import { Display } from '../services/ElementRegistry'; import { @@ -93,7 +94,15 @@ export const Inline = function (props) { return null; } - const children = groupInlineNodes(childElements); + // Browsers ignore white space (new lines) around element tags, + // we need to remove it here manually so it doesn't get rendered by RN. + const trimmedChildren = removeWhiteSpace(childElements); + + // Group inline elements, such as text, so that + // it gets shown in the same line. Like concatenation. + // Block elements are standalone because they break the line. + const children = groupInlineNodes(trimmedChildren); + const renderedChildren = renderGroupedChildren(children, renderElement); if (isInline(children)) { diff --git a/html/elements/Text.js b/html/elements/Text.js index 3bb04488..cf469ca5 100644 --- a/html/elements/Text.js +++ b/html/elements/Text.js @@ -1,14 +1,29 @@ import React from 'react'; import { Text } from 'react-native'; +import _ from 'lodash'; import { ElementPropTypes, combineMappers, mapElementProps } from '../Html'; -function removeNewLines(childElements) { - return childElements.filter(child => child !== '\n'); +function isWhiteSpaceWrappedWithText(element) { + return _.size(element.childElements) === 1 && isWhiteSpaceString(element.childElements[0]); +} + +function isWhiteSpaceString(element) { + return _.isString(element) && element.trim().length === 0; +} + +function isWhiteSpace(element) { + return isWhiteSpaceString(element) || isWhiteSpaceWrappedWithText(element); +} + +export function removeWhiteSpace(childElements) { + return childElements.filter(child => !isWhiteSpace(child)); } export function TextElement(props) { - const textualChildElements = removeNewLines(props.childElements); + // Remove empty white space lines used just to move element in new line. + // Use "p" or "br" to add new line. + const textualChildElements = removeWhiteSpace(props.childElements); if (textualChildElements.length === 0) { // Even if there is no children to render, the Text must be rendered diff --git a/html/elements/list/Li.js b/html/elements/list/Li.js index b406ba5a..ec066d5f 100644 --- a/html/elements/list/Li.js +++ b/html/elements/list/Li.js @@ -12,15 +12,15 @@ import { Inline } from '../Inline'; * @param style {Object} * @returns {Component} */ -function Li({ childElements, renderElement, prefix, style }) { +function Li({ element, renderElement, style }) { + const { childElements, attributes: { key } } = element; return ( - - {prefix || null} - - + ); } diff --git a/html/elements/list/Ol.js b/html/elements/list/Ol.js index 108df77b..2f6388e2 100644 --- a/html/elements/list/Ol.js +++ b/html/elements/list/Ol.js @@ -7,10 +7,12 @@ import pickLiChildElements from './helpers/pickLiChildElements'; import { ElementPropTypes, combineMappers, mapElementProps } from '../../Html'; import Li from './Li'; -function createPrefixCreator(type, prefixStyle) { - return function (element, index) { - // TODO (Braco) - Handle all types - return {index}; +function createNumberElement(element, index) { + return { + tag: 'number', + attributes: { + index, + }, }; } @@ -18,7 +20,7 @@ export function Ol({ style, childElements, type, renderElement }) { const liItems = pickLiChildElements(childElements); return ( - {renderItems(Li, liItems, renderElement, createPrefixCreator(type, style.prefix))} + {renderItems(liItems, renderElement, createNumberElement)} ); } diff --git a/html/elements/list/Ul.js b/html/elements/list/Ul.js index 079f4335..04fbf0f0 100644 --- a/html/elements/list/Ul.js +++ b/html/elements/list/Ul.js @@ -1,4 +1,5 @@ import React from 'react'; +import { Text } from '@shoutem/ui'; import { View } from '../../../components/View'; import { ElementPropTypes, combineMappers, mapElementProps } from '../../Html'; @@ -6,12 +7,18 @@ import renderItems from './helpers/renderItems'; import pickLiChildElements from './helpers/pickLiChildElements'; import Li from './Li'; +function createBulletElement(element, index) { + return { + tag: 'bullet', + }; +} + export function Ul({ style, childElements, renderElement }) { // TODO (Braco) - handle list-style-type from inlineStyle prop const liItems = pickLiChildElements(childElements); return ( - {renderItems(Li, liItems, renderElement)} + {renderItems(liItems, renderElement, createBulletElement)} ); } diff --git a/html/elements/list/helpers/renderItems.js b/html/elements/list/helpers/renderItems.js index 5016b4a2..7ac5e56e 100644 --- a/html/elements/list/helpers/renderItems.js +++ b/html/elements/list/helpers/renderItems.js @@ -1,17 +1,21 @@ import React from 'react'; import _ from 'lodash'; -export default function renderItems(Component, childElements, renderElement, prefix) { +import { createElementNode } from '../../../services/HtmlParser'; + +export default function renderItems(childElements, renderElement, createPrefixElement) { return _.reduce(childElements, (items, element, index) => { - const resolvedPrefix = _.isFunction(prefix) ? prefix(element, index) : undefined; - items.push( - - ); + const { childElements: itemChildElements } = element; + + const prefix = createPrefixElement ? createPrefixElement(element, index) : null; + const childElements = prefix ? [prefix, ...itemChildElements] : itemChildElements; + + const elem = { + ...element, + childElements, + }; + + items.push(renderElement(elem)); return items; }, []); } diff --git a/html/elements/list/index.js b/html/elements/list/index.js index 0924eb02..b97d2412 100644 --- a/html/elements/list/index.js +++ b/html/elements/list/index.js @@ -1,9 +1,13 @@ import Ul from './Ul'; import Li from './Li'; import Ol from './Ol'; +import Bullet from './prefix/Bullet'; +import Number from './prefix/Number'; export { Ul, Ol, Li, + Bullet, + Number, }; diff --git a/html/elements/list/prefix/Bullet.js b/html/elements/list/prefix/Bullet.js new file mode 100644 index 00000000..94967031 --- /dev/null +++ b/html/elements/list/prefix/Bullet.js @@ -0,0 +1,6 @@ +import React from 'react'; +import { Text } from '@shoutem/ui'; + +export default function ({ style }) { + return ; +} diff --git a/html/elements/list/prefix/Number.js b/html/elements/list/prefix/Number.js new file mode 100644 index 00000000..84840cef --- /dev/null +++ b/html/elements/list/prefix/Number.js @@ -0,0 +1,8 @@ +import React from 'react'; +import { View, Text } from '@shoutem/ui'; + +export default function ({ element, style }) { + const { index } = element.attributes; + + return {index}.; +}; diff --git a/html/index.js b/html/index.js index ff6ef9f9..119adb47 100644 --- a/html/index.js +++ b/html/index.js @@ -20,9 +20,10 @@ import Inline, { InlineSettings } from './elements/Inline'; import Virtual from './elements/Virtual'; import Block from './elements/Block'; import Text from './elements/Text'; -import { Ul, Ol, Li } from './elements/list'; +import { Ul, Ol, Li, Bullet, Number } from './elements/list'; import Img from './elements/Img'; import A from './elements/A'; +import Br from './elements/Br'; // Text elements with primary inline display Html.registerElement('em', Inline, InlineSettings); @@ -34,6 +35,7 @@ Html.registerElement('span', Inline, InlineSettings); // Functional Html.registerElement('a', A, InlineSettings); Html.registerElement('img', Img); +Html.registerElement('br', Br, InlineSettings); // Containers Html.registerElement('header', Virtual); @@ -45,6 +47,9 @@ Html.registerElement('section', Virtual); // List Html.registerElement('ul', Ul); Html.registerElement('ol', Ol); +Html.registerElement('li', Li); +Html.registerElement('bullet', Bullet, { display: Display.INLINE }); +Html.registerElement('number', Number, { display: Display.INLINE }); // Text base Html.registerElement('text', Text, { display: Display.INLINE }); diff --git a/package.json b/package.json index a5d9d052..ebeef5c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@shoutem/ui", - "version": "0.16.0", + "version": "0.17.0", "description": "Styleable set of components for React Native applications", "dependencies": { "@shoutem/animation": "~0.11.0", diff --git a/theme.js b/theme.js index 1317139c..f0217ebb 100644 --- a/theme.js +++ b/theme.js @@ -1482,6 +1482,9 @@ export default (variables = defaultThemeVariables) => ({ }), }; }, + boxingAnimation() { + return {}; + }, position: 'absolute', right: 0, top: 0, @@ -1983,14 +1986,23 @@ export default (variables = defaultThemeVariables) => ({ // HTML lists ul: { container: {}, - prefix: {}, // Not implemented yet }, ol: { container: {}, - prefix: {}, }, - li: { - flexDirection: 'row', + number: { + // Font should be monospace so that item content has same offset + // Can not apply width to the Text for some reason + fontFamily: Platform.OS === 'ios' ? 'Menlo-Regular' : 'monospace', + fontSize: 12, + }, + bullet: { + }, + li: { // Inline element + container: { + }, + text: { + }, }, // HTML containers