Skip to content

Commit fbbbf5f

Browse files
authored
Merge pull request #45 from geolessel/more-options
feature(react_component): allow `html_element` and other options
2 parents 47f7890 + 9f47588 commit fbbbf5f

File tree

6 files changed

+87
-19
lines changed

6 files changed

+87
-19
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ dependencies in `mix.exs`:
3232
```elixir
3333
def deps do
3434
[
35-
{:react_phoenix, "~> 1.0.1"}
35+
{:react_phoenix, "~> 1.1.0"}
3636
]
3737
end
3838
```

lib/react_phoenix/client_side.ex

+31-4
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,41 @@ defmodule ReactPhoenix.ClientSide do
7676
7777
The resulting `<div>` tag is formatted specifically for the included javascript
7878
helper to then turn into your named React component and then pass in the props specified.
79+
80+
## Options
81+
82+
You can pass a Keyword list of options that controls the rendering of the final html element
83+
that the react component will be rendered into.
84+
85+
* `target_id` - If you have a rendered html element already on your page with a unique `id`
86+
attribute, this will render your react component into _that_ already-existing element
87+
instead of creating one of its own. The default is an empty string, which will cause it
88+
to render into its own created element.
89+
* `html_element` - By default, `ReactPhoenix.ClientSide.react_component/3` will create a
90+
`div` for output in your template. If you'd rather use a different element (`span`, `ul`, etc.),
91+
you can specify it here as an atom (e.g. `:span`, `:ul`, etc.).
92+
93+
Anything else you pass in will be further passed directly to the html element it
94+
creates as attributes. This allows you more control over the element. Some useful examples
95+
of what you would specify are `class`, `id`, `style`, etc.
7996
"""
80-
@spec react_component(name :: String.t(), props :: map, opts :: [target_id: String.t()]) ::
97+
@spec react_component(name :: String.t(), props :: map, opts :: list()) ::
8198
Phoenix.HTML.safe()
8299
def react_component(name, props, opts) when is_map(props) do
83100
props = Jason.encode!(props)
84101

85-
content_tag(:div, "", [
86-
{:data, [react_class: name, react_props: props, react_target_id: opts[:target_id]]}
87-
])
102+
{html_element, opts} = Keyword.pop(opts, :html_element, :div)
103+
{target_id, opts} = Keyword.pop(opts, :target_id, "")
104+
105+
content_tag(
106+
html_element,
107+
"",
108+
Keyword.merge(
109+
[
110+
{:data, [react_class: name, react_props: props, react_target_id: target_id]}
111+
],
112+
opts
113+
)
114+
)
88115
end
89116
end

mix.exs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
defmodule ReactPhoenix.Mixfile do
22
use Mix.Project
33

4-
@version "1.0.1"
4+
@version "1.1.0"
55
@source_url "https://github.com/geolessel/react-phoenix"
66

77
def project do

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-phoenix",
3-
"version": "1.0.1",
3+
"version": "1.1.0",
44
"scripts": {
55
"release": "node ./node_modules/.bin/babel src/react_phoenix.js | node ./node_modules/uglify-js/bin/uglifyjs - --mangle --compress --output priv/js/react_phoenix.js"
66
},

priv/js/react_phoenix.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/react_phoenix/client_side_test.exs

+52-11
Original file line numberDiff line numberDiff line change
@@ -3,44 +3,85 @@ defmodule ReactPhoenix.ClientSideTest do
33
doctest ReactPhoenix.ClientSide
44
import ReactPhoenix.ClientSide
55

6-
test "react_component returns a safe tuple" do
6+
test "react_component/1 returns a safe tuple" do
77
assert {:safe, _} = react_component("test")
88
end
99

10-
test "react_component returns a renderable div" do
11-
html = Phoenix.HTML.safe_to_string(react_component("test"))
10+
test "react_component/1 returns a renderable div" do
11+
html =
12+
"test"
13+
|> react_component()
14+
|> Phoenix.HTML.safe_to_string()
15+
1216
assert String.match?(html, ~r|^<div.*></div>$|)
1317
end
1418

15-
test "react_component returns a renderable div with data-react-class containing component name" do
16-
html = Phoenix.HTML.safe_to_string(react_component("test"))
19+
test "react_component/1 returns a renderable div with data-react-class containing component name" do
20+
html =
21+
"test"
22+
|> react_component()
23+
|> Phoenix.HTML.safe_to_string()
24+
1725
assert String.match?(html, ~r|data-react-class="test"|)
1826
end
1927

20-
test "react_component returns a renderable div with data-react-props containing props list" do
21-
html = Phoenix.HTML.safe_to_string(react_component("test", my: "props"))
28+
test "react_component/2 returns a renderable div with data-react-props containing props list" do
29+
html =
30+
"test"
31+
|> react_component(my: "props")
32+
|> Phoenix.HTML.safe_to_string()
2233

2334
expected =
2435
"<div data-react-class=\"test\" data-react-props=\"{&quot;my&quot;:&quot;props&quot;}\"></div>"
2536

2637
assert html == expected
2738
end
2839

29-
test "react_component returns a renderable div with data-react-props containing props map" do
30-
html = Phoenix.HTML.safe_to_string(react_component("test", %{my: "props"}))
40+
test "react_component/2 returns a renderable div with data-react-props containing props map" do
41+
html =
42+
"test"
43+
|> react_component(%{my: "props"})
44+
|> Phoenix.HTML.safe_to_string()
3145

3246
expected =
3347
"<div data-react-class=\"test\" data-react-props=\"{&quot;my&quot;:&quot;props&quot;}\"></div>"
3448

3549
assert html == expected
3650
end
3751

38-
test "react_component accepts a target div option" do
39-
html = Phoenix.HTML.safe_to_string(react_component("test", %{}, target_id: "test-id"))
52+
test "react_component/3 accepts a target div option" do
53+
html =
54+
"test"
55+
|> react_component(%{}, target_id: "test-id")
56+
|> Phoenix.HTML.safe_to_string()
4057

4158
expected =
4259
"<div data-react-class=\"test\" data-react-props=\"{}\" data-react-target-id=\"test-id\"></div>"
4360

4461
assert html == expected
4562
end
63+
64+
test "react_component/3 accepts a html_element option" do
65+
html =
66+
"test"
67+
|> react_component(%{}, html_element: :span)
68+
|> Phoenix.HTML.safe_to_string()
69+
70+
expected =
71+
"<span data-react-class=\"test\" data-react-props=\"{}\" data-react-target-id=\"\"></span>"
72+
73+
assert html == expected
74+
end
75+
76+
test "react_component/3 passes on extra options to the html element" do
77+
html =
78+
"test"
79+
|> react_component(%{}, class: "row", id: "content")
80+
|> Phoenix.HTML.safe_to_string()
81+
82+
expected =
83+
"<div class=\"row\" data-react-class=\"test\" data-react-props=\"{}\" data-react-target-id=\"\" id=\"content\"></div>"
84+
85+
assert html == expected
86+
end
4687
end

0 commit comments

Comments
 (0)