Awesome
<h1 align="center">Prism</h1> <p align="center">Minimal, idiomatic style management for React Native.</p> <p align="center"> <img width="256" height="256" src="https://raw.githubusercontent.com/tmpfs/prism/master/prism.png" /> </p>Installation
Use your preferred package manager for installation.
npm i --save react-native-prism
yarn add react-native-prism
Synopsis
Prism is a library that returns a Higher Order Component (HOC) exposing access to a style registry containing user-defined colors, fonts and styles.
It provides a simple yet flexible mechanism for mapping properties to styles and finding style declarations in the registry.
For any non-trival RN application the question arises on how to manage styles for your components. The Prism library provides a solution using idiomatic techniques that will leave your JSX clean and serene allowing you to focus on your application's state and logic.
If you want to migrate an existing application you should start with Prism Primitives which provides a drop-in replacement for the RN visual components. See Prism Components for some slightly more advanced components; if you want to see a running application clone and run the RN app in the Prism Components repository.
Getting Started
Defining Styles
To configure your application stylesheets first create a theme with some styles, colors and fonts.
File: theme.js
export default {
colors: {
bg: 'steelblue',
highlight: '#fdfbdf',
normal: '#9a9a9a'
},
fonts: {
regular: 'WorkSans-Regular',
medium: 'WorkSans-Medium'
},
styles: ({colors, fonts}) => {
return {
Label: {
fontSize: 20,
fontFamily: fonts.regular,
color: colors.normal
},
bold: {
fontFamily: fonts.medium
}
}
}
}
Styles
Styles are declared as a function that is passed the style registry, typically you only need access to the colors and fonts.
Colors
Colors are a map from color name to string value. Use of custom color names is optional but it can help make your styles more semantic.
Fonts
Fonts are a map from font identifier to string font family name.
{regular: 'WorkSans-Regular'}
Because Android uses the file name and iOS uses the PostScript name the easiest thing to do is name your fonts using the PostScript name otherwise use platform styles.
Application Configuration
To configure your application create a style registry with your theme and instruct your components to use it:
File: App.js
import React, {Component} from 'react';
import {Prism, StyleRegistry} from 'react-native-prism'
import theme from './theme'
import Label from './Label'
const registry = new StyleRegistry({theme})
Prism.configure(
registry,
{
extendedProperties: true,
fontProperties: true,
experimentalPlugins: true,
textTransform: true,
colorNames: true
}
)
export default class Application extends Component {
render () {
return (
<Label
background='bg'
color='highlight'
bold
align='center'
textTransform='capitalize'
padding={15}>
Prism example application
</Label>
)
}
}
With the extendedProperties
option all the built in and extended style properties are available.
Note that you should import
all your Prism enabled components before calling configure()
.
Components
Defining Styled Components
To create a styled component you just need to pass the component class to the Prism
function which will return the HOC component.
import {View} from 'react-native'
import {Prism} from 'react-native-prism'
export default Prism(View, 'View')
Here is a working example for the application shown above.
File: Label.js
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {Text} from 'react-native'
import {Prism} from 'react-native-prism'
class Label extends Component {
static styleName = 'Label'
static styleOptions = {
supportsText: true
}
render () {
// Get the computed style sheet
const {style} = this.props
return (
<Text style={style}>{this.props.children}</Text>
)
}
}
export default Prism(Label)
Because the component configured styleName
with Label
the style rule we created earlier already provides styles for our new component!
Quick Components
Prism.style(Type, style, props)
Sometimes you want to wrap a component using fixed styles without too much fuss, use Prism.style()
to wrap a component with basic styles.
This is particularly useful when you just want to draw a shape, a convoluted example to illustrate inheritance:
const Rectangle = Prism.style(
View,
{
flex: 0,
width: 20,
height: 20,
// Set absolute minimum color (defaultProps.style)
backgroundColor: 'red'
},
{
// Override backgroundColor with extended property
background: 'green'
}
)
// Use the green background
<Rectangle />
// Resize and use a blue background
<Rectangle width={50} height={50} background='blue' />
Bundling Styles
Component libraries should supply a style registry which is merged with the user-supplied registry to bundle their default styles. Pass a theme and the bundle
flag to a style registry assigned to the component, here is how we wire it up:
import {Prism, StyleRegistry} from 'react-native-prism'
const namespace = 'prism'
const theme = {
styles: () => {
return {
'prism|Label': {
fontSize: 22,
color: 'white',
backgroundColor: 'black'
}
}
}
}
const registry = new StyleRegistry({theme, bundle: true})
class Label extends Component {
static styleName = 'Label'
static styleOptions = {
registry: registry
}
}
export default Prism(Label, {namespace})
Then a user of the component can just overwrite the declarations they need to change:
'prism|Label': {
color: 'black',
backgroundColor: 'white'
}
The default fontSize
is respected but now the colors are inverted!
An example of bundling default styles for a component library is in the Layout and corresponding theme for Prism Components.
Default Styles
It is recommended that you bundle styles using a theme and style registry however it is possible to set the bare minimum styles for a component with defaultProps
, to do so you use an object named using the corresponding property:
static defaultProps = {
style: {
fontSize: 16,
color: 'black'
}
}
We can declare default styles for child components too.
static mapPropsToStyle = {
labelStyle: {}
}
static defaultProps = {
style: {
flex: 1
},
labelStyle: {
fontSize: 16,
color: 'black'
}
}
Style Names
You must give your component a styleName
which becomes the default style to use for the component. If a component is namespaced this does not affect the namespace it affects the class name. An earlier version of prism inferred the style name from the class name but this will not work in release builds as the name of a function is not guaranteed after name mangling.
The styleName
static declaration is preferred:
class Label extends Component {
// Look up a style sheet using selector `Label` by default
static styleName = 'Label'
}
Alternatively you can pass a string or styleName
option to Prism:
// Same as above, use `Label` as selector
export default Prism(Label, 'Label')
// Use `prism|Label` as the selector
export default Prism(Label, {namespace: 'prism', styleName: 'Label'})
Style Name Property
You may pass a styleName
property to any component and it will overwrite the static styleName
defined by the component just for that instance.
This allows you to create completely different groups of styles for an existing component without defining a wrapper component class. For example, it is common to want two or more completely different button styles.
If you pass styleName
to a button component:
<TouchButton styleName='TextButton'>
Label Text
</TouchButton>
You can now style it using the assigned style name:
export default {
'prism|TextButton': {
/* TextButton does not have a background style */
},
'prism|TextButton label': {
color: 'white'
},
'prism|TextButton label:disabled': {
color: '#999999'
}
}
Notice that the namespace for the component definition is respected.
Mapping Properties To Styles
Components have varied needs for mapping properties to style declarations so the library provides several ways to map properties depending upon the requirement.
Each of the mapping options may be either a function or object, when it is a function it is passed the style registry and should return an object.
Prism is flexible with these declarations, the static
style is the most terse and preferred when other styleOptions
are not needed:
The following are all equivalent:
static mapPropsToStyle = {
bold: ({styleSheet}) => styleSheet.bold
}
static styleOptions = {
mapPropsToStyle: ({styleSheet}) => {
return {
bold: () => styleSheet.bold
}
}
}
static styleOptions = ({styleSheet}) => {
return {
mapPropsToStyle: {
bold: () => styleSheet.bold
}
}
}
mapPropsToStyle
Use mapPropsToStyle
when you want the presence of a property to trigger inclusion of styles into the computed style. Each object key maps to a property name and the corresponding function is called when the property is defined on the component.
You have access to all the properties so you can apply styles conditionally based on other properties:
static mapPropsToStyle = {
space: ({prop, props}) => {
const {horizontal} = props
const styleProp = horizontal ? 'marginRight' : 'marginBottom'
const style = {}
style[styleProp] = prop
return style
}
}
Functions declared in this way have access to the style registry and it's properties (colors
etc) the props
, current prop
and propName
. Functions should return a style object or array of objects to be included in the computed styles, to take no action return undefined
.
When the passed prop
is returned a style rule is created using the property name and value which is useful when the property name matches the style property name:
{color: ({prop}) => prop}
Is shorthand for:
{
color: ({prop}) => {
return {color: prop}
}
}
Pseudo State
If you call css.pseudo()
with a string a style sheet is resolved using the familiar a:hover
syntax.
For a component called Notice
:
static mapPropsToStyle = {
error: ({css, prop, propName}) => {
if (prop === true) {
// Include the style for Notice:error
return css.pseudo(propName)
}
}
}
Would result in including the rule for Notice:error
when the error
property is true
:
{
'Notice:error': {
backgroundColor: 'red',
color: 'white'
}
}
<Notice error>Error message</Notice>
This can be an easy way to trigger style variations that are resolved from the style sheet based on a property value. For example, if you have a size
property that accepts small|medium|large
you can do:
static mapPropsToStyle = {
size: ({css, prop}) => css.pseudo(prop)
}
To resolve a style sheet for the value of size
, eg: Notice:small
, Notice:medium
or Notice:large
.
Child Components
For composite components you can route properties to styles that you apply to child components.
At it's simplest level the empty object just declares that your component wants a style object to pass to a child, but you can also route properties to child style objects:
static mapPropsToStyle = {
headerStyle: {
color: ({prop}) => prop
},
bodyStyle: {}
}
Which will define and create the headerStyle
and bodyStyle
properties for your component and route the color
property in to the headerStyle
object. The propTypes
for the child style objects are automatically declared as we know ahead of time they should have the same property type as style
.
The immediate benefit is that you can now define style rules for the child components which will automatically be resolved as default styles.
'Panel header': {
color: 'blue',
padding: 10
},
'Panel body': {
padding: 20
}
For style declaration lookup the child component name is determined by the property name with any Style
suffix removed. If the component is namespaced use the fully qualified name, eg: prism|Panel header
.
Then your render should route the properties to child components, for example:
render () {
const {style, headerStyle, bodyStyle, label} = this.props
return (
<View style={style}>
<Text style={headerStyle}>
{label}
</Text>
<View style={bodyStyle}>
{this.props.children}
</View>
</View>
)
}
Now use of the color
property on the parent is directed to the headerStyle
object (and therefore the child component):
<Panel color='red' />
You can combine css.pseudo()
with multiple child components to create some interesting behaviour:
static mapPropsToStyle = {
titleStyle: {
size: ({css, prop}) => css.pseudo(prop)
},
numberStyle: {
size: ({css, prop}) => css.pseudo(prop)
}
}
For a component NumberStack
:
<NumberStack size='medium' />
Will resolve NumberStack title:small
to include in titleStyle
and NumberStack number:small
for the numberStyle
.
mapStyleToProps
This is the inverse mapping that extracts a style property and assigns it as a property on the component.
It is recommended to only use mapStyleToProps
when you absolutely must as it requires flattening the computed styles.
static mapStyleToProps = {
tintColor: ({prop}) => prop
}
Typically this is used to deal with invariants as in the example above which allows your component to respect tintColor
in a style rule:
Activity: {
tintColor: 'purple'
}
And have it extracted to a property on the component:
render () {
const {style, tintColor} = this.props
return (
<View style={style}>
<ActivityIndicator tintColor={tintColor} />
</View>
)
}
See Activity.js for a complete implementation.
Component State
For most use cases when you are triggering state changes from a property mapPropsToStyle
and css.pseudo()
will do the job just fine (see pseudo state). However there are times when you need finer control over style invalidation as the component state changes.
To enable state invalidation you need to specify the withState
configuration option and enable supportsState
in your component:
static styleOptions = {
supportsState: true
}
A typical scenario is when you are managing state based on events from a child component and want the state change to be reflected in the styles.
render () {
const toggle = () => this.setState({active: !this.state.active})
return (
<ChildComponent onPress={toggle} />
)
}
Once state invalidation is enabled you can do:
static mapPropsToStyle = {
state: ({state, css}) => {
if (state.active) {
return css.pseudo('active')
}
}
}
To add the :active
pseudo class to the component when state.active
is true. If you want the state change to automatically be applied to child components you can use the cascadeState
option:
static styleOptions = {
supportsState: true,
cascadeState: true
}
static mapPropsToStyle = {
state: ({state, css}) => {
if (state.active) {
return css.pseudo('active')
}
}
// We don't need to declare a state handler
// for these as `cascadeState` is enabled
// the `:active` pseudo class will be triggered
// for these styles automatically
headerStyle: {},
footerStyle: {}
}
You should try to match the default style of your component to the default state but you can trigger invalidation of the styles using the initial component state when it mounts by declaring the mountStateStyle
option for your component.
static styleOptions = {
supportsState: true,
mountStateStyle: true
}
Lifecycle
The component state functionality decorates your component with a simple lifecycle that lets you decide when state changes should trigger style invalidation.
By default as soon as you enable this feature every call to setState()
will trigger invalidation of the styles but you can implement shouldStyleUpdate()
on your component to control this behaviour.
shouldStyleUpdate
shouldStyleUpdate(state, newState)
Implement this function to control whether to invalidate the styles when the state changes, it should return a boolean.
Options
supportsState
opt-in to state style invalidation.cascadeState
call primary state handler for child component styles.mountStateStyle
automatically invalidate using the state of the component when it mounts.
Property Type Validation
It is important to know that the propTypes
you declare are assigned to the HOC so properties work as expected and that your static propTypes
are augmented with all the style properties.
Built in propTypes
are merged first so your propTypes
will win if there is a property name collision however the behaviour is undefined so you should take care that your propTypes
do not conflict.
If you need it the Prism.propTypes
field exposes the system property types.
Namespaces
The Prism
function accepts a namespace option which can be used to specify a namespace for your component. This is useful (and recommended) when designing reusable component sets.
const namespace = 'prism'
class Label extends Component {
static styleName = 'Label'
/* ... */
}
export default Prism(Label, {namespace})
Now the default component style declaration name uses CSS-style namespaces prism|Label
and a consumer needs to declare the style using the fully qualified name:
'prism|Label': {
color: 'black'
}
Requirements
Sometimes a component or library of components needs certain conditions to be met to be able to work correctly.
You may pass a requirements
option to Prism()
which is a function passed the registry
and config
and can be used to validate the component requirements.
Here is an example from the Prism Components:
const requirements = ({config}) => {
if (config.extendedProperties !== true) {
return `extendedProperties must be set in config ` +
`to use the ${namespace} component library`
}
}
export default Prism(Layout, {requirements})
If the component requirements are not met you can throw an error or return an error or a string. When a string is returned it is wrapped in an error and thrown.
Note that you can use this technique to validate style rules exist, for example:
const requirements = ({registry}) => {
if (!registry.has('bold')) {
return `bold style rule is required`
}
}
Properties
Style Properties
By default plugins are enabled that expose the following properties on all styled components.
The property mapping API and these properties should be sufficient for most applications and indeed it would be considered best practice not to use the extended and experimental properties so that all styling information can be maintained in a single file.
style
Array | Object
Inline styles for the component.
className
String | Array<String>
Assign stylesheets to the component. When a string is given separate stylesheet names should be delimited with whitespace.
The declaration in the style sheet should use a dot prefix as is the CSS convention:
'.highlight': {
color: 'orange'
}
Extended Style Properties
Extended properties allow for rapidly mocking layouts with a variety of convenient shortcuts for common style properties. Enable the extendedProperties
option to use these properties.
Some extended properties require a component opt-in using styleOptions
for the style to be applied, for example to receive the color
property:
static styleOptions = () => {
return {
supportsText: true
}
}
supportsText
: Component can receive text style props.supportsDimension
: Component can receivewidth
andheight
.
Note that the supportsText
option is also used to test whether a component can receive textTransform
on it's children.
background
String
Set the backgroundColor
style property.
border
String | Array | Object
Enables a border for the component, this shortcut is great for quickly visualizing component dimensions.
When a string is given borderColor
is set and a default borderWidth
is used.
When an array is given it takes the form [width, color]
.
{
color: 'red',
top: 0,
right: 0,
bottom: 0,
left: 0
}
Note that not all RN components will set borders as expected when different widths are given for each side, if you experience problems with this syntax ensure the style is applied to a View
rather than Image
etc.
padding
Number | Object | Array
Sets padding properties, a number sets all edges to be equal.
Arrays are a shorthand for setting vertical and horizontal values and take the form: [vertical, horizontal]
.
{top: 0, right: 0, bottom: 0, top:0}
[5,10]
margin
Number | Object | Array
Sets margin properties, a number sets all edges to be equal.
Arrays are a shorthand for setting vertical and horizontal values and take the form: [vertical, horizontal]
.
{top: 0, right: 0, bottom: 0, top:0}
[5,10]
flex
Number | Boolean | Object
Shorthand for flex
properties. A number is assigned directly to the flex
style property, boolean is coerced to a number (yields zero or one).
Object notation supports the grow
, row
and wrap
fields:
{
grow: 1,
row: true,
wrap: true
}
The row
boolean sets flexDirection
, wrap
sets flexWrap
and grow
sets the flex
property.
row
Boolean
Set the flexDirection
style property to row
.
wrap
Boolean
Set the flexWrap
style property.
justify
Enum<String> (center|start|end|between|around)
Set the justifyContent
style property, note that the flex-
prefixes are omitted.
position
Object
Makes a component absolutely positioned (relative to the parent as is the RN way) and sets the style properties to the given values.
{top: 0, right: 0, bottom: 0, top:0}
radius
Number | Object
Sets border radius style properties.
{
top: {left: 0, right: 0},
bottom: {left: 0, right: 0}
}
width
Number | String
Pass the width
property into the computed style, requires the supportsDimension
flag.
height
Number | String
Pass the height
property into the computed style, requires the supportsDimension
flag.
Font Properties
When the fontProperties
option is given these properties are configured.
Only Text
and TextInput
components can accept these style properties so components that wish to receive them in their computed stylesheet must specify the supportsText
option.
color
String
Set the color
style property.
align
Enum<String> (left|center|right)
Sets the textAlign
style property.
bold
Boolean
Looks for a style rule named bold
and returns it if available otherwise sets fontWeight
to bold
.
font
The font
property provides a convenient shortcut for all the Text Style Props and can be useful if you have a lot of inline text styling.
Note that to propagate down to children this property requires that experimentalPlugins
is enabled so that context
is used, see experimental properties.
An example using Prism Components:
<Layout font={{size: 'large', color: 'red'}}>
<Layout>
<Label>Red text</Label>
<Label font={{color: 'green'}}>
Font style properties combined with those inherited from the grandparent
</Label>
</Layout>
</Layout>
The shape of the font object is described in propTypes.js.
Experimental Properties
When the experimentalPlugins
option is given these properties are configured.
They are considered experimental due to use of context
to propagate values to child components and the behaviour is undefined when components wrapped by Prism()
make use of the context
.
textTransform
lowercase|uppercase|capitalize
The textTransform
property provides a means to apply text transformations to components, it requires the supportsText
flag on receiving components and requires that the textTransform
and experimentalPlugins
options are enabled.
This property is distinct from the font
property as it's behaviour is very different, instead of injecting values into a style sheet it modifies a component's children.
In a style sheet:
'Panel header': {
textTransform: 'capitalize'
}
Inline property usage illustrating inheritance:
<List space={5} textTransform='uppercase'>
<List space={10}>
<Paragraph>
This is some uppercase text <Label textTransform='lowercase'>including some lowercase text in a Label</Label> in a paragraph. <Label textTransform='capitalize'>We can capitalize too</Label>.
</Paragraph>
</List>
</List>
Caveat that you cannot undo a transformation on a child (none
is not supported), you can only override with a new transformation.
Cascade
This section gives an overview of the cascade or inheritance mechanism using the default configuration.
- Compute style from
defaultProps
- Include styles from
defaultStyleRule
- Process global plugins (property mapping)
- Process property plugins (eg: extended and experimental)
- Run processors
Note that property plugins are massaged so that style
, labelStyle
etc always execute after other configured property plugins.
This means the inheritance for say color
of Label
can be described in this order.
Default Properties
static defaultProps = {
style: {
color: 'red'
}
}
// Color is red
<Label />
Default Style Rule
'Label': {
color: 'green'
}
// Color is green now we have a default style rule
<Label />
Component Mapping
static mapPropsToStyle = {
color: () => {
return {color: 'blue'}
}
}
// Our component now says it should be blue
<Label />
Class Name
'.highlight': {
color: 'steelblue'
}
// Prefer the color in another style rule
<Label className='highlight' />
Inline Property
// Prefer the inline property over the className style
<Label className='highlight' color='orange' />
Inline Style
// Inline style beats everything else
<Label className='highlight' color='orange' style={{color: 'purple'}} />
Configuration
You can pass a configuration object as the second argument to Prism.configure()
to modify the library configuration. These are the common configuration options, some more advanced options are shown in plugin configuration.
defaultProps
use the defaultProps plugin, default istrue
.defaultStyleRule
use the defaultStyleRule plugin, default istrue
.mapPropsToStyle
use the mapPropsToStyle plugin, default istrue
.mapStyleToProps
use the mapStyleToProps plugin, default istrue
.className
use the property plugin for className, default istrue
.extendedProperties
enables the extended property plugins.fontProperties
enables the font property plugins.experimentalPlugins
enables the experimental plugins.colorNames
enables the color names processor.textTransform
enables the text transform support (requires experimental plugins).withState
enables component state support.pure
advanced option, see pure mode.debug
print information at boot, default value is__DEV__
.
When no configuration object is given support for the className
property is enabled and the global plugins to support mapping properties to styles and resolving default styles.
This is a sensible minimal default configuration which will be sufficient for many applications and creates the least chance of conflict if you want to integrate Prism with an existing application.
To use the extended style properties and enable color name lookup:
Prism.configure(registry, {extendedProperties: true, colorNames: true})
To use textTransform
you need to enable experimentalPlugins
:
Prism.configure(
registry,
{
experimentalPlugins: true,
textTransform: true
}
)
File: configuration.js
export default {
plugins: [],
processors: [],
defaultProps: true,
defaultStyleRule: true,
mapPropsToStyle: true,
mapStyleToProps: true,
className: true,
extendedProperties: false,
fontProperties: false,
experimentalPlugins: false,
withState: false,
inlineStyle: true,
colorNames: false,
textTransform: false,
pure: false,
debug: __DEV__,
invariants: [],
sizes: {
'xx-small': 12,
'x-small': 13,
'small': 14,
'medium': 16,
'large': 18,
'x-large': 22,
'xx-large': 26
}
}
Appendix
Platform Styles
You can use platform specific styles for your fonts and style sheets by using the standard notation passed to Platform.select()
.
If you need a platform-specific font family specify an object in your fonts map:
export default {
regular: {
ios: 'WorkSans-Regular',
android: 'worksans'
}
}
Platform-specific styles are merged over the top of default rules using a selective merge so you can overwrite declarations and inherit the other styles. To illustrate:
export default {
Label: {
fontSize: 20,
color: 'red'
},
android: {
Label: {
// Overwrite for android but inherit
// fontSize from the top-level Label
color: 'green'
}
}
}
Color Names
Styles are much easier to change and we can add semantic meaning to our colors if we can refer to them by name, use the colorNames
option to enable this functionality.
With the colorNames
option enabled and a theme like:
{
colors: {
primary: '#333333',
muted: '#999999',
},
styles: ({colors}) => {
return {
Label: {
fontSize: 16,
color: colors.primary
}
}
}
}
You can now override the color by name:
<Label color='muted' />
To work in all scenarios (default properties, style sheets and properties) this logic is implemented as a processor and adds overhead therefore it is not enabled by default.
Consider that there may be a better way for your application to manage named colors internally before enabling this option.
Flat Styles
Sometimes you are wrapping a third-party component and want to proxy the style
object to the component but it does not accept an array for the style
property; it enforces an object only property type.
The computed style
property passed to your component is guaranteed to be an array; here however we need it to be an object. To do so you can use the flat
option:
static styleOptions = {
flat: true
}
Now you can just proxy it to the child component knowing it will be an object:
render () {
const {style} = this.props
return (
<NonIdiomaticComponent style={style} />
)
}
Flat styles are applied to child components too.
Plugins
Plugins allow you to change the default behaviour.
Creating Plugins
To create a plugin you pass a plugin name, handler function and plugin options:
import {Plugin} from 'react-native-prism'
new Plugin(
'pluginName',
() => { /* ... */ },
{/* options */}
)
Property Plugins
If your plugin is for a property you should use the propType
option:
import PropTypes from 'prop-types'
const plugins = [
new Plugin(
'transform',
({prop, propName, styleSheet, colors}) => {
// Return some transform specific style declarations
},
{propType: PropTypes.object}
)
]
These plugins will only execute when the property is defined on the component.
See extendedPropertyPlugins.js for several examples.
Global Plugins
Global plugins are those without a propType
option:
new Plugin(
'globalPlugin',
({props, styleSheet}) => { /* ... */ },
{requireOptions: true}
)
These plugins provide the ability to modify the computed style sheets without being triggered by the presence of a property.
They can provide options that filter when they are executed. For example requireOptions
means only run this plugin for components that have declared a corresponding options object.
For the example above a component needs to explicitly enable the plugin:
static styleOptions: {
// Trigger execution of the plugin for this component
globalPlugin: {}
}
Plugin Configuration
Use these configuration options to control plugins:
additionalPlugins
array of plugin definitions to append to the system plugins.disabledPlugins
array of string plugin names to disable.plugins
array of plugin definitions to use, overrides the system plugins.
plugins
Use your own plugins
array when you want to specify a list of plugins to use before any plugins enabled using the configuration flags, you can disable className
and mapPropsToStyle
etc to use only the custom plugins you specify.
additionalPlugins
Use the additionalPlugins
option to add custom functionality to all your styled components, see plugins for information on defining custom plugins.
Prism.configure(
registry,
{
extendedProperties: true,
additionalPlugins: [
new Plugin(
'customGlobalPlugin',
({props, styleSheet}) => {
// Do something cool
}
)
]
}
)
disabledPlugins
You may want to remove plugins you don't need or if you find a property name collision:
Prism.configure(
registry,
{
extendedProperties: true,
disabledPlugins: ['position', 'wrap']
}
)
The disabledPlugins
option is processed after plugins
and additionalPlugins
so you may use this to disable your custom plugins. If you give a plugin name that does not exist it is ignored.
Processor
Processors are plugins that operate on a flat representation of the computed styles, they are used to support named colors and invariants. The default configuration does not enable any processors but it is worth knowing that certain configuration options add some processing overhead:
colorNames
textTransform
Invariants
Invariants are unknown style declarations that would trigger an error when compiling style sheets with StyleSheet.create()
. This strict behaviour of RN is very useful but there are occasions where it makes more sense to put the information in a style sheet and invariants allow us to do that. Internally they are extracted as invariant style rules and later resolved when styles are computed.
An example of this is tintColor
where we need to assign to the tintColor
property of ActivityIndicator
but really it's styling information and is better suited to being in a style sheet.
Also the experimental textTransform
property is treated as an invariant so it can be declared in style rules and processed using the plugin system yet never appear in compiled or computed style sheets.
Invariants use a processor to ensure computed styles do not contain these properties so they incur the same performance penalty.
Best Practices
You are free to do as you please however here are some guidelines:
- Avoid setting styles in
defaultProps
. - Use class name style rule for default styles (eg:
Label
). - Prefer
className
as first option for style overrides. - Use extended properties sparingly, useful for rapid devlopment, later migrate to
className
. - Avoid inline
style
properties.
Pure Mode
If you like the style sheet paradigm that Prism has but want to get closer to the metal we offer a pure mode of operation. When the pure
configuration option is given plugins and style computation are disabled. Your components are given direct access to the style registry instead.
In pure mode your components are only passed two properties by the HOC:
styleRegistry
the application style registry.styleSheet
alias for the registry style sheet.
Note that style
is no longer passed!
Now you need to pass the styles manually by finding them in the registry:
render () {
const {styleSheet} = this.props
<Text style={styleSheet.text}>
{this.props.children}
</Text>
}
Typically you would decide to use this mode of operation from the beginning. If you enable pure mode for an existing application using Prism features your views will revert to zero style.
This would apply to any third-party components you may be using too!
Performance
We have made every effort to keep iterations and function calls to a bare minimum and in it's default configuration performance impact should be minimal.
However performance may be impacted if you use any of the following features as they all require a flat representation of the computed styles:
- Processor operate on flat computed styles.
- Invariants implies use of a processor.
- Flat Styles computes a component-specific flat stylesheet.
And of course caveat emptor this is not the sort of thing you want to use to style say many thousands of game sprites.
License
MIT
Created by mkdoc on June 18, 2018