diff --git a/Gemfile b/Gemfile index d3f90c9..36dd1fd 100644 --- a/Gemfile +++ b/Gemfile @@ -8,9 +8,10 @@ group :development, :test do gem "activemodel", "~> 8.0" # for model-bound / validation-inference specs gem "daisyui", ">= 1.2" # soft runtime dependency; present here to test the daisy theme # soft runtime dependency (gemspec has no hard dep); present here to test - # Forms::Live and the Forms::TagField tag primitives (>= 0.11.4 ships the - # reactive_tags client handlers the tag widget's wire contract targets). - gem "phlex-reactive", ">= 0.11.4" + # Forms::Live and the Forms::TagField tag primitives (>= 0.12.2 ships the + # reactive_tags(name:)/reactive_filter(input:) escape hatches the tag widget's + # instance-dynamic wire name needs — issue #6 Caveats 1 & 2). + gem "phlex-reactive", ">= 0.12.2" gem "debug" gem "gem-release" gem "rake" diff --git a/docs/Gemfile b/docs/Gemfile index 15cd35f..3a7cf02 100644 --- a/docs/Gemfile +++ b/docs/Gemfile @@ -15,8 +15,9 @@ gem "phlex-forms", path: ".." # Soft deps of phlex-forms, loaded here so the live docs examples render with # full styling (daisyui, already above) and the client-only tag/live behavior -# (phlex-reactive >= 0.11.4 ships the reactive_tags handlers the tag_field uses). -gem "phlex-reactive", ">= 0.11.4" +# (phlex-reactive >= 0.12.2 ships the reactive_tags(name:)/reactive_filter(input:) +# escape hatches the tag_field's instance-dynamic wire name uses — issue #6). +gem "phlex-reactive", ">= 0.12.2" # Expose these docs to AI agents over MCP (a read-only /mcp endpoint, drawn in # config/routes.rb), with rack-attack throttling the public AI/tooling diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index d965c46..76bcb0c 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -205,7 +205,7 @@ GEM phlex (~> 2.4.0) railties (>= 7.1, < 9) zeitwerk (~> 2.7) - phlex-reactive (0.11.5) + phlex-reactive (0.12.2) globalid (~> 1.0) phlex-rails (>= 2.0, < 3) railties (>= 7.1, < 9.0) @@ -376,7 +376,7 @@ DEPENDENCIES mcp phlex-forms! phlex-rails - phlex-reactive (>= 0.11.4) + phlex-reactive (>= 0.12.2) propshaft puma (>= 5.0) rack-attack @@ -468,7 +468,7 @@ CHECKSUMS phlex (2.4.1) sha256=e596717fbfe38b5271840266758779ebe75092e02629f0c170287e6290a70b12 phlex-forms (0.2.6) phlex-rails (2.4.0) sha256=2bcddbd488681acb25753bab1887d3ac150e644244ff8ba307f2171a4d0195f5 - phlex-reactive (0.11.5) sha256=9c51b4c3e108850a6e96fd021b2917d0d1d0b9683624718a0c5999eff958a384 + phlex-reactive (0.12.2) sha256=b8d4606ed20ba9e339d0fcf121badfe99ea803d10040321874e751392da9643f pp (0.6.4) sha256=dfcb0fce700c41456265922884f9fe195d7fbb0674a3578e6c0f69588e82b570 prettyprint (0.2.0) sha256=2bc9e15581a94742064a3cc8b0fb9d45aae3d03a1baa6ef80922627a0766f193 prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85 diff --git a/lib/forms/live.rb b/lib/forms/live.rb index 119a09b..e586e0f 100644 --- a/lib/forms/live.rb +++ b/lib/forms/live.rb @@ -168,10 +168,16 @@ def form_attributes # widget (rendered in the block) is driven by this root, which then DOM-owns # its hidden field. Name/id derived through field_name/field_id — the same # path the rootless render uses, so the [name=…]/#…_query selectors match. + # This form IS a reactive component, so it has reactive_tags/reactive_filter + # itself — the same 0.12.2 escape-hatch sugar Forms::TagField uses, emitting + # both filter selectors the client needs (issue #6 Caveats 1 & 2). tag = self.class.live_tags_declaration return attrs unless tag - mix(attrs, Forms::TagField.root_tag_attributes(name: field_name(tag[:name]), id: field_id(tag[:name]))) + query_id = Forms::TagField.query_id(field_id(tag[:name])) + mix(attrs, + reactive_tags(name: field_name(tag[:name])), + reactive_filter(input: "##{query_id}")) end # Untouched fields get no error set, so nothing flashes before the user diff --git a/lib/forms/tag_field.rb b/lib/forms/tag_field.rb index 62af0ec..b202a31 100644 --- a/lib/forms/tag_field.rb +++ b/lib/forms/tag_field.rb @@ -18,11 +18,13 @@ module Forms # The reactive_tags_* client helpers require phlex-reactive >= 0.11.4. # # It uses the reactive_tags_add/option/remove helpers for the chip/query/option - # behavior, but emits the ROOT's `data-reactive-tags-field` raw rather than via - # reactive_tags(:tags): that helper compiles a SYMBOL through the class-level - # reactive_scope, but a form builder's wire name is per-instance ("user[tags]"). - # The data attribute IS the public contract; any CSS selector works (issue #6 - # Caveats 1 & 2). Likewise the query input targets by #id so it never submits. + # behavior, and the ROOT's wire attrs come from the 0.12.2 escape-hatch sugar: + # reactive_tags(name: @name) takes the per-instance wire name verbatim ("user[tags]") + # — the class-level reactive_scope compile can't express it — validated at render; + # reactive_filter(input: "#…_query") targets the query input by id so it never + # submits, and (unlike the old raw -input-only attr) also emits + # data-reactive-filter-option so the 0.12.x client type-ahead actually runs + # (issue #6 Caveats 1 & 2). class TagField < Phlex::HTML include Phlex::Reactive::ClientBindings @@ -48,21 +50,26 @@ def view_template end end - # The root's tag wire attrs. Raw, not reactive_tags(:tags)/reactive_filter(:q) - # (Caveats 1 & 2): target the hidden field by [name=…] and the query input by - # #id (an id selector means the query input never submits a stray param). - # Public so Forms::Live can hoist these onto the