Skip to content

Commit fdf742d

Browse files
committed
Introduce InertiaRails.scroll
1 parent e3a3c3f commit fdf742d

16 files changed

+1673
-53
lines changed

Gemfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ gem 'responders'
1717
gem 'rspec-rails', '~> 6.0'
1818
gem 'rubocop', '~> 1.21'
1919
gem 'sqlite3'
20+
21+
gem 'kaminari'
22+
gem 'pagy'

lib/inertia_rails/defer_prop.rb

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,16 @@
22

33
module InertiaRails
44
class DeferProp < IgnoreOnFirstLoadProp
5-
DEFAULT_GROUP = 'default'
5+
prepend PropMergeable
66

7-
attr_reader :group, :match_on
7+
DEFAULT_GROUP = 'default'
88

9-
def initialize(group: nil, merge: nil, deep_merge: nil, match_on: nil, &block)
10-
raise ArgumentError, 'Cannot set both `deep_merge` and `merge` to true' if deep_merge && merge
9+
attr_reader :group
1110

11+
def initialize(**props, &block)
1212
super(&block)
1313

14-
@group = group || DEFAULT_GROUP
15-
@merge = merge || deep_merge
16-
@deep_merge = deep_merge
17-
@match_on = match_on.nil? ? nil : Array(match_on)
18-
end
19-
20-
def merge?
21-
@merge
22-
end
23-
24-
def deep_merge?
25-
@deep_merge
14+
@group = props[:group] || DEFAULT_GROUP
2615
end
2716
end
2817
end

lib/inertia_rails/inertia_rails.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
# frozen_string_literal: true
22

3+
require 'inertia_rails/prop_mergeable'
34
require 'inertia_rails/base_prop'
45
require 'inertia_rails/ignore_on_first_load_prop'
56
require 'inertia_rails/always_prop'
67
require 'inertia_rails/lazy_prop'
78
require 'inertia_rails/optional_prop'
89
require 'inertia_rails/defer_prop'
910
require 'inertia_rails/merge_prop'
11+
require 'inertia_rails/scroll_prop'
1012
require 'inertia_rails/configuration'
1113
require 'inertia_rails/meta_tag'
1214

@@ -34,8 +36,8 @@ def always(&block)
3436
AlwaysProp.new(&block)
3537
end
3638

37-
def merge(match_on: nil, &block)
38-
MergeProp.new(match_on: match_on, &block)
39+
def merge(...)
40+
MergeProp.new(...)
3941
end
4042

4143
def deep_merge(match_on: nil, &block)
@@ -45,5 +47,9 @@ def deep_merge(match_on: nil, &block)
4547
def defer(group: nil, merge: nil, deep_merge: nil, match_on: nil, &block)
4648
DeferProp.new(group: group, merge: merge, deep_merge: deep_merge, match_on: match_on, &block)
4749
end
50+
51+
def scroll(metadata = nil, **options, &block)
52+
ScrollProp.new(metadata: metadata, **options, &block)
53+
end
4854
end
4955
end

lib/inertia_rails/merge_prop.rb

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,11 @@
22

33
module InertiaRails
44
class MergeProp < BaseProp
5-
attr_reader :match_on
5+
prepend PropMergeable
66

7-
def initialize(deep_merge: false, match_on: nil, &block)
7+
def initialize(**_props, &block)
88
super(&block)
9-
@deep_merge = deep_merge
10-
@match_on = match_on.nil? ? nil : Array(match_on)
11-
end
12-
13-
def merge?
14-
true
15-
end
16-
17-
def deep_merge?
18-
@deep_merge
9+
@merge = true
1910
end
2011
end
2112
end
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# frozen_string_literal: true
2+
3+
module InertiaRails
4+
module PropMergeable
5+
attr_reader :match_on, :appends_at_paths, :prepends_at_paths
6+
7+
def initialize(**props, &block)
8+
raise ArgumentError, 'Cannot set both `deep_merge` and `merge` to true' if props[:deep_merge] && props[:merge]
9+
10+
@deep_merge = props.fetch(:deep_merge, false)
11+
@merge = props[:merge] || @deep_merge
12+
@match_on = props[:match_on].nil? ? nil : Array(props[:match_on])
13+
@appends_at_paths = []
14+
@prepends_at_paths = []
15+
@append = true
16+
17+
append(props[:append]) if props.key?(:append)
18+
prepend(props[:prepend]) if props.key?(:prepend)
19+
20+
super
21+
end
22+
23+
def appends_at_root?
24+
@append && merges_at_root?
25+
end
26+
27+
def prepends_at_root?
28+
!@append && merges_at_root?
29+
end
30+
31+
def merges_at_root?
32+
merge? && appends_at_paths.none? && prepends_at_paths.none?
33+
end
34+
35+
def merge?
36+
@merge
37+
end
38+
39+
def deep_merge?
40+
@deep_merge
41+
end
42+
43+
private
44+
45+
def append(path, match_on: nil)
46+
case path
47+
when TrueClass, FalseClass
48+
@append = path
49+
when String
50+
@appends_at_paths << path
51+
when Array
52+
@appends_at_paths += path
53+
when Hash
54+
@match_on ||= []
55+
path.each do |key, value|
56+
@appends_at_paths << key.to_s
57+
@match_on << "#{key}.#{value}" if value
58+
end
59+
end
60+
61+
(@match_on ||= []) << "#{path}.#{match_on}" if match_on && path.is_a?(String)
62+
end
63+
64+
def prepend(path, match_on: nil)
65+
case path
66+
when TrueClass, FalseClass
67+
@append = !path
68+
when String
69+
@prepends_at_paths << path
70+
when Array
71+
@prepends_at_paths += path
72+
when Hash
73+
@match_on ||= []
74+
path.each do |key, value|
75+
@prepends_at_paths << key.to_s
76+
@match_on << "#{key}.#{value}" if value
77+
end
78+
end
79+
80+
(@match_on ||= []) << "#{path}.#{match_on}" if match_on && path.is_a?(String)
81+
end
82+
end
83+
end

