API Reference
Seamstress
import Seamstress from 'react-seamstress';
The entry point into the Seamstress library.
Seamstress.createContainer
HigherOrderComponent createContainer(
ReactClass/Component/Function WrappedComponent,
object config
)
Returns a higher-order component that processes props.styles
and passes the result as props.computedStyles
to WrappedComponent
.
The configuration object passed as the second argument determines how the input styles are processed.
Note:
If your
config.getStyleState()
function needs access tothis.state
, or your component's API exposes any instance properties or methods, usecreateDecorator
, instead.
Seamstress.createDecorator
decoratorFunction createDecorator(object config)
Returns a decorator function that takes the following form:
SeamstressComponent decoratorFunction(ReactClass/Component YourComponent)
The decorator returns a component that derives from YourComponent
and supplies some additional behaviors:
this.getComputedStyles()
providescomputedStyles
to your component.propTypes
is enhanced with a customstyles
validator ifstyleStateTypes
orsubComponentTypes
were configured.
Note:
If
YourComponent
is a stateless component, or yourconfig.getStyleState()
function doesn't need access to component state, usecreateContainer
, instead.
config
{
styles: string/object/function/Array,
getStyleState: Function,
[styleStateTypes: object],
[subComponentTypes: object],
}
config.styles
The "default" styles for your component.
Takes the same form as the styles
prop.
These styles are applied unless explicitly overridden by props.styles
.
config.getStyleState
getStyleState: function ({
props: object,
context: object,
[state: object],
}) {
return {
// style-state values go here
};
}
A function that returns all style-related state of your component.
This should be a pure function of the props
, context
, and if applicable, the state
of your component.
The state
parameter is only specified when using Seamstress.createDecorator()
.
config.styleStateTypes
styleStateTypes: {
['style-state': React.PropType],
...,
}
An optional (but recommended) way to declare the state your component exposes for styling purposes.
Takes the same form as propTypes
.
In a nutshell, bool
style-state items correspond to a single :pseudo-selector
, and all other types are only accessible via style callbacks.
Much like propTypes
, styleStateTypes
will help ensure your component is being styled correctly by providing warnings whenever unspecified or non-boolean style-states are used as :pseudo-selectors
.
The result of config.getStyleState()
is also validated using these prop-types.
Note:
Validations are skipped and warnings will be suppressed when executing in a production environment.
config.subComponentTypes
styleStateTypes: {
['sub-component': Seamstress.SubComponentType],
...,
}
An optional (but recommended) way to declare the styleable sub-components (if any) that your component contains.
In a nutshell, each named sub-component corresponds to a single ::pseudo-element
.
Values must come from Seamstress.SubComponentTypes
.
If specified, props.styles
will warn the user if any unspecified ::sub-component
is used.
If unspecified, all ::sub-components
are assumed to be SubComponentTypes.simple
.
Note:
Validations are skipped and warnings will be suppressed when executing in a production environment.
Seamstress.SubComponentTypes
// A simple sub-component that expects `className` and `style` props:
Seamstress.SubComponentTypes.simple
// A Seamstress-enabled sub-component that expects a `styles` prop:
Seamstress.SubComponentTypes.composite
computedStyles
The applicable style-related props for your component and any of its sub-components. Typically used inside a render()
function.
Can be accessed in one of two ways, depending on how you created your Seamstress-enabled component:
If (and only if) you're using Seamstress.createDecorator:
this.getComputedStyles()
If (and only if) you're using Seamstress.createContainer:
props.computedStyles
The computedStyles
object takes on the following shape:
{
root: { className, style },
(simple sub-component): { className, style },
(composite sub-component): { styles },
}
The root
property is always defined on computedStyles
, because it corresponds to all "top-level" styles from props.styles
. Typically, root
props are passed to the outermost styleable element inside your component's render()
method.
All other items in computedStyles
apply to the named sub-components of your component.
simple
sub-components are automatically merged into low-level style props (in the case of the DOM, className
and style
).
composite
sub-components retain the original unprocessed styles
prop that should only be passed to other Seamstress-wrapped components.
By default, all sub-components are assumed to be simple
. Use config.subComponentTypes
to control how each individual sub-component's style props are processed.
props.styles
<SeamstressComponent styles={string/object/function/Array} />
A prop for expressing how a Seamstress component should be styled.
Think of it as a combination of React inline styles with custom :pseudo-selectors
, ::pseudo-elements
, and [prop]
selectors.
Values can be a string
, an object
, a callback function
, or an Array
containing any combination of such types.
All other value types (boolean
, null
, undefined
, etc) are ignored.
Default styles specified with config.styles
are retained unless explicitly overridden by props.styles
.
See Styles_Prop_Examples.md for a comprehensive list of the forms props.styles
can take.
Top-level styles
All keys in a styles object
that don't begin with :
are considered "top-level" styles. These will be combined into computedStyles.root
.
Top-level CSS classes can be applied as a standalone string
, a string
in an array, or with the :base
pseudo-selector.
:pseudo-selectors
':some-style-state-name': string/object/Function
Inside any object
, keys beginning with a single :
correspond to styles that are only applied when the matching value returned from config.getStyleState()
is true
.
For instance, the key-value-pair ':busy': {opacity: 0.5}
translates to "When the component is busy, set opacity
to 0.5
."
If multiple style-state selectors are specified (i.e. :busy:expanded
), the associated styles only apply when all correspinding style-states are true
.
To apply a specific CSS class, provide a string
instead of an object (i.e. ':busy': 'MyComponent_busy'
).
Note:
Seamstress
:pseudo-selectors
are not CSS pseudo-selectors.For instance,
:hover
will only apply if you explicitly keep track of the hover state and include it in the result ofconfig.getStyleState()
.However, ordinary CSS selectors may still be used within your actual CSS, of course! Seamstress merely combines and applies the applicable CSS classes for you.
[prop] selectors
'[prop]': string/object/Function
'[prop=false]': string/object/Function
'[prop=42]': string/object/Function
'[prop="string"]': string/object/Function
Seamstress implements a syntax inspired by CSS's [attr]
selector to allow you to style your components purely based on their props without the need to write any getStyleState
boilerplate.
There are some key differences from standard CSS [attr]
selectors, however:
- Only
[prop]
and[prop=<value>]
syntax supported. [prop]
only applies whenprop
is truthy.- Note: boolean props can also be tested explicitly, i.e.
[prop=true]
or[prop=false]
- Note: boolean props can also be tested explicitly, i.e.
- String values must include double-quotes, i.e.
[prop="string"]
Note: Seamstress examines your component's
propTypes
to ensure all such selectors are valid. PropTypes-style warnings will be logged when invalid comparisons are made (i.e.[number="this should be a number"]
).
:base
':base': string/object/Function
A special style-state used to unconditionally apply styles to a component. This is mostly useful for specifying a default classnames, (i.e. ':base': 'MyComponent'
).
::pseudo-elements
'::some-sub-component-name': string/object/Function
Inside any object
, keys containing ::
correspond to styles that apply to nested sub-components (i.e. '::indicator': 'Indicator'
).
These can be used in combination with :pseudo-selectors
to conditionally apply style properties to sub-components (i.e. ':busy::indicator': 'Indicator_busy'
).
Use config.subComponentTypes
to declare which ::sub-components
are valid, and how their style props should be processed inside computedStyles
.
Note:
Seamstress
::pseudo-elements
are not CSS pseudo-elements.For instance,
::first-letter
only means something if the component-author explicitly appliescomputedStyles['first-letter]
to something like a<span>
wrapped around the first letter of its internal content.However, ordinary CSS selectors may still be used within your actual CSS, of course! Seamstress merely combines and applies the applicable CSS classes for you.
Style callbacks
object/array/String styleCallback ({
object styleState,
object props
})
When a function
is encountered in a styles
object, it is treated as a callback.
This function receives a single object argument with two named values:
styleState
- the return value ofconfig.getStyleState()
props
- the current props of this component
Such callbacks can be used to compute the entire styles
prop, the style pertaining to a specific selector, or a single inline-style value (i.e. (styleState, props) => { return {color: 'red'} }
).
Nested callbacks are not supported, but you may return a styles
definition containing nested :pseudo-selector
and ::pseudo-element
items.
Note:
Callbacks should be avoided. They are generally less predictable and need to be re-evaluated every
render()
, and purely-declarative styles may be optimized by Seamstress, behind the scenes.