Skip to content

Commit fdd8efc

Browse files
committed
closes #111 #112
1 parent 8e8f0a8 commit fdd8efc

File tree

5 files changed

+164
-9
lines changed

5 files changed

+164
-9
lines changed

ruby/hyper-component/lib/hyperstack/component/element.rb

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ def initialize(native_element, type = nil, properties = {}, block = nil)
3333
@native = native_element
3434
end
3535

36+
def _update_ref(x)
37+
@ref = x
38+
@_child_element._update_ref(x) if @_child_element
39+
end
40+
41+
def ref
42+
@ref || raise("#{self} has not been mounted yet")
43+
end
44+
45+
def dom_node
46+
@type.is_a?(String) ? ref : ref.dom_node
47+
end
48+
3649
# Attach event handlers.
3750

3851
def on(*event_names, &block)
@@ -49,8 +62,8 @@ def render(*props, &new_block)
4962
if props.empty?
5063
Hyperstack::Internal::Component::RenderingContext.render(self)
5164
else
52-
props = Hyperstack::Internal::Component::ReactWrapper.convert_props(props)
53-
Hyperstack::Internal::Component::RenderingContext.render(
65+
props = Hyperstack::Internal::Component::ReactWrapper.convert_props(*props)
66+
@_child_element = Hyperstack::Internal::Component::RenderingContext.render(
5467
Element.new(`React.cloneElement(#{@native}, #{props.shallow_to_n})`,
5568
type, @properties.merge(props), block)
5669
)

ruby/hyper-component/lib/hyperstack/internal/component/react_wrapper.rb

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ def self.create_element(type, *args, &block)
178178
end
179179

180180
# Convert Passed in properties
181-
properties = convert_props(args)
181+
ele = nil
182+
properties = convert_props(type, { ref: ->(ref) { ele._update_ref(ref) } }, *args)
182183
params << properties.shallow_to_n
183184

184185
# Children Nodes
@@ -190,14 +191,14 @@ def self.create_element(type, *args, &block)
190191
}
191192
}
192193
end
193-
Hyperstack::Component::Element.new(`React.createElement.apply(null, #{params})`, type, properties, block)
194+
ele = Hyperstack::Component::Element.new(`React.createElement.apply(null, #{params})`, type, properties, block)
194195
end
195196

196197
def self.clear_component_class_cache
197198
@@component_classes = {}
198199
end
199200

200-
def self.convert_props(args)
201+
def self.convert_props(type, *args)
201202
# merge args together into a single properties hash
202203
properties = {}
203204
args.each do |arg|
@@ -234,14 +235,26 @@ def self.convert_props(args)
234235
# process properties according to react rules
235236
props = {}
236237
properties.each do |key, value|
237-
if ["style", "dangerously_set_inner_HTML"].include? key
238+
if %w[style dangerously_set_inner_HTML].include? key
238239
props[lower_camelize(key)] = value.to_n
239240

240-
elsif key == "className"
241+
elsif key == :className
241242
props[key] = value.join(' ')
242243

243-
elsif key == "key"
244-
props["key"] = value.to_key
244+
elsif key == :key
245+
props[:key] = value.to_key
246+
247+
elsif key == :init
248+
if %w[select textarea].include? type
249+
key = :defaultValue
250+
elsif type == :input
251+
key = if %w[radio checkbox].include? properties[:type]
252+
:defaultChecked
253+
else
254+
:defaultValue
255+
end
256+
end
257+
props[key] = value
245258

246259
elsif key == 'ref'
247260
unless value.respond_to?(:call)