lib/inertia_rails/renderer.rb

Lines changed: 79 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,13 @@ def computed_props
104104
.tap do |props| # Add meta tags last (never transformed)
105105
props[:_inertia_meta] = meta_tags if meta_tags.present?
106106
end
107-
108107
# rubocop:enable Style/MultilineBlockChain
109108
end
110109

111110
def page
112-
default_page = {
111+
return @page if defined?(@page)
112+
113+
@page = {
113114
component: component,
114115
props: computed_props,
115116
url: @request.original_fullpath,
@@ -119,21 +120,11 @@ def page
119120
}
120121

121122
deferred_props = deferred_props_keys
122-
default_page[:deferredProps] = deferred_props if deferred_props.present?
123-
124-
deep_merge_props, merge_props = all_merge_props.partition do |_key, prop|
125-
prop.deep_merge?
126-
end
123+
@page[:deferredProps] = deferred_props if deferred_props.present?
124+
@page[:scrollProps] = scroll_props if scroll_props.present?
125+
@page.merge!(resolve_merge_props)
127126

128-
match_props_on = all_merge_props.filter_map do |key, prop|
129-
prop.match_on.map { |ms| "#{key}.#{ms}" } if prop.match_on.present?
130-
end.flatten
131-
132-
default_page[:mergeProps] = merge_props.map(&:first) if merge_props.present?
133-
default_page[:deepMergeProps] = deep_merge_props.map(&:first) if deep_merge_props.present?
134-
default_page[:matchPropsOn] = match_props_on if match_props_on.present?
135-
136-
default_page
127+
@page
137128
end
138129

139130
def deep_transform_props(props, parent_path = [])
@@ -165,10 +156,28 @@ def deferred_props_keys
165156
end
166157
end
167158

168-
def all_merge_props
169-
@all_merge_props ||= @props.select do |key, prop|
159+
def resolve_merge_props
160+
deep_merge_props, merge_props = all_merge_props.partition do |_key, prop|
161+
prop.deep_merge?
162+
end
163+
164+
{
165+
mergeProps: append_merge_props(merge_props),
166+
prependProps: prepend_merge_props(merge_props),
167+
deepMergeProps: deep_merge_props.map!(&:first),
168+
matchPropsOn: resolve_match_on_props,
169+
}.delete_if { |_, v| v.blank? }
170+
end
171+
172+
def resolve_match_on_props
173+
all_merge_props.filter_map do |key, prop|
174+
prop.match_on.map! { |ms| "#{key}.#{ms}" } if prop.match_on.present?
175+
end.flatten
176+
end
177+
178+
def requested_merge_props
179+
@requested_merge_props ||= @props.select do |key, prop|
170180
next unless prop.try(:merge?)
171-
next if reset_keys.include?(key)
172181
next if rendering_partial_component? && (
173182
(partial_keys.present? && partial_keys.exclude?(key.name)) ||
174183
(partial_except_keys.present? && partial_except_keys.include?(key.name))
@@ -178,16 +187,64 @@ def all_merge_props
178187
end
179188
end
180189

190+
def append_merge_props(props)
191+
return props if props.empty?
192+
193+
root_append_props, nested_append_props = props.partition { |_key, prop| prop.appends_at_root? }
194+
195+
result = Set.new(root_append_props.map!(&:first))
196+
197+
nested_append_props.each do |key, prop|
198+
prop.appends_at_paths.each do |path|
199+
result.add("#{key}.#{path}")
200+
end
201+
end
202+
203+
result.to_a
204+
end
205+
206+
def prepend_merge_props(props)
207+
return props if props.empty?
208+
209+
root_prepend_props, nested_prepend_props = props.partition { |_key, prop| prop.prepends_at_root? }
210+
211+
result = Set.new(root_prepend_props.map!(&:first))
212+
213+
nested_prepend_props.each do |key, prop|
214+
prop.prepends_at_paths.each do |path|
215+
result.add("#{key}.#{path}")
216+
end
217+
end
218+
219+
result.to_a
220+
end
221+
222+
def scroll_props
223+
return @scroll_props if defined?(@scroll_props)
224+
225+
@scroll_props = {}
226+
requested_merge_props.each do |key, prop|
227+
next unless prop.is_a?(ScrollProp)
228+
229+
@scroll_props[key] = prop.metadata.merge!(reset: reset_keys.include?(key))
230+
end
231+
@scroll_props
232+
end
233+
234+
def all_merge_props
235+
@all_merge_props ||= requested_merge_props.reject { |key,| reset_keys.include?(key) }
236+
end
237+
181238
def partial_keys
182-
@partial_keys ||= (@request.headers['X-Inertia-Partial-Data'] || '').split(',').compact
239+
@partial_keys ||= (@request.headers['X-Inertia-Partial-Data'] || '').split(',').compact_blank!
183240
end
184241

185242
def reset_keys
186-
(@request.headers['X-Inertia-Reset'] || '').split(',').compact.map(&:to_sym)
243+
@reset_keys ||= (@request.headers['X-Inertia-Reset'] || '').split(',').compact_blank!.map!(&:to_sym)
187244
end
188245

189246
def partial_except_keys
190-
(@request.headers['X-Inertia-Partial-Except'] || '').split(',').compact
247+
@partial_except_keys ||= (@request.headers['X-Inertia-Partial-Except'] || '').split(',').compact_blank!
191248
end
192249

193250
def rendering_partial_component?

0 commit comments

Comments
 (0)