Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
d296e01
api improvements
catmando May 6, 2015
0d18326
state is now readable during events
catmando May 8, 2015
984f0c2
allow Element values to be passed to render and unmount
catmando May 8, 2015
84fdebd
added more nicieties
catmando May 14, 2015
ed915e4
added top level component file
catmando May 14, 2015
d2c4fbc
fixed issue with using state(bang) in TopLevelComponent
catmando May 14, 2015
b5827e8
removed puts statement
catmando May 15, 2015
2004e0a
updated comments
catmando May 16, 2015
adf1c28
WIP
catmando May 20, 2015
f30c5a2
WIP added exception method if render fails
catmando May 21, 2015
64afab2
WIP observable now works with ampersand unary
catmando May 22, 2015
b0ee712
WIP added nicer define_state syntax String#display and param method d…
catmando May 24, 2015
94ba3a9
WIP added global states and changed name space - need to merge with 0…
catmando May 27, 2015
4b38775
WIP added export_state, and export_component to support react-rails
catmando May 27, 2015
ef064cd
export_component changes :: to . following JS convention
catmando May 28, 2015
95da11f
WIP fixed export for component nesting greater than 2 levels deep
catmando May 28, 2015
45bd94b
tweaking export so it works nice with rails-react
catmando May 28, 2015
dfcb45c
added some sample logos
catmando May 28, 2015
f9fa66b
moved logos
catmando May 28, 2015
9f25da3
got nested tree of module names working for export
catmando May 29, 2015
900822d
added optional react-rails style view helper
catmando May 29, 2015
dea8688
some missing parameter info in the react_component method
catmando May 29, 2015
8b4d427
fixed problem with global states during unmount
catmando May 30, 2015
c03113d
added ability to watch state changes
catmando Jun 1, 2015
d1e122a
states can now be defined call backs
catmando Jun 1, 2015
567b37c
added another logo option
catmando Jun 3, 2015
ba920d2
added ability to detach nodes so will work with bootstrap
catmando Jun 6, 2015
c4b5150
added features so native components can be imported and used
catmando Jun 8, 2015
8683973
pulling in last element to rendering context does not always work
catmando Jun 8, 2015
c5c26ce
last string in a component gets output
catmando Jun 8, 2015
af45ecc
added support for reactive-record while_loading needs work
catmando Jun 23, 2015
8c43f42
lots of changes to support reactive-record needs some cleanup
catmando Jun 28, 2015
58188c3
allow for empty (nil) component rendering
catmando Jun 28, 2015
4348393
made tags like td work again if used with a block
catmando Jun 28, 2015
52df9e2
allow br to be used without string
catmando Jun 28, 2015
06701f3
moved while_loading function from reactive_record
catmando Jul 1, 2015
57a77fe
straightening out requires
catmando Jul 2, 2015
c779d11
added serialization independent of as_json
catmando Jul 6, 2015
a07f181
added BigDecimal and FalseClass to serializers
catmando Jul 6, 2015
40c36df
updated version
catmando Jul 7, 2015
8aa99c8
Update README.md
catmando Jul 20, 2015
091c420
fixed up simplified examples and documentation
catmando Jul 20, 2015
ce1d971
documentation changes plus minor eliminated need for .to_n in a coupl…
catmando Jul 21, 2015
afa0388
fixed problem in tutorial when text is empty
catmando Jul 21, 2015
63b9001
turned on development mode
catmando Jul 21, 2015
eba9113
added haml style class notation to tags
catmando Jul 22, 2015
3ab5596
added _ to - translation
catmando Jul 22, 2015
832d78b
removing include native from module API
catmando Jul 23, 2015
c8c0db7
updated version
catmando Jul 23, 2015
afaac7c
fixed problem with haml style classes overridden other props
catmando Jul 23, 2015
a1e9c18
Fix a small formatting issue in the readme
lexun Jul 26, 2015
009ae3f
Merge pull request #1 from lexun/patch-1
catmando Aug 3, 2015
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
source 'https://rubygems.org'
gemspec
gemspec
gem 'opal', :git => "https://github.com/catprintlabs/opal.git"
32 changes: 17 additions & 15 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,46 +1,48 @@
GIT
remote: https://github.com/catprintlabs/opal.git
revision: 3682db6f2b23a584787a68d5338a7ee9cb35565a
specs:
opal (0.7.1)
hike (~> 1.2)
sourcemap (~> 0.1.0)
sprockets (>= 2.2.3, < 4.0.0)
tilt (~> 1.4)

PATH
remote: .
specs:
react.rb (0.0.2)
opal (~> 0.7.0)
opal
opal-activesupport

