super 0.17.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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