ruact 0.0.18 → 0.0.19

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afeffed3bf00af43d750b220dbffbdd62758269d578bb649912d7fbee157df86
4
- data.tar.gz: 2bae60da180b2a5b6c85fe49c3adc42d3431c1cfee7666c9fdbf79b92815049b
3
+ metadata.gz: 7d7fb20ee09bec81b05b4e1cafba8f511e46a77d2bee2afc7bb92ca8e026483d
4
+ data.tar.gz: 6111ba333bf9067854a13c62ec66f13297c78c3a6c4c419f39284d001d57d2c4
5
5
  SHA512:
6
- metadata.gz: 79f5785e73237b512b1fce27e9b085538c57954921bf92544fc8d4f80c2646f27e5e46baa23b1a565beb567b8e4762a108a0f2885b3ec85f9b822216889afadd
7
- data.tar.gz: 3421862773a8f0669533bd70e39aed531b9ae2c4ce42205bc6939bc6311d76f5c45e4527d39752793bebc343af29ba96ebffd3fd58a6f414bb16fba879cfcbeb
6
+ metadata.gz: 1b9ed6e86719935a5494f4a847c1938e903c4440f0b026ba3c1780eb0407fe6cf2214b448b3a6e34b8c10e45f42c3e4964dd2bcbaa14c33ec35d5e71114d7bbc
7
+ data.tar.gz: c25217ef2564fc948c0aee0191878a4addeefaf4e3edb45986e6d0b1d8b547f17cdc72b15a366d8a9d886db378e522b3c7394fd00ba22f9e05fd11dab8e49a61
data/CHANGELOG.md CHANGED
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.0.19] - 2026-10-08
11
+
12
+ ### Fixed
13
+
14
+ - **A component exported from a file that exports several now renders as itself.** When one file exported more than one client component — as shadcn/ui's `components/ui/dialog.tsx` exports `Dialog`, `DialogTrigger`, `DialogContent` and the rest — every ERB tag naming one of them rendered whichever of the file's components the manifest listed first, with no error: a `<DialogTrigger>` rendered a `Dialog`, and a dialog composed from its parts in ERB never opened. Each tag now imports its own export. Files exporting a single component were not affected.
15
+
16
+ ### Changed
17
+
18
+ - **The `AGENTS.md` section the install writes tells agents to key list items.** In an ERB loop whose items hold components, each item needs a `data-react-key`: ERB has no `key`, so React matches the items by position, and when the list changes a component's state shows on the wrong item, with no warning. Re-run `rails generate ruact:install --force` to refresh the section.
19
+
10
20
  ## [0.0.18] - 2026-10-07
11
21
 
12
22
  ### Added
@@ -480,7 +490,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
480
490
 
481
491
  - **E2E test app** — `e2e/` Rails app (no DB, in-memory Post model) with full CRUD system tests validating the complete request cycle.
482
492
 
483
- [Unreleased]: https://github.com/luizcg/ruact/compare/v0.0.18...HEAD
493
+ [Unreleased]: https://github.com/luizcg/ruact/compare/v0.0.19...HEAD
494
+ [0.0.19]: https://github.com/luizcg/ruact/releases/tag/v0.0.19
484
495
  [0.0.18]: https://github.com/luizcg/ruact/releases/tag/v0.0.18
485
496
  [0.0.17]: https://github.com/luizcg/ruact/releases/tag/v0.0.17
486
497
  [0.0.16]: https://github.com/luizcg/ruact/releases/tag/v0.0.16
@@ -20,8 +20,7 @@ truth" below) instead of guessing.
20
20
  adds it; `ruact_pages only:` narrows it). The page's renderer owns navigation:
21
21
  going between a ruact page and a plain Rails/Turbo page is a full page load.
22
22
  - Interactive components live in `app/javascript/components/` as `"use client"`
23
- files, mounted from ERB with a PascalCase self-closing tag:
24
- `<LikeButton postId={@post.id} />`.
23
+ files, mounted from ERB with a PascalCase tag: `<LikeButton postId={@post.id} />`.
25
24
  - Mutations are ordinary non-GET controller actions on a controller that does
26
25
  `include Ruact::Server`. Reads are `Ruact::Query` classes in `app/queries/`.
27
26
  - ruact generates a typed TypeScript module from the route table; React imports
@@ -78,10 +77,11 @@ READ IT instead of simulating the name generation. Regenerate after routes/queri
78
77
  ## Five traps
79
78
 
80
79
  1. **Every component tag closes.** `<Badge label={@x} />` has no children;
81
- `<Card title={@t}>...</Card>` passes the ERB between its tags — HTML, loops,
82
- partials, other components — to the component as `children`. An opening tag
83
- that never closes, or a closing tag with no opening, fails LOUDLY with a
80
+ `<Card title={@t}>...</Card>` passes the ERB between its tags to the
81
+ component as `children`. An unclosed or stray tag fails LOUDLY with a
84
82
  `PreprocessorError` naming file:line. `<Suspense fallback="...">` pairs too.
83
+ In a loop of items holding components, give each item a `data-react-key`
84
+ (the record's id): React matches them by position otherwise, silently.
85
85
  2. **`{}` props are Ruby, not JavaScript.** `<Badge label={@post.title} />`
86
86
  evaluates `@post.title` as a Ruby expression in the ERB. No JS ternaries,
87
87
  no `{...spread}`. A quoted value (`title="Hi"`) is a
@@ -49,9 +49,13 @@ module Ruact
49
49
  # every client component eagerly (`virtual:ruact/registry`), so there is
50
50
  # nothing to load — and React reads +chunks+ as `[chunkId, filename]` pairs,
51
51
  # which the manifest's one-URL list is not.
52
- def resolve(module_id, _export_name)
53
- entry = by_module_id(module_id)
54
- raise "ClientManifest: no entry for module_id=#{module_id.inspect}" unless entry
52
+ #
53
+ # The entry is looked up by module AND export: one file can export several
54
+ # components (shadcn/ui's dialog.tsx exports Dialog, DialogTrigger, …), and
55
+ # each tag imports its own.
56
+ def resolve(module_id, export_name)
57
+ entry = data.each_value.find { |e| e["id"] == module_id && e["name"] == export_name }
58
+ raise "ClientManifest: no entry for module_id=#{module_id.inspect} export=#{export_name.inspect}" unless entry
55
59
 
56
60
  [entry["id"], NO_CHUNKS, entry["name"]]
57
61
  end
@@ -248,9 +252,5 @@ module Ruact
248
252
  def entries_by_name
249
253
  data
250
254
  end
251
-
252
- def by_module_id(id)
253
- data.values.find { |entry| entry["id"] == id }
254
- end
255
255
  end
256
256
  end
data/lib/ruact/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruact
4
- VERSION = "0.0.18"
4
+ VERSION = "0.0.19"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruact
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.18
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luiz Garcia