GEM
remote: https://rubygems.org/
specs:
hike (1.2.3)
multi_json (1.10.1)
opal (0.7.1)
hike (~> 1.2)
sourcemap (~> 0.1.0)
sprockets (>= 2.2.3, < 4.0.0)
tilt (~> 1.4)
opal-activesupport (0.1.0)
opal (>= 0.5.0, < 1.0.0)
opal-jquery (0.3.0)
opal (~> 0.7.0)
opal-rspec (0.4.1)
opal-rspec (0.4.2)
opal (~> 0.7.0)
rack (1.6.0)
rack-protection (1.5.3)
rack
react-source (0.12.2)
sinatra (1.4.5)
react-source (0.13.2)
sinatra (1.4.6)
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.4)
tilt (>= 1.3, < 3)
sourcemap (0.1.1)
sprockets (2.12.3)
hike (~> 1.2)
multi_json (~> 1.0)
sprockets (3.0.3)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
tilt (1.4.1)

PLATFORMS
ruby

DEPENDENCIES
opal!
opal-jquery
opal-rspec
react-source (~> 0.12)
Expand Down
151 changes: 100 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,89 +9,98 @@ It lets you write reactive UI components, with Ruby's elegance and compiled to r

## Installation

Currently this branch (0.8 in catprint labs) is being used with the following configuration.
It is suggested to begin with this
set of gems which is known to work and then add / remove them as needed. Let us know if you discover anything.

Currently we are using rails 3.x

```ruby
# Gemfile
gem "react.rb"
# gem 'react-rails', git: "https://github.com/catprintlabs/react-rails.git" # include if you want integration with rails
gem 'opal'

# gem 'opal', git: "https://github.com/catprintlabs/opal.git" # use this if you are stuck on rails 3.x
# gem 'opal-jquery', git: "https://github.com/catprintlabs/opal-jquery.git" # same as above

# include if you want integration with rails
# gem 'opal-rails'

# while not absolutely necessary you will probably want this at least for timers and such
# gem 'opal-browser'

gem 'opal-react', git: "https://github.com/catprintlabs/react.rb.git", :branch => 'opal-0.8'

# access active record models from opal!
# gem 'reactive_record', git: "https://github.com/catprintlabs/reactive-record.git"

# include if you want to use bootstrap
# gem 'react-bootstrap-rails'
```

and in your Opal application,

```ruby
require "opal"
require "opal-react"
require "react"

React.render(React.create_element('h1'){ "Hello World!" }, `document.body`)
```

