Creating a WYSIWYG editor with React @ipeychev (or lets see how deep the rabbit hole goes)
Creating a WYSIWYG editor with React
@ipeychev
(or lets see how deep the rabbit hole goes)
ReactA JavaScript library for building user interfaces
Why React?
Why React?
React allows you to concentrate on the UI of your application
Why React?
Instead to focus on implementation details, fighting with the DOM and resolving performance issues
React in a nutshell
React in a nutshell
Library, not a framework
Implements one-way reactive data
flow
Blazingly fast
React in a nutshell
Virtual DOM
JSX
JavaScript syntax extension (JSX)
React in a nutshell
Native applications
Isomorphic applications
Client-side applications
Creating UI with React
Main UI
Nested Components
Data flow
Creating a component
Render the component
Update state
But... Isn't that slow?!
Performance
And rendering is fast
Virtual DOM rulez
Performance
Components
Component are state machines
You render initially the components based on the properties
Components
Then you change their state and they will be automatically re-rendered
React renders nested components with deep hierarchy
Without compromising the performance
Components performance
(thanks to the Virtual DOM)
Components example
} Main component with nested components
Render part}
Reusable code
1 var HelloWorld = React.createClass({ 2 mixins: [MyMixin, YourMixin], 3 4 render: function() { 5 var a = this.getA(); 6 var b = this.getB(); 7 8 return (a + b); 9 }
Mixins
A higher-order component is a function that takes an existing component and returns another component that wraps it
Higher-order components
Properties
Unconditionally configure your components
Which will help you to debug and test them
Properties are immutable, they are owned by the parent element
Properties
Properties
Properties
State
State
Change your components based on user actions or data from server
When the state is updated, the component re-renders itself.
State should be considered as private data
Properties vs State
Properties are initialized when components are created
State is only seen on the inside of components definitions
Properties vs State
Events
Attaching events
<button onClick={this._handleClick} ...
Attach them in DOM 0 way:
Events are not attached to the element itself
React is listening for all events at the top level using a single event listener
When an event occurs, React dispatches it accordingly
Events delegation
React autobinds the method to its component instance
Events autobinding
There is no need to write .bind(this):
<button onClick={this._handleClick .bind(this)}
Let's see how deep the rabbit hole goes
An Open Source
WYSIWYG editor
built with React
AlloyEditor design goals
The developer should be able to replace the UI entirely
!It should be accessible"
Toolbars should appear when needed and where needed
#
The UI should be separated from the core$
The UI should be easy to be styled%
AlloyEditor design goals
It should work on all browsers
AlloyEditor architecture
UI core Plugins, low level modules
Engine CKEditor Core
Toolbar Toolbar Toolbar
Button Button } AlloyEditor UI
based on React + our own code around it
AlloyEditor architecture
Code around React
React provides the rendering part only
That is not enough
Core, Attributes and Events
Basic stuff is needed, for example:
OOP
Types validation
Configurations
Custom Events
Instantiating AlloyEditor
Instantiating AlloyEditor
Many editors can be instantiated on one page
1 <script> 2 var editor1 = AlloyEditor.editable('description'); 3 var editor2 = AlloyEditor.editable('editable'); 4 </script>
Selections
Selections
Currently there are four types:
Image Text Table Link
Selections
Exposed in AlloyEditor.Selections
You can add your own
Buttons reordering
Buttons reordering
1 <script> 2 AlloyEditor.Selections[2].buttons = ['bold', 'italic', 'underline', 'link', 'twitter']; 3 </script>
AlloyEditor.Selections[2] is the text selection.
Instead of hardcoding it, you can also retrieve it by enumerating it inside the array
Buttons reordering
1 <script> 2 AlloyEditor.Selections[2].buttons = ['italic', 'bold', 'underline', 'link', 'twitter']; 3 </script>
AlloyEditor.Selections[2] is the text selection.
Instead of hardcoding it, you can also retrieve it by enumerating it inside the array
Buttons reordering
1 <script> 2 _.find(AlloyEditor.Selections, function(selection) { 3 var found = selection.name === 'text'; 4 5 if (found) { 6 selection.buttons = ['bold', 'italic', 'underline', 'link', 'twitter']; 7 } 8 9 return found; 10 }); 11 </script>
Buttons reordering
1 <script> 2 _.find(AlloyEditor.Selections, function(selection) { 3 var found = selection.name === 'text'; 4 5 if (found) { 6 selection.buttons = ['italic', 'bold', 'underline', 'link', 'twitter']; 7 } 8 9 return found; 10 }); 11 </script>
Adding new buttons
A button is just a ReactJS module
1 var ButtonH4 = React.createClass({ 2 mixins: [AlloyEditor.ButtonStyle, AlloyEditor.ButtonStateClasses, AlloyEditor.ButtonActionStyle], 3 4 statics: { 5 key: 'h4' 6 }, 7 8 getDefaultProps: function() { 9 return { 10 style: { 11 element: 'h4' 12 } 13 }; 14 }, 15 16 render: function() { 17 var cssClass = 'alloy-editor-button ' + this.getStateClasses(); 18 19 return ( 20 <button className={cssClass} data-type="button-h4" onClick={this.applyStyle}tabIndex={this.props.tabIndex}> 21 <span className="alloy-editor-icon-h4"></span> 22 </button> 23 ); 24 } 25 }); 26 27 AlloyEditor.Buttons[ButtonH4.key] = AlloyEditor.ButtonH4 = ButtonH4;
Adding a new button
1 <script> 2 _.find(AlloyEditor.Selections, function(selection) { 3 var found = selection.name === 'text'; 4 5 if (found) { 6 selection.buttons = ['h4', 'italic', 'bold', 'underline', 'link']; 7 } 8 9 return found; 10 }); 11 </script>
Skins!
Wait, there is even more!
More stuff available!
Drag&Drop images from Desktop to the editor&
Auto link creation&
Placeholder plugin&
Your own toolbars and buttons!&
Roadmap
Roadmap
Mobile support♥
Implement more buttons♥
Improve accessibility♥
Any ideas?
Demo time
Thanks!
Questions?
ipeychev