ruby/hyper-component/spec/client_features/misc_fixes_spec.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class TestComp < HyperComponent
4747
input.send_keys 'hello'
4848
expect(input.value).to eq('123hello4567890')
4949
end
50+
5051
# it "and it can still use the deprecated mutate syntax" do
5152
# mount "TestComp" do
5253
# class TestComp < Hyperloop::Component
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
require 'spec_helper'
2+
3+
describe 'getting ref from an Element', js: true do
4+
it 'the ref method will return the mounted component instance' do
5+
mount 'TestComponent' do
6+
class AnotherComponent < HyperComponent
7+
render(DIV) { "another component"}
8+
end
9+
class TestComponent < HyperComponent
10+
after_mount { raise "Failed" unless @another_component.ref.is_a? AnotherComponent }
11+
render do
12+
@another_component = AnotherComponent()
13+
end
14+
end
15+
end
16+
expect(page).to have_content('another component')
17+
end
18+
19+
it 'the ref method has a dom_node method that works with native dom nodes' do
20+
mount 'TestComponent' do
21+
class TestComponent < HyperComponent
22+
after_mount { raise "Failed" unless jQ[@another_component].html == 'my sweet div' }
23+
render do
24+
@another_component = DIV { 'my sweet div' }
25+
end
26+
end
27+
end
28+
expect(page).to have_content('my sweet div')
29+
end
30+
31+
it 'the ref method has a dom_node method that works with application components' do
32+
mount 'TestComponent' do
33+
class AnotherComponent < HyperComponent
34+
render(DIV) { "another component"}
35+
end
36+
class TestComponent < HyperComponent
37+
after_mount { raise "Failed" unless jQ[@another_component].html == 'another component' }
38+
render do
39+
@another_component = AnotherComponent()
40+
end
41+
end
42+
end
43+
expect(page).to have_content('another component')
44+
end
45+
46+
it 'the ref method has a dom_node method that works with application components' do
47+
mount 'TestComponent' do
48+
class AnotherComponent < HyperComponent
49+
other :others
50+
render(DIV) { "another component named #{@Others[:foo]}"}
51+
end
52+
class TestComponent < HyperComponent
53+
after_mount { raise "Failed" unless @ref_1.ref == @ref_2.ref }
54+
render do
55+
@ref_1 = AnotherComponent().as_node
56+
@ref_2 = @ref_1.render(foo: :bar)
57+
end
58+
end
59+
end
60+
expect(page).to have_content('another component named bar')
61+
end
62+
63+
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require 'spec_helper'
2+
3+
describe 'uncontrolled components initial value', js: true do
4+
it 'with default (text) INPUT tag' do
5+
mount 'TestComponent' do
6+
class TestComponent < HyperComponent
7+
render(INPUT, id: :input, init: 'some value')
8+
end
9+
end
10+
expect(find('#input').value).to eq('some value')
11+
end
12+
it 'with text INPUT tag' do
13+
mount 'TestComponent' do
14+
class TestComponent < HyperComponent
15+
render(INPUT, id: :input, type: :text, init: 'some value')
16+
end
17+
end
18+
expect(find('#input').value).to eq('some value')
19+
end
20+
it 'with TEXTAREA tag' do
21+
mount 'TestComponent' do
22+
class TestComponent < HyperComponent
23+
render(TEXTAREA, id: :input, init: 'some value')
24+
end
25+
end
26+
expect(find('#input').value).to eq('some value')
27+
end
28+
it 'with SELECT tag' do
29+
mount 'TestComponent' do
30+
class TestComponent < HyperComponent
31+
render(SELECT, id: :input, init: 'some value') do
32+
OPTION(value: 'wrong value')
33+
OPTION(id: :correct_option, value: 'some value')
34+
OPTION(value: 'other value')
35+
end
36+
end
37+
end
38+
expect(find('#input').value).to eq('some value')
39+
expect(find('#correct_option')).to be_selected
40+
end
41+
it 'with checkbox INPUT tag' do
42+
mount 'TestComponent' do
43+
class TestComponent < HyperComponent
44+
render(DIV) do
45+
INPUT(id: :input1, type: :checkbox, init: true)
46+
INPUT(id: :input2, type: :checkbox, init: false)
47+
end
48+
end
49+
end
50+
expect(find('#input1')).to be_checked
51+
expect(find('#input2')).not_to be_checked
52+
end
53+
it 'with radio INPUT tag' do
54+
mount 'TestComponent' do
55+
class TestComponent < HyperComponent
56+
render(DIV) do
57+
INPUT(id: :input1, type: :radio, init: true)
58+
INPUT(id: :input2, type: :radio, init: false)
59+
end
60+
end
61+
end
62+
expect(find('#input1')).to be_checked
63+
expect(find('#input2')).not_to be_checked
64+
end
65+
end

0 commit comments

Comments
 (0)