poetry-simple_form 0.0.3

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 938d26d4ca15b34d244fdc9d37b32310d8bab58ada91a2e53f097649d74ddbb8
4
+ data.tar.gz: 989eb21341bad9296b31e74f4c62410930db2d5350aef9da3bba7c45c9b21749
5
+ SHA512:
6
+ metadata.gz: ba8eac52747366e0d54c09ca3c4bb293a155ffed98bdcb7bacbff33d0502d433ad8136eed3f39898989696c9ca48800eb45e65b3740b9a576df2ef8f1ae4937e
7
+ data.tar.gz: 3ce40235c63fbf05532db9d055de1e7aa19e844fe29b309ea453c5d9852e73b594106a218cdc3bd551ac6460ee9fce4ee069202bc3334631576ee68fa09f43fb
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # Changelog
2
+
3
+ ## [Unreleased]
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Matt Solt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # poetry-simple_form
2
+
3
+ The **migration bridge** from simple_form to poetry. One initializer re-maps
4
+ simple_form's input types onto classes that render whole poetry Fields
5
+ through `Poetry::Ui::FormBuilder` — existing `f.input` calls keep working,
6
+ now with the quartet (label / hint / error / aria) derived from the model
7
+ exactly like the native builder, because the shim renders *through* it.
8
+
9
+ ```ruby
10
+ # Gemfile
11
+ gem "poetry-simple_form"
12
+ ```
13
+
14
+ ```sh
15
+ bin/rails g poetry:simple_form:install # writes the one-line initializer
16
+ ```
17
+
18
+ ## What you get
19
+
20
+ - `f.input` for string/email/url/tel/search/uuid/password/text/json/boolean/
21
+ numeric/range/date/time/file and the collection trio (select /
22
+ radio_buttons / check_boxes), plus grouped_select and time_zone, renders
23
+ poetry Fields: `aria-required` (never native), maxlength/min/max/step
24
+ from validations, errors wired via `aria-describedby`.
25
+ - `f.association` works unchanged (simple_form fetches the records; the
26
+ shim's collection inputs render them as poetry pickers).
27
+ - Every poetry form control is reachable by its poetry name through `as:`,
28
+ even the ones simple_form never had: `:switch`, `:slider`, `:otp`,
29
+ `:sensitive`, `:tag_group`, `:date_picker`, `:calendar`, `:combobox`,
30
+ `:autocomplete`, `:native_select`.
31
+ - `required: true/false` overrides the model's presence inference; `label_method:`
32
+ and `value_method:` (symbols or callables) are honored on every collection
33
+ input, with simple_form's detection chain as the fallback.
34
+ - Poetry-only options ride a `poetry:` hash - `f.input :active, poetry:
35
+ { switch: true }`, `f.input :code, as: :otp, poetry: { length: 4 }` -
36
+ merged last, so it wins over anything simple_form derived. `input_html`
37
+ still lands on the control (minus class and id, which the component owns).
38
+ - `:datetime` renders poetry's DateTimeField (one datetime-local control,
39
+ local wall time on the wire). `:rich_text_area`, `:hidden`, and `:country`
40
+ fall back to stock simple_form rendering on purpose (no editor, nothing to
41
+ render, and a country list poetry does not carry).
42
+ - Remove the initializer to restore stock rendering instantly.
43
+
44
+ The full type-to-component table is `Poetry::SimpleForm::COVERAGE`; a
45
+ parity test in this gem fails when a new poetry form control has no
46
+ simple_form route, so the two vocabularies cannot drift apart.
47
+
48
+ ## What this is not
49
+
50
+ Not the end state. The bridge exists so views can migrate to
51
+ `form_with(model:, builder: Poetry::Ui::FormBuilder)` (and `f.input`
52
+ there) at your own pace — see the poetry docs `/forms` guide. simple_form
53
+ itself contributes only type resolution here; its wrapper tree is bypassed
54
+ by design (a flat wrapper cannot express the Field quartet).
55
+
56
+ Existing `simple_form.*` i18n keys (labels/hints/placeholders) keep
57
+ working — poetry's builder reads them as a fallback chain.
58
+
59
+ ## License
60
+
61
+ Available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+
5
+ module Poetry
6
+ module SimpleForm
7
+ # The gem's Rails generators.
8
+ module Generators
9
+ # `rails g poetry:simple_form:install` - one initializer, the whole
10
+ # shim: activate! re-maps the input types and installs the
11
+ # passthrough wrapper. Delete the file to fall back to stock
12
+ # simple_form rendering.
13
+ class InstallGenerator < Rails::Generators::Base
14
+ source_root File.expand_path("templates", __dir__)
15
+
16
+ # Write config/initializers/poetry_simple_form.rb.
17
+ # @api private
18
+ def create_initializer
19
+ create_file "config/initializers/poetry_simple_form.rb", <<~RUBY_FILE
20
+ # poetry renders simple_form's inputs (the migration bridge):
21
+ # f.input keeps working while views move to
22
+ # form_with(builder: Poetry::Ui::FormBuilder). Remove this file
23
+ # to restore stock simple_form rendering.
24
+ Poetry::SimpleForm.activate!
25
+ RUBY_FILE
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ # The input classes the bridge maps simple_form's types onto.
6
+ module Inputs
7
+ # The shim's shared floor: every input renders through a
8
+ # Poetry::Ui::FormBuilder bound to the SAME object/template, so the
9
+ # poetry Field quartet (label/hint/error/aria) is byte-identical to
10
+ # the native-builder path - no duplicated derivation.
11
+ class Base < ::SimpleForm::Inputs::Base
12
+ # Render the attribute as a whole poetry Field through the bound
13
+ # Poetry::Ui::FormBuilder; the subclass's `poetry_as` pins the
14
+ # control type (nil lets poetry infer it).
15
+ #
16
+ # @param _wrapper_options [Hash, nil] unused - the Field owns its chrome
17
+ # @return [String] the rendered Field HTML
18
+ def input(_wrapper_options = nil)
19
+ poetry_builder.input(attribute_name, as: poetry_as, **poetry_options)
20
+ end
21
+
22
+ private
23
+
24
+ # Subclasses answer the poetry `as:` value (nil lets poetry infer).
25
+ def poetry_as = nil
26
+
27
+ def poetry_builder
28
+ Poetry::Ui::FormBuilder.new(object_name, object, template, {})
29
+ end
30
+
31
+ # simple_form option vocabulary -> poetry's: label/hint/placeholder
32
+ # pass through (false stays false-y as an omission), required:
33
+ # explicit override wins, input_html lands on the control minus the
34
+ # class string (poetry components own their classes; append via
35
+ # input_html: { class: } consciously with poetry_class:). A `poetry:`
36
+ # hash is the first-class channel for poetry-only options (switch:,
37
+ # length:, orientation:, ...) - merged last, so it wins.
38
+ def poetry_options
39
+ opts = input_html_options.except(:class, :id)
40
+ opts[:hint] = options[:hint] if options[:hint].is_a?(String)
41
+ label = options[:label].is_a?(String) ? options[:label] : translate_from_namespace(:labels)
42
+ opts[:label] = label if label.is_a?(String) # simple_form.labels.* keys, its own lookup chain
43
+ placeholder = options[:placeholder] || input_html_options[:placeholder]
44
+ opts[:placeholder] = placeholder if placeholder.is_a?(String)
45
+ opts[:required] = options[:required] if options.key?(:required) # explicit beats inference
46
+ opts.merge!(options[:poetry].to_h.transform_keys(&:to_sym)) if options[:poetry]
47
+ opts
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # The horizontal boolean Field (poetry's f.input boolean story);
7
+ # input_html: { switch: true } opts into the setting-row Switch.
8
+ class BooleanInput < Base
9
+ private
10
+
11
+ def poetry_as = :boolean
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # The collection floor: pairs from options[:collection] (both
7
+ # f.input(collection:) and f.association arrive here - association
8
+ # fetches the records first), label/value methods resolved with
9
+ # simple_form's own detection chain.
10
+ class CollectionBase < Base
11
+ private
12
+
13
+ def label_value_pairs(collection = Array(options[:collection]))
14
+ return [] if collection.empty?
15
+
16
+ sample = collection.first
17
+ label = options[:label_method]
18
+ value = options[:value_method]
19
+ if (sample.is_a?(Array) || !sample.respond_to?(:id)) && !(label || value)
20
+ collection.map { |item| item.is_a?(Array) ? item : [item.to_s, item] }
21
+ else
22
+ # simple_form's label_method:/value_method: (symbols or callables)
23
+ # win; otherwise its detection chain (name, title, to_s / id, to_s).
24
+ label ||= ::SimpleForm.collection_label_methods.find { |m| sample.respond_to?(m) }
25
+ value ||= ::SimpleForm.collection_value_methods.find { |m| sample.respond_to?(m) }
26
+ collection.map { |item| [read(item, label), read(item, value)] }
27
+ end
28
+ end
29
+
30
+ def read(item, method)
31
+ method.respond_to?(:call) ? method.call(item) : item.public_send(method)
32
+ end
33
+ end
34
+
35
+ # Serves `as: :select` (and f.association's default): a poetry Field
36
+ # wrapping the Select component; the hidden native <select> stays the
37
+ # serialization truth.
38
+ class CollectionSelectInput < CollectionBase
39
+ # Render the collection as a Field-wrapped Select;
40
+ # include_blank/prompt becomes the placeholder option.
41
+ #
42
+ # @return [String] the rendered Field HTML
43
+ def input(_wrapper_options = nil)
44
+ poetry_builder.poetry_select(attribute_name, label_value_pairs,
45
+ include_blank: options[:include_blank] || options[:prompt],
46
+ **poetry_options)
47
+ end
48
+ end
49
+
50
+ # Serves `as: :radio_buttons`: a poetry Field wrapping the
51
+ # RadioGroup component, one row per collection item.
52
+ class CollectionRadioButtonsInput < CollectionBase
53
+ # Render the collection as a Field-wrapped RadioGroup.
54
+ #
55
+ # @return [String] the rendered Field HTML
56
+ def input(_wrapper_options = nil)
57
+ pairs = label_value_pairs.map { |label, value| [value, label] }
58
+ poetry_builder.radio_group(attribute_name, pairs, **poetry_options)
59
+ end
60
+ end
61
+
62
+ # Serves `as: :check_boxes`: a poetry Field wrapping the checkbox
63
+ # group - one Checkbox row per collection item, posting an array.
64
+ class CollectionCheckBoxesInput < CollectionBase
65
+ # Render the collection as a Field-wrapped checkbox group.
66
+ #
67
+ # @return [String] the rendered Field HTML
68
+ def input(_wrapper_options = nil)
69
+ pairs = label_value_pairs.map { |label, value| [value, label] }
70
+ poetry_builder.checkbox_group(attribute_name, pairs, **poetry_options)
71
+ end
72
+ end
73
+
74
+ # Serves `as: :native_select`: a poetry Field wrapping the styled
75
+ # native <select> (the no-JS picker).
76
+ class NativeSelectInput < CollectionBase
77
+ # @return [String] the rendered Field HTML
78
+ def input(_wrapper_options = nil)
79
+ poetry_builder.native_select(attribute_name, label_value_pairs,
80
+ include_blank: options[:include_blank] || options[:prompt],
81
+ **poetry_options)
82
+ end
83
+ end
84
+
85
+ # Serves `as: :combobox`: a poetry Field wrapping the filterable Combobox.
86
+ class ComboboxInput < CollectionBase
87
+ # @return [String] the rendered Field HTML
88
+ def input(_wrapper_options = nil)
89
+ poetry_builder.poetry_combobox(attribute_name, label_value_pairs,
90
+ include_blank: options[:include_blank] || options[:prompt],
91
+ **poetry_options)
92
+ end
93
+ end
94
+
95
+ # Serves `as: :autocomplete`: a poetry Field wrapping the Autocomplete;
96
+ # the collection becomes its suggestions.
97
+ class AutocompleteInput < CollectionBase
98
+ # @return [String] the rendered Field HTML
99
+ def input(_wrapper_options = nil)
100
+ poetry_builder.autocomplete(attribute_name, label_value_pairs, **poetry_options)
101
+ end
102
+ end
103
+
104
+ # Serves `as: :grouped_select`: simple_form's group_method /
105
+ # group_label_method resolve the groups, poetry's Select renders them
106
+ # as labelled groups.
107
+ class GroupedCollectionSelectInput < CollectionBase
108
+ # @return [String] the rendered Field HTML
109
+ def input(_wrapper_options = nil)
110
+ poetry_builder.poetry_select(attribute_name, grouped_pairs,
111
+ include_blank: options[:include_blank] || options[:prompt],
112
+ **poetry_options)
113
+ end
114
+
115
+ private
116
+
117
+ # { "Group label" => [[label, value], ...] } in collection order.
118
+ def grouped_pairs
119
+ groups = options[:collection]
120
+ groups = groups.call if groups.respond_to?(:call)
121
+ group_method = options.fetch(:group_method)
122
+ Array(groups).to_h do |group|
123
+ [group_label_for(group).to_s, label_value_pairs(Array(group.public_send(group_method)))]
124
+ end
125
+ end
126
+
127
+ def group_label_for(group)
128
+ method = options[:group_label_method] ||
129
+ ::SimpleForm.collection_label_methods.find { |m| group.respond_to?(m) }
130
+ method ? group.public_send(method) : group
131
+ end
132
+ end
133
+
134
+ # Serves `as: :time_zone`: every ActiveSupport::TimeZone in a poetry
135
+ # Select, the priority zones (priority: or SimpleForm.time_zone_priority)
136
+ # listed first.
137
+ class TimeZoneInput < CollectionBase
138
+ # @return [String] the rendered Field HTML
139
+ def input(_wrapper_options = nil)
140
+ poetry_builder.poetry_select(attribute_name, zone_pairs,
141
+ include_blank: options[:include_blank] || options[:prompt],
142
+ **poetry_options)
143
+ end
144
+
145
+ private
146
+
147
+ def zone_pairs
148
+ zones = ActiveSupport::TimeZone.all
149
+ priority = Array(options[:priority] || ::SimpleForm.time_zone_priority)
150
+ first = priority.filter_map do |zone|
151
+ zone.is_a?(ActiveSupport::TimeZone) ? zone : ActiveSupport::TimeZone[zone]
152
+ end
153
+ (first + (zones - first)).map { |zone| [zone.to_s, zone.name] }
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # The poetry controls with no simple_form ancestor, each reachable by
7
+ # its poetry name: `f.input :active, as: :switch`. They are thin on
8
+ # purpose - the Field quartet and every option ride the shared Base.
9
+
10
+ # Serves `as: :switch`: a Field in the setting orientation wrapping the Switch.
11
+ class SwitchInput < Base
12
+ private
13
+
14
+ def poetry_as = :switch
15
+ end
16
+
17
+ # Serves `as: :slider` and simple_form's `:range`: a Field wrapping the Slider.
18
+ class SliderInput < Base
19
+ private
20
+
21
+ def poetry_as = :slider
22
+ end
23
+
24
+ # Serves `as: :otp`: a Field wrapping the InputOtp (length: via poetry:).
25
+ class OtpInput < Base
26
+ private
27
+
28
+ def poetry_as = :otp
29
+ end
30
+
31
+ # Serves `as: :sensitive`: a Field wrapping the masked, reveal-on-demand SensitiveInput.
32
+ class SensitiveInput < Base
33
+ private
34
+
35
+ def poetry_as = :sensitive
36
+ end
37
+
38
+ # Serves `as: :tag_group`: a Field wrapping the TagGroup.
39
+ class TagGroupInput < Base
40
+ private
41
+
42
+ def poetry_as = :tag_group
43
+ end
44
+
45
+ # Serves `as: :date_picker`: a Field wrapping the DatePicker (popover calendar).
46
+ class DatePickerInput < Base
47
+ private
48
+
49
+ def poetry_as = :date_picker
50
+ end
51
+
52
+ # Serves `as: :calendar`: a Field wrapping the inline Calendar.
53
+ class CalendarInput < Base
54
+ private
55
+
56
+ def poetry_as = :calendar
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # date -> DateField, time -> TimeField; :datetime falls back to
7
+ # poetry's own DateTimeField (one datetime-local control, no select trio).
8
+ class DateTimeInput < ::SimpleForm::Inputs::DateTimeInput
9
+ # Render :date/:time/:datetime attributes as poetry DateField /
10
+ # TimeField / DateTimeField - one control each, ISO on the wire.
11
+ #
12
+ # @return [String] the rendered HTML
13
+ def input(_wrapper_options = nil)
14
+ Poetry::Ui::FormBuilder.new(object_name, object, template, {})
15
+ .input(attribute_name, as: input_type)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # Serves `as: :file`: a poetry Field wrapping the FileInput
7
+ # component (the native file control in poetry chrome; input_html
8
+ # options such as variant:/multiple: pass through).
9
+ class FileInput < Base
10
+ private
11
+
12
+ def poetry_as = :file
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # NumberField; poetry re-derives min/max/step from numericality, so
7
+ # the shim passes nothing simple_form computed.
8
+ class NumericInput < Base
9
+ private
10
+
11
+ def poetry_as = :number
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # Serves `as: :password`: a poetry Field wrapping a type=password
7
+ # Input; the value never round-trips into the markup.
8
+ class PasswordInput < Base
9
+ private
10
+
11
+ def poetry_as = :password
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # string/email/url/tel/search/citext: the resolved simple_form
7
+ # input_type IS poetry's as: vocabulary (citext folds to string).
8
+ class StringInput < Base
9
+ private
10
+
11
+ def poetry_as
12
+ # :string is simple_form's no-column fallback (ActiveModel,
13
+ # virtual attributes) - hand poetry a nil so ITS inference runs
14
+ # (type_for_attribute + name heuristics); a concretely resolved
15
+ # type passes through.
16
+ return nil if %i[string citext uuid].include?(input_type)
17
+
18
+ input_type
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ module Inputs
6
+ # Serves `as: :text`: a poetry Field wrapping the Textarea
7
+ # component.
8
+ class TextInput < Base
9
+ private
10
+
11
+ def poetry_as = :text
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "poetry/simple_form/inputs/base"
4
+ require "poetry/simple_form/inputs/string_input"
5
+ require "poetry/simple_form/inputs/password_input"
6
+ require "poetry/simple_form/inputs/text_input"
7
+ require "poetry/simple_form/inputs/boolean_input"
8
+ require "poetry/simple_form/inputs/numeric_input"
9
+ require "poetry/simple_form/inputs/date_time_input"
10
+ require "poetry/simple_form/inputs/file_input"
11
+ require "poetry/simple_form/inputs/collection_inputs"
12
+ require "poetry/simple_form/inputs/custom_inputs"
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Poetry
4
+ module SimpleForm
5
+ # The gem version.
6
+ VERSION = "0.0.3"
7
+ end
8
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "simple_form"
4
+ require "poetry/simple_form/version"
5
+ require "poetry/simple_form/inputs"
6
+
7
+ # The Poetry namespace, shared by every gem in the family.
8
+ module Poetry
9
+ # The simple_form migration bridge: one initializer re-maps simple_form's
10
+ # input types onto classes that render whole poetry Fields through
11
+ # Poetry::Ui::FormBuilder. Every f.input keeps working; every poetry form
12
+ # control is reachable by name through as:.
13
+ module SimpleForm
14
+ # simple_form input type => bridge input class. activate! installs
15
+ # exactly this table, so the coverage below cannot drift from it.
16
+ INPUTS = {
17
+ string: Inputs::StringInput, email: Inputs::StringInput, url: Inputs::StringInput,
18
+ tel: Inputs::StringInput, search: Inputs::StringInput, citext: Inputs::StringInput,
19
+ uuid: Inputs::StringInput,
20
+ password: Inputs::PasswordInput, sensitive: Inputs::SensitiveInput,
21
+ text: Inputs::TextInput, hstore: Inputs::TextInput, json: Inputs::TextInput, jsonb: Inputs::TextInput,
22
+ boolean: Inputs::BooleanInput, switch: Inputs::SwitchInput,
23
+ integer: Inputs::NumericInput, decimal: Inputs::NumericInput, float: Inputs::NumericInput,
24
+ range: Inputs::SliderInput, slider: Inputs::SliderInput,
25
+ date: Inputs::DateTimeInput, time: Inputs::DateTimeInput, datetime: Inputs::DateTimeInput,
26
+ date_picker: Inputs::DatePickerInput, calendar: Inputs::CalendarInput,
27
+ file: Inputs::FileInput, otp: Inputs::OtpInput, tag_group: Inputs::TagGroupInput,
28
+ select: Inputs::CollectionSelectInput, grouped_select: Inputs::GroupedCollectionSelectInput,
29
+ time_zone: Inputs::TimeZoneInput, native_select: Inputs::NativeSelectInput,
30
+ combobox: Inputs::ComboboxInput, autocomplete: Inputs::AutocompleteInput,
31
+ radio_buttons: Inputs::CollectionRadioButtonsInput, check_boxes: Inputs::CollectionCheckBoxesInput
32
+ }.freeze
33
+
34
+ # simple_form input type => the poetry component it renders (a registry
35
+ # key).
36
+ # The parity gate (test/poetry/simple_form/coverage_test.rb) checks this
37
+ # against every form-facing component in the registry.
38
+ COVERAGE = {
39
+ string: "input", email: "input", url: "input", tel: "input", citext: "input", uuid: "input",
40
+ password: "input", search: "search_field", sensitive: "sensitive_input",
41
+ text: "textarea", hstore: "textarea", json: "textarea", jsonb: "textarea",
42
+ boolean: "checkbox", switch: "switch",
43
+ integer: "number_field", decimal: "number_field", float: "number_field",
44
+ range: "slider", slider: "slider",
45
+ date: "date_field", time: "time_field", datetime: "date_time_field",
46
+ date_picker: "date_picker", calendar: "calendar",
47
+ file: "file_input", otp: "input_otp", tag_group: "tag_group",
48
+ select: "select", grouped_select: "select", time_zone: "select", native_select: "native_select",
49
+ combobox: "combobox", autocomplete: "autocomplete",
50
+ radio_buttons: "radio_group", check_boxes: "checkbox"
51
+ }.freeze
52
+
53
+ # simple_form types left to simple_form entirely, with the reason.
54
+ STOCK = {
55
+ rich_text_area: "poetry ships no rich-text editor",
56
+ hidden: "nothing to render",
57
+ country: "the country list comes from the country_select gem, which poetry does not depend on"
58
+ }.freeze
59
+
60
+ # Form-facing poetry components deliberately not reachable through a
61
+ # simple_form type, with the reason (empty today; the gate reads it).
62
+ BRIDGE_EXEMPT = {}.freeze
63
+
64
+ # Install the bridge: map every type in INPUTS and make the flat poetry
65
+ # wrapper the default (the Field owns its chrome, so the wrapper
66
+ # contributes only display: contents).
67
+ #
68
+ # @return [void]
69
+ def self.activate!
70
+ builder = ::SimpleForm::FormBuilder
71
+ INPUTS.each { |type, klass| builder.map_type type, to: klass }
72
+
73
+ ::SimpleForm.setup do |config|
74
+ config.wrappers :poetry, tag: :div, class: "contents" do |b|
75
+ b.use :input
76
+ end
77
+ config.default_wrapper = :poetry
78
+ end
79
+ end
80
+ end
81
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: poetry-simple_form
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Matt Solt
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: poetry-ui
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '='
17
+ - !ruby/object:Gem::Version
18
+ version: 0.0.3
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - '='
24
+ - !ruby/object:Gem::Version
25
+ version: 0.0.3
26
+ - !ruby/object:Gem::Dependency
27
+ name: simple_form
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '5.3'
33
+ - - "<"
34
+ - !ruby/object:Gem::Version
35
+ version: '6'
36
+ type: :runtime
37
+ prerelease: false
38
+ version_requirements: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '5.3'
43
+ - - "<"
44
+ - !ruby/object:Gem::Version
45
+ version: '6'
46
+ description: An opt-in shim that re-maps simple_form's input types onto Poetry's model-bound
47
+ Field components, so existing simple_form views keep working mid-migration. The
48
+ end state is Poetry::Ui::FormBuilder - this bridge exists to make getting there
49
+ boring.
50
+ email:
51
+ - mattsolt@gmail.com
52
+ executables: []
53
+ extensions: []
54
+ extra_rdoc_files: []
55
+ files:
56
+ - CHANGELOG.md
57
+ - LICENSE.txt
58
+ - README.md
59
+ - lib/generators/poetry/simple_form/install/install_generator.rb
60
+ - lib/poetry/simple_form.rb
61
+ - lib/poetry/simple_form/inputs.rb
62
+ - lib/poetry/simple_form/inputs/base.rb
63
+ - lib/poetry/simple_form/inputs/boolean_input.rb
64
+ - lib/poetry/simple_form/inputs/collection_inputs.rb
65
+ - lib/poetry/simple_form/inputs/custom_inputs.rb
66
+ - lib/poetry/simple_form/inputs/date_time_input.rb
67
+ - lib/poetry/simple_form/inputs/file_input.rb
68
+ - lib/poetry/simple_form/inputs/numeric_input.rb
69
+ - lib/poetry/simple_form/inputs/password_input.rb
70
+ - lib/poetry/simple_form/inputs/string_input.rb
71
+ - lib/poetry/simple_form/inputs/text_input.rb
72
+ - lib/poetry/simple_form/version.rb
73
+ homepage: https://poetryui.com
74
+ licenses:
75
+ - MIT
76
+ metadata:
77
+ homepage_uri: https://poetryui.com
78
+ documentation_uri: https://poetryui.com/docs
79
+ source_code_uri: https://github.com/roboruby/poetry-simple_form
80
+ changelog_uri: https://github.com/roboruby/poetry-simple_form/blob/main/CHANGELOG.md
81
+ bug_tracker_uri: https://github.com/roboruby/poetry-simple_form/issues
82
+ rubygems_mfa_required: 'true'
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: 3.4.0
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubygems_version: 4.0.16
98
+ specification_version: 4
99
+ summary: 'The simple_form migration bridge for Poetry: f.input renders Poetry Fields.'
100
+ test_files: []