diff --git a/CHANGELOG.md b/CHANGELOG.md
index ac876d41..d5f066b6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+- Added parent_component configuration for field components (#160)
+
## [0.2.6] - 2023-10-11
### Added
- Support for Rails 7.1 (#151)
diff --git a/README.md b/README.md
index 6c44807b..c69605ae 100644
--- a/README.md
+++ b/README.md
@@ -194,6 +194,12 @@ You can use the same approach to inject options, wrap the input in a `
`, et
We'll add more use cases to the documentation soon.
+### Configuration
+
+| Attribute | Purpose | Default |
+| ------------------ | ----------------------------------------------- | --------------------- |
+| `parent_component` (string) | Parent class for all `ViewComponent::Form` components | `"ViewComponent::Base"` |
+
### Building your own components
When building your own ViewComponents for using in forms, it's recommended to inherit from `ViewComponent::Form::FieldComponent`, so you get access to the following helpers:
@@ -339,6 +345,22 @@ def length_validator
end
```
+### Setting up your own base component class
+
+1. Setup some base component from which the form components will inherit from
+```rb
+class ApplicationFormComponent < ViewComponent::Base
+end
+```
+2. Configure the parent component class
+```rb
+# config/initializers/vcf.rb
+
+ViewComponent::Form.configure do |config|
+ config.parent_component = 'ApplicationFormComponent'
+end
+```
+
### Using your form components without a backing model
If you want to ensure that your fields display consistently across your app, you'll need to lean on Rails' own helpers. You may be used to using form tag helpers such as `text_field_tag` to generate tags, or even writing out plain HTML tags. These can't be integrated with a form builder, so they won't offer you the benefits of this gem.
diff --git a/app/components/view_component/form/base_component.rb b/app/components/view_component/form/base_component.rb
index b2206141..e2ad2961 100644
--- a/app/components/view_component/form/base_component.rb
+++ b/app/components/view_component/form/base_component.rb
@@ -2,7 +2,7 @@
module ViewComponent
module Form
- class BaseComponent < ViewComponent::Base
+ class BaseComponent < ViewComponent::Form.configuration.parent_component.constantize
class << self
attr_accessor :default_options
end
diff --git a/lib/view_component/form.rb b/lib/view_component/form.rb
index 438d26b9..01030c59 100644
--- a/lib/view_component/form.rb
+++ b/lib/view_component/form.rb
@@ -5,6 +5,15 @@
module ViewComponent
module Form
+ class << self
+ def configuration
+ @configuration ||= Configuration.new
+ end
+
+ def configure
+ yield configuration
+ end
+ end
end
end
diff --git a/lib/view_component/form/configuration.rb b/lib/view_component/form/configuration.rb
new file mode 100644
index 00000000..9f9d0084
--- /dev/null
+++ b/lib/view_component/form/configuration.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+module ViewComponent
+ module Form
+ class Configuration
+ attr_accessor :parent_component
+
+ def initialize
+ @parent_component = "ViewComponent::Base"
+ end
+ end
+ end
+end
diff --git a/spec/internal/app/components/application_form_component.rb b/spec/internal/app/components/application_form_component.rb
new file mode 100644
index 00000000..b6ded24d
--- /dev/null
+++ b/spec/internal/app/components/application_form_component.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+
+class ApplicationFormComponent < ViewComponent::Base
+end
diff --git a/spec/internal/config/initializers/view_component_form.rb b/spec/internal/config/initializers/view_component_form.rb
new file mode 100644
index 00000000..36203470
--- /dev/null
+++ b/spec/internal/config/initializers/view_component_form.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+ViewComponent::Form.configure do |config|
+ config.parent_component = "ApplicationFormComponent"
+end
diff --git a/spec/view_component/form/base_component_spec.rb b/spec/view_component/form/base_component_spec.rb
index afb75929..c90de8fa 100644
--- a/spec/view_component/form/base_component_spec.rb
+++ b/spec/view_component/form/base_component_spec.rb
@@ -46,4 +46,12 @@ def name
it { expect(component.object_errors?).to be(false) }
end
end
+
+ describe "parent_component" do
+ subject { described_class }
+
+ context "without configured parent_component" do
+ it { is_expected.to be < ViewComponent::Base }
+ end
+ end
end
diff --git a/spec/view_component/form/builder_spec.rb b/spec/view_component/form/builder_spec.rb
index 3d1c2f6f..a912de81 100644
--- a/spec/view_component/form/builder_spec.rb
+++ b/spec/view_component/form/builder_spec.rb
@@ -192,4 +192,12 @@
it { expect(builder.send(:validation_context)).to eq(:create) }
end
end
+
+ describe "base component parent" do
+ subject(:field) { described_class.new(object_name, object, template, options).send(:component_klass, :text_field) }
+
+ it "is configured via initializer" do
+ expect(field.ancestors).to include(ApplicationFormComponent)
+ end
+ end
end
diff --git a/spec/view_component/form/configuration_spec.rb b/spec/view_component/form/configuration_spec.rb
new file mode 100644
index 00000000..fb4b0387
--- /dev/null
+++ b/spec/view_component/form/configuration_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+RSpec.describe ViewComponent::Form::Configuration do
+ subject(:configuration) { described_class.new }
+
+ describe "defaults" do
+ it do
+ expect(configuration).to have_attributes(parent_component: "ViewComponent::Base")
+ end
+ end
+end
diff --git a/spec/view_component/form_spec.rb b/spec/view_component/form_spec.rb
index 8ba29782..3a48a788 100644
--- a/spec/view_component/form_spec.rb
+++ b/spec/view_component/form_spec.rb
@@ -5,6 +5,10 @@
expect(ViewComponent::Form::VERSION).not_to be_nil
end
+ it "is configurable" do
+ expect { |block| described_class.configure(&block) }.to yield_with_args(ViewComponent::Form::Configuration)
+ end
+
if ENV.fetch("VIEW_COMPONENT_FORM_USE_ACTIONTEXT", "false") == "true"
it "loads ActionText" do
expect(defined?(ActionView::Helpers::Tags::ActionText)).to eq("constant")