Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 33 additions & 19 deletions src/pacomo.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import classNames from 'classnames'
import { isValidElement, cloneElement, Children, PropTypes } from 'react'

function pacomoStrategy(packageName){
const strategy = {
getComponentName: function(component){
return component.displayName || component.name;
},
getComponentClassName: function(component){
const componentName = strategy.getComponentName(component);
return `${packageName}-${componentName}`;
},
getPropClassName: function(component, name){
const prefix = strategy.getComponentClassName(component);
return `${prefix}-${name}`;
}
};
return strategy;
}

export function prefixedClassNames(prefix, ...args) {
export function prefixedClassNames(strategy, component, ...args) {
return (
classNames(...args)
.split(/\s+/)
.filter(name => name !== "")
.map(name => `${prefix}-${name}`)
.filter(name => !!name)
.map(name => strategy.getPropClassName(component, name))
.join(' ')
)
}
Expand Down Expand Up @@ -46,7 +62,7 @@ function transformElementProps(props, fn, childrenOnly) {
changes.children = transformedChildren
}
}

if (!childrenOnly) {
for (let key of Object.keys(props)) {
if (key == 'children') continue
Expand Down Expand Up @@ -75,7 +91,7 @@ function skipPropElements(props) {
}


export function transformWithPrefix(prefix) {
export function transformWithPrefix(strategy, componentFunction) {
const childTransform = element => transform(element)

// Prefix all `className` props on the passed in ReactElement object, its
Expand All @@ -92,7 +108,7 @@ export function transformWithPrefix(prefix) {
)

if (element.props.className) {
changes.className = `${rootClass || ''} ${prefixedClassNames(prefix, element.props.className)} ${suffixClasses}`
changes.className = `${rootClass || ''} ${prefixedClassNames(strategy, componentFunction, element.props.className)} ${suffixClasses}`
}
else if (rootClass) {
changes.className = `${rootClass} ${suffixClasses}`
Expand All @@ -108,19 +124,21 @@ export function transformWithPrefix(prefix) {
return transform
}

export function withPackageName(packageName){
return withStrategy(pacomoStrategy(packageName));
}

export function withPackageName(packageName) {
export function withStrategy(strategy) {
return {
// Transform a stateless function component
transformer(componentFunction) {
const componentName = componentFunction.displayName || componentFunction.name
const prefix = `${packageName}-${componentName}`
const transform = transformWithPrefix(prefix)
const componentName = strategy.getComponentName(componentFunction);
const transform = transformWithPrefix(strategy, componentFunction)

const transformedComponent = (props, ...args) =>
transform(
componentFunction(skipPropElements(props), ...args),
prefix,
strategy.getComponentClassName(componentFunction),
props.className
)

Expand All @@ -135,26 +153,22 @@ export function withPackageName(packageName) {

// Transform a React.Component class
decorator(componentClass) {
const componentName = componentClass.displayName || componentClass.name
const prefix = `${packageName}-${componentName}`
const transform = transformWithPrefix(prefix)
const componentName = strategy.getComponentName(componentClass);
const transform = transformWithPrefix(strategy, componentClass)

const DecoratedComponent = class DecoratedComponent extends componentClass {
render() {
const rawProps = this.props
this.props = skipPropElements(this.props)
const transformed = transform(super.render(), prefix, this.props.className)
const transformed = transform(super.render(), strategy.getComponentClassName(componentClass), this.props.className)
this.props = rawProps
return transformed
}
}

DecoratedComponent.displayName = `pacomo(${componentName})`

// Add `className` propType, if none exists
DecoratedComponent.propTypes = { className: PropTypes.string, ...componentClass.propTypes }

return DecoratedComponent
return DecoratedComponent
},
}
}
35 changes: 19 additions & 16 deletions test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import 'babel-polyfill'
import {prefixedClassNames, withPackageName, transformWithPrefix} from './lib/pacomo'
import {
PacomoStrategy,
prefixedClassNames,
withPackageName,
transformWithPrefix
} from './lib/pacomo'
import React, {Component, PropTypes} from 'react'
import TestUtils from 'react-addons-test-utils'
import assert from 'assert'


const testTransform = transformWithPrefix('test')
const testTransform = transformWithPrefix({
getPropClassName: (component, name)=> `test-${name}`
});
const { transformer, decorator } = withPackageName('prefix')


Expand All @@ -16,7 +22,7 @@ const { transformer, decorator } = withPackageName('prefix')
function shallowRenderElement(element) {
const shallowRenderer = TestUtils.createRenderer()
shallowRenderer.render(element)
return shallowRenderer.getRenderOutput()
return shallowRenderer.getRenderOutput()
}

function shallowRenderComponent(Component, props) {
Expand Down Expand Up @@ -127,16 +133,6 @@ describe('decorator', () => {
"other propTypes from original class is passed through"
)
})

it("should add a className propType if one doesn't already exist", () => {
const decoratedClass = decorator(BareComponent)

assert.equal(
decoratedClass.propTypes.className,
PropTypes.string,
"className propType exists"
)
})
})


Expand Down Expand Up @@ -260,9 +256,16 @@ describe('stateless render', () => {


describe('prefixedClassNames', () => {
let strategy;
beforeEach(()=>{
strategy = {
getPropClassName: (component, name)=> `test-prefix-${name}`
};
})

it("accepts an object, producing the correct result", () => {
assert.equal(
prefixedClassNames('test-prefix', {
prefixedClassNames(strategy, null, {
active: true,
inactive: false,
}),
Expand All @@ -273,7 +276,7 @@ describe('prefixedClassNames', () => {

it("accepts a string, producing the correct result", () => {
assert.equal(
prefixedClassNames('test-prefix', 'test1', 'test2'),
prefixedClassNames(strategy, null, 'test1', 'test2'),
'test-prefix-test1 test-prefix-test2',
"`classNames` produces the correct string when a string is passed in"
)
Expand Down