react-web-sdk
Experimental / API proof of concept
Components for building web applications and SDKs. Based on react-native's
components.
- Styles are plain JavaScript objects.
- Styles are passed to a component's
styleprop. - Non-dynamic styles rely on static CSS classes.
- Dynamic styles are written as inline styles on the DOM node.
Each Component defines StylePropTypes and filters out any style properties
that are not part of its style API. For example, View does not support any
typographic properties. You must use Text to wrap and style any text strings.
Implementation notes
The current implementation uses a prebuilt CSS library – 200+ single-purpose, obfuscated selectors. It provides a large number of common, knowable styles needed to build apps. This makes the foundational CSS fixed (~5KB gzipped) and highly cachable. Inline styles are used for anything the CSS library doesn't provide, but their use is significantly reduced.
A better implementation would generate the CSS library from the declarations
defined in the source code, replace static variables (use webpack's
DefinePlugin?), and only use inline-styles for dynamic, instance-specific
styles.
What about media queries? Perhaps rely on mediaMatch and re-render when the
style prop needs to change; works better with DOM-related changes that need
to happen at breakpoints. And that would avoid the need for any additional
CSS. Alternatively, rely on something similar to react-style's approach and
duplicate the single-purpose classes within static CSS media queries.
Example
import React from 'react';
import {Image, Text, View} from 'react-web-sdk';
class Example extends React.Component {
render() {
return (
<View element="main" style={{ ...style.common, ...style.root }}>
<Image alt="accessibility text" src="/image.png" style={style.image} />
<Text style={{ ...style.common, ...(Math.random() > 0.5 && style.text) }}>
Example component
</Text>
</View>
);
}
}
const style = {
common: {
backgroundColor: 'white',
borderRadius: '1em'
},
root: {
flexDirection: 'row',
justifyContent: 'space-between'
},
image: {
opacity: 0.5
},
text: {
fontWeight: '300'
}
};
export default Example;
Component: SDKComponent
A component that manages styles across the className and style properties.
The building block upon which all other components in react-web-sdk are
build.
PropTypes
All other props are transferred directly to the element.
className:stringelement:funcorstringstyle:object
Examples
const ViewStylePropTypes = {
opacity: PropTypes.number
};
const ViewStyleDefaultProps = {
opacity: 1
};
class ViewExample extends React.Component {
render() {
// filter other props
const other = ReactWebSDK.getOtherProps(this);
// exclude other styles
const supportedStyle = ReactWebSDK.objectWithProps(this.props.style, ViewStylePropTypes);
// merge defaults with instance styles
const style = { ...ViewStyleDefaultProps, ...supportedStyle }
return (
<SDKComponent
{...other}
children={this.props.children}
className={`ViewExample ${this.props.className}`}
element={this.props.element}
style={style}
/>
);
}
}
Component: Image
TODO
PropTypes
All other props are transferred directly to the element.
alt:stringasync:bool(TODO)className:stringsrc:stringstyle:ImageStylePropTypes
ImageStylePropTypes
BackgroundPropTypesBorderThemePropTypesLayoutPropTypesopacity:string
Component: Text
Text layout and styles.
PropTypes
All other props are transferred directly to the element.
className:stringelement:funcorstring(default"div")style:TextStylePropTypes
TextStylePropTypes
- ViewStylePropTypes
- TypographicPropTypes
Component: View
View is a flexbox container and the fundamental building block for UI. It is
designed to be nested inside other View's and to have 0-to-many children of
any type.
PropTypes
All other props are transferred directly to the element.
className:stringelement:funcorstring(default"div")pointerEvents:oneOf('all', 'box-only', 'box-none', 'none')style:ViewStylePropTypes
ViewStylePropTypes
- BackgroundPropTypes
- BorderThemePropTypes
- LayoutPropTypes
boxShadow:stringcolor:stringopacity:number
ViewStyleDefaultProps
Implements the default styles from facebook/css-layout.
const ViewStyleDefaultProps = {
alignItems: 'stretch', // 1
borderWidth: 0,
borderStyle: 'solid',
boxSizing: 'border-box', // 2
display: 'flex', // 3
flexBasis: 'auto', // 1
flexDirection: 'column', // 1
flexShrink: 0, // 1
listStyle: 'none',
margin: 0,
padding: 0,
position: 'relative' // 4
};
-
All the flex elements are oriented from top-to-bottom, left-to-right and do not shrink. This is how things are laid out using the default CSS settings and what you'd expect.
-
The most convenient way to express the relation between width and other box-model properties.
-
Everything is
display:flexby default. All the behaviors ofblockandinline-blockcan be expressed in term of flex but not the opposite. -
Everything is
position:relative. This makesposition:absolutetarget the direct parent and not some parent which is either relative or absolute. If you want to position an element relative to something else, you should move it in the DOM instead of relying of CSS. It also makestop,left,right,bottomdo something when not specifyingposition:absolute.
Examples
// TODO
StylePropTypes
Background
backgroundColor:stringbackgroundImage:stringbackgroundPosition:stringbackgroundRepeat:stringbackgroundSize:string
BorderTheme
borderColor:stringborderTopColor:stringborderRightColor:stringborderBottomColor:stringborderLeftColor:stringborderStyle:stringborderRadius:numberorstringborderTopLeftRadius:numberorstringborderTopRightRadius:numberorstringborderBottomLeftRadius:numberorstringborderBottomRightRadius:numberorstring
BoxModel
borderWidth:numberorstringborderTopWidth:numberorstringborderRightWidth:numberorstringborderBottomWidth:numberorstringborderLeftWidth:numberorstringboxSizing:oneOf('border-box', 'content-box')display:oneOf('block', 'flex', 'inline', 'inline-block', 'inline-flex')height:numberorstringmargin:numberorstringmarginTop:numberorstringmarginRight:numberorstringmarginBottom:numberorstringmarginLeft:numberorstringpadding:numberorstringpaddingTop:numberorstringpaddingRight:numberorstringpaddingBottom:numberorstringpaddingLeft:numberorstringwidth:numberorstring
Flexbox
alignContent:oneOf('center', 'flex-end', 'flex-start', 'stretch', 'space-around', 'space-between')alignItems:oneOf('baseline', 'center', 'flex-end', 'flex-start', 'stretch')alignSelf:oneOf('auto', 'baseline', 'center', 'flex-end', 'flex-start', 'stretch')flexBasis:stringflexDirection:oneOf('column', 'column-reverse', 'row', 'row-reverse')flexGrow:numberflexShrink:numberflexWrap:oneOf('nowrap', 'wrap', 'wrap-reverse')justifyContent:oneOf('center', 'flex-end', 'flex-start', 'space-around', 'space-between')order:number
See this guide to flexbox.
Layout
- BoxModel
- Flexbox
- Position
Position
position:oneOf('absolute', 'fixed', 'relative')bottom:numberorstringleft:numberorstringright:numberorstringtop:numberorstringzIndex:number
Typographic
direction:oneOf('auto', 'ltr', 'rtl')fontFamily:stringfontSize:stringfontWeight:oneOf('100', '200', '300', '400', '500', '600', '700', '800', '900', 'bold', 'normal')fontStyle:oneOf('normal', 'italic')letterSpacing:stringlineHeight:numberorstringtextAlign:oneOf('auto', 'left', 'right', 'center')textDecoration:oneOf('none', 'underline')textTransform:oneOf('capitalize', 'lowercase', 'none', 'uppercase')wordWrap:oneOf('break-word', 'normal')
Development
npm run build
npm run build:watch
open index.html