Creating React Components for POWr Settings
Create new file in app/views/apps/settings_partials​
- Add a div with the class of your component with a powr-react attribute. This will be where the React component will render. The naming convention is
powr-_<component__name>-js. Ensure you add the namespace data attr on both react component container and the hidden inout - that is what links them to each other.
.powr-react-component-js{'powr-react': "PowrColorPicker", data: {namespace: "#{namespace}Color"}}
%input{type:'hidden', name: "#{namespace}Color", data: {label: label, namespace: "#{namespace}Color"}.merge(data)}
- Also add a hidden input to help tie React to the Backbone Model. Make sure that you add all the information you will need in your component.
- data = {namespace: namespace,label: label, options: options}.merge(params.as_json(only: [:premium_status, :help_text]))
%input{type: "hidden", name: namespace, data: data}
Pulling data out of the hidden input hash makes it a little more readable. Please don't pass the entire opts/params to data.
Add a method to app_form_helper.rb (or wherever appropriate) that will render your partial.​
- If you are replacing an existing component with a react one, updating the existing method will mean that your component will be used everywhere that the original one was placed in settings files.
def card_select(label, namespace, options = {})
render :partial => 'apps/settings_partials/card_select.html.haml', :locals => { label: label, namespace: namespace, options: options }
end
Create your actual component jsx file and place in app/javascript/modules/react_components​
- REACT COMPONENT TEMPLATE
- Name component with "Powr" in front of it, must be capitalized for react. Name file "powr_text.jsx"
import React from 'react';at the top along with any other components you need.- If you need access to the premium status star, feature blocker, and upgrade popover, you will want to add
import SettingsComponentWrapper from './settings_component_wrapper';- that component includes all of that functionality. - es6 JS Class
class CardSelect extends React.Component { - in the class, include static defaultProps, a constructor that at least calls super(props), and a render method that returns valid HTML
- although class attributes should use className instead
- any tags without children should be written as self-closing like
<i className="fa fa-star" /> - and all sibling elements in the return statement must be wrapped in a parent element (basically you can return a single div or something similar and can put as much as you want inside of it)
- Example with SettingsComponentWrapper to give it premium star, feature blocking, and upgrade popover:```render () {const props = this.props;const currentClass = props.selected == props.value ? "selectedCard" : "";
return (
<li className="margin-bottom-s">
<SettingsComponentWrapper
userPremiumStatus={this.props.userPremiumStatus}
featurePremiumStatus= {this.props.plan}
anchorComponentName={this.props.value}
>
<div className="cardSelectItem" onClick={this.handleClick} >
<div className={cardSelectContainer card has-shadow container ${props.value} ${currentClass}} value={props.value} id= {props.value} >
<ImageOrIcon image_url={props.image_url} icon={props.icon} />
<div className="cardSelectText">
<h6 className="cardSelectHeadline">{props.headline}</h6>
<p className="cardSelectCaption">{props.caption}</p>
</div>
</div>
</div>
</SettingsComponentWrapper>
</li>
);
}
- export default CardSelect (your class name) at the bottom
- Please add documentation for usage, required props, and an example of calling the component at the top of the jsx file.
- For an example, see: app/javascript/modules/react_components/card_select.jsx
- ### Add your component to base_settings.jsx
- import at top of file
``` import CardSelect from "./react_components/card_select";
- add your react component to the
reactComponentshash'card-select': CardSelect( <component-name-from-haml> : _<reactcomponentnamefromimport_> ) - Create an initialize function that finds all instances that have not already been initialized and marks them as such and then renders your component
- Call your initialize function in base_settings.jsx
initializeCardSelect: function() {
var self = this;
this.initializePowrReactComponents({
component: 'card-select',
propLinkedToRealInputVal: 'selected'
});
},
\AND CALL THE INITIALIZE FUNCTION IN THE CORRECT PLACE IN THE DOCUMENT
this.initializeCardSelect();
Add your CSS file to app/assets/stylesheets/partials/modules/react_components​
Import your CSS file in _settings.scss​
@import 'partials/modules/react_components/card_select.scss';
Translations​
now located at: https://www.getoutline.com/doc/translations-and-simple-copy-or-simple-copies-uvyV0IJq16
Triggers​
These happen automatically using initializePowrReactComponents but if you want to handle special cases here is how you can use two triggers:
Tp update the backbone model to match the value of the react component, call
$realInput.trigger('reactUpdateRequest');
Then you can listen to
el.on('change reactUpdateRequest', '[name="type"]', function() {
To update the react component's state, update the data attribute and call
$realInput
.data('placeholder', 'cheese')
.trigger('forceUpdateComponent');