Skip to content

Commit 51849c3

Browse files
javivelascodavid-slayte
authored andcommitted
Deprecate withRef for innerRef (javivelasco#46)
1 parent 67e207a commit 51849c3

File tree

4 files changed

+22
-73
lines changed

4 files changed

+22
-73
lines changed

Diff for: README.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,12 @@ Makes available a `theme` context to use in styled components. The shape of the
158158
159159
Returns a `function` to wrap a component and make it themeable.
160160

161-
The returned component accepts a `theme` and `composeTheme` apart from the props of the original component. They are used to provide a `theme` to the component and to configure the style composition, which can be configured via options too. The function arguments are:
161+
The returned component accepts a `theme`, `composeTheme` and `innerRef` props apart from the props of the original component. They former two are used to provide a `theme` to the component and to configure the style composition, which can be configured via options too, while the latter is used to pass a ref callback to the decorated component. The function arguments are:
162162

163163
- `Identifier` *(String)* used to provide a unique identifier to the component that will be used to get a theme from context.
164164
- `[defaultTheme]` (*Object*) is classname object resolved from CSS modules. It will be used as the default theme to calculate a new theme that will be passed to the component.
165165
- `[options]` (*Object*) If specified it allows to customize the behavior:
166166
- [`composeTheme = 'deeply'`] *(String)* allows to customize the way themes are merged or to disable merging completely. The accepted values are `deeply` to deeply merge themes, `softly` to softly merge themes and `false` to disable theme merging.
167-
- [`withRef = false`] *(Boolean)* if true, stores a ref to the wrapped component instance and makes it available via `getWrappedInstance()` method. Defaults to false.
168167

169168
## About
170169

Diff for: index.d.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@ declare module "react-css-themr"
66
{
77
/** @default "deeply" */
88
composeTheme?: "deeply" | "softly" | false,
9-
/** @default false */
10-
withRef?: boolean
119
}
1210

1311
export interface ThemeProviderProps
1412
{
13+
innerRef?: Function,
1514
theme: {}
1615
}
1716

@@ -22,7 +21,7 @@ declare module "react-css-themr"
2221

2322
interface ThemedComponent<P, S> extends React.Component<P, S>
2423
{
25-
getWrappedInstance(): React.Component<P, S>;
24+
2625
}
2726

2827
interface ThemedComponentClass<P, S> extends React.ComponentClass<P>

Diff for: src/components/themr.js

+12-23
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,14 @@ import invariant from 'invariant'
88
/**
99
* @typedef {{}} TReactCSSThemrOptions
1010
* @property {String|Boolean} [composeTheme=COMPOSE_DEEPLY]
11-
* @property {Boolean} [withRef=false]
1211
*/
1312

1413
const COMPOSE_DEEPLY = 'deeply'
1514
const COMPOSE_SOFTLY = 'softly'
1615
const DONT_COMPOSE = false
1716

1817
const DEFAULT_OPTIONS = {
19-
composeTheme: COMPOSE_DEEPLY,
20-
withRef: false
18+
composeTheme: COMPOSE_DEEPLY
2119
}
2220

2321
const THEMR_CONFIG = typeof Symbol !== 'undefined' ?
@@ -32,7 +30,7 @@ const THEMR_CONFIG = typeof Symbol !== 'undefined' ?
3230
* @returns {function(ThemedComponent:Function):Function} - ThemedComponent
3331
*/
3432
export default (componentName, localTheme, options = {}) => (ThemedComponent) => {
35-
const { composeTheme: optionComposeTheme, withRef: optionWithRef } = { ...DEFAULT_OPTIONS, ...options }
33+
const { composeTheme: optionComposeTheme } = { ...DEFAULT_OPTIONS, ...options }
3634
validateComposeOption(optionComposeTheme)
3735

3836
let config = ThemedComponent[THEMR_CONFIG]
@@ -59,6 +57,7 @@ export default (componentName, localTheme, options = {}) => (ThemedComponent) =>
5957
static propTypes = {
6058
...ThemedComponent.propTypes,
6159
composeTheme: PropTypes.oneOf([ COMPOSE_DEEPLY, COMPOSE_SOFTLY, DONT_COMPOSE ]),
60+
innerRef: PropTypes.func,
6261
theme: PropTypes.object,
6362
themeNamespace: PropTypes.string
6463
}
@@ -74,9 +73,9 @@ export default (componentName, localTheme, options = {}) => (ThemedComponent) =>
7473
}
7574

7675
getWrappedInstance() {
77-
invariant(optionWithRef,
78-
'To access the wrapped instance, you need to specify ' +
79-
'{ withRef: true } as the third argument of the themr() call.'
76+
invariant(true,
77+
'DEPRECATED: To access the wrapped instance, you have to pass ' +
78+
'{ innerRef: fn } and retrieve with a callback ref style.'
8079
)
8180

8281
return this.refs.wrappedInstance
@@ -136,25 +135,15 @@ export default (componentName, localTheme, options = {}) => (ThemedComponent) =>
136135
}
137136

138137
render() {
139-
let renderedElement
140138
//exclude themr-only props
141139
//noinspection JSUnusedLocalSymbols
142-
const { composeTheme, themeNamespace, ...props } = this.props //eslint-disable-line no-unused-vars
143-
144-
if (optionWithRef) {
145-
renderedElement = React.createElement(ThemedComponent, {
146-
...props,
147-
ref: 'wrappedInstance',
148-
theme: this.theme_
149-
})
150-
} else {
151-
renderedElement = React.createElement(ThemedComponent, {
152-
...props,
153-
theme: this.theme_
154-
})
155-
}
140+
const { composeTheme, innerRef, themeNamespace, ...props } = this.props //eslint-disable-line no-unused-vars
156141

157-
return renderedElement
142+
return React.createElement(ThemedComponent, {
143+
...props,
144+
ref: innerRef,
145+
theme: this.theme_
146+
})
158147
}
159148
}
160149

Diff for: test/components/themr.spec.js

+7-45
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe('Themr decorator function', () => {
1010
class Passthrough extends Component {
1111
render() {
1212
const { theme, ...props } = this.props //eslint-disable-line no-unused-vars
13-
return <div {...props} />
13+
return <div ref={(node) => { this.rootNode = node }} {...props} />
1414
}
1515
}
1616

@@ -278,55 +278,18 @@ describe('Themr decorator function', () => {
278278
expect(stub.props.theme).toEqual({})
279279
})
280280

281-
it('should throw when trying to access the wrapped instance if withRef is not specified', () => {
282-
const theme = { Container: { foo: 'foo_1234' } }
283-
284-
@themr('Container')
281+
it('gets the reference to a decorated component using innerRef prop', () => {
285282
class Container extends Component {
286283
render() {
287284
return <Passthrough {...this.props} />
288285
}
289286
}
290287

291-
const tree = TestUtils.renderIntoDocument(
292-
<ProviderMock theme={theme}>
293-
<Container />
294-
</ProviderMock>
295-
)
296-
297-
const container = TestUtils.findRenderedComponentWithType(tree, Container)
298-
expect(() => container.getWrappedInstance()).toThrow(
299-
/To access the wrapped instance, you need to specify \{ withRef: true \} as the third argument of the themr\(\) call\./
300-
)
301-
})
302-
303-
it('should return the instance of the wrapped component for use in calling child methods', () => {
304-
const someData = {
305-
some: 'data'
306-
}
307-
308-
class Container extends Component {
309-
someInstanceMethod() {
310-
return someData
311-
}
312-
313-
render() {
314-
return <Passthrough />
315-
}
316-
}
317-
318-
const decorator = themr('Component', null, { withRef: true })
319-
const Decorated = decorator(Container)
320-
321-
const tree = TestUtils.renderIntoDocument(
322-
<Decorated />
323-
)
324-
325-
const decorated = TestUtils.findRenderedComponentWithType(tree, Decorated)
326-
327-
expect(() => decorated.someInstanceMethod()).toThrow()
328-
expect(decorated.getWrappedInstance().someInstanceMethod()).toBe(someData)
329-
expect(decorated.refs.wrappedInstance.someInstanceMethod()).toBe(someData)
288+
const spy = sinon.stub()
289+
const ThemedContainer = themr('Container')(Container)
290+
const tree = TestUtils.renderIntoDocument(<ThemedContainer innerRef={spy} />)
291+
const stub = TestUtils.findRenderedComponentWithType(tree, Container)
292+
expect(spy.withArgs(stub).calledOnce).toBe(true)
330293
})
331294

332295
it('should throw if themeNamespace passed without theme', () => {
@@ -510,7 +473,6 @@ describe('Themr decorator function', () => {
510473
)
511474

512475
const stub = TestUtils.findRenderedComponentWithType(tree, Passthrough)
513-
// expect(stub.props.theme).toEqual(containerTheme)
514476
expect(stub.props.themeNamespace).toNotExist()
515477
expect(stub.props.composeTheme).toNotExist()
516478
expect(stub.props.theme).toExist()

0 commit comments

Comments
 (0)