ruact 0.0.12 → 0.0.14

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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -1
  3. data/README.md +4 -4
  4. data/lib/generators/ruact/install/install_generator.rb +418 -128
  5. data/lib/generators/ruact/install/templates/AGENTS.md.tt +14 -13
  6. data/lib/generators/ruact/install/templates/Procfile.dev.tt +1 -1
  7. data/lib/generators/ruact/install/templates/initializer.rb.tt +29 -7
  8. data/lib/generators/ruact/install/templates/package.json.tt +4 -4
  9. data/lib/generators/ruact/install/templates/tsconfig.json.tt +3 -0
  10. data/lib/generators/ruact/layout/layout_generator.rb +52 -0
  11. data/lib/generators/ruact/scaffold/scaffold_generator.rb +39 -12
  12. data/lib/generators/ruact/scaffold/scaffold_shadcn_preflight.rb +4 -3
  13. data/lib/generators/ruact/scaffold/templates/components/List.tsx.tt +8 -8
  14. data/lib/generators/ruact/scaffold/templates/components/agnostic/List.tsx.tt +8 -8
  15. data/lib/generators/ruact/scaffold/templates/controller.rb.tt +5 -3
  16. data/lib/generators/ruact/scaffold/templates/queries/query.rb.tt +2 -2
  17. data/lib/generators/ruact/scaffold/templates/views/index.html.erb.tt +1 -1
  18. data/lib/ruact/configuration.rb +71 -17
  19. data/lib/ruact/controller/document_rendering.rb +72 -16
  20. data/lib/ruact/controller/page_rendering.rb +134 -0
  21. data/lib/ruact/controller/pages.rb +116 -0
  22. data/lib/ruact/controller.rb +78 -11
  23. data/lib/ruact/doctor.rb +233 -25
  24. data/lib/ruact/layout_source.rb +29 -7
  25. data/lib/ruact/navigation_boundary.rb +240 -0
  26. data/lib/ruact/railtie.rb +30 -0
  27. data/lib/ruact/routing.rb +24 -6
  28. data/lib/ruact/server.rb +10 -1
  29. data/lib/ruact/version.rb +1 -1
  30. data/lib/ruact/view_helper.rb +158 -1
  31. data/lib/ruact/views/layouts/ruact.html.erb +32 -0
  32. data/lib/ruact.rb +29 -0
  33. data/vendor/javascript/vite-plugin-ruact/ruact-router.test.mjs +433 -0
  34. data/vendor/javascript/vite-plugin-ruact/runtime/ruact-router.js +170 -7
  35. data/vendor/javascript/vite-plugin-ruact/tsconfig.scaffold-agnostic.json +1 -1
  36. data/vendor/javascript/vite-plugin-ruact/type-tests/scaffold/PostList.tsx +3 -3
  37. data/vendor/javascript/vite-plugin-ruact/type-tests/scaffold/agnostic/PostList.tsx +3 -3
  38. data/vendor/javascript/vite-plugin-ruact/type-tests/scaffold/agnostic/ambient.d.ts +4 -4
  39. data/vendor/javascript/vite-plugin-ruact/type-tests/scaffold/ambient.d.ts +4 -4
  40. metadata +8 -2
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "//": "Story 14.4 (AC5) — type-check the GENERATED design-system-AGNOSTIC `<Model>{List,Form,DeleteDialog}.tsx` fixtures in ISOLATION against an ambient stub (type-tests/scaffold/agnostic/ambient.d.ts) that declares ONLY React + @/.ruact/server-functions and NO @/components/ui/* module. A stray shadcn import would fail to resolve → the typecheck goes red, proving the agnostic default needs zero design-system resolution. Mirrors tsconfig.scaffold.json (the shadcn isolated typecheck), but scoped to the agnostic subdir so the two ambient stubs never merge. Run via `npm run typecheck`.",
3
- "//noImplicitAny": "Relaxed ONLY here: native-element event handler params (e.g. `onChange={(e) => …}`) get no contextual type from the permissive ambient `JSX.IntrinsicElements` (no @types/react / lib:dom). The load-bearing types — PostRow, the typed `search` accessor (FR99), the required `posts` prop, the controlled DeleteDialog contract — are all EXPLICITLY annotated and stay fully checked under `strict`.",
3
+ "//noImplicitAny": "Relaxed ONLY here: native-element event handler params (e.g. `onChange={(e) => …}`) get no contextual type from the permissive ambient `JSX.IntrinsicElements` (no @types/react / lib:dom). The load-bearing types — PostRow, the typed `searchPosts` accessor (FR99), the required `posts` prop, the controlled DeleteDialog contract — are all EXPLICITLY annotated and stay fully checked under `strict`.",
4
4
  "compilerOptions": {
5
5
  "strict": true,
6
6
  "noImplicitAny": false,
@@ -18,7 +18,7 @@
18
18
  // freshly scaffolded app will not resolve these until 10.5 lands; that is
19
19
  // expected (the end-to-end live demo is Story 10.7).
20
20
  import { useState } from "react";
21
- import { search as searchPosts, destroyPost, useQuery } from "@/.ruact/server-functions";
21
+ import { searchPosts, destroyPost, useQuery } from "@/.ruact/server-functions";
22
22
  import { PostDeleteDialog } from "./PostDeleteDialog";
23
23
  import { Badge } from "@/components/ui/badge";
24
24
  import { Button } from "@/components/ui/button";
@@ -194,7 +194,7 @@ function RowActions({ record, onDeleted }: {
194
194
  }
195
195
 
196
196
  export function PostList({
197
- posts = [],
197
+ posts: initialRows = [],
198
198
  emptyLabel = "No posts yet — create one.",
199
199
  }: { posts?: PostRow[]; emptyLabel?: string }) {
200
200
  const [q, setQ] = useState("");
@@ -215,7 +215,7 @@ export function PostList({
215
215
  // the box is idle and we fall back to the server-rendered rows.
216
216
  const { data: searchData, loading: searchLoading } = useQuery<PostRow[]>(searchPosts, { q: q.trim() });
217
217
 
218
- const source = searching ? searchData ?? [] : posts;
218
+ const source = searching ? searchData ?? [] : initialRows;
219
219
  const rows = removedIds.length === 0 ? source : source.filter((row) => !removedIds.includes(row.id));
220
220
  // Always sort a COPY — never mutate the prop/source array.
221
221
  const sortedRows = sort ? [...rows].sort((a, b) => compareRows(a, b, sort)) : rows;
@@ -13,7 +13,7 @@
13
13
  // sort/pagination is Phase-3 territory. (The richer shadcn DataTable styling is
14
14
  // the opt-in `--shadcn` path — Story 14.5.)
15
15
  import { useState } from "react";
16
- import { search as searchPosts, destroyPost, useQuery } from "@/.ruact/server-functions";
16
+ import { searchPosts, destroyPost, useQuery } from "@/.ruact/server-functions";
17
17
  import { PostDeleteDialog } from "./PostDeleteDialog";
18
18
 
19
19
  type PostRow = { id: number; title: string | null; body: string | null; published: boolean | null; views: number | null; published_on: string | null; published_at: string | null; author_id: number | null };
@@ -139,7 +139,7 @@ function RowActions({ record, onDeleted }: {
139
139
  }
140
140
 
141
141
  export function PostList({
142
- posts = [],
142
+ posts: initialRows = [],
143
143
  emptyLabel = "No posts yet — create one.",
144
144
  }: { posts?: PostRow[]; emptyLabel?: string }) {
145
145
  const [q, setQ] = useState("");
@@ -160,7 +160,7 @@ export function PostList({
160
160
  // the box is idle and we fall back to the server-rendered rows.
161
161
  const { data: searchData, loading: searchLoading } = useQuery<PostRow[]>(searchPosts, { q: q.trim() });
162
162
 
163
- const source = searching ? searchData ?? [] : posts;
163
+ const source = searching ? searchData ?? [] : initialRows;
164
164
  const rows = removedIds.length === 0 ? source : source.filter((row) => !removedIds.includes(row.id));
165
165
  // Always sort a COPY — never mutate the prop/source array.
166
166
  const sortedRows = sort ? [...rows].sort((a, b) => compareRows(a, b, sort)) : rows;
@@ -53,10 +53,10 @@ declare module "@/.ruact/server-functions" {
53
53
  // FR88/FR99 wire union — the only param value type a query accessor accepts.
54
54
  type Wire = string | number | boolean | null;
55
55
 
56
- // The codegen exports a generic `search` from `<Plural>Query#search(q:)`,
57
- // typed from the declared `(q:)` kwarg (Story 13.4). The List aliases it
58
- // `search<Plural>`.
59
- export const search: (params: { q: Wire }) => Promise<unknown>;
56
+ // The codegen exports `searchPosts` from `PostsQuery#search_posts(q:)`,
57
+ // typed from the declared `(q:)` kwarg (Story 13.4). The scaffold names the
58
+ // query after the resource: query names share one namespace.
59
+ export const searchPosts: (params: { q: Wire }) => Promise<unknown>;
60
60
 
61
61
  // Action accessors the generated Form imports. Actions are NOT typed by FR99
62
62
  // (only queries are — Story 13.4 decision A), so the accessors take a loose
@@ -39,10 +39,10 @@ declare module "@/.ruact/server-functions" {
39
39
  // FR88/FR99 wire union — the only param value type a query accessor accepts.
40
40
  type Wire = string | number | boolean | null;
41
41
 
42
- // The codegen exports a generic `search` from `<Plural>Query#search(q:)`,
43
- // typed from the declared `(q:)` kwarg (Story 13.4). The List aliases it
44
- // `search<Plural>`.
45
- export const search: (params: { q: Wire }) => Promise<unknown>;
42
+ // The codegen exports `searchPosts` from `PostsQuery#search_posts(q:)` —
43
+ // the scaffold names the query after the resource, because query names
44
+ // share one namespace across every query class.
45
+ export const searchPosts: (params: { q: Wire }) => Promise<unknown>;
46
46
 
47
47
  // Action accessors the generated Form imports (Story 10.3). Actions are NOT
48
48
  // typed by FR99 (only queries are — Story 13.4 decision A), so the accessors
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruact
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 0.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luiz Garcia
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-09 00:00:00.000000000 Z
11
+ date: 2026-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -51,6 +51,7 @@ files:
51
51
  - lib/generators/ruact/install/templates/package.json.tt
52
52
  - lib/generators/ruact/install/templates/tsconfig.json.tt
53
53
  - lib/generators/ruact/install/templates/vite.config.js.tt
54
+ - lib/generators/ruact/layout/layout_generator.rb
54
55
  - lib/generators/ruact/scaffold/scaffold_attribute.rb
55
56
  - lib/generators/ruact/scaffold/scaffold_form_helpers.rb
56
57
  - lib/generators/ruact/scaffold/scaffold_generator.rb
@@ -75,6 +76,8 @@ files:
75
76
  - lib/ruact/configuration.rb
76
77
  - lib/ruact/controller.rb
77
78
  - lib/ruact/controller/document_rendering.rb
79
+ - lib/ruact/controller/page_rendering.rb
80
+ - lib/ruact/controller/pages.rb
78
81
  - lib/ruact/doctor.rb
79
82
  - lib/ruact/erb_preprocessor.rb
80
83
  - lib/ruact/erb_preprocessor_hook.rb
@@ -88,6 +91,7 @@ files:
88
91
  - lib/ruact/html_converter.rb
89
92
  - lib/ruact/layout_source.rb
90
93
  - lib/ruact/manifest_resolver.rb
94
+ - lib/ruact/navigation_boundary.rb
91
95
  - lib/ruact/packaging.rb
92
96
  - lib/ruact/query.rb
93
97
  - lib/ruact/railtie.rb
@@ -124,6 +128,7 @@ files:
124
128
  - lib/ruact/validation_errors_collector.rb
125
129
  - lib/ruact/version.rb
126
130
  - lib/ruact/view_helper.rb
131
+ - lib/ruact/views/layouts/ruact.html.erb
127
132
  - lib/rubocop/cop/ruact.rb
128
133
  - lib/rubocop/cop/ruact/no_extend_self.rb
129
134
  - lib/rubocop/cop/ruact/no_io_in_flight.rb
@@ -144,6 +149,7 @@ files:
144
149
  - vendor/javascript/vite-plugin-ruact/package-lock.json
145
150
  - vendor/javascript/vite-plugin-ruact/package.json
146
151
  - vendor/javascript/vite-plugin-ruact/registry.test.mjs
152
+ - vendor/javascript/vite-plugin-ruact/ruact-router.test.mjs
147
153
  - vendor/javascript/vite-plugin-ruact/runtime/bootstrap.jsx
148
154
  - vendor/javascript/vite-plugin-ruact/runtime/flight-client.js
149
155
  - vendor/javascript/vite-plugin-ruact/runtime/ruact-router.js