From 538d378c6875395b216c2b2abb36e09ffac4e187 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Wed, 14 May 2025 15:06:44 +0200 Subject: [PATCH 1/3] Add css-zero initializer --- README.md | 12 + .../simple_form/install_generator.rb | 9 +- .../initializers/simple_form_css_zero.rb | 284 ++++++++++++++++++ test/generators/simple_form_generator_test.rb | 8 + 4 files changed, 310 insertions(+), 3 deletions(-) create mode 100644 lib/generators/simple_form/templates/config/initializers/simple_form_css_zero.rb diff --git a/README.md b/README.md index 97dc60d07..c4f72d351 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ INFO: This README refers to **Simple Form** 5.0. For older releases, check the r - [Installation](#installation) - [Bootstrap](#bootstrap-5) + - [Css-zero](#css-zero) - [Zurb Foundation 5](#zurb-foundation-5) - [Country Select](#country-select) - [Usage](#usage) @@ -84,6 +85,17 @@ For more information see the generator output, our [example application code](https://github.com/heartcombo/simple_form-bootstrap) and [the live example app](https://simple-form-bootstrap.herokuapp.com/). +### CSS-Zero + +To generate wrappers that are compatible with [CSS-Zero](https://github.com/lazaronixon/css-zero), pass +the `css_zero` option to the generator, like this: + +```console +rails generate simple_form:install --css-zero +``` + +Please see the [Installation instructions](https://github.com/lazaronixon/css-zero?tab=readme-ov-file#installation) for more information. + ### Zurb Foundation 5 To generate wrappers that are compatible with [Zurb Foundation 5](http://foundation.zurb.com/), pass diff --git a/lib/generators/simple_form/install_generator.rb b/lib/generators/simple_form/install_generator.rb index bf7ca0653..6c9548825 100644 --- a/lib/generators/simple_form/install_generator.rb +++ b/lib/generators/simple_form/install_generator.rb @@ -7,12 +7,13 @@ class InstallGenerator < Rails::Generators::Base class_option :template_engine, desc: 'Template engine to be invoked (erb, haml or slim).' class_option :bootstrap, type: :boolean, desc: 'Add the Bootstrap 5 wrappers to the SimpleForm initializer.' class_option :foundation, type: :boolean, desc: 'Add the Zurb Foundation 5 wrappers to the SimpleForm initializer.' + class_option :css_zero, type: :boolean, desc: 'Add the CSS Zero wrappers to the SimpleForm initializer.' def info_bootstrap - return if options.bootstrap? || options.foundation? - puts "SimpleForm supports Bootstrap 5 and Zurb Foundation 5. If you want "\ + return if options.bootstrap? || options.foundation? || options.css_zero? + puts "SimpleForm supports Bootstrap 5, Zurb Foundation 5 and CSS Zero. If you want "\ "a configuration that is compatible with one of these frameworks, then please " \ - "re-run this generator with --bootstrap or --foundation as an option." + "re-run this generator with --bootstrap, --foundation or --css-zero as an option." end def copy_config @@ -20,6 +21,8 @@ def copy_config if options[:bootstrap] template "config/initializers/simple_form_bootstrap.rb" + elsif options[:css_zero] + template "config/initializers/simple_form_css_zero.rb" elsif options[:foundation] template "config/initializers/simple_form_foundation.rb" end diff --git a/lib/generators/simple_form/templates/config/initializers/simple_form_css_zero.rb b/lib/generators/simple_form/templates/config/initializers/simple_form_css_zero.rb new file mode 100644 index 000000000..621ec363e --- /dev/null +++ b/lib/generators/simple_form/templates/config/initializers/simple_form_css_zero.rb @@ -0,0 +1,284 @@ +# frozen_string_literal: true + +# These defaults are defined for CSS Zero +# Please submit feedback, changes and tests through proper channels. + +# Uncomment this and change the path if necessary to include your own +# components. +# See https://github.com/heartcombo/simple_form#custom-components +# to know more about custom components. +# Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f } + +# Use this setup block to configure all options available in SimpleForm. +SimpleForm.setup do |config| # rubocop:disable Metrics/BlockLength + # Default class for buttons + # See: https://github.com/renuo/css-zero/blob/main/lib/generators/css_zero/add/templates/app/assets/stylesheets/button.css + config.button_class = "btn" + + # Define the default class of the input wrapper of the boolean input. + config.boolean_label_class = "checkbox" + + # How the label text should be generated altogether with the required text. + config.label_text = ->(label, required, _explicit_label) { "#{label} #{required}" } + + # Define the way to render check boxes / radio buttons with labels. + config.boolean_style = :inline + + # You can wrap each item in a collection of radio/check boxes with a tag + config.item_wrapper_tag = :div + + # Defines if the default input wrapper class should be included in radio + # collection wrappers. + config.include_default_input_wrapper_class = false + + # CSS class to add for error notification helper. + # See: https://github.com/renuo/css-zero/blob/main/lib/generators/css_zero/add/templates/app/assets/stylesheets/input.css + config.error_notification_class = "invalid-feedback" + + # Method used to tidy up errors. Specify any Rails Array method. + # :first lists the first message for each field. + # :to_sentence to list all errors for each field. + config.error_method = :to_sentence + + # add validation classes to `input_field` + # See: https://github.com/renuo/css-zero/blob/main/lib/generators/css_zero/add/templates/app/assets/stylesheets/input.css + config.input_field_error_class = "field_with_errors" + config.input_field_valid_class = "field_without_errors" + + config.wrappers :default do |b| + b.use :html5 + end + + # vertical forms + # + # vertical default_wrapper + config.wrappers :vertical_form, class: "mbe-3" do |b| + b.use :placeholder + b.optional :maxlength + b.optional :minlength + b.optional :pattern + b.optional :min_max + b.optional :readonly + b.use :label, class: "mbe-1" + b.use :input, class: "input", error_class: "field_with_errors", valid_class: "field_without_errors" + b.use :error, wrap_with: { class: "invalid-feedback block" } + b.use :hint, wrap_with: { class: "text-subtle" } + end + + # vertical input for boolean + config.wrappers :vertical_boolean, tag: "fieldset", class: "mbe-3" do |b| + b.optional :readonly + b.wrapper :form_check_wrapper, class: "flex items-center" do |bb| + bb.use :input, class: "checkbox", error_class: "field_with_errors", valid_class: "field_without_errors" + bb.use :label, class: "mis-2" + bb.use :error, wrap_with: { class: "invalid-feedback block" } + bb.use :hint, wrap_with: { class: "text-subtle" } + end + end + + # vertical input for radio buttons and check boxes + config.wrappers :vertical_collection, item_wrapper_class: "flex items-center", item_label_class: "mis-2", + tag: "fieldset", class: "mbe-3" do |b| + b.optional :readonly + b.wrapper :legend_tag, tag: "legend", class: "mbe-1" do |ba| + ba.use :label_text + end + b.use :input, class: "radio", error_class: "field_with_errors", valid_class: "field_without_errors" + b.use :error, wrap_with: { class: "invalid-feedback block" } + b.use :hint, wrap_with: { class: "text-subtle" } + end + + # vertical input for inline radio buttons and check boxes + config.wrappers :vertical_collection_inline, item_wrapper_class: "flex items-center mie-2", + item_label_class: "mis-2", tag: "fieldset", class: "mbe-3" do |b| + b.optional :readonly + b.wrapper :legend_tag, tag: "legend", class: "mbe-1" do |ba| + ba.use :label_text + end + b.use :input, class: "radio", error_class: "field_with_errors", valid_class: "field_without_errors" + b.use :error, wrap_with: { class: "invalid-feedback block" } + b.use :hint, wrap_with: { class: "text-subtle" } + end + + # vertical file input + config.wrappers :vertical_file, class: "mbe-3" do |b| + b.use :placeholder + b.optional :maxlength + b.optional :minlength + b.optional :readonly + b.use :label, class: "mbe-1" + b.use :input, class: "input", error_class: "field_with_errors", valid_class: "field_without_errors" + b.use :error, wrap_with: { class: "invalid-feedback block" } + b.use :hint, wrap_with: { class: "text-subtle" } + end + + # vertical select input + config.wrappers :vertical_select, class: "mbe-3" do |b| + b.optional :readonly + b.use :label, class: "mbe-1" + b.use :input, class: "input", error_class: "field_with_errors", valid_class: "field_without_errors" + b.use :error, wrap_with: { class: "invalid-feedback block" } + b.use :hint, wrap_with: { class: "text-subtle" } + end + + # vertical multi select + config.wrappers :vertical_multi_select, class: "mbe-3" do |b| + b.optional :readonly + b.use :label, class: "mbe-1" + b.wrapper class: "flex flex-col gap" do |ba| + ba.use :input, class: "input mbe-2", error_class: "field_with_errors", valid_class: "field_without_errors" + end + b.use :error, wrap_with: { class: "invalid-feedback block" } + b.use :hint, wrap_with: { class: "text-subtle" } + end + + # Date and time inputs + config.wrappers :date_time_inputs, class: "mbe-3" do |b| + b.use :placeholder + b.optional :readonly + b.use :label, class: "mbe-1" + b.wrapper class: "flex flex-row gap" do |ba| + ba.use :input, class: "input", error_class: "field_with_errors", valid_class: "field_without_errors" + end + b.use :error, wrap_with: { class: "invalid-feedback block" } + b.use :hint, wrap_with: { class: "text-subtle" } + end + + # horizontal forms + # + # horizontal default_wrapper + config.wrappers :horizontal_form, class: "flex flex-col mb-3" do |b| + b.use :placeholder + b.optional :maxlength + b.optional :minlength + b.optional :pattern + b.optional :min_max + b.optional :readonly + b.use :label, class: "mbe-2" + b.wrapper :grid_wrapper, class: "flex flex-col" do |ba| + ba.use :input, class: "input", error_class: "field_with_errors", valid_class: "field_without_errors" + ba.use :error, wrap_with: { class: "invalid-feedback block" } + ba.use :hint, wrap_with: { class: "text-subtle" } + end + end + + # horizontal input for boolean + config.wrappers :horizontal_boolean, class: "mbe-3" do |b| + b.optional :readonly + b.wrapper :grid_wrapper, class: "flex items-center" do |wr| + wr.wrapper :form_check_wrapper, class: "flex items-center" do |bb| + bb.use :input, class: "checkbox", error_class: "field_with_errors", valid_class: "field_without_errors" + bb.use :label, class: "mis-2" + bb.use :error, wrap_with: { class: "invalid-feedback block" } + bb.use :hint, wrap_with: { class: "text-subtle" } + end + end + end + + # horizontal input for radio buttons and check boxes + config.wrappers :horizontal_collection, item_wrapper_class: "flex items-center", item_label_class: "mis-2", + class: "mbe-3" do |b| + b.optional :readonly + b.use :label, class: "mbe-2" + b.wrapper :grid_wrapper, class: "flex flex-col" do |ba| + ba.use :input, class: "radio", error_class: "field_with_errors", valid_class: "field_without_errors" + ba.use :error, wrap_with: { class: "invalid-feedback block" } + ba.use :hint, wrap_with: { class: "text-subtle" } + end + end + + # horizontal input for inline radio buttons and check boxes + config.wrappers :horizontal_collection_inline, item_wrapper_class: "flex items-center mie-3", + item_label_class: "mis-2", class: "mbe-3" do |b| + b.optional :readonly + b.use :label, class: "mbe-2" + b.wrapper :grid_wrapper, class: "flex" do |ba| + ba.use :input, class: "radio", error_class: "field_with_errors", valid_class: "field_without_errors" + ba.use :error, wrap_with: { class: "invalid-feedback block" } + ba.use :hint, wrap_with: { class: "text-subtle" } + end + end + + # horizontal file input + config.wrappers :horizontal_file, class: "mbe-3" do |b| + b.use :placeholder + b.optional :maxlength + b.optional :minlength + b.optional :readonly + b.use :label, class: "mbe-2" + b.wrapper :grid_wrapper, class: "flex flex-col" do |ba| + ba.use :input, class: "input", error_class: "field_with_errors", valid_class: "field_without_errors" + ba.use :error, wrap_with: { class: "invalid-feedback block" } + ba.use :hint, wrap_with: { class: "text-subtle" } + end + end + + # horizontal select input + config.wrappers :horizontal_select, class: "mbe-3" do |b| + b.optional :readonly + b.use :label, class: "mbe-2" + b.wrapper :grid_wrapper, class: "flex flex-col" do |ba| + ba.use :input, class: "input", error_class: "field_with_errors", valid_class: "field_without_errors" + ba.use :error, wrap_with: { class: "invalid-feedback block" } + ba.use :hint, wrap_with: { class: "text-subtle" } + end + end + + # horizontal multi select + config.wrappers :horizontal_multi_select, class: "mbe-3" do |b| + b.optional :readonly + b.use :label, class: "mbe-2" + b.wrapper :grid_wrapper, class: "flex flex-col" do |ba| + ba.wrapper class: "flex flex-col gap" do |bb| + bb.use :input, class: "input mbe-2", error_class: "field_with_errors", valid_class: "field_without_errors" + end + ba.use :error, wrap_with: { class: "invalid-feedback block" } + ba.use :hint, wrap_with: { class: "text-subtle" } + end + end + + # inline forms + # + # inline default_wrapper + config.wrappers :inline_form, class: "i-full" do |b| + b.use :placeholder + b.optional :maxlength + b.optional :minlength + b.optional :pattern + b.optional :min_max + b.optional :readonly + b.use :label, class: "sr-only" + + b.use :input, class: "input", error_class: "field_with_errors", valid_class: "field_without_errors" + b.use :error, wrap_with: { class: "invalid-feedback block" } + b.optional :hint, wrap_with: { class: "text-subtle" } + end + + # inline input for boolean + config.wrappers :inline_boolean, class: "i-full" do |b| + b.optional :readonly + b.wrapper :form_check_wrapper, class: "flex items-center" do |bb| + bb.use :input, class: "checkbox", error_class: "field_with_errors", valid_class: "field_without_errors" + bb.use :label, class: "mis-2" + bb.use :error, wrap_with: { class: "invalid-feedback block" } + bb.optional :hint, wrap_with: { class: "text-subtle" } + end + end + + # The default wrapper to be used by the FormBuilder. + config.default_wrapper = :vertical_form + + # Custom wrappers for input types. This should be a hash containing an input + # type as key and the wrapper that will be used for all inputs with specified type. + config.wrapper_mappings = { + boolean: :vertical_boolean, + check_boxes: :vertical_collection, + date: :date_time_inputs, + datetime: :date_time_inputs, + file: :vertical_file, + radio_buttons: :vertical_collection, + range: :vertical_multi_select, + time: :date_time_inputs, + select: :vertical_select + } +end diff --git a/test/generators/simple_form_generator_test.rb b/test/generators/simple_form_generator_test.rb index abb526316..5d0946276 100644 --- a/test/generators/simple_form_generator_test.rb +++ b/test/generators/simple_form_generator_test.rb @@ -34,6 +34,14 @@ class SimpleFormGeneratorTest < Rails::Generators::TestCase /config\.default_wrapper = :vertical_form/, /config\.item_wrapper_tag = :div/ end + test 'generates the simple_form initializer with the css-zero wrappers' do + run_generator %w[--css-zero] + assert_file 'config/initializers/simple_form.rb', + /config\.default_wrapper = :default/, /config\.boolean_style = :nested/ + assert_file 'config/initializers/simple_form_css_zero.rb', /config\.wrappers :vertical_form/, + /config\.default_wrapper = :vertical_form/, /config\.item_wrapper_tag = :div/ + end + %w[erb haml slim].each do |engine| test "generates the scaffold template when using #{engine}" do run_generator ['-e', engine] From f99452b593ad3aac965cd3681809ae3010ab5f29 Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Wed, 14 May 2025 15:51:23 +0200 Subject: [PATCH 2/3] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec90eaba3..2b48b2e55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Remove redundant `aria-required` attribute for required fields. [@aduth](https://github.com/aduth) * Add `weekday` input. [@nashby](https://github.com/nashby) +* Add support for `css-zero` framework [@CuddlyBunion341](https://github.com/CuddlyBunion341) ## 5.3.1 From f74a6ff2531055bbbb40e0be2106ad95730a04bc Mon Sep 17 00:00:00 2001 From: Daniel Bengl Date: Wed, 14 May 2025 16:32:22 +0200 Subject: [PATCH 3/3] Update initializer --- .../initializers/simple_form_css_zero.rb | 49 ------------------- 1 file changed, 49 deletions(-) diff --git a/lib/generators/simple_form/templates/config/initializers/simple_form_css_zero.rb b/lib/generators/simple_form/templates/config/initializers/simple_form_css_zero.rb index 621ec363e..f8c1add0f 100644 --- a/lib/generators/simple_form/templates/config/initializers/simple_form_css_zero.rb +++ b/lib/generators/simple_form/templates/config/initializers/simple_form_css_zero.rb @@ -11,37 +11,14 @@ # Use this setup block to configure all options available in SimpleForm. SimpleForm.setup do |config| # rubocop:disable Metrics/BlockLength - # Default class for buttons - # See: https://github.com/renuo/css-zero/blob/main/lib/generators/css_zero/add/templates/app/assets/stylesheets/button.css config.button_class = "btn" - - # Define the default class of the input wrapper of the boolean input. config.boolean_label_class = "checkbox" - - # How the label text should be generated altogether with the required text. config.label_text = ->(label, required, _explicit_label) { "#{label} #{required}" } - - # Define the way to render check boxes / radio buttons with labels. config.boolean_style = :inline - - # You can wrap each item in a collection of radio/check boxes with a tag config.item_wrapper_tag = :div - - # Defines if the default input wrapper class should be included in radio - # collection wrappers. config.include_default_input_wrapper_class = false - - # CSS class to add for error notification helper. - # See: https://github.com/renuo/css-zero/blob/main/lib/generators/css_zero/add/templates/app/assets/stylesheets/input.css config.error_notification_class = "invalid-feedback" - - # Method used to tidy up errors. Specify any Rails Array method. - # :first lists the first message for each field. - # :to_sentence to list all errors for each field. config.error_method = :to_sentence - - # add validation classes to `input_field` - # See: https://github.com/renuo/css-zero/blob/main/lib/generators/css_zero/add/templates/app/assets/stylesheets/input.css config.input_field_error_class = "field_with_errors" config.input_field_valid_class = "field_without_errors" @@ -49,9 +26,6 @@ b.use :html5 end - # vertical forms - # - # vertical default_wrapper config.wrappers :vertical_form, class: "mbe-3" do |b| b.use :placeholder b.optional :maxlength @@ -65,7 +39,6 @@ b.use :hint, wrap_with: { class: "text-subtle" } end - # vertical input for boolean config.wrappers :vertical_boolean, tag: "fieldset", class: "mbe-3" do |b| b.optional :readonly b.wrapper :form_check_wrapper, class: "flex items-center" do |bb| @@ -76,7 +49,6 @@ end end - # vertical input for radio buttons and check boxes config.wrappers :vertical_collection, item_wrapper_class: "flex items-center", item_label_class: "mis-2", tag: "fieldset", class: "mbe-3" do |b| b.optional :readonly @@ -88,7 +60,6 @@ b.use :hint, wrap_with: { class: "text-subtle" } end - # vertical input for inline radio buttons and check boxes config.wrappers :vertical_collection_inline, item_wrapper_class: "flex items-center mie-2", item_label_class: "mis-2", tag: "fieldset", class: "mbe-3" do |b| b.optional :readonly @@ -100,7 +71,6 @@ b.use :hint, wrap_with: { class: "text-subtle" } end - # vertical file input config.wrappers :vertical_file, class: "mbe-3" do |b| b.use :placeholder b.optional :maxlength @@ -112,7 +82,6 @@ b.use :hint, wrap_with: { class: "text-subtle" } end - # vertical select input config.wrappers :vertical_select, class: "mbe-3" do |b| b.optional :readonly b.use :label, class: "mbe-1" @@ -121,7 +90,6 @@ b.use :hint, wrap_with: { class: "text-subtle" } end - # vertical multi select config.wrappers :vertical_multi_select, class: "mbe-3" do |b| b.optional :readonly b.use :label, class: "mbe-1" @@ -132,7 +100,6 @@ b.use :hint, wrap_with: { class: "text-subtle" } end - # Date and time inputs config.wrappers :date_time_inputs, class: "mbe-3" do |b| b.use :placeholder b.optional :readonly @@ -144,9 +111,6 @@ b.use :hint, wrap_with: { class: "text-subtle" } end - # horizontal forms - # - # horizontal default_wrapper config.wrappers :horizontal_form, class: "flex flex-col mb-3" do |b| b.use :placeholder b.optional :maxlength @@ -162,7 +126,6 @@ end end - # horizontal input for boolean config.wrappers :horizontal_boolean, class: "mbe-3" do |b| b.optional :readonly b.wrapper :grid_wrapper, class: "flex items-center" do |wr| @@ -175,7 +138,6 @@ end end - # horizontal input for radio buttons and check boxes config.wrappers :horizontal_collection, item_wrapper_class: "flex items-center", item_label_class: "mis-2", class: "mbe-3" do |b| b.optional :readonly @@ -187,7 +149,6 @@ end end - # horizontal input for inline radio buttons and check boxes config.wrappers :horizontal_collection_inline, item_wrapper_class: "flex items-center mie-3", item_label_class: "mis-2", class: "mbe-3" do |b| b.optional :readonly @@ -199,7 +160,6 @@ end end - # horizontal file input config.wrappers :horizontal_file, class: "mbe-3" do |b| b.use :placeholder b.optional :maxlength @@ -213,7 +173,6 @@ end end - # horizontal select input config.wrappers :horizontal_select, class: "mbe-3" do |b| b.optional :readonly b.use :label, class: "mbe-2" @@ -224,7 +183,6 @@ end end - # horizontal multi select config.wrappers :horizontal_multi_select, class: "mbe-3" do |b| b.optional :readonly b.use :label, class: "mbe-2" @@ -237,9 +195,6 @@ end end - # inline forms - # - # inline default_wrapper config.wrappers :inline_form, class: "i-full" do |b| b.use :placeholder b.optional :maxlength @@ -254,7 +209,6 @@ b.optional :hint, wrap_with: { class: "text-subtle" } end - # inline input for boolean config.wrappers :inline_boolean, class: "i-full" do |b| b.optional :readonly b.wrapper :form_check_wrapper, class: "flex items-center" do |bb| @@ -265,11 +219,8 @@ end end - # The default wrapper to be used by the FormBuilder. config.default_wrapper = :vertical_form - # Custom wrappers for input types. This should be a hash containing an input - # type as key and the wrapper that will be used for all inputs with specified type. config.wrapper_mappings = { boolean: :vertical_boolean, check_boxes: :vertical_collection,