Skip to content

Commit

Permalink
V0.2
Browse files Browse the repository at this point in the history
  • Loading branch information
hamlim committed Jan 18, 2021
1 parent 453d063 commit a2c3d4f
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 51 deletions.
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,12 @@ let simpleProps = createSimpleProps({
property: 'backgroundColor',
scale: 'color',
},
p({ prop, value, props }) {
return {
paddingLeft: `var(--space-${value})`,
paddingRight: `var(--space-${value})`,
paddingBottom: `var(--space-${value})`,
paddingTop: `var(--space-${value})`,
}
},
},
pseudoProps: {
_hover: '&:hover',
_focus: '&:focus',
},
breakpoints: [200, 400, 800],
})

// Either pull in your favorite CSS-in-JS library...
Expand All @@ -44,8 +41,25 @@ function Box(props) {
let styles = simpleProps(props)
return <div {...props} style={styles} />
}

// or use it to generate styles staticly:
let styles = simpleProps({
_focus: {
color: 'primary',
},
_hover: {
color: 'secondary',
},
bg: 'white',
})
```

Supports:

- Generating static styles
- Pseudo-props for pseudo selectors
- Responsive prop values for different values at different breakpoints

### Tools:

- Typescript
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simple-props",
"version": "0.1.0",
"version": "0.2.0",
"main": "dist/index.js",
"source": "src/index.tsx",
"types": "dist/index.d.ts",
Expand Down
88 changes: 88 additions & 0 deletions src/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,91 @@ test('supports creating your own variables', () => {
}
`)
})

test('supports pseudo props', () => {
let simpleProps = createSimpleProps({
props: {
color: true,
},
pseudoProps: {
_hover: '&:hover',
},
})

let styles = simpleProps({
color: 'primary',
_hover: {
color: 'secondary',
},
})

expect(styles).toMatchInlineSnapshot(`
Object {
"&:hover": Object {
"color": "var(--color-secondary)",
},
"color": "var(--color-primary)",
}
`)
})

test('supports responsive props', () => {
let simpleProps = createSimpleProps({
props: {
color: true,
},
breakpoints: [200, 400, 800],
})

let styles = simpleProps({
color: {
_: 'primary',
200: 'secondary',
800: 'white',
},
})

expect(styles).toMatchInlineSnapshot(`
Object {
"@media screen and (min-width: 200px)": Object {
"color": "var(--color-secondary)",
},
"@media screen and (min-width: 800px)": Object {
"color": "var(--color-white)",
},
"color": "var(--color-primary)",
}
`)
})

test('supports custom media queries for responsive props', () => {
let simpleProps = createSimpleProps({
props: {
color: true,
},
breakpoints: [200, 400, 800],
createMediaQuery({ query }) {
return `@media screen and (max-width: ${query}px)`
},
})

let styles = simpleProps({
color: {
_: 'primary',
200: 'secondary',
800: 'white',
},
})

expect(styles).toMatchInlineSnapshot(`
Object {
"@media screen and (max-width: 200px)": Object {
"color": "var(--color-secondary)",
},
"@media screen and (max-width: 800px)": Object {
"color": "var(--color-white)",
},
"color": "var(--color-primary)",
}
`)
})
144 changes: 102 additions & 42 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,85 +1,145 @@
import * as CSS from 'csstype'

export type FindProp = (
configuredProps: Array<string>,
propName: string,
) => string | void

function defaultFindPropInPropConfig(
configuredProps: Array<string>,
propName: string,
): string | void {
return configuredProps.find((prop) => {
return prop === propName
})
}

export type ToVariable = ({
scale,
value,
props,
breakpoint,
}: {
scale: string
value: any
props: { [name: string]: any }
breakpoint: string | number
}) => string

function defaultToVariable({ scale, value }) {
return `var(--${scale}-${value})`
}

interface Props {
[name: string]:
| (({
prop,
value,
props,
}: {
prop: string
value: string | number | object
props: object
}) => object)
| { scale: string; property: string }
| boolean
[name: string]: { scale: string; property: string } | boolean
}
export interface PseudoProps {
[name: string]: string
}

export type Breakpoints = Array<string | number>

export type CreateMediaQuery = ({ query }: { query: string }) => string

function defaultCreateMediaQuery({
query,
}: {
query: string | number
}): string {
// @ts-ignore
let appendPx = typeof query === 'number' || Number(query) == query
let units = appendPx ? 'px' : ''
return `@media screen and (min-width: ${query}${units})`
}

function sortByAllFirst(a: string, b: string): number {
if (a === '_') {
return -1
} else if (b === '_') {
return 1
} else {
// @ts-ignore
return a - b
}
}

export type SimpleProps = (props: { [name: string]: any }) => CSS.Properties

export default function createSimpleProps({
props: propConfig,
findPropInPropConfig = defaultFindPropInPropConfig,
pseudoProps: pseudoConfig = {},
breakpoints = undefined,
toVariable = defaultToVariable,
createMediaQuery = defaultCreateMediaQuery,
}: {
props: Props
findPropInPropConfig?: FindProp
pseudoProps?: PseudoProps
breakpoints?: Breakpoints
toVariable?: ToVariable
createMediaQuery?: CreateMediaQuery
}): SimpleProps {
let configuredProps = Object.keys(propConfig)
let breakpointsProvided = Array.isArray(breakpoints)
return function simpleProps(props) {
let styles = {}
// color="primary" p={{_: 0, 360: 4}}
for (let prop in props) {
let foundProp = findPropInPropConfig(configuredProps, prop)
if (foundProp) {
// prop === "color" or prop === "p"
let propValue = props[prop]
let isSimpleProp = prop in propConfig
let isPseudoSimpleProp = prop in pseudoConfig

if (isPseudoSimpleProp) {
// prop === _hover
// propValue === { color: 'primary' }
// @TODO? Responsive pseudo props?
let rawPseudo = pseudoConfig[prop]
let pseudoStyles = simpleProps(propValue)

styles = {
...styles,
[rawPseudo]: pseudoStyles,
}
}

if (isSimpleProp) {
let scale, property
let resolvedConfig = propConfig[foundProp]
let resolvedConfig = propConfig[prop]
if (typeof resolvedConfig === 'boolean') {
scale = property = prop
} else if (typeof resolvedConfig === 'function') {
} else {
scale = resolvedConfig.scale
property = resolvedConfig.property
}
if (
breakpointsProvided &&
typeof propValue === 'object' &&
propValue != null
) {
// _, 360
let queries = Object.keys(propValue).sort(sortByAllFirst)
styles = queries.reduce((newStyles, query) => {
if (query === '_') {
return {
...newStyles,
[property]: toVariable({
scale,
value: propValue[query],
props,
breakpoint: query,
}),
}
}
let queryKey = createMediaQuery({ query })
return {
...newStyles,
[queryKey]: {
...(newStyles[queryKey] || {}),
[property]: toVariable({
scale,
value: propValue[query],
props,
breakpoint: query,
}),
},
}
}, styles)
} else {
// non-responsive prop values
styles = {
...styles,
...resolvedConfig({
prop,
[property]: toVariable({
scale,
value: props[prop],
props,
breakpoint: '_',
}),
}
} else {
scale = resolvedConfig.scale
property = resolvedConfig.property
}
styles = {
...styles,
[property]: toVariable({ scale, value: props[prop], props }),
}
}
}
Expand Down

0 comments on commit a2c3d4f

Please sign in to comment.