For integration with server (Sinatra, etc), see setup of [TodoMVC](example/todos) or the [official docs](http://opalrb.org/docs/) of Opal.

## Usage

### A Simple Component
For a complete example covering most key features, as well as integration with a server (Sinatra, etc), see setup of [Examples](example/tutorial). For additional information on integrating Opal with a server see the [official docs](http://opalrb.org/docs/) of Opal.

A ruby class which define method `render` is a valid component.
## React Overview

```ruby
class HelloMessage
def render
React.create_element("div") { "Hello World!" }
end
end
### Basics

puts React.render_to_static_markup(React.create_element(HelloMessage))
The biggest problem with react is that its almost too simple.

# => '<div>Hello World!</div>'
```
In react you define components. Components are simply classes that have a "render" method. The render method "draws" a chunk of
HTML.

### More complicated one

To hook into native ReactComponent life cycle, the native `this` will be passed to the class's initializer. And all corresponding life cycle methods (`componentDidMount`, etc) will be invoked on the instance using the snake-case method name.
Here is a very simple component:

```ruby
class HelloMessage
def initialize(native)
@native = Native(native)
end

def component_will_mount
puts "will mount!"
end
require 'opal'
require 'opal-react'

class Hello
def render
React.create_element("div") { "Hello #{@native[:props][:name]}!" }
"hello world"
end
end

puts React.render_to_static_markup(React.create_element(HelloMessage, name: 'John'))

# => will_mount!
# => '<div>Hello John!</div>'
```

### React::Component

Hey, we are using Ruby, simply include `React::Component` to save your typing and have some handy methods defined.
Include the `React::Component` mixin in a class to turn it into a react component

```ruby
require 'opal'
require 'opal-react'

class HelloMessage
include React::Component

include React::Component # will create a new component named HelloMessage

MSG = {great: 'Cool!', bad: 'Cheer up!'}

define_state(:foo) { "Default greeting" }
optional_param :mood
required_param :name
define_state :foo, "Default greeting"

before_mount do
self.foo = "#{self.foo}: #{MSG[params[:mood]]}"
before_mount do # you can define life cycle callbacks inline
foo! "#{name}: #{MSG[mood]}" if mood # change the state of foo using foo!, read the state using foo
end

after_mount :log
after_mount :log # you can also define life cycle callbacks by reference to a method

def log
puts "mounted!"
end

def render
div do
span { self.foo + " #{params[:name]}!" }
def render # render method MUST return just one component
div do # basic dsl syntax component_name(options) { ...children... }
span { "#{foo} #{name}!" } # all html5 components are defined with lower case text
end
end
end
Expand All @@ -100,17 +109,16 @@ class App
include React::Component

def render
present HelloMessage, name: 'John', mood: 'great'
HelloMessage name: 'John', mood: :great # new components are accessed via the class name
end
end

puts React.render_to_static_markup(React.create_element(App))

# => '<div><span>Default greeting: Cool! John!</span></div>'
# later we will talk about nicer ways to do this: For now wait till doc is loaded
# then tell React to create an "App" and render it into the document body.

React.render(React.create_element(App), `document.body`)
`window.onload = #{lambda {React.render(React.create_element(App), `document.body`)}}`

# mounted!
# -> console says: mounted!
```

* Callback of life cycle could be created through helpers `before_mount`, `after_mount`, etc
Expand Down Expand Up @@ -204,6 +212,47 @@ end
# => ... for 5 times then stop ticking after 5 seconds
```


### A Simple Component

A ruby class which define method `render` is a valid component.

```ruby
class HelloMessage
def render
React.create_element("div") { "Hello World!" }
end
end

puts React.render_to_static_markup(React.create_element(HelloMessage))

# => '<div>Hello World!</div>'
```

### More complicated one

To hook into native ReactComponent life cycle, the native `this` will be passed to the class's initializer. And all corresponding life cycle methods (`componentDidMount`, etc) will be invoked on the instance using the snake-case method name.

```ruby
class HelloMessage
def initialize(native)
@native = Native(native)
end

def component_will_mount
puts "will mount!"
end

def render
React.create_element("div") { "Hello #{@native[:props][:name]}!" }
end
end

puts React.render_to_static_markup(React.create_element(HelloMessage, name: 'John'))

# => will_mount!
# => '<div>Hello John!</div>'
```
## Example

* React Tutorial: see [example/react-tutorial](example/react-tutorial), the original CommentBox example.
Expand Down
7 changes: 7 additions & 0 deletions example/examples/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source 'http://rubygems.org'

gem 'opal'
gem 'opal-react', :path => '../..'
gem 'sinatra'
#gem 'opal-jquery'
gem 'react-source'
45 changes: 45 additions & 0 deletions example/examples/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
PATH
remote: ../..
specs:
opal-react (0.1.1)
opal
opal-activesupport

GEM
remote: http://rubygems.org/
specs:
hike (1.2.3)
opal (0.8.0)
hike (~> 1.2)
sourcemap (~> 0.1.0)
sprockets (~> 3.1)
tilt (>= 1.4)
opal-activesupport (0.1.0)
opal (>= 0.5.0, < 1.0.0)
opal-jquery (0.4.0)
opal (>= 0.7.0, < 0.9.0)
rack (1.6.4)
rack-protection (1.5.3)
rack
react-source (0.13.3)
sinatra (1.4.6)
rack (~> 1.4)
rack-protection (~> 1.4)
tilt (>= 1.3, < 3)
sourcemap (0.1.1)
sprockets (3.2.0)
rack (~> 1.0)
tilt (2.0.1)

PLATFORMS
ruby

DEPENDENCIES
opal
opal-jquery
opal-react!
react-source
sinatra

BUNDLED WITH
1.10.2
44 changes: 44 additions & 0 deletions example/examples/config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# config.ru
require 'bundler'
Bundler.require

require "react/source"

Opal::Processor.source_map_enabled = true

opal = Opal::Server.new {|s|
s.append_path './'
s.append_path File.dirname(::React::Source.bundled_path_for("react-with-addons.js"))
s.main = 'example'
s.debug = true
}

map opal.source_maps.prefix do
run opal.source_maps
end rescue nil

map '/assets' do
run opal.sprockets
end

get '/example/:example' do
example = params[:example]
<<-HTML
<!doctype html>
<html>
<head>
<title>Example: #{example}.rb</title>
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script>
<script src="/assets/react-with-addons.min.js"></script>
<script src="/assets/#{example}.js"></script>
<script>#{Opal::Processor.load_asset_code(opal.sprockets, example+".js")}</script>
</head>
<body>
<div id="content"></div>
</body>
</html>
HTML
end

run Sinatra::Application
Loading