bemto-components
Advanced tools
Comparing version 1.3.0 to 1.4.0
# `bemto-components` changelog | ||
## v1.4.0 (2017-11-16) | ||
- Added context handling for polymorphic tags. | ||
- Added modifiers declaration on block with possible passing of functions. | ||
- Added a way to pass props on element declaration. | ||
- Fixed a tag getter from the tagString of an element declaration. | ||
## v1.3.0 (2017-11-08) | ||
@@ -4,0 +11,0 @@ |
302
lib/index.js
const React = require('react'); | ||
const PropTypes = require('prop-types'); | ||
@@ -15,4 +16,36 @@ // The code below is a mess, I'm sorry. But it is a working mess at least! | ||
const gatherModifiers = function(props) { | ||
return Object.keys(props).filter(prop => props[prop] && prop[0] === '_' && prop[1] !== '_').map(key => typeof props[key] === 'string' ? `${key}_${props[key]}` : key ); | ||
const renderModifier = function(key, value, props) { | ||
const type = typeof value; | ||
if (type === 'string' || type === 'number') { | ||
return `${key}_${value}`; | ||
} | ||
if (type === 'function') { | ||
modValue = value(props); | ||
if (modValue) { | ||
return renderModifier(key, modValue, props); | ||
} else { | ||
return; | ||
} | ||
} | ||
if (value) { | ||
return key; | ||
} | ||
} | ||
const gatherModifiers = function(props, modifiersObj) { | ||
if (!props) return []; | ||
const propKeys = Object.keys(props); | ||
const modifiers = propKeys.filter(prop => props[prop] && prop[0] === '_' && prop[1] !== '_').map(key => renderModifier(key, props[key], props)); | ||
if (modifiersObj) { | ||
for (var key in modifiersObj) { | ||
if (propKeys.indexOf(key) === -1) { | ||
const modValue = renderModifier(key, modifiersObj[key], props); | ||
if (modValue) { | ||
modifiers.push(modValue); | ||
} | ||
} | ||
} | ||
} | ||
return modifiers; | ||
}; | ||
@@ -30,3 +63,3 @@ | ||
// Base for polymorphic tag names | ||
const selectTag = function(props, defaultTag) { | ||
const selectTag = function(props, defaultTag, context) { | ||
if (typeof defaultTag === 'string') { | ||
@@ -41,3 +74,10 @@ if (props.href) return 'a'; | ||
} | ||
if (context) { | ||
if (context === 'list') return 'li'; | ||
if (context === 'optionlist') return 'option'; | ||
} | ||
} | ||
if (defaultTag === 'div') { | ||
if (context && context === 'inline') return 'span'; | ||
} | ||
} | ||
@@ -47,4 +87,27 @@ return defaultTag; | ||
const applyToAll = function(content, func) { | ||
return (content && content.constructor === Array) ? content.map(func) : func(content); | ||
const applyToAll = function(content, func, modifier) { | ||
if (React.isValidElement(content)) { | ||
if (modifier) { | ||
return { | ||
content: content, | ||
type: 'reactContent', | ||
modifier: modifier | ||
}; | ||
} | ||
return content; | ||
} | ||
const isArray = (content && content.constructor === Array); | ||
if (modifier) { | ||
const modifyContent = function(content) { | ||
for (var key in modifier) { | ||
content[key] = modifier[key]; | ||
} | ||
return content; | ||
} | ||
const modifiedContent = applyToAll(content, modifyContent); | ||
return isArray ? modifiedContent.map(func) : func(modifiedContent); | ||
} | ||
return isArray ? content.map(func) : func(content); | ||
}; | ||
@@ -55,62 +118,127 @@ | ||
const collectOptions = function(tagString, additionalOptions) { | ||
const options = additionalOptions || typeof tagString !== 'string' && tagString || {}; | ||
options.type = 'block'; | ||
options.tagString = options.tagString || typeof tagString === 'string' && tagString; | ||
options.parsedTagString = parseTagString(options.tagString || ''); | ||
options.tag = options.tag || options.parsedTagString.tag; | ||
options.props = options.props || options.parsedTagString.props || {}; | ||
options.props.className = (options.props.className || options.className || '')+ ' ' + options.parsedTagString.className | ||
options.props.id = options.props.id || options.id || options.parsedTagString.id; | ||
return options; | ||
const options = additionalOptions || typeof tagString === 'object' && tagString || {}; | ||
const parsedTagString = parseTagString(options.tagString || typeof tagString === 'string' && tagString || ''); | ||
options.type = typeof tagString === 'function' ? 'wrapper' : 'block'; | ||
options.tag = options.tag || (typeof tagString === 'function' && tagString) || parsedTagString.tag; | ||
options.props = options.props || parsedTagString.props || {}; | ||
options.props.className = [options.props.className, options.className, parsedTagString.className].filter(className => className).join(' '); | ||
options.props.id = options.props.id || options.id || parsedTagString.id; | ||
return { | ||
tag: options.tag, | ||
type: options.type, | ||
props: options.props, | ||
content: options.content, | ||
modifiers: options.modifiers | ||
}; | ||
}; | ||
// Most of the props-handling stuff happens there | ||
// TODO: refactor this to a few specialized funcions. | ||
const gatherOptions = function(outerOptions, baseOptions) { | ||
// Clone & merge options from arguments | ||
const options = Object.assign(baseOptions, outerOptions); | ||
options.props = Object.assign({}, outerOptions.props); | ||
const normalizeClassNames = function(classNames) { | ||
const classNamesArray = classNames.split(/\s+/); | ||
return classNamesArray.filter((item, index) => classNamesArray.indexOf(item) === index).join(' '); | ||
}; | ||
// Modify options if we're at elem scope | ||
options.elem = options.tagProps.__BemtoElem; | ||
if (options.elem) { | ||
options.type = 'elem'; | ||
const elemParsedTagString = options.elem.parsedTagString || parseTagString(options.elem.tagString || ''); | ||
if (elemParsedTagString.tag) { | ||
options.tag = elemParsedTagString.tag; | ||
const moveValidProps = function(fromProps, toProps, tag) { | ||
if (fromProps) { | ||
for (var key in fromProps) { | ||
if (!(typeof tag === 'string' && key[0] === '_') && key !== 'children' && key !== 'className') { | ||
toProps[key] = fromProps[key]; | ||
} | ||
} | ||
if (elemParsedTagString.id) { | ||
options.props.id = elemParsedTagString.id; | ||
} | ||
options.props.className = elemParsedTagString.className || ''; | ||
toProps.className = (toProps.className || '') + ' ' + (fromProps.className || ''); | ||
} | ||
}; | ||
options.finalProps = {}; | ||
for (var key in (options.elem && (options.elem.props || {}) || options.tagProps)) { | ||
if (!(typeof options.tag === 'string' && key[0] === '_') && key !== 'children') { | ||
options.finalProps[key] = (options.elem && (options.elem.props || {}) || options.tagProps)[key]; | ||
} | ||
} | ||
// Most of the props-handling stuff happens there | ||
const gatherOptions = function(outerOptions, baseOptions) { | ||
// Preparing all the objects | ||
const options = Object.assign({}, outerOptions); | ||
const originalProps = Object.assign({}, options.props); | ||
const elem = baseOptions.tagProps.__BemtoElem; | ||
// Starting to initiate base props | ||
const fullProps = elem ? elem.props : baseOptions.tagProps; | ||
const finalOptions = | ||
elem | ||
? collectOptions(elem.tagString, elem.parsedTagString) | ||
: Object.assign({}, options); | ||
finalOptions.props = Object.assign({}, finalOptions && finalOptions.props); | ||
finalOptions.modifiers = elem ? elem.modifiers : finalOptions.modifiers; | ||
finalOptions.tagContext = elem ? elem.tagContext || finalOptions.tagContext || 'block' : baseOptions.tagContext; | ||
if (options.props.id && !options.finalProps.id) { | ||
options.finalProps.id = options.props.id; | ||
} | ||
// Use just the props that don't start with underscore for the final version | ||
moveValidProps(fullProps, finalOptions.props, finalOptions.tag) | ||
if (options.elem) { | ||
options.finalProps.className = (options.finalProps.className || '') + ' ' + createElemClassNames(((options.tagProps.className || '') + ' ' + options.parsedTagString.className), [options.elem.name]); | ||
if (elem) { | ||
// Adding Element parts to classNames | ||
finalOptions.props.className += ' ' + createElemClassNames(((baseOptions.tagProps.className || '') + ' ' + originalProps.className), [elem.name]); | ||
} else { | ||
// Otherwise, add the block's className | ||
finalOptions.props.className += ' ' + originalProps.className; | ||
} | ||
options.finalProps.className = modifyClassNames((options.finalProps.className || '') + ' ' + options.props.className, gatherModifiers(options.elem && (options.elem.props || {}) || options.tagProps)); | ||
// Applying modifiers | ||
finalOptions.props.className = modifyClassNames( | ||
finalOptions.props.className, | ||
gatherModifiers(finalOptions.type !== 'wrapper' && fullProps, finalOptions.modifiers)); | ||
// FIXME: replace with joining className_s_ (which don't exist yet) | ||
options.finalProps.className = options.finalProps.className.replace(/\s{2,}/g, ' '); | ||
// Normalizing classNames (removing duplicates etc.) | ||
finalOptions.props.className = normalizeClassNames(finalOptions.props.className); | ||
options.finalTag = selectTag(options.finalProps, options.tag); | ||
// Handling id (hmm, should be done somehow better?) | ||
if (originalProps.id && !finalOptions.props.id) { | ||
finalOptions.props.id = originalProps.id; | ||
} | ||
if (!finalOptions.props.id) { | ||
delete finalOptions.props.id; | ||
} | ||
if (!finalOptions.props.className) { | ||
delete finalOptions.props.className; | ||
} | ||
return options; | ||
return { | ||
finalTag: selectTag(finalOptions.props, finalOptions.tag, finalOptions.tagContext), | ||
finalProps: finalOptions.props, | ||
children: baseOptions.children | ||
}; | ||
} | ||
const SELF_CLOSING_TAGS = ['hr', 'br', 'wbr', 'source', 'img', 'input']; | ||
const INLINE_TAGS = ['a', 'abbr', 'acronym', 'b', 'code', 'em', 'font', 'i', 'ins', 'kbd', 'map', 'pre', 'samp', 'small', 'span', 'strong', 'sub', 'sup', 'textarea', 'time']; | ||
const INLINE_CONTEXT_TAGS = ['label', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6']; | ||
const LIST_CONTEXT_TAGS = ['ul', 'ol']; | ||
const OPTIONS_CONTEXT_TAGS = ['select', 'datalist']; | ||
// TODO: add plaintext context? | ||
const getContextFromTag = function(tag, context) { | ||
if (tag === 'div') { | ||
return context === 'inline' ? 'inline' : 'block'; | ||
} | ||
if (typeof tag !== 'string') { | ||
return; | ||
} | ||
if (INLINE_TAGS.indexOf(tag) !== -1 || INLINE_CONTEXT_TAGS.indexOf(tag) !== -1) { | ||
return 'inline'; | ||
} | ||
if (LIST_CONTEXT_TAGS.indexOf(tag) !== -1) { | ||
return 'list'; | ||
} | ||
if (OPTIONS_CONTEXT_TAGS.indexOf(tag) !== -1) { | ||
return 'optionlist'; | ||
} | ||
if (SELF_CLOSING_TAGS.indexOf(tag) !== -1) { | ||
return 'empty'; | ||
} | ||
return 'block'; | ||
}; | ||
// Recursive unfolder of children for the object to elements generator | ||
const unfoldChildren = function(props, generator) { | ||
const unfoldFunction = function(item, index) { | ||
const unfoldFunction = function(item, index, modifier) { | ||
if (React.isValidElement(item)) { | ||
return item; | ||
} | ||
// Not sure if we need it there or if won't be ever used? | ||
if (item.type && item.type === 'reactContent') { | ||
return item.content; | ||
} | ||
const elemName = item.name || item.elem; | ||
@@ -141,11 +269,19 @@ let elemProp = props['__' + elemName] || item.parents && props['__' + item.parents.filter(name => props['__' + name]).reverse()[0]]; | ||
const parsedTagString = parseTagString(item.tagString); | ||
parsedTagString.tag = item.tag || 'div'; | ||
parsedTagString.tag = item.tag || parsedTagString.tag || 'div'; | ||
if (item.className) { parsedTagString.className += ' ' + item.className; } | ||
const myPropsProps = elemProp && elemProp.props || {}; | ||
const myPropsProps = elemProp && elemProp.props || item.props || {}; | ||
if (elemProp && elemProp.props) { | ||
for (var key in elemProp.props) { | ||
myPropsProps[key] = elemProp.props[key]; | ||
} | ||
} | ||
myPropsProps.key = index; | ||
const myProps = Object.assign({ | ||
__BemtoElem: { | ||
tagContext: item.tagContext, | ||
name: elemName, | ||
props: myPropsProps, | ||
parsedTagString: parsedTagString | ||
parsedTagString: parsedTagString, | ||
modifiers: item.modifiers | ||
} | ||
@@ -158,3 +294,6 @@ }, props); | ||
parents.push(elemName); | ||
content.parents = parents; | ||
const contentModifier = { | ||
parents: parents | ||
}; | ||
contentModifier.tagContext = getContextFromTag(selectTag(myPropsProps, parsedTagString.tag, item.tagContext)) | ||
if (item.list && elemProp && elemProp.constructor === Array) { | ||
@@ -184,3 +323,3 @@ const key_prefix = myPropsProps.key + '_'; | ||
} | ||
return generator(myProps, applyToAll(content, unfoldFunction)); | ||
return generator(myProps, applyToAll(content, unfoldFunction, contentModifier)); | ||
} else if (item.children || item.type === 'children') { | ||
@@ -193,2 +332,18 @@ return props.children; | ||
// Provider of bemto tag context for using when there are stuff inbetween that won't set it | ||
class BemtoContextProvider extends React.Component { | ||
getChildContext() { | ||
return { bemtoTagContext: this.props.context } | ||
} | ||
render() { | ||
return this.props.children; | ||
} | ||
} | ||
BemtoContextProvider.propTypes = { | ||
context: PropTypes.string.isRequired, | ||
}; | ||
BemtoContextProvider.childContextTypes = { | ||
bemtoTagContext: PropTypes.string.isRequired | ||
}; | ||
// Our main factory | ||
@@ -198,14 +353,26 @@ const bemto = function(tagString, additionalOptions) { | ||
const bemtoFactory = class bemtoTag extends React.Component { | ||
constructor(props, context) { | ||
super(props); | ||
this.state = { | ||
bemtoTagContext: getContextFromTag(blockOptions.tag, context && context.bemtoTagContext) | ||
}; | ||
} | ||
getChildContext() { | ||
return { bemtoTagContext: this.state.bemtoTagContext } | ||
} | ||
render() { | ||
const generateTag = (props, children) => { | ||
const isReactElem = children && children.type && children.type === 'reactContent'; | ||
const options = gatherOptions(blockOptions, { | ||
tagProps: props, | ||
children: children | ||
children: isReactElem ? React.createElement(BemtoContextProvider, { context: children.modifier.tagContext }, children.content) : children, | ||
tagContext: this.context.bemtoTagContext | ||
}) | ||
return React.createElement(options.finalTag, options.finalProps, options.children); | ||
}; | ||
const children = blockOptions.content | ||
? applyToAll(blockOptions.content, unfoldChildren(this.props, generateTag)) | ||
const content = !this.props.__BemtoElem && blockOptions.content; | ||
const children = content | ||
? applyToAll(content, unfoldChildren(this.props, generateTag), { | ||
tagContext: getContextFromTag(blockOptions.tag) | ||
}) | ||
: this.props.children; | ||
@@ -216,8 +383,14 @@ return generateTag(this.props, children); | ||
bemtoFactory.elem = (elemName, tagString) => { | ||
return bemto.elem(bemtoFactory, elemName, tagString || ''); | ||
bemtoFactory.childContextTypes = { | ||
bemtoTagContext: PropTypes.string | ||
}; | ||
bemtoFactory.contextTypes = { | ||
bemtoTagContext: PropTypes.string | ||
}; | ||
bemtoFactory.elem = (elemName, tagString, options) => { | ||
return bemto.elem(bemtoFactory, elemName, tagString || '', options); | ||
}; | ||
bemtoFactory.addElem = (elemName, tagString) => { | ||
bemtoFactory[elemName] = bemtoFactory.elem(elemName, tagString); | ||
bemtoFactory.addElem = (elemName, tagString, options) => { | ||
bemtoFactory[elemName] = bemtoFactory.elem(elemName, tagString, options); | ||
return bemtoFactory; | ||
@@ -229,3 +402,3 @@ }; | ||
bemto.elem = function(block, elemName, tagString) { | ||
bemto.elem = function(block, elemName, tagString, options) { | ||
const parsedTagString = parseTagString(tagString); | ||
@@ -238,3 +411,4 @@ return class bemtoTag extends React.Component { | ||
props: this.props, | ||
parsedTagString: parsedTagString | ||
parsedTagString: parsedTagString, | ||
options: options | ||
}; | ||
@@ -241,0 +415,0 @@ return React.createElement(block, props, this.props.children); |
{ | ||
"name": "bemto-components", | ||
"version": "1.3.0", | ||
"version": "1.4.0", | ||
"description": "Smart components for using parts of BEM methodology with React", | ||
@@ -5,0 +5,0 @@ "main": "lib/index.js", |
@@ -27,2 +27,3 @@ # bemto-components 🍱 | ||
5. `bemto-components` allows you to sometimes omit the tag names and get them from the context: if you'd call a bemto block from inside another bemto block which has inline context (like a `span` tag) without explicitly stating a tag (or for some reason trying to have a `div`), it would become a `span`. The same would happen for `ul` and `select`: its items would be by default `li` and `option`. | ||
@@ -29,0 +30,0 @@ ## Disclaimer |
406
test/test.js
@@ -80,2 +80,87 @@ const React = require('react'); | ||
test('with modifiers passed in the modifiers object', () => { | ||
testSnapshot( | ||
bemto('.block', { | ||
modifiers: { | ||
_modWithVal: 'value', | ||
_modBool: true, | ||
_modNum: 2, | ||
_noMod: false | ||
} | ||
}) | ||
); | ||
}); | ||
test('with modifiers passed in the modifiers object while having an element', () => { | ||
testSnapshot( | ||
bemto('.block', { | ||
content: [ | ||
{ children: true }, | ||
{ | ||
elem: 'Helper', | ||
modifiers: { | ||
_elemModWithVal: 'value', | ||
_elemModBool: true, | ||
_elemModNum: 2, | ||
_elemNoMod: false | ||
} | ||
} | ||
], | ||
modifiers: { | ||
_modWithVal: 'value', | ||
_modBool: true, | ||
_modNum: 2, | ||
_noMod: false | ||
} | ||
}) | ||
); | ||
}); | ||
test('with modifiers passed in the modifiers object based on other props', () => { | ||
testSnapshot( | ||
bemto('.block', { | ||
modifiers: { | ||
_hasTitle: (props) => !!props.title, | ||
_titleText: (props) => props.title, | ||
_moreThan9000: (props) => props.power > 9000 | ||
} | ||
}), | ||
{ | ||
title: 'hello', | ||
power: 9042 | ||
} | ||
); | ||
}); | ||
test('with modifiers passed in the modifiers object based on other props (absense)', () => { | ||
testSnapshot( | ||
bemto('.block', { | ||
modifiers: { | ||
_hasTitle: (props) => !!props.title, | ||
_titleText: (props) => props.title, | ||
_moreThan9000: (props) => props.power > 9000 | ||
} | ||
}) | ||
); | ||
}); | ||
test('with modifiers passed in the modifiers object based on other props which are then overriden', () => { | ||
testSnapshot( | ||
bemto('.block', { | ||
modifiers: { | ||
_hasTitle: (props) => !!props.title, | ||
_titleText: (props) => props.title, | ||
_moreThan9000: (props) => props.power > 9000 | ||
} | ||
}), | ||
{ | ||
title: 'hello', | ||
power: 9042, | ||
_moreThan9000: false, | ||
_titleText: 'goodbye', | ||
_hasTitle: false | ||
} | ||
); | ||
}); | ||
test('with tag and explicit class name', () => { | ||
@@ -210,2 +295,15 @@ testSnapshot( | ||
test('with a wrapped component', () => { | ||
const wrappedComponent = bemto('span.wrappedComponent'); | ||
testSnapshot( | ||
bemto(wrappedComponent, { | ||
className: 'wrapComponent' | ||
}), | ||
{ | ||
className: 'externalClassname', | ||
_mod: 'value' | ||
} | ||
); | ||
}); | ||
test('should become an anchor based on an attrubute, even when defined as a button', () => { | ||
@@ -382,2 +480,307 @@ testSnapshot( | ||
test('simple block with a Helper item before children with some added props', () => { | ||
testSnapshot( | ||
bemto('.myBlock', { | ||
content: [ | ||
{ | ||
elem: 'Helper', | ||
props: { | ||
title: 'Oh wow', | ||
hidden: true | ||
} | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('with nested bemto block in inline context', () => { | ||
testSnapshot( | ||
bemto('span.inlineClass1'), | ||
{}, | ||
React.createElement(bemto('.class2')) | ||
); | ||
}); | ||
test('with nested bemto block in list context', () => { | ||
testSnapshot( | ||
bemto('ul.listClass1'), | ||
{}, | ||
React.createElement(bemto('.class2')) | ||
); | ||
}); | ||
test('with nested bemto block in select context', () => { | ||
testSnapshot( | ||
bemto('select.selectClass1'), | ||
{}, | ||
React.createElement(bemto('.class2')) | ||
); | ||
}); | ||
test('with multiple nested bemto blocks in inline context', () => { | ||
testSnapshot( | ||
bemto('span.inlineClass1'), | ||
{}, | ||
React.createElement(bemto('.class2'), {}, React.createElement(bemto('.class3'))) | ||
); | ||
}); | ||
test('with a more complex nested context', () => { | ||
const Minimal = bemto(); | ||
const List = bemto('ol'); | ||
const Strong = bemto('strong'); | ||
testSnapshot( | ||
List, | ||
{}, | ||
React.createElement(Minimal, {}, [ | ||
'Item', | ||
React.createElement(Strong, { key: 'a'}, [ | ||
React.createElement(Minimal, { key: 'a'}, 'with '), | ||
React.createElement(Minimal, { key: 'b'}, 'spans') | ||
]), | ||
React.createElement(Minimal, { key: 'b'}, 'And a new line') | ||
]) | ||
); | ||
}); | ||
test('simple block with a Helper item before children with inline context', () => { | ||
testSnapshot( | ||
bemto('span.myInlineBlock', { | ||
content: [ | ||
{ | ||
elem: 'Helper' | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('simple block with a Helper containing an extra elem at inline context', () => { | ||
testSnapshot( | ||
bemto('span.myInlineBlock', { | ||
content: [ | ||
{ | ||
elem: 'Helper', | ||
content: React.createElement(bemto('.class2')) | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('simple block with a Helper containing an array of extra elems at inline context', () => { | ||
testSnapshot( | ||
bemto('span.myInlineBlock', { | ||
content: [ | ||
{ | ||
elem: 'Helper', | ||
content: [ | ||
React.createElement(bemto('.class2'), { key: 'a' }), | ||
React.createElement(bemto('.class2'), { key: 'b' }) | ||
] | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('with a nested Helpers containing an extra elem at inner inline context', () => { | ||
testSnapshot( | ||
bemto('.myBlock', { | ||
content: [ | ||
{ | ||
elem: 'InlineHelper', | ||
tag: 'span', | ||
content: { | ||
elem: 'Helper2', | ||
content: React.createElement(bemto('.class2')) | ||
} | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('with a nested Helpers containing an extra elem at inner inline context overridden by label', () => { | ||
testSnapshot( | ||
bemto('span.myInlineBlock', { | ||
content: [ | ||
{ | ||
elem: 'LabelHelper', | ||
tag: 'label', | ||
content: [ | ||
{ | ||
elem: 'Helper2' | ||
}, | ||
{ | ||
elem: 'Helper3', | ||
content: React.createElement(bemto('.class2')) | ||
} | ||
] | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('simple block with a Helper item before children with list context', () => { | ||
testSnapshot( | ||
bemto('ul.myListBlock', { | ||
content: [ | ||
{ | ||
elem: 'Helper' | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('simple block with a Helper item before children with select context', () => { | ||
testSnapshot( | ||
bemto('select.mySelectBlock', { | ||
content: [ | ||
{ | ||
elem: 'Helper' | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('simple block with a Helper item before children with nested list context', () => { | ||
testSnapshot( | ||
bemto('ul.myListBlock', { | ||
content: [ | ||
{ | ||
elem: 'Helper', | ||
content: { elem: 'Helper__Item' } | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('simple block with a Helper item before children with list nested in normal item', () => { | ||
testSnapshot( | ||
bemto('.myBlock', { | ||
content: [ | ||
{ | ||
elem: 'myListHelper', | ||
tag: 'ul', | ||
content: { elem: 'myListHelper__Item' } | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('block with a complex elements structure', () => { | ||
testSnapshot( | ||
bemto('.myBlock', { | ||
content: [ | ||
{ | ||
elem: 'Elem1', | ||
tag: 'span', | ||
content: [ | ||
{ elem: 'Elem1__Elem1' }, | ||
{ | ||
elem: 'Elem1__Elem2', | ||
content: [ | ||
{ elem: 'Elem1__Elem2__Elem1' }, | ||
{ elem: 'Elem1__Elem2__Elem2' } | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
elem: 'Elem2', | ||
tag: 'ul', | ||
content: [ | ||
{ elem: 'Elem2__Elem1' }, | ||
{ | ||
elem: 'Elem2__Elem2', | ||
content: [ | ||
{ elem: 'Elem2__Elem2__Elem1' }, | ||
{ elem: 'Elem2__Elem2__Elem2' } | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
elem: 'Elem3', | ||
tag: 'span', | ||
content: [ | ||
{ elem: 'Elem3__Elem1', tag: 'label' }, | ||
{ | ||
elem: 'Elem3__Elem2', | ||
props: { href: '#x' }, | ||
content: [ | ||
{ elem: 'Elem3__Elem2__Elem1' }, | ||
{ elem: 'Elem3__Elem2__Elem2' } | ||
] | ||
} | ||
] | ||
}, | ||
{ | ||
children: true | ||
} | ||
] | ||
}), | ||
{}, | ||
'children text' | ||
); | ||
}); | ||
test('simple block with a Helper item before children using a button tag on parent', () => { | ||
@@ -463,2 +866,4 @@ testSnapshot( | ||
// FIXME: problem with array and keys =_= so this test gives a warning | ||
/* | ||
test('block with passing content to an element through props (passing a list of proper elements)', () => { | ||
@@ -487,2 +892,3 @@ const MyBlock = bemto('.myBlock', { | ||
}); | ||
*/ | ||
@@ -489,0 +895,0 @@ test('block with passing content to an element through props using an object', () => { |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
80177
1537
381
0