super 0.0.9 → 0.0.10

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/super/application.js +5 -4
  3. data/app/helpers/super/form_builder_helper.rb +23 -0
  4. data/app/views/super/application/_filter.html.erb +2 -2
  5. data/app/views/super/application/_filter_type_select.html.erb +5 -18
  6. data/app/views/super/application/_filter_type_text.html.erb +4 -10
  7. data/app/views/super/application/_filter_type_timestamp.html.erb +4 -16
  8. data/app/views/super/application/_form_field__destroy.html.erb +1 -9
  9. data/app/views/super/application/_form_field_checkbox.html.erb +1 -15
  10. data/app/views/super/application/_form_field_rich_text_area.html.erb +1 -13
  11. data/app/views/super/application/_form_field_select.html.erb +1 -23
  12. data/app/views/super/application/_form_field_text.html.erb +1 -13
  13. data/app/views/super/application/_super_schema_display_index.html.erb +2 -2
  14. data/app/views/super/application/_super_schema_form.html.erb +2 -2
  15. data/app/views/super/application/edit.html.erb +1 -0
  16. data/app/views/super/application/index.html.erb +1 -0
  17. data/app/views/super/application/new.html.erb +1 -0
  18. data/app/views/super/application/show.html.erb +1 -0
  19. data/frontend/super-frontend/dist/application.js +5 -4
  20. data/lib/super.rb +1 -0
  21. data/lib/super/engine.rb +2 -0
  22. data/lib/super/error.rb +9 -0
  23. data/lib/super/form/builder.rb +194 -38
  24. data/lib/super/form/inline_errors.rb +26 -0
  25. data/lib/super/version.rb +1 -1
  26. data/lib/super/view_helper.rb +0 -19
  27. metadata +10 -19
  28. data/app/views/super/application/_form_field_generic.html.erb +0 -19
  29. data/app/views/super/application/_form_inline_errors.html.erb +0 -10
  30. data/frontend/super-frontend/build.js +0 -36
  31. data/frontend/super-frontend/package.json +0 -20
  32. data/frontend/super-frontend/postcss.config.js +0 -6
  33. data/frontend/super-frontend/src/javascripts/super/application.js +0 -15
  34. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.js +0 -17
  35. data/frontend/super-frontend/src/javascripts/super/toggle_pending_destruction_controller.js +0 -15
  36. data/frontend/super-frontend/src/stylesheets/super/application.css +0 -77
  37. data/frontend/super-frontend/tailwind.config.js +0 -15
  38. data/frontend/super-frontend/yarn.lock +0 -5443
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b01ea90f28d8e14b5a5f4bd454e2a15676b9c95623200a17d1a2ed2fb71d87f
4
- data.tar.gz: 753365f90dcc880f4249ab60d9eea04034189fd221ecb03d500a8fc78f02a7a9
3
+ metadata.gz: 043677dcee80c7b83903b21904f1768a411f807567190d7227928df9bf7922c7
4
+ data.tar.gz: 5de2f073926089e4823a4228dc4f7be912fed0471d862f9b6f0f56dde280f154
5
5
  SHA512:
6
- metadata.gz: ec08f45761eefc5645daa6f4976b9b3844fba97c04b81ddbee3217dfd6392666c30eabb7e7a2eca0516f2dad861b4f8a5f85ac8ac36ed583baa6dcb38d7fb4f2
7
- data.tar.gz: ed215af314d49cc4454ba98cb8fd84d351ca32808de1eceaa4c079b2199f18bfbd6ebfc1aa8d388738012868b764482741d933e1e232ac1cf30bf02f3effe26f
6
+ metadata.gz: feeba0baacdaf977c16f9e785e7abf6637679ebe2f624716f1006cce290157e29157b046a01f3d287d1b826378a04ece8c482b59cd2f21dc53bf463a28cf2848
7
+ data.tar.gz: a7d1a568a4c918ececb0200305f1e30042b4fc48946796f13e9568c27b5f95368b60aaac51ac977211566cb79f4973dd3d96a48a421531934c41884ce33ac084
@@ -4303,8 +4303,6 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
4303
4303
 
4304
4304
  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
4305
4305
 
4306
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
4307
-
4308
4306
  var _default = /*#__PURE__*/function (_Controller) {
4309
4307
  _inherits(_default, _Controller);
4310
4308
 
@@ -4324,14 +4322,17 @@ var _default = /*#__PURE__*/function (_Controller) {
4324
4322
  var content = this.templateTarget.innerHTML.replace(/TEMPLATEINDEX/g, unixtime.toString());
4325
4323
  this.templateTarget.insertAdjacentHTML("beforebegin", content);
4326
4324
  }
4325
+ }], [{
4326
+ key: "targets",
4327
+ get: function get() {
4328
+ return ["template"];
4329
+ }
4327
4330
  }]);
4328
4331
 
4329
4332
  return _default;
4330
4333
  }(_stimulus.Controller);
4331
4334
 
4332
4335
  exports.default = _default;
4333
-
4334
- _defineProperty(_default, "targets", ["template"]);
4335
4336
  },{"stimulus":"../node_modules/stimulus/index.js"}],"javascripts/super/toggle_pending_destruction_controller.js":[function(require,module,exports) {
4336
4337
  "use strict";
4337
4338
 
@@ -0,0 +1,23 @@
1
+ module Super
2
+ module FormBuilderHelper
3
+ def super_form_for(record, options = {}, &block)
4
+ original = ActionView::Base.field_error_proc
5
+ ActionView::Base.field_error_proc = Form::Builder::FIELD_ERROR_PROC
6
+
7
+ options[:builder] ||= Form::Builder
8
+ return form_for(record, options, &block)
9
+ ensure
10
+ ActionView::Base.field_error_proc = original
11
+ end
12
+
13
+ def super_form_with(**options, &block)
14
+ original = ActionView::Base.field_error_proc
15
+ ActionView::Base.field_error_proc = Form::Builder::FIELD_ERROR_PROC
16
+
17
+ options[:builder] ||= Form::Builder
18
+ return form_with(**options, &block)
19
+ ensure
20
+ ActionView::Base.field_error_proc = original
21
+ end
22
+ end
23
+ end
@@ -1,6 +1,6 @@
1
1
  <%= render(Super::Panel.new) do %>
2
2
  <h1 class="text-xl">Filters</h1>
3
- <%= form_for(filter, url: filter.url, method: :get, as: :q, html: { class: "mt-4" }) do |form| %>
3
+ <%= super_form_for(filter, url: filter.url, method: :get, as: :q, html: { class: "mt-4" }) do |form| %>
4
4
  <% filter.each_field do |filter_field| %>
5
5
  <div class="mt-4">
6
6
  <%= render(filter_field, form: form) %>
@@ -8,7 +8,7 @@
8
8
  <% end %>
9
9
 
10
10
  <div>
11
- <%= form.submit "Filter", class: "super-button super-button--border-gray mt-6" %>
11
+ <%= form.super.submit "Filter", class: "super-button--border-gray mt-6" %>
12
12
  </div>
13
13
  <% end %>
14
14
  <% end %>
@@ -1,31 +1,18 @@
1
1
  <div class="super-field-group">
2
2
  <%= form.fields_for(filter_type_select.field_name, filter_type_select) do |form_field| %>
3
3
  <%= form_field.label(:q, filter_type_select.humanized_field_name) %>
4
- <div class="super-input-select inline-block">
5
- <%= form_field.select(
4
+ <div class="relative inline-block">
5
+ <%= form_field.super.select(
6
6
  :op,
7
7
  filter_type_select.operators,
8
- {},
9
- { class: "super-input super-input-select-field" }
8
+ { include_blank: false },
10
9
  ) %>
11
- <div class="super-input-select-icon text-gray-700">
12
- <span class="h-4 w-4">
13
- <%= render "super/feather/chevron_down" %>
14
- </span>
15
- </div>
16
10
  </div>
17
- <div class="super-input-select mt-3">
18
- <%= form_field.select(
11
+ <div class="mt-3">
12
+ <%= form_field.super.select(
19
13
  :q,
20
14
  filter_type_select.field_type.collection,
21
- { include_blank: true },
22
- { class: "super-input super-input-select-field" }
23
15
  ) %>
24
- <div class="super-input-select-icon text-gray-700">
25
- <span class="h-4 w-4">
26
- <%= render "super/feather/chevron_down" %>
27
- </span>
28
- </div>
29
16
  </div>
30
17
  <% end %>
31
18
  </div>
@@ -2,21 +2,15 @@
2
2
  <%= form.fields_for(filter_type_text.field_name, filter_type_text) do |form_field| %>
3
3
  <%= form_field.label(:q, filter_type_text.humanized_field_name) %>
4
4
  <div class="relative inline-block">
5
- <%= form_field.select(
5
+ <%= form_field.super.select(
6
6
  :op,
7
7
  filter_type_text.operators,
8
- {},
9
- { class: "super-input super-input-select-field" }
8
+ { include_blank: false }
10
9
  ) %>
11
- <div class="super-input-select-icon text-gray-700">
12
- <span class="h-4 w-4">
13
- <%= render "super/feather/chevron_down" %>
14
- </span>
15
- </div>
16
10
  </div>
17
- <%= form_field.text_field(
11
+ <%= form_field.super.text_field(
18
12
  :q,
19
- class: "super-input w-full mt-3"
13
+ class: "mt-3"
20
14
  ) %>
21
15
  <% end %>
22
16
  </div>
@@ -2,33 +2,21 @@
2
2
  <%= form.fields_for(filter_type_timestamp.field_name, filter_type_timestamp) do |form_field| %>
3
3
  <%= form_field.label(:q0, filter_type_timestamp.humanized_field_name) %>
4
4
  <div class="relative inline-block mt-2">
5
- <%= form_field.select(
5
+ <%= form_field.super.select(
6
6
  :op,
7
7
  filter_type_timestamp.operators,
8
- {},
9
- { class: "super-input super-input-select-field" }
8
+ { include_blank: false}
10
9
  ) %>
11
- <div class="super-input-select-icon text-gray-700">
12
- <span class="h-4 w-4">
13
- <%= render "super/feather/chevron_down" %>
14
- </span>
15
- </div>
16
10
  </div>
17
11
  <div class="flex items-center mt-3">
18
12
  <div class="flex-initial">
19
- <%= form_field.text_field(
20
- :q0,
21
- class: "super-input w-full"
22
- ) %>
13
+ <%= form_field.super.text_field(:q0) %>
23
14
  </div>
24
15
  <div class="flex-initial px-2">
25
16
  &ndash;
26
17
  </div>
27
18
  <div class="flex-initial">
28
- <%= form_field.text_field(
29
- :q1,
30
- class: "super-input w-full"
31
- ) %>
19
+ <%= form_field.super.text_field(:q1) %>
32
20
  </div>
33
21
  </div>
34
22
  <% end %>
@@ -1,9 +1 @@
1
- <% if !local_assigns[:ungrouped] %>
2
- <div class="super-field-group">
3
- <% end %>
4
- <%= form.check_box(column, data: { action: "toggle-pending-destruction#call" }) %>
5
- <%= form.label(column) %>
6
- <%= render "form_inline_errors", form: form, column: column %>
7
- <% if !local_assigns[:ungrouped] %>
8
- </div>
9
- <% end %>
1
+ <%= form.super.check_box!(column, field: { data: { action: "toggle-pending-destruction#call" } }) %>
@@ -1,15 +1 @@
1
- <% if !local_assigns[:ungrouped] %>
2
- <div class="super-field-group">
3
- <% end %>
4
- <div class="<%= Super::ViewHelper.classes(["mt-1", !local_assigns[:hide_label]]) %>">
5
- <div>
6
- <%= form.check_box(column) %>
7
- <% if !local_assigns[:hide_label] %>
8
- <%= form.label(column, class: "select-none") %>
9
- <% end %>
10
- </div>
11
- <%= render "form_inline_errors", form: form, column: column %>
12
- </div>
13
- <% if !local_assigns[:ungrouped] %>
14
- </div>
15
- <% end %>
1
+ <%= form.super.check_box!(column) %>
@@ -1,13 +1 @@
1
- <% if !local_assigns[:ungrouped] %>
2
- <div class="super-field-group">
3
- <% end %>
4
- <% if !local_assigns[:hide_label] %>
5
- <%= form.label(column, class: "block") %>
6
- <% end %>
7
- <div class="<%= Super::ViewHelper.classes(["mt-1", !local_assigns[:hide_label]]) %>">
8
- <%= form.rich_text_area(column, class: "trix-content super-input w-full") %>
9
- <%= render "form_inline_errors", form: form, column: column %>
10
- </div>
11
- <% if !local_assigns[:ungrouped] %>
12
- </div>
13
- <% end %>
1
+ <%= form.super.rich_text_area!(column) %>
@@ -1,23 +1 @@
1
- <% if !local_assigns[:ungrouped] %>
2
- <div class="super-field-group">
3
- <% end %>
4
- <% if !local_assigns[:hide_label] %>
5
- <%= form.label(column, class: "block") %>
6
- <% end %>
7
- <div class="<%= Super::ViewHelper.classes("super-input-select", ["mt-1", !local_assigns[:hide_label]]) %>">
8
- <%= form.select(
9
- column,
10
- form_field_select[:collection],
11
- { include_blank: true }.merge(form_field_select[:options] || {}),
12
- { class: "super-input super-input-select-field" }
13
- ) %>
14
- <div class="super-input-select-icon text-gray-700">
15
- <span class="h-4 w-4">
16
- <%= render "super/feather/chevron_down" %>
17
- </span>
18
- </div>
19
- </div>
20
- <%= render "form_inline_errors", form: form, column: column %>
21
- <% if !local_assigns[:ungrouped] %>
22
- </div>
23
- <% end %>
1
+ <%= form.super.select!(column, form_field_select[:collection]) %>
@@ -1,13 +1 @@
1
- <% if !local_assigns[:ungrouped] %>
2
- <div class="super-field-group">
3
- <% end %>
4
- <% if !local_assigns[:hide_label] %>
5
- <%= form.label(column, class: "block") %>
6
- <% end %>
7
- <div class="<%= Super::ViewHelper.classes(["mt-1", !local_assigns[:hide_label]]) %>">
8
- <%= form.text_field(column, class: "super-input w-full") %>
9
- <%= render "form_inline_errors", form: form, column: column %>
10
- </div>
11
- <% if !local_assigns[:ungrouped] %>
12
- </div>
13
- <% end %>
1
+ <%= form.super.text_field!(column) %>
@@ -1,9 +1,9 @@
1
- <div class="mt-4 overflow-x-auto lg:overflow-x-visible">
1
+ <div class="mt-4 overflow-x-auto">
2
2
  <table class="w-full border-separate relative" cellspacing="0" cellpadding="0">
3
3
  <thead class="">
4
4
  <tr class="">
5
5
  <% super_schema_display_index.each_attribute_name do |attribute_name| %>
6
- <th class="p-2 first:pl-6 border-b border-b-2 border-gray-400 text-gray-600 text-left text-sm font-normal bg-white sticky top-0 z-10">
6
+ <th class="p-2 first:pl-6 border-b border-b-2 border-gray-400 text-gray-600 text-left text-sm font-normal bg-white top-0 z-10">
7
7
  <%= controls.model.human_attribute_name(attribute_name) %>
8
8
  </th>
9
9
  <% end %>
@@ -1,4 +1,4 @@
1
- <%= form_for(Super.configuration.path_parts(@record), builder: Super::Form::Builder) do |f| %>
1
+ <%= super_form_for(Super.configuration.path_parts(@record), builder: Super::Form::Builder) do |f| %>
2
2
  <div class="max-w-3xl">
3
3
  <% super_schema_form.each_attribute do |field, type| %>
4
4
  <%= render(
@@ -9,7 +9,7 @@
9
9
  <% end %>
10
10
 
11
11
  <div>
12
- <%= f.submit class: "super-button super-button--fill-blue mt-2" %>
12
+ <%= f.super.submit class: "super-button--fill-blue mt-2" %>
13
13
  </div>
14
14
  </div>
15
15
  <% end %>
@@ -1 +1,2 @@
1
+ <% raise Super::Error::NothingToRender, "edit" if @view.nil? %>
1
2
  <%= render(@view) %>
@@ -1 +1,2 @@
1
+ <% raise Super::Error::NothingToRender, "index" if @view.nil? %>
1
2
  <%= render(@view) %>
@@ -1 +1,2 @@
1
+ <% raise Super::Error::NothingToRender, "new" if @view.nil? %>
1
2
  <%= render(@view) %>
@@ -1 +1,2 @@
1
+ <% raise Super::Error::NothingToRender, "show" if @view.nil? %>
1
2
  <%= render(@view) %>
@@ -4303,8 +4303,6 @@ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Re
4303
4303
 
4304
4304
  function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
4305
4305
 
4306
- function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
4307
-
4308
4306
  var _default = /*#__PURE__*/function (_Controller) {
4309
4307
  _inherits(_default, _Controller);
4310
4308
 
@@ -4324,14 +4322,17 @@ var _default = /*#__PURE__*/function (_Controller) {
4324
4322
  var content = this.templateTarget.innerHTML.replace(/TEMPLATEINDEX/g, unixtime.toString());
4325
4323
  this.templateTarget.insertAdjacentHTML("beforebegin", content);
4326
4324
  }
4325
+ }], [{
4326
+ key: "targets",
4327
+ get: function get() {
4328
+ return ["template"];
4329
+ }
4327
4330
  }]);
4328
4331
 
4329
4332
  return _default;
4330
4333
  }(_stimulus.Controller);
4331
4334
 
4332
4335
  exports.default = _default;
4333
-
4334
- _defineProperty(_default, "targets", ["template"]);
4335
4336
  },{"stimulus":"../node_modules/stimulus/index.js"}],"javascripts/super/toggle_pending_destruction_controller.js":[function(require,module,exports) {
4336
4337
  "use strict";
4337
4338
 
@@ -23,6 +23,7 @@ require "super/filter/schema_types"
23
23
  require "super/form"
24
24
  require "super/form/builder"
25
25
  require "super/form/guesser"
26
+ require "super/form/inline_errors"
26
27
  require "super/form/schema_types"
27
28
  require "super/form/strong_params"
28
29
  require "super/layout"
@@ -1,6 +1,8 @@
1
1
  module Super
2
2
  # Configures the host Rails app to work with Super
3
3
  class Engine < ::Rails::Engine
4
+ isolate_namespace Super
5
+
4
6
  initializer "super.assets.precompile" do |app|
5
7
  if Super::Assets::Handler.sprockets_available?
6
8
  app.config.assets.precompile << "config/super_manifest.js"
@@ -13,5 +13,14 @@ module Super
13
13
  class ActionInquirerError < Error; end
14
14
  # Error raised when a `Super::Link` couldn't be found
15
15
  class LinkNotRegistered < Error; end
16
+ # Error raised when rendering if `@view` wasn't set by the controller
17
+ class NothingToRender < Error
18
+ def initialize(basename)
19
+ super(
20
+ "Super's built-in `#{basename}.html.erb` requires `@view` to be set " \
21
+ "by the controller, but it wasn't set"
22
+ )
23
+ end
24
+ end
16
25
  end
17
26
  end
@@ -1,48 +1,204 @@
1
1
  module Super
2
2
  class Form
3
- module FieldErrorProc
4
- def error_wrapping(html_tag)
5
- if Thread.current[:super_form_builder]
6
- return html_tag
7
- end
3
+ # Example
4
+ #
5
+ # ```ruby
6
+ # super_form_for([:admin, @member]) do |f|
7
+ # # the long way
8
+ # f.super.label :name
9
+ # f.super.text_field :name
10
+ # f.super.inline_errors :name
11
+ #
12
+ # # the short way (slightly different from the long way, for alignment)
13
+ # f.super.text_field! :position
14
+ # end
15
+ # ```
16
+ #
17
+ # Refer to the Rails docs:
18
+ # https://api.rubyonrails.org/classes/ActionView/Helpers/FormBuilder.html
19
+ class Builder < ActionView::Helpers::FormBuilder
20
+ FIELD_ERROR_PROC = proc { |html_tag, instance| html_tag }
21
+ FORM_BUILDER_DEFAULTS = { builder: self }.freeze
8
22
 
9
- super
23
+ def super(**options)
24
+ @super_wrappers ||= Wrappers.new(self, @template)
10
25
  end
11
- end
12
26
 
13
- class Builder < ActionView::Helpers::FormBuilder
14
- # These methods were originally defined in the following files
15
- #
16
- # * actionview/lib/action_view/helpers/form_helper.rb
17
- # * actionview/lib/action_view/helpers/form_options_helper.rb
18
- # * actionview/lib/action_view/helpers/date_helper.rb
19
- %w[
20
- label text_field password_field hidden_field file_field text_area
21
- check_box radio_button color_field search_field telephone_field
22
- date_field time_field datetime_field month_field week_field url_field
23
- email_field number_field range_field
24
-
25
- select collection_select grouped_collection_select time_zone_select
26
- collection_radio_buttons collection_check_boxes
27
-
28
- time_select datetime_select date_select
29
- ].each do |field_type_method|
30
- class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
31
- def #{field_type_method}(*)
32
- Thread.current[:super_form_builder] = true
33
- super
34
- ensure
35
- Thread.current[:super_form_builder] = nil
27
+ class Wrappers
28
+ def initialize(builder, template)
29
+ @builder = builder
30
+ @template = template
31
+ end
32
+
33
+ def inline_errors(attribute)
34
+ if @builder.object
35
+ messages = InlineErrors.error_messages(@builder.object, attribute).map do |msg|
36
+ error_content_tag(msg)
37
+ end
38
+
39
+ @template.safe_join(messages)
40
+ else
41
+ error_content_tag(<<~MSG.html_safe)
42
+ This form doesn't have an object, so something is probably wrong.
43
+ Maybe <code>accepts_nested_attributes_for</code> isn't set up?
44
+ MSG
36
45
  end
37
- RUBY
38
- end
46
+ end
47
+
48
+ def label(attribute, text = nil, options = {}, &block)
49
+ options, defaults = split_defaults(options, class: "block")
50
+ options[:class] = join_classes(defaults[:class], options[:class])
51
+
52
+ @builder.label(attribute, text, options, &block)
53
+ end
54
+
55
+ def check_box(attribute, options = {}, checked_value = "1", unchecked_value = "0")
56
+ @builder.check_box(attribute, options, checked_value, unchecked_value)
57
+ end
58
+
59
+ def password_field(attribute, options = {})
60
+ options, defaults = split_defaults(options, class: "super-input w-full")
61
+ options[:class] = join_classes(defaults[:class], options[:class])
62
+
63
+ @builder.password_field(attribute, options)
64
+ end
65
+
66
+ def rich_text_area(attribute, options = {})
67
+ options, defaults = split_defaults(options, class: "trix-content super-input w-full")
68
+ options[:class] = join_classes(defaults[:class], options[:class])
69
+
70
+ @builder.rich_text_area(attribute, options)
71
+ end
72
+
73
+ def select(attribute, choices, options = {}, html_options = {}, &block)
74
+ options, defaults = split_defaults(options, include_blank: true)
75
+ options = defaults.merge(options)
76
+ html_options, html_defaults = split_defaults(html_options, class: "super-input super-input-select-field")
77
+ html_options[:class] = join_classes(html_defaults[:class], html_options[:class])
78
+
79
+ parts = [
80
+ %(<div class="super-input-select">).html_safe,
81
+ @builder.select(attribute, choices, options, html_options, &block),
82
+ <<~HTML.html_safe,
83
+ <div class="super-input-select-icon text-blue-700">
84
+ <span class="h-4 w-4">
85
+ HTML
86
+ @template.render("super/feather/chevron_down"),
87
+ <<~HTML.html_safe,
88
+ </span>
89
+ </div>
90
+ HTML
91
+ %(</div>).html_safe,
92
+ ]
93
+
94
+ @template.safe_join(parts)
95
+ end
96
+
97
+ def submit(value = nil, options = {})
98
+ value, options = nil, value if value.is_a?(Hash)
99
+ options, defaults = split_defaults(options, class: "super-button")
100
+ options[:class] = join_classes(defaults[:class], options[:class])
101
+
102
+ @builder.submit(value, options)
103
+ end
104
+
105
+ def text_field(attribute, options = {})
106
+ options, defaults = split_defaults(options, class: "super-input w-full")
107
+ options[:class] = join_classes(defaults[:class], options[:class])
108
+
109
+ @builder.text_field(attribute, options)
110
+ end
39
111
 
40
- alias datetime_local_field datetime_field
41
- alias phone_field telephone_field
112
+ def container(&block)
113
+ @template.content_tag(:div, class: "super-field-group", &block)
114
+ end
115
+
116
+ def check_box!(attribute, checked_value = "1", unchecked_value = "0", label: {}, field: {}, show_errors: true)
117
+ label[:super] ||= {}
118
+ label[:super] = { class: "select-none ml-1" }.merge(label[:super])
119
+ container do
120
+ compact_join([
121
+ "<div>".html_safe,
122
+ public_send(:check_box, attribute, field, checked_value, unchecked_value),
123
+ public_send(:label, attribute, nil, label),
124
+ "</div>".html_safe,
125
+ show_errors && inline_errors(attribute),
126
+ ])
127
+ end
128
+ end
129
+
130
+ def password_field!(attribute, label: {}, field: {}, show_errors: true)
131
+ container do
132
+ compact_join([
133
+ public_send(:label, attribute, label),
134
+ %(<div class="mt-1">).html_safe,
135
+ public_send(:password_field, attribute, field),
136
+ show_errors && inline_errors(attribute),
137
+ %(</div>).html_safe,
138
+ ])
139
+ end
140
+ end
141
+
142
+ def rich_text_area!(attribute, label: {}, field: {}, show_errors: true)
143
+ container do
144
+ compact_join([
145
+ public_send(:label, attribute, label),
146
+ %(<div class="mt-1">).html_safe,
147
+ public_send(:rich_text_area, attribute, field),
148
+ show_errors && inline_errors(attribute),
149
+ %(</div>).html_safe,
150
+ ])
151
+ end
152
+ end
153
+
154
+ def select!(attribute, collection, label: {}, field: {}, show_errors: true)
155
+ container do
156
+ compact_join([
157
+ public_send(:label, attribute, label),
158
+ %(<div class="mt-1">).html_safe,
159
+ public_send(:select, attribute, collection, field),
160
+ show_errors && inline_errors(attribute),
161
+ %(</div>).html_safe,
162
+ ])
163
+ end
164
+ end
165
+
166
+ def text_field!(attribute, label: {}, field: {}, show_errors: true)
167
+ container do
168
+ compact_join([
169
+ public_send(:label, attribute, label),
170
+ %(<div class="mt-1">).html_safe,
171
+ public_send(:text_field, attribute, field),
172
+ show_errors && inline_errors(attribute),
173
+ %(</div>).html_safe,
174
+ ])
175
+ end
176
+ end
177
+
178
+ private
179
+
180
+ def split_defaults(options, **internal_defaults)
181
+ defaults = options.delete(:super) || {}
182
+ # prefer options set in `defaults`, since they are user overrides
183
+ defaults = internal_defaults.merge(defaults)
184
+
185
+ [options, defaults]
186
+ end
187
+
188
+ def join_classes(*class_lists)
189
+ class_lists.flatten.map(&:presence).compact
190
+ end
191
+
192
+ def error_content_tag(content)
193
+ @template.content_tag(:p, content, class: "text-red-400 text-xs italic pt-1")
194
+ end
195
+
196
+ def compact_join(*parts)
197
+ @template.safe_join(
198
+ parts.flatten.map(&:presence).compact
199
+ )
200
+ end
201
+ end
42
202
  end
43
203
  end
44
204
  end
45
-
46
- ActionView::Helpers::Tags::Base.class_eval do
47
- prepend Super::Form::FieldErrorProc
48
- end