New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

@jongold/st

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jongold/st

Functional styling

latest
Source
npmnpm
Version
0.1.1
Version published
Maintainers
1
Created
Source

st

npm CircleCI FantasyLand

styling for functional UIs

  • algebraic style composition
  • compose evolutions & transformations
  • abstract interaction with props

Usage

import Style from '@jongold/st';
import { add, always, compose as c, evolve } from 'ramda';
import chroma from 'chroma';
import { Touchable, View } from 'react-primitives'; // or react-native etc

// define some abstract style transformations
// bumpFontSize :: CSS -> CSS
const bumpFontSize = evolve({
  fontSize: add(4),
});

// darkenText :: CSS -> CSS
const darkenText = evolve({
  color: c => chroma(a).darken(),
});

// brandify :: CSS -> CSS
const brandify = evolve({
  fontFamily: always('Circular Air Pro'),
});

// and some primitive styles
const boxShadow = {
  boxShadow: '0 2px 3px rgba(0,0,0,.25)',
};

// encapsulate a style that varies on props
const GenericButtonStyle = Style(props => ({
  fontSize: 16,
  fontWeight: 'bold',
  fontFamily: 'SF UI Display'
  backgroundColor: props.primary ? 'green' : 'blue',
  color: 'white',
}));

// and maybe another transform
// that relies on more props
const outlineify = style => Style(props => ({
  ...style,
  border: props.outline ? '1px solid currentColor' : 'none',
  color: props.outline ? style.backgroundColor : style.color,
  backgroundColor: props.outline ? 'transparent' : style.backgroundColor,
}));

// compose some of those transformations
const MyButtonStyle = GenericButtonStyle.map(
  c(bumpFontSize, darkenText, brandify)
).concat(boxShadow).chain(outlineify);

// associative, so could be written as
const MyButtonStyle = GenericButtonStyle
  .map(bumpFontSize)
  .map(darkenText)
  .map(brandify)
  .concat(boxShadow)
  .chain(outlineify);

// Notice that we have passed in any props yet
// so neither GenericButtonStyle nor MyButton
// are complete.

// Let's use it in context. I'm using Flow +
// react-primitives but neither are necessary
type P = {
  children: string,
  primary: bool,
  outline: bool,
  onPress: () => void,
}
const MyButton = (props: P) =>
  <Touchable onPress={props.onPress}>
    <View style={MyButtonStyle.resolve(props)}>
      { props.children }
    </View>
  </Touchable>

<MyButton primary={true} />
// => rendered View has style:
// {
//   fontSize: 20,
//   fontWeight: 'bold',
//   fontFamily: 'Circular Air Pro',
//   backgroundColor: 'darkGreen',
//   color: 'white',
//   boxShadow: '0 2px 3px rgba(0,0,0,.25)',
// }

<MyButton primary={false} outline={true} />
// => rendered View has style:
// {
//   fontSize: 20,
//   fontWeight: 'bold',
//   fontFamily: 'Circular Air Pro',
//   color: 'darkBlue',
//   backgroundColor: 'transparent',
//   border: '1px solid darkBlue',
//   boxShadow: '0 2px 3px rgba(0,0,0,.25)',
// }

Interoperability

Fantasy Land

St implements FantasyLand 1, FantasyLand 2, FantasyLand 3 compatible Semigroup, Monoid, Functor, Apply, Applicative, Chain, ChainRec and Monad.

Table of contents

Documentation

Type signatures

Hindley-Milner type signatures are used to document functions. Signatures starting with a . refer to "static" functions, whereas signatures starting with a # refer to functions on the prototype.

A list of types used within the signatures:

  • Style - Instances of Style provided by St
  • Props - any JS prop object
  • CSS - raw CSS style objects

Creating Styles

Style

Style :: => (Props -> CSS) -> Style CSS
Style(props => ({
  backgroundColor: props.color,
  fontSize: 16,
});
// Style({ backgroundColor: __color__, fontSize: 16 })

of

.of :: a -> Style a

applicative

Style.of({
  backgroundColor: 'red',
  fontSize: 16,
});
// Style({ backgroundColor: 'red', fontSize: 16, });

Transforming Styles

concat

#concat :: Style a ~> Style a ~> Style a

semigroup

Style.of({ fontWeight: 'bold', fontSize: 14 }).concat({ fontSize: 16, backgroundColor: 'red' })
// Style({ fontWeight: 'bold', fontSize: 16, backgroundColor: 'red' }))

empty

.empty :: () -> Style _

monoid

Style.empty()
// Style({})

map

#map :: Style a ~> (a -> b) -> Style b

functor

Style.of({
  backgroundColor: 'red',
  fontSize: 14
}).map(style => ({
  ...style,
  fontSize: 16
});
// Style({ backgroundColor: 'red, fontSize: 16 }))

Style.of({
  backgroundColor: 'red',
  fontSize: 14
}).map(evolve({
  fontSize: x => x * 2
});
// { backgroundColor: 'red, fontSize: 24 })

chain

#chain :: Style a ~> Style a -> Style a

chain

wip

ap

#ap :: Style (a -> b) ~> Style a -> Style b

apply

Style.of(style => ({
  ...style,
  fontSize: style.fontSize * 2,
}).ap({ color: 'red', fontSize: 14 })
//

Consuming styles

resolve

#resolve :: Style a ~> Props -> CSS
const st = Style(props => ({
  backgroundColor: props.primary ? 'green' : 'gray',
  fontSize: 16,
})).map(evolve({ fontSize: add(2) }))

st.resolve({ title: 'sign up', primary: true })
// { backgroundColor: 'red', fontSize: 18 }

e.g., in a render function

const Button = props =>
  <button style={st.resolve(props)}>
    { props.children }
  </button>
// <button style="background-color: 'red', font-size: 18">sign up</button>

Contributors

Made with love and monads by (emoji key):


Jon Gold

📖 💡 👀

James Baxley

💻

Keywords

fantasyland

FAQs

Package last updated on 14 Mar 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts