super 0.17.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/app/assets/javascripts/super/application.js +1260 -117
  4. data/app/assets/stylesheets/super/application.css +90711 -90034
  5. data/app/controllers/super/application_controller.rb +34 -4
  6. data/app/controllers/super/substructure_controller.rb +125 -29
  7. data/app/helpers/super/form_builder_helper.rb +4 -4
  8. data/app/views/layouts/super/application.html.erb +1 -1
  9. data/app/views/super/application/_batch_button.html.erb +12 -0
  10. data/app/views/super/application/_batch_checkbox.csv.erb +1 -0
  11. data/app/views/super/application/_batch_checkbox.html.erb +9 -0
  12. data/app/views/super/application/_batch_form.html.erb +3 -0
  13. data/app/views/super/application/_collection_header.html.erb +7 -6
  14. data/app/views/super/application/_csv_button.html.erb +25 -0
  15. data/app/views/super/application/_display_actions.html.erb +2 -2
  16. data/app/views/super/application/_form.html.erb +1 -1
  17. data/app/views/super/application/_layout.html.erb +13 -14
  18. data/app/views/super/application/_link.html.erb +8 -0
  19. data/app/views/super/application/_member_header.html.erb +7 -7
  20. data/app/views/super/application/_pagination.html.erb +2 -4
  21. data/app/views/super/application/_site_footer.html.erb +1 -1
  22. data/app/views/super/application/_site_header.html.erb +4 -4
  23. data/app/views/super/application/_view_chain.html.erb +5 -0
  24. data/app/views/super/application/index.csv.erb +14 -0
  25. data/config/locales/en.yml +15 -1
  26. data/frontend/super-frontend/dist/application.css +90711 -90034
  27. data/frontend/super-frontend/dist/application.js +6512 -5379
  28. data/frontend/super-frontend/dist/package.json +13 -0
  29. data/lib/generators/super/webpacker/USAGE +1 -7
  30. data/lib/generators/super/webpacker/templates/pack_super_application.js.tt +2 -0
  31. data/lib/generators/super/webpacker/webpacker_generator.rb +10 -6
  32. data/lib/super/action_inquirer.rb +3 -0
  33. data/lib/super/cheat.rb +1 -0
  34. data/lib/super/display/schema_types.rb +6 -0
  35. data/lib/super/display.rb +2 -1
  36. data/lib/super/engine.rb +5 -0
  37. data/lib/super/error.rb +11 -0
  38. data/lib/super/form/schema_types.rb +8 -36
  39. data/lib/super/form_builder/action_text_methods.rb +16 -0
  40. data/lib/super/form_builder/base_methods.rb +73 -0
  41. data/lib/super/form_builder/flatpickr_methods.rb +75 -0
  42. data/lib/super/form_builder/option_methods.rb +73 -0
  43. data/lib/super/form_builder.rb +143 -0
  44. data/lib/super/layout.rb +9 -33
  45. data/lib/super/link.rb +49 -70
  46. data/lib/super/link_builder.rb +24 -47
  47. data/lib/super/packaged_asset.rb +49 -0
  48. data/lib/super/pagination.rb +2 -1
  49. data/lib/super/reorderable_hash.rb +88 -0
  50. data/lib/super/reset.rb +20 -1
  51. data/lib/super/useful/i19.rb +35 -0
  52. data/lib/super/version.rb +1 -1
  53. data/lib/super/view_chain.rb +25 -0
  54. data/lib/super.rb +9 -1
  55. metadata +55 -10
  56. data/lib/generators/super/webpacker/templates/pack_super_application.js.erb.tt +0 -2
  57. data/lib/super/form/builder.rb +0 -289
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "@superadministration/super",
3
+ "description": "The frontend code for Super, a Rails admin framework",
4
+ "homepage": "https://github.com/superadministration/super",
5
+ "license": "LGPL-3.0-only",
6
+ "main": "application.js",
7
+ "files": [
8
+ "application.js",
9
+ "application.css",
10
+ "package.json"
11
+ ],
12
+ "version": "0.20.0"
13
+ }
@@ -1,15 +1,9 @@
1
1
  Description:
2
2
  Creates the necessary files for assets to be served under Webpacker
3
3
 
4
- Webpacker support requires that you install ERB support for Webpacker.
5
-
6
- Installing ERB on webpacker is usually done by running the command:
7
- `rails webpacker:install:erb`
8
-
9
4
  Example:
10
- rails webpacker:install:erb # if you hadn't set up ERB already
11
5
  rails generate super:webpacker
12
6
 
13
7
  This will:
14
- Create app/javascript/packs/super/application.js.erb
8
+ Create app/javascript/packs/super/application.js
15
9
  Modify config/initializers/super.rb
@@ -0,0 +1,2 @@
1
+ import Super from "@superadministration/super";
2
+ import "@superadministration/super/application.css";
@@ -7,12 +7,12 @@ module Super
7
7
  def copy_the_pack_file
8
8
  path =
9
9
  if Gem::Dependency.new("webpacker", ">= 6.0.0.beta2", "!= 6.0.0.pre1", "!= 6.0.0.pre2").matching_specs.any?
10
- "app/packs/entrypoints/super/application.js.erb"
10
+ "app/packs/entrypoints/super/application.js"
11
11
  else
12
- "app/javascript/packs/super/application.js.erb"
12
+ "app/javascript/packs/super/application.js"
13
13
  end
14
14
 
15
- template("pack_super_application.js.erb", path)
15
+ template("pack_super_application.js", path)
16
16
  end
17
17
 
18
18
  def set_asset_handler_to_webpacker
@@ -24,9 +24,13 @@ module Super
24
24
  )
25
25
  end
26
26
 
27
- def remind_about_erb
28
- say "Make sure ERB is set up for Webpacker!", :bold
29
- say "Run if needed: bundle exec rails webpacker:install:erb"
27
+ def install_via_yarn
28
+ super_root = Pathname.new(__dir__).join("../../../..")
29
+ if super_root.join("dummy_path.rb").file?
30
+ run "yarn add file:#{super_root.join("frontend/super-frontend/dist")}"
31
+ else
32
+ run "yarn add @superadministration/super@#{Super::VERSION} --exact"
33
+ end
30
34
  end
31
35
  end
32
36
  end
@@ -22,6 +22,9 @@ module Super
22
22
  "read" => %w[index show new edit],
23
23
  "write" => %w[create update destroy],
24
24
  "delete" => %w[destroy],
25
+
26
+ "collection" => %w[index new create],
27
+ "member" => %w[show edit update destroy],
25
28
  }
26
29
  end
27
30
 
data/lib/super/cheat.rb CHANGED
@@ -8,6 +8,7 @@ module Super
8
8
  paths
9
9
  .map { |f| File.read(File.expand_path(f, __dir__)) }
10
10
  .flat_map { |content| content.scan(/^\s+(?:helper_method )?def .*$/) }
11
+ .reject { |method| method =~ /\bdef self\./ }
11
12
  .map { |method| method.strip.sub(/^(?:helper_method )?def /, "#") }
12
13
 
13
14
  puts "== Super::ApplicationController"
@@ -129,6 +129,12 @@ module Super
129
129
  real(:column, &transform_block)
130
130
  end
131
131
 
132
+ def batch
133
+ real do |value|
134
+ Partial.new("batch_checkbox", locals: { value: value })
135
+ end
136
+ end
137
+
132
138
  def string; real(&:to_s); end
133
139
 
134
140
  def timestamp; real(&:to_s); end
data/lib/super/display.rb CHANGED
@@ -32,10 +32,11 @@ module Super
32
32
  yield(@fields, @schema_types)
33
33
  end
34
34
 
35
- def apply(action:)
35
+ def apply(action:, format:)
36
36
  @action_inquirer = action
37
37
  return self if !@action_inquirer.index?
38
38
  return self if @schema_types.actions_called?
39
+ return self if !format.html?
39
40
  @fields[:actions] = @schema_types.actions
40
41
  self
41
42
  end
data/lib/super/engine.rb CHANGED
@@ -15,6 +15,11 @@ module Super
15
15
  Super::Plugin::Registry.controller.ordered do |klass, method_name|
16
16
  Super::ApplicationController.public_send(method_name, klass)
17
17
  end
18
+
19
+ Super::PackagedAsset.warning_message =
20
+ if !Super::PackagedAsset.version_matches_gem?(Rails.root.join("package.json"))
21
+ I18n.t("super.mismatching_package_json_gemfile_versions")
22
+ end
18
23
  end
19
24
  end
20
25
  end
data/lib/super/error.rb CHANGED
@@ -30,11 +30,22 @@ module Super
30
30
  class ArgumentError < Error; end
31
31
  class AlreadyRegistered < Error; end
32
32
  class AlreadyTranscribed < Error; end
33
+ class NotImplementedError < Error; end
34
+ class IncompleteBuilder < Error; end
33
35
 
34
36
  class Enum < Error
35
37
  class ImpossibleValue < Enum; end
36
38
  class ArgumentError < Enum; end
37
39
  class UndefinedCase < Enum; end
38
40
  end
41
+
42
+ class ReorderableHash < Error
43
+ class DuplicateKey < ReorderableHash; end
44
+ class KeyError < ReorderableHash; end
45
+ end
46
+
47
+ class ViewChain < Error
48
+ class ChainAlreadyStarted < ViewChain; end
49
+ end
39
50
  end
40
51
  end
@@ -105,42 +105,6 @@ module Super
105
105
  Direct.new(super_builder: super_builder, method_name: method_name, args: args, kwargs: kwargs)
106
106
  end
107
107
 
108
- def select(*args, **kwargs)
109
- Direct.new(super_builder: true, method_name: :select!, args: args, kwargs: kwargs)
110
- end
111
-
112
- def text_field(*args, **kwargs)
113
- Direct.new(super_builder: true, method_name: :text_field!, args: args, kwargs: kwargs)
114
- end
115
-
116
- def rich_text_area(*args, **kwargs)
117
- Direct.new(super_builder: true, method_name: :rich_text_area!, args: args, kwargs: kwargs)
118
- end
119
-
120
- def check_box(*args, **kwargs)
121
- Direct.new(super_builder: true, method_name: :check_box!, args: args, kwargs: kwargs)
122
- end
123
-
124
- def date_flatpickr(*args, **kwargs)
125
- Direct.new(super_builder: true, method_name: :date_flatpickr!, args: args, kwargs: kwargs)
126
- end
127
-
128
- def datetime_flatpickr(*args, **kwargs)
129
- Direct.new(super_builder: true, method_name: :datetime_flatpickr!, args: args, kwargs: kwargs)
130
- end
131
-
132
- def hidden_field(*args, **kwargs)
133
- Direct.new(super_builder: false, method_name: :hidden_field, args: args, kwargs: kwargs)
134
- end
135
-
136
- def password_field(*args, **kwargs)
137
- Direct.new(super_builder: true, method_name: :password_field!, args: args, kwargs: kwargs)
138
- end
139
-
140
- def time_flatpickr(*args, **kwargs)
141
- Direct.new(super_builder: true, method_name: :time_flatpickr!, args: args, kwargs: kwargs)
142
- end
143
-
144
108
  def has_many(reader, **extras)
145
109
  subfields = Schema::Fields.new
146
110
  @fields.nested do
@@ -176,6 +140,14 @@ module Super
176
140
  nested: {}
177
141
  )
178
142
  end
143
+
144
+ def self.define_schema_type_for(method_name)
145
+ class_eval(<<~RUBY)
146
+ def #{method_name}(*args, **kwargs)
147
+ Direct.new(super_builder: true, method_name: :#{method_name}!, args: args, kwargs: kwargs)
148
+ end
149
+ RUBY
150
+ end
179
151
  end
180
152
  end
181
153
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class FormBuilder
5
+ class Wrappers
6
+ def rich_text_area(attribute, options = {})
7
+ options, defaults = split_defaults(options, class: "trix-content super-input w-full")
8
+ options[:class] = join_classes(defaults[:class], options[:class])
9
+
10
+ @builder.rich_text_area(attribute, options)
11
+ end
12
+
13
+ define_convenience :rich_text_area
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class FormBuilder
5
+ class Wrappers
6
+ skipped_field_helpers = [:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field]
7
+ (ActionView::Helpers::FormBuilder.field_helpers - skipped_field_helpers).each do |builder_method_name|
8
+ class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
9
+ def #{builder_method_name}(attribute, options = {})
10
+ options, defaults = split_defaults(options, class: "super-input w-full")
11
+ options[:class] = join_classes(defaults[:class], options[:class])
12
+
13
+ @builder.#{builder_method_name}(attribute, options)
14
+ end
15
+
16
+ define_convenience :#{builder_method_name}
17
+ RUBY
18
+ end
19
+
20
+ def label(attribute, text = nil, options = {}, &block)
21
+ options, defaults = split_defaults(options, class: "block")
22
+ options[:class] = join_classes(defaults[:class], options[:class])
23
+
24
+ @builder.label(attribute, text, options, &block)
25
+ end
26
+
27
+ def check_box(attribute, options = {}, checked_value = "1", unchecked_value = "0")
28
+ @builder.check_box(attribute, options, checked_value, unchecked_value)
29
+ end
30
+
31
+ def check_box!(attribute, checked_value: "1", unchecked_value: "0", label_text: nil, label: {}, field: {}, show_errors: true)
32
+ label[:super] ||= {}
33
+ label[:super] = { class: "select-none ml-1" }.merge(label[:super])
34
+ container do
35
+ compact_join([
36
+ "<div>".html_safe,
37
+ public_send(:check_box, attribute, field, checked_value, unchecked_value),
38
+ public_send(:label, attribute, label_text, label),
39
+ "</div>".html_safe,
40
+ show_errors && inline_errors(attribute),
41
+ ])
42
+ end
43
+ end
44
+
45
+ ::Super::Form::SchemaTypes.define_schema_type_for(:check_box)
46
+
47
+ # def file_field(attribute, options = {})
48
+ # end
49
+
50
+ # def file_field!(attribute, label_text: nil, label: {}, field: {}, show_errors: true)
51
+ # end
52
+
53
+ def hidden_field(attribute, options = {})
54
+ @builder.hidden_field(attribute, options)
55
+ end
56
+
57
+ # def radio_button(attribute, tag_value, options = {})
58
+ # @builder.radio_button(attribute, tag_value, options)
59
+ # end
60
+
61
+ # def radio_button(attribute, tag_value, label_text: nil, label: {}, field: {}, show_errors: true)
62
+ # end
63
+
64
+ def submit(value = nil, options = {})
65
+ value, options = nil, value if value.is_a?(Hash)
66
+ options, defaults = split_defaults(options, class: "super-button")
67
+ options[:class] = join_classes(defaults[:class], options[:class])
68
+
69
+ @builder.submit(value, options)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class FormBuilder
5
+ class Wrappers
6
+ def date_flatpickr(attribute, options = {})
7
+ options, defaults = split_defaults(
8
+ options,
9
+ class: "super-input w-full",
10
+ data: {
11
+ controller: "flatpickr",
12
+ flatpickr_options_value: {
13
+ dateFormat: "Y-m-d",
14
+ }
15
+ }
16
+ )
17
+ options[:class] = join_classes(defaults[:class], options[:class])
18
+ options[:data] = defaults[:data].deep_merge(options[:data] || {})
19
+ options[:value] = @builder.object.public_send(attribute).presence
20
+ options[:value] = options[:value].iso8601 if options[:value].respond_to?(:iso8601)
21
+
22
+ @builder.text_field(attribute, options)
23
+ end
24
+
25
+ define_convenience :date_flatpickr
26
+
27
+ def datetime_flatpickr(attribute, options = {})
28
+ options, defaults = split_defaults(
29
+ options,
30
+ class: "super-input w-full",
31
+ data: {
32
+ controller: "flatpickr",
33
+ flatpickr_options_value: {
34
+ enableSeconds: true,
35
+ enableTime: true,
36
+ dateFormat: "Z",
37
+ }
38
+ }
39
+ )
40
+ options[:class] = join_classes(defaults[:class], options[:class])
41
+ options[:data] = defaults[:data].deep_merge(options[:data] || {})
42
+ options[:value] = @builder.object.public_send(attribute).presence
43
+ options[:value] = options[:value].iso8601 if options[:value].respond_to?(:iso8601)
44
+
45
+ @builder.text_field(attribute, options)
46
+ end
47
+
48
+ define_convenience :datetime_flatpickr
49
+
50
+ def time_flatpickr(attribute, options = {})
51
+ options, defaults = split_defaults(
52
+ options,
53
+ class: "super-input w-full",
54
+ data: {
55
+ controller: "flatpickr",
56
+ flatpickr_options_value: {
57
+ enableSeconds: true,
58
+ enableTime: true,
59
+ noCalendar: true,
60
+ dateFormat: "H:i:S",
61
+ }
62
+ }
63
+ )
64
+ options[:class] = join_classes(defaults[:class], options[:class])
65
+ options[:data] = defaults[:data].deep_merge(options[:data] || {})
66
+ options[:value] = @builder.object.public_send(attribute).presence
67
+ options[:value] = options[:value].strftime("%H:%M:%S") if options[:value].respond_to?(:strftime)
68
+
69
+ @builder.text_field(attribute, options)
70
+ end
71
+
72
+ define_convenience :time_flatpickr
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ class FormBuilder
5
+ class Wrappers
6
+ def select(attribute, choices, options = {}, html_options = {}, &block)
7
+ options, defaults = split_defaults(options, include_blank: true)
8
+ options = defaults.merge(options)
9
+ html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
10
+ html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
11
+
12
+ @builder.select(attribute, choices, options, html_options, &block)
13
+ end
14
+
15
+ define_convenience :select
16
+
17
+ def collection_select(attribute, collection, value_method, text_method, options = {}, html_options = {})
18
+ options, defaults = split_defaults(options, include_blank: true)
19
+ options = defaults.merge(options)
20
+ html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
21
+ html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
22
+
23
+ @builder.collection_select(attribute, collection, value_method, text_method, options, html_options)
24
+ end
25
+
26
+ define_convenience :collection_select
27
+
28
+ def grouped_collection_select(attribute, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
29
+ options, defaults = split_defaults(options, include_blank: true)
30
+ options = defaults.merge(options)
31
+ html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
32
+ html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
33
+
34
+ @builder.grouped_collection_select(attribute, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
35
+ end
36
+
37
+ define_convenience :grouped_collection_select
38
+
39
+ def time_zone_select(attribute, priority_zones = nil, options = {}, html_options = {})
40
+ options, defaults = split_defaults(options, include_blank: true)
41
+ options = defaults.merge(options)
42
+ html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
43
+ html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
44
+
45
+ @builder.time_zone_select(attribute, priority_zones, options, html_options)
46
+ end
47
+
48
+ define_convenience :time_zone_select, priority_zones: "nil"
49
+
50
+ def collection_check_boxes(attribute, collection, value_method, text_method, options = {}, html_options = {}, &block)
51
+ options, defaults = split_defaults(options, include_blank: true)
52
+ options = defaults.merge(options)
53
+ html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
54
+ html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
55
+
56
+ @builder.collection_check_boxes(attribute, collection, value_method, text_method, options, html_options, &block)
57
+ end
58
+
59
+ define_convenience :collection_check_boxes
60
+
61
+ def collection_radio_buttons(attribute, collection, value_method, text_method, options = {}, html_options = {}, &block)
62
+ options, defaults = split_defaults(options, include_blank: true)
63
+ options = defaults.merge(options)
64
+ html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select")
65
+ html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
66
+
67
+ @builder.collection_radio_buttons(attribute, collection, value_method, text_method, options, html_options, &block)
68
+ end
69
+
70
+ define_convenience :collection_radio_buttons
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,143 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Super
4
+ # Example
5
+ #
6
+ # ```ruby
7
+ # super_form_for([:admin, @member]) do |f|
8
+ # # the long way
9
+ # f.super.label :name
10
+ # f.super.text_field :name
11
+ # f.super.inline_errors :name
12
+ #
13
+ # # the short way (slightly different from the long way, for alignment)
14
+ # f.super.text_field! :position
15
+ # end
16
+ # ```
17
+ #
18
+ # Refer to the Rails docs:
19
+ # https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html
20
+ class FormBuilder < ActionView::Helpers::FormBuilder
21
+ FIELD_ERROR_PROC = proc { |html_tag, instance| html_tag }
22
+ FORM_BUILDER_DEFAULTS = { builder: self }.freeze
23
+
24
+ def super(**options)
25
+ @super_wrappers ||= Wrappers.new(self, @template)
26
+ end
27
+
28
+ class Wrappers
29
+ def initialize(builder, template)
30
+ @builder = builder
31
+ @template = template
32
+ end
33
+
34
+ def inline_errors(attribute)
35
+ if @builder.object
36
+ messages = Form::InlineErrors.error_messages(@builder.object, attribute).map do |msg|
37
+ error_content_tag(msg)
38
+ end
39
+
40
+ @template.safe_join(messages)
41
+ else
42
+ error_content_tag(<<~MSG.html_safe)
43
+ This form doesn't have an object, so something is probably wrong.
44
+ Maybe <code>accepts_nested_attributes_for</code> isn't set up?
45
+ MSG
46
+ end
47
+ end
48
+
49
+ def container(&block)
50
+ @template.content_tag(:div, class: "super-field-group", &block)
51
+ end
52
+
53
+ private
54
+
55
+ private_class_method def self.define_with_label_tag(method_name, **optionals)
56
+ parameters = instance_method(method_name).parameters
57
+ definition = []
58
+ call = []
59
+ definition_last = ["label_text: nil", "label: {}", "show_errors: true"]
60
+ call_last = []
61
+ parameters.each do |type, name|
62
+ if name == :options && type == :opt
63
+ definition.push("field: {}")
64
+ call.push("field")
65
+ elsif name == :html_options && type == :opt
66
+ definition.push("field_html: {}")
67
+ call.push("field_html")
68
+ elsif type == :block
69
+ definition_last.push("&#{name}")
70
+ call_last.push("&#{name}")
71
+ else
72
+ if type == :req
73
+ definition.push(name.to_s)
74
+ call.push(name.to_s)
75
+ elsif type == :opt || type == :key
76
+ if !optionals.key?(name)
77
+ raise Super::Error::ArgumentError, "Form bang method has optional argument, but doesn't know the default value: #{name}"
78
+ end
79
+
80
+ default_value = optionals[name]
81
+
82
+ if type == :opt
83
+ definition.push("#{name} = #{default_value}")
84
+ call.push(name.to_s)
85
+ elsif type == :key
86
+ definition.push("#{name}: #{default_value}")
87
+ call.push("#{name}: #{name}")
88
+ else
89
+ raise Super::Error::ArgumentError, "Form bang method has a unprocessable argument with name #{name}"
90
+ end
91
+ else
92
+ raise Super::Error::ArgumentError, "Form bang method has keyword argument type #{type} and name #{name}"
93
+ end
94
+ end
95
+ end
96
+
97
+ definition += definition_last
98
+ call += call_last
99
+
100
+ class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
101
+ def #{method_name}!(#{definition.join(", ")})
102
+ container do
103
+ compact_join([
104
+ public_send(:label, attribute, label_text, label),
105
+ %(<div class="mt-1">).html_safe,
106
+ #{method_name}(#{call.join(", ")}),
107
+ show_errors && inline_errors(attribute),
108
+ %(</div>).html_safe,
109
+ ])
110
+ end
111
+ end
112
+ RUBY
113
+ end
114
+
115
+ private_class_method def self.define_convenience(method_name, *args, **kwargs)
116
+ define_with_label_tag(method_name, *args, **kwargs)
117
+ ::Super::Form::SchemaTypes.define_schema_type_for(method_name)
118
+ end
119
+
120
+ def split_defaults(options, **internal_defaults)
121
+ defaults = options.delete(:super) || {}
122
+ # prefer options set in `defaults`, since they are user overrides
123
+ defaults = internal_defaults.merge(defaults)
124
+
125
+ [options, defaults]
126
+ end
127
+
128
+ def join_classes(*class_lists)
129
+ class_lists.flatten.map(&:presence).compact
130
+ end
131
+
132
+ def error_content_tag(content)
133
+ @template.content_tag(:p, content, class: "text-red-400 text-xs italic pt-1")
134
+ end
135
+
136
+ def compact_join(*parts)
137
+ @template.safe_join(
138
+ parts.flatten.map(&:presence).compact
139
+ )
140
+ end
141
+ end
142
+ end
143
+ end
data/lib/super/layout.rb CHANGED
@@ -6,44 +6,20 @@ module Super
6
6
  class Layout
7
7
  include Super::Partial::Resolving
8
8
 
9
- def initialize(headers: nil, asides: nil, mains: nil, footers: nil)
10
- @headers = Array(headers).compact
11
- @asides = Array(asides).compact
12
- @mains = Array(mains).compact
13
- @footers = Array(footers).compact
9
+ def initialize(header: nil, aside: nil, main: nil, footer: nil)
10
+ @header = header
11
+ @aside = aside
12
+ @main = main
13
+ @footer = footer
14
14
  end
15
15
 
16
- attr_reader :headers
17
- attr_reader :asides
18
- attr_reader :mains
19
- attr_reader :footers
16
+ attr_reader :header
17
+ attr_reader :aside
18
+ attr_reader :main
19
+ attr_reader :footer
20
20
 
21
21
  def to_partial_path
22
22
  "layout"
23
23
  end
24
-
25
- def resolve(template)
26
- @resolved_headers = resolve_for_rendering(template, headers, nil)
27
- @resolved_asides = resolve_for_rendering(template, asides, nil)
28
- @resolved_mains = resolve_for_rendering(template, mains, nil)
29
- @resolved_footers = resolve_for_rendering(template, footers, nil)
30
- self
31
- end
32
-
33
- def resolved_headers
34
- @resolved_headers || []
35
- end
36
-
37
- def resolved_asides
38
- @resolved_asides || []
39
- end
40
-
41
- def resolved_mains
42
- @resolved_mains || []
43
- end
44
-
45
- def resolved_footers
46
- @resolved_footers || []
47
- end
48
24
  end
49
25
  end