Skip to content

Commit

Permalink
feat(prop): add polymorphic type checking (#11)
Browse files Browse the repository at this point in the history
* feat(prop): add polymorphic type checking

* test(polymorphic): add tests

* docs(readme): polymorphic

* build(tsconfig): no implicit any
  • Loading branch information
danilowoz authored Apr 30, 2021
1 parent e6101b1 commit 003f70c
Show file tree
Hide file tree
Showing 11 changed files with 410 additions and 213 deletions.
10 changes: 4 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const ThemeColorText = styl(Text)(({ theme }) => ({
The `useTheme` hook let you access the currently active theme.

```jsx
import { useTheme, Provider as StyleProvider } from "react-native-styl"
import { useTheme, Provider as StyleProvider } from 'react-native-styl'

const Main = ({ children }) => {
const theme = useTheme()
Expand All @@ -113,9 +113,8 @@ const Main = ({ children }) => {
}

const App = () => {

return (
<StyleProvider theme={{ color: { brand: "blue" }}}>
<StyleProvider theme={{ color: { brand: 'blue' } }}>
<Main />
</StyleProvider>
)
Expand Down Expand Up @@ -148,7 +147,7 @@ const ExtendedText = styl(BaseText)({
</details>

<details>
<summary><strong>`as` prop:</strong></summary>
<summary><strong>Polymorphic elements: `as` prop</strong></summary>

Render a new styled component passing a valid React component to `as` prop:

Expand All @@ -165,8 +164,6 @@ const Base = styl(Text)({
</Base>
```

> Typescript is not yet supported [Help is needed to implement it](https://github.com/danilowoz/react-native-styl/issues/3).
</details>

<details>
Expand Down Expand Up @@ -285,6 +282,7 @@ This package was inspired by people's work on the following projects:
- [Glamorous-native.](https://github.com/robinpowered/glamorous-native)

### Special thanks to:

- [Airfordable](https://github.com/Airfordable);
- [Significa](https://github.com/significa).

Expand Down
50 changes: 27 additions & 23 deletions examples/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react'
import { SafeAreaView, ScrollView, Text, TouchableOpacity } from 'react-native'
import React, {useRef} from 'react';
import {SafeAreaView, ScrollView, Text, TouchableOpacity} from 'react-native';

import Highlighter from './SyntaxHighlight'
import { Provider, styl } from '../styl'
import Highlighter from './SyntaxHighlight';
import {Provider, styl} from '../styl';

/**
* Pieces
Expand All @@ -12,45 +12,47 @@ const Title = styl(Text)({
fontWeight: '700',
paddingTop: 32,
paddingHorizontal: 16,
})
});

const DynamicText = styl(Text)<{ color: string }>(({ props }) => ({
const DynamicText = styl(Text)<{color: string}>(({props}) => ({
padding: 16,
color: props.color,
}))
}));

const Theme: React.FC = ({ children }) => (
<Provider theme={{ primary: 'blue' }}>{children}</Provider>
)
const Theme: React.FC = ({children}) => (
<Provider theme={{primary: 'blue'}}>{children}</Provider>
);

const ColorTheme = styl(Text)(({ theme }) => ({
color: theme.primary,
const ColorTheme = styl(Text)(({theme}) => ({
color: (theme as any).primary,
padding: 16,
}))
}));

const BaseText = styl(Text)({
color: 'red',
})
});

const ExtendedText = styl(BaseText)({
color: 'green',
padding: 16,
})
});

const AsComp = styl(Text)({
padding: 16
})
padding: 16,
});

const PresetComp = styl((props) => (
<Text ellipsizeMode="tail" numberOfLines={1} {...props} />
))({ padding: 16 })
))({padding: 16});

const App = () => {
const ref = useRef();

return (
<SafeAreaView>
<ScrollView>
{/* */}
<Title>Styling native elements</Title>
<Title ref={ref}>Styling native elements</Title>
<Highlighter>
{`const Wrapper = styl(ScrollView)({
padding: 16
Expand Down Expand Up @@ -125,7 +127,9 @@ const ExtendedText = styl(BaseText)({

{/* */}
<Title>`as` prop</Title>
<AsComp as={TouchableOpacity}><Text>TouchableOpacity</Text></AsComp>
<AsComp as={TouchableOpacity}>
<Text>TouchableOpacity</Text>
</AsComp>

<Highlighter>
{`const AsComp = styl(Text)({
Expand All @@ -136,7 +140,7 @@ const ExtendedText = styl(BaseText)({
</Highlighter>
</ScrollView>
</SafeAreaView>
)
}
);
};

export default App
export default App;
36 changes: 36 additions & 0 deletions examples/styl/__snapshots__/styl.test.tsx.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`styl props \`as\` prop works properly > ScrollView 1`] = `
<RCTScrollView
scrollEnabled={true}
style={
Array [
Object {
"color": "blue",
},
Object {},
]
}
>
<View>
<Text>
TouchableWithoutFeedback
</Text>
</View>
</RCTScrollView>
`;

exports[`styl props \`as\` prop works properly > TouchableWithoutFeedback 1`] = `
<Text
accessible={true}
focusable={true}
onClick={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
>
TouchableWithoutFeedback
</Text>
`;

exports[`styl props \`as\` prop works properly 1`] = `
<Text
accessible={true}
Expand Down
4 changes: 2 additions & 2 deletions examples/styl/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { styl, Provider } from './styl'
import { styl, Provider, DefaultTheme, useTheme } from './styl'

export { styl, Provider }
export { styl, Provider, DefaultTheme, useTheme }
export default styl
82 changes: 67 additions & 15 deletions examples/styl/styl.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import React, { useRef } from 'react'
import { Text, TouchableWithoutFeedback } from 'react-native'
import { ScrollView, Text, TouchableWithoutFeedback } from 'react-native'
import renderer from 'react-test-renderer'
import { renderHook } from '@testing-library/react-hooks'

import { styl, Provider } from '.'

type TempTheme = { theme: { primary: string } }
import { styl, Provider, useTheme } from '.'

describe('styl', () => {
describe('render', () => {
Expand All @@ -17,7 +16,7 @@ describe('styl', () => {

it('renders a type of original component', () => {
const Title = styl(Text)({})
const tree = renderer.create(<Title />).toJSON()
const tree = renderer.create(<Title />).toTree()

expect(tree?.type).toBe('Text')
expect(tree).toMatchSnapshot()
Expand Down Expand Up @@ -71,11 +70,16 @@ describe('styl', () => {

describe('props', () => {
it('renders custom props', () => {
const GOAL = 'blue'
const Title = styl(Text)<{ color: string }>(({ props }) => ({
enum GOAL {
'blue' = 'blue',
}

const Title = styl(Text)<{ color: GOAL }>(({ props }) => ({
color: props.color,
}))
const render = renderer.create(<Title color={GOAL} />)
const render = renderer.create(
<Title as={() => null} color={GOAL.blue} />
)

// Check tree
const tree = render.toTree()
Expand All @@ -86,7 +90,7 @@ describe('styl', () => {
expect(json).toMatchSnapshot()
})

it('`as` prop works properly', () => {
it('polymorphic > TouchableWithoutFeedback', () => {
const ORIGINAL = Text
const GOAL = TouchableWithoutFeedback

Expand All @@ -111,6 +115,43 @@ describe('styl', () => {
tree?.props.onPress()
expect(fn).toBeCalled()
})

it('polymorphic > ScrollView', () => {
const ORIGINAL = Text
const GOAL = ScrollView

const Comp = styl(ORIGINAL)({ color: 'blue' })

const render = renderer.create(
<Comp as={GOAL} scrollEnabled>
<Text>TouchableWithoutFeedback</Text>
</Comp>
)

// Check tree
const tree = render.toTree()
expect(tree?.instance instanceof GOAL).toBe(true)

// Snapshot
const json = render.toJSON()
expect(json).toMatchSnapshot()
})

it('polymorphic > ref', () => {
let ref = useRef<ScrollView>()

const Title = styl(Text)<{ color: string }>({})

const Element = () => {
// reassign in a new context
ref = useRef<ScrollView>()
return <Title />
}

renderer.create(<Element />).toJSON()

expect(ref.current instanceof Text).toBe(true)
})
})

describe('theme/provider', () => {
Expand All @@ -121,7 +162,7 @@ describe('styl', () => {
<Provider theme={{ primary: GOAL }}>{children}</Provider>
)

const Title = styl(Text)(({ theme }: TempTheme) => ({
const Title = styl(Text)(({ theme }: any) => ({
color: theme.primary,
}))

Expand All @@ -131,7 +172,7 @@ describe('styl', () => {
<Title />
</ProviderTheme>
)
.toJSON()
.toTree()

expect(render?.props.style.color).toBe(GOAL)
expect(render).toMatchSnapshot()
Expand All @@ -149,7 +190,7 @@ describe('styl', () => {
<Provider theme={{ primary: GOAL }}>{children}</Provider>
)

const Title = styl(Text)(({ theme }: TempTheme) => ({
const Title = styl(Text)(({ theme }: any) => ({
color: theme.primary,
}))

Expand All @@ -161,21 +202,32 @@ describe('styl', () => {
</ThemeB>
</ThemeA>
)
.toJSON()
.toTree()

expect(render?.props.style.color).toBe(GOAL)
expect(render).toMatchSnapshot()
})

it('useTheme', () => {
const theme = { color: 'red' }
const wrapper: React.FC = ({ children }) => (
<Provider theme={theme}>{children}</Provider>
)

const { result } = renderHook(() => useTheme(), { wrapper })

expect((result.current as typeof theme).color).toBe(theme.color)
})
})

describe('ref', () => {
it('gets proper ref', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let ref: any
let ref = useRef<Text>()

const Title = styl(Text)({})

const Element = () => {
// reassign in a new context
ref = useRef<Text>()
return <Title ref={ref} />
}
Expand Down
Loading

0 comments on commit 003f70c

Please sign in to comment.