jac-client 0.2.2__py3-none-any.whl → 0.2.6__py3-none-any.whl

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 (202) hide show
  1. jac_client/examples/all-in-one/assets/workers/worker.py +5 -0
  2. jac_client/examples/all-in-one/src/app.jac +841 -0
  3. jac_client/examples/all-in-one/{button.jac → src/button.jac} +1 -1
  4. jac_client/examples/all-in-one/{components → src/components}/button.jac +1 -1
  5. jac_client/examples/asset-serving/css-with-image/{app.jac → src/app.jac} +2 -2
  6. jac_client/examples/asset-serving/image-asset/{app.jac → src/app.jac} +2 -2
  7. jac_client/examples/asset-serving/import-alias/{app.jac → src/app.jac} +7 -7
  8. jac_client/examples/basic/{app.jac → src/app.jac} +2 -2
  9. jac_client/examples/basic-auth/src/app.jac +377 -0
  10. jac_client/examples/basic-auth-with-router/{app.jac → src/app.jac} +18 -18
  11. jac_client/examples/basic-full-stack/{app.jac → src/app.jac} +175 -130
  12. jac_client/examples/css-styling/js-styling/{app.jac → src/app.jac} +6 -6
  13. jac_client/examples/css-styling/material-ui/{app.jac → src/app.jac} +5 -5
  14. jac_client/examples/css-styling/pure-css/{app.jac → src/app.jac} +6 -6
  15. jac_client/examples/css-styling/sass-example/{app.jac → src/app.jac} +6 -6
  16. jac_client/examples/css-styling/styled-components/{app.jac → src/app.jac} +5 -5
  17. jac_client/examples/css-styling/tailwind-example/{app.jac → src/app.jac} +6 -6
  18. jac_client/examples/full-stack-with-auth/{app.jac → src/app.jac} +37 -37
  19. jac_client/examples/little-x/{app.jac → src/app.jac} +27 -32
  20. jac_client/examples/little-x/src/submit-button.jac +16 -0
  21. jac_client/examples/nested-folders/nested-advance/{ButtonRoot.jac → src/ButtonRoot.jac} +1 -1
  22. jac_client/examples/nested-folders/nested-advance/{app.jac → src/app.jac} +1 -1
  23. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/ButtonSecondL.jac +1 -1
  24. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/Card.jac +1 -1
  25. jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/level2/ButtonThirdL.jac +1 -1
  26. jac_client/examples/nested-folders/nested-basic/{app.jac → src/app.jac} +2 -2
  27. jac_client/examples/nested-folders/nested-basic/{button.jac → src/button.jac} +1 -1
  28. jac_client/examples/nested-folders/nested-basic/{components → src/components}/button.jac +1 -1
  29. jac_client/examples/ts-support/src/app.jac +35 -0
  30. jac_client/examples/with-router/{app.jac → src/app.jac} +11 -11
  31. jac_client/plugin/cli.jac +547 -0
  32. jac_client/plugin/client.jac +52 -0
  33. jac_client/plugin/client_runtime.cl.jac +38 -0
  34. jac_client/plugin/impl/client.impl.jac +134 -0
  35. jac_client/plugin/impl/client_runtime.impl.jac +177 -0
  36. jac_client/plugin/impl/vite_client_bundle.impl.jac +72 -0
  37. jac_client/plugin/plugin_config.jac +195 -0
  38. jac_client/plugin/src/__init__.jac +20 -0
  39. jac_client/plugin/src/asset_processor.jac +33 -0
  40. jac_client/plugin/src/babel_processor.jac +18 -0
  41. jac_client/plugin/src/compiler.jac +66 -0
  42. jac_client/plugin/src/config_loader.jac +32 -0
  43. jac_client/plugin/src/impl/asset_processor.impl.jac +127 -0
  44. jac_client/plugin/src/impl/babel_processor.impl.jac +84 -0
  45. jac_client/plugin/src/impl/compiler.impl.jac +251 -0
  46. jac_client/plugin/src/impl/config_loader.impl.jac +119 -0
  47. jac_client/plugin/src/impl/import_processor.impl.jac +33 -0
  48. jac_client/plugin/src/impl/jac_to_js.impl.jac +41 -0
  49. jac_client/plugin/src/impl/package_installer.impl.jac +105 -0
  50. jac_client/plugin/src/impl/vite_bundler.impl.jac +513 -0
  51. jac_client/plugin/src/import_processor.jac +19 -0
  52. jac_client/plugin/src/jac_to_js.jac +35 -0
  53. jac_client/plugin/src/package_installer.jac +26 -0
  54. jac_client/plugin/src/vite_bundler.jac +36 -0
  55. jac_client/plugin/vite_client_bundle.jac +31 -0
  56. jac_client/tests/conftest.py +281 -0
  57. jac_client/tests/fixtures/basic-app/app.jac +2 -2
  58. jac_client/tests/fixtures/cl_file/app.cl.jac +2 -2
  59. jac_client/tests/fixtures/client_app_with_antd/app.jac +1 -1
  60. jac_client/tests/fixtures/js_import/app.jac +5 -5
  61. jac_client/tests/fixtures/spawn_test/app.jac +7 -7
  62. jac_client/tests/fixtures/with-ts/app.jac +35 -0
  63. jac_client/tests/test_cli.py +755 -0
  64. jac_client/tests/test_it.py +347 -67
  65. {jac_client-0.2.2.dist-info → jac_client-0.2.6.dist-info}/METADATA +30 -24
  66. jac_client-0.2.6.dist-info/RECORD +74 -0
  67. {jac_client-0.2.2.dist-info → jac_client-0.2.6.dist-info}/WHEEL +2 -1
  68. jac_client-0.2.6.dist-info/entry_points.txt +4 -0
  69. jac_client-0.2.6.dist-info/top_level.txt +1 -0
  70. jac_client/docs/README.md +0 -689
  71. jac_client/docs/advanced-state.md +0 -1265
  72. jac_client/docs/asset-serving/intro.md +0 -209
  73. jac_client/docs/assets/pipe_line-v2.svg +0 -32
  74. jac_client/docs/assets/pipe_line.png +0 -0
  75. jac_client/docs/file-system/app.jac.md +0 -121
  76. jac_client/docs/file-system/backend-frontend.md +0 -217
  77. jac_client/docs/file-system/intro.md +0 -72
  78. jac_client/docs/file-system/nested-imports.md +0 -348
  79. jac_client/docs/guide-example/intro.md +0 -115
  80. jac_client/docs/guide-example/step-01-setup.md +0 -270
  81. jac_client/docs/guide-example/step-02-components.md +0 -416
  82. jac_client/docs/guide-example/step-03-styling.md +0 -478
  83. jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
  84. jac_client/docs/guide-example/step-05-local-state.md +0 -530
  85. jac_client/docs/guide-example/step-06-events.md +0 -749
  86. jac_client/docs/guide-example/step-07-effects.md +0 -468
  87. jac_client/docs/guide-example/step-08-walkers.md +0 -534
  88. jac_client/docs/guide-example/step-09-authentication.md +0 -586
  89. jac_client/docs/guide-example/step-10-routing.md +0 -539
  90. jac_client/docs/guide-example/step-11-final.md +0 -963
  91. jac_client/docs/imports.md +0 -1141
  92. jac_client/docs/lifecycle-hooks.md +0 -773
  93. jac_client/docs/routing.md +0 -659
  94. jac_client/docs/styling/intro.md +0 -249
  95. jac_client/docs/styling/js-styling.md +0 -367
  96. jac_client/docs/styling/material-ui.md +0 -341
  97. jac_client/docs/styling/pure-css.md +0 -299
  98. jac_client/docs/styling/sass.md +0 -403
  99. jac_client/docs/styling/styled-components.md +0 -395
  100. jac_client/docs/styling/tailwind.md +0 -298
  101. jac_client/examples/all-in-one/.babelrc +0 -9
  102. jac_client/examples/all-in-one/README.md +0 -16
  103. jac_client/examples/all-in-one/app.jac +0 -426
  104. jac_client/examples/all-in-one/assets/burger.png +0 -0
  105. jac_client/examples/all-in-one/package.json +0 -29
  106. jac_client/examples/all-in-one/styles.css +0 -26
  107. jac_client/examples/all-in-one/vite.config.js +0 -28
  108. jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
  109. jac_client/examples/asset-serving/css-with-image/README.md +0 -91
  110. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  111. jac_client/examples/asset-serving/css-with-image/package.json +0 -28
  112. jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
  113. jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
  114. jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
  115. jac_client/examples/asset-serving/image-asset/README.md +0 -119
  116. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  117. jac_client/examples/asset-serving/image-asset/package.json +0 -28
  118. jac_client/examples/asset-serving/image-asset/styles.css +0 -26
  119. jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
  120. jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
  121. jac_client/examples/asset-serving/import-alias/README.md +0 -83
  122. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  123. jac_client/examples/asset-serving/import-alias/package.json +0 -28
  124. jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
  125. jac_client/examples/basic/.babelrc +0 -9
  126. jac_client/examples/basic/README.md +0 -16
  127. jac_client/examples/basic/package.json +0 -27
  128. jac_client/examples/basic/vite.config.js +0 -27
  129. jac_client/examples/basic-auth/.babelrc +0 -9
  130. jac_client/examples/basic-auth/README.md +0 -16
  131. jac_client/examples/basic-auth/app.jac +0 -308
  132. jac_client/examples/basic-auth/package.json +0 -27
  133. jac_client/examples/basic-auth/vite.config.js +0 -27
  134. jac_client/examples/basic-auth-with-router/.babelrc +0 -9
  135. jac_client/examples/basic-auth-with-router/README.md +0 -60
  136. jac_client/examples/basic-auth-with-router/package.json +0 -28
  137. jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
  138. jac_client/examples/basic-full-stack/.babelrc +0 -9
  139. jac_client/examples/basic-full-stack/README.md +0 -18
  140. jac_client/examples/basic-full-stack/package.json +0 -28
  141. jac_client/examples/basic-full-stack/vite.config.js +0 -27
  142. jac_client/examples/css-styling/js-styling/.babelrc +0 -9
  143. jac_client/examples/css-styling/js-styling/README.md +0 -183
  144. jac_client/examples/css-styling/js-styling/package.json +0 -28
  145. jac_client/examples/css-styling/js-styling/styles.js +0 -100
  146. jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
  147. jac_client/examples/css-styling/material-ui/.babelrc +0 -9
  148. jac_client/examples/css-styling/material-ui/README.md +0 -16
  149. jac_client/examples/css-styling/material-ui/package.json +0 -32
  150. jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
  151. jac_client/examples/css-styling/pure-css/.babelrc +0 -9
  152. jac_client/examples/css-styling/pure-css/README.md +0 -16
  153. jac_client/examples/css-styling/pure-css/package.json +0 -28
  154. jac_client/examples/css-styling/pure-css/styles.css +0 -111
  155. jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
  156. jac_client/examples/css-styling/sass-example/.babelrc +0 -9
  157. jac_client/examples/css-styling/sass-example/README.md +0 -16
  158. jac_client/examples/css-styling/sass-example/package.json +0 -29
  159. jac_client/examples/css-styling/sass-example/styles.scss +0 -153
  160. jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
  161. jac_client/examples/css-styling/styled-components/.babelrc +0 -9
  162. jac_client/examples/css-styling/styled-components/README.md +0 -16
  163. jac_client/examples/css-styling/styled-components/package.json +0 -29
  164. jac_client/examples/css-styling/styled-components/styled.js +0 -90
  165. jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
  166. jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
  167. jac_client/examples/css-styling/tailwind-example/README.md +0 -16
  168. jac_client/examples/css-styling/tailwind-example/global.css +0 -1
  169. jac_client/examples/css-styling/tailwind-example/package.json +0 -30
  170. jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
  171. jac_client/examples/full-stack-with-auth/.babelrc +0 -9
  172. jac_client/examples/full-stack-with-auth/README.md +0 -16
  173. jac_client/examples/full-stack-with-auth/package.json +0 -28
  174. jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
  175. jac_client/examples/little-x/package.json +0 -23
  176. jac_client/examples/little-x/submit-button.jac +0 -8
  177. jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
  178. jac_client/examples/nested-folders/nested-advance/README.md +0 -77
  179. jac_client/examples/nested-folders/nested-advance/package.json +0 -29
  180. jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
  181. jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
  182. jac_client/examples/nested-folders/nested-basic/README.md +0 -183
  183. jac_client/examples/nested-folders/nested-basic/app.js +0 -7
  184. jac_client/examples/nested-folders/nested-basic/package.json +0 -28
  185. jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
  186. jac_client/examples/with-router/.babelrc +0 -9
  187. jac_client/examples/with-router/README.md +0 -17
  188. jac_client/examples/with-router/package.json +0 -28
  189. jac_client/examples/with-router/vite.config.js +0 -27
  190. jac_client/plugin/cli.py +0 -244
  191. jac_client/plugin/client.py +0 -152
  192. jac_client/plugin/client_runtime.jac +0 -234
  193. jac_client/plugin/vite_client_bundle.py +0 -503
  194. jac_client/tests/fixtures/js_import/utils.js +0 -21
  195. jac_client/tests/fixtures/package-lock.json +0 -329
  196. jac_client/tests/fixtures/package.json +0 -11
  197. jac_client/tests/test_asset_examples.py +0 -322
  198. jac_client/tests/test_cl.py +0 -530
  199. jac_client/tests/test_create_jac_app.py +0 -131
  200. jac_client/tests/test_nested_file.py +0 -374
  201. jac_client-0.2.2.dist-info/RECORD +0 -171
  202. jac_client-0.2.2.dist-info/entry_points.txt +0 -4
@@ -1,659 +0,0 @@
1
- # Routing in Jac: Building Multi-Page Applications
2
-
3
- Learn how to create multi-page applications with client-side routing using Jac's declarative routing API.
4
-
5
- ---
6
-
7
- ## Table of Contents
8
-
9
- - [What is Routing?](#what-is-routing)
10
- - [Getting Started](#getting-started)
11
- - [Basic Routing Setup](#basic-routing-setup)
12
- - [Route Components](#route-components)
13
- - [Navigation with Link](#navigation-with-link)
14
- - [Programmatic Navigation with useNavigate](#programmatic-navigation-with-usenavigate)
15
- - [URL Parameters with useParams](#url-parameters-with-useparams)
16
- - [Current Location with useLocation](#current-location-with-uselocation)
17
- - [Protected Routes Pattern](#protected-routes-pattern)
18
- - [Complete Examples](#complete-examples)
19
- - [Best Practices](#best-practices)
20
-
21
- ---
22
-
23
- ## What is Routing?
24
-
25
- Routing allows you to create multi-page applications where different URLs display different components without page refreshes.
26
-
27
- **Key Benefits:**
28
- - **Single Page Application (SPA)**: No page refreshes when navigating
29
- - **Declarative Syntax**: Define routes using JSX components
30
- - **URL Parameters**: Dynamic routes with params like `/user/:id`
31
- - **Browser History**: Back/forward buttons work automatically
32
- - **Hash-based URLs**: Uses `#/path` for maximum compatibility
33
- - **Battle-tested**: Built on industry-standard routing technology
34
-
35
- ---
36
-
37
- ## Getting Started
38
-
39
- Import routing components from `@jac-client/utils`:
40
-
41
- ```jac
42
- cl import from "@jac-client/utils" {
43
- Router,
44
- Routes,
45
- Route,
46
- Link,
47
- Navigate,
48
- useNavigate,
49
- useLocation,
50
- useParams
51
- }
52
- ```
53
-
54
- **Core Components:**
55
- - **`<Router>`**: Container that wraps your entire application
56
- - **`<Routes>`**: Groups multiple routes together
57
- - **`<Route>`**: Defines a single route with path and element
58
- - **`<Link>`**: Navigation links that don't refresh the page
59
- - **`<Navigate>`**: Component for conditional redirects
60
-
61
- **Hooks:**
62
- - **`useNavigate()`**: Get navigate function for programmatic navigation
63
- - **`useLocation()`**: Access current location and pathname
64
- - **`useParams()`**: Access URL parameters from dynamic routes
65
-
66
- ---
67
-
68
- ## Basic Routing Setup
69
-
70
- ### Simple Three-Page App
71
-
72
- ```jac
73
- cl import from react { useState, useEffect }
74
- cl import from "@jac-client/utils" { Router, Routes, Route, Link }
75
-
76
- cl {
77
- # Page Components
78
- def Home() -> any {
79
- return <div>
80
- <h1> Home Page</h1>
81
- <p>Welcome to the home page!</p>
82
- </div>;
83
- }
84
-
85
- def About() -> any {
86
- return <div>
87
- <h1>ℹ About Page</h1>
88
- <p>Learn more about our application.</p>
89
- </div>;
90
- }
91
-
92
- def Contact() -> any {
93
- return <div>
94
- <h1> Contact Page</h1>
95
- <p>Email: contact@example.com</p>
96
- </div>;
97
- }
98
-
99
- # Main App with React Router
100
- def app() -> any {
101
- return <Router>
102
- <div>
103
- <nav>
104
- <Link to="/">Home</Link>
105
- {" | "}
106
- <Link to="/about">About</Link>
107
- {" | "}
108
- <Link to="/contact">Contact</Link>
109
- </nav>
110
- <Routes>
111
- <Route path="/" element={<Home />} />
112
- <Route path="/about" element={<About />} />
113
- <Route path="/contact" element={<Contact />} />
114
- </Routes>
115
- </div>
116
- </Router>;
117
- }
118
- }
119
- ```
120
-
121
- **How It Works:**
122
- 1. **`<Router>`** wraps your entire app and manages routing state
123
- 2. **`<Routes>`** contains all your route definitions
124
- 3. **`<Route>`** maps a URL path to an element (note: `element={<Component />}`)
125
- 4. **`<Link>`** creates clickable navigation links
126
- 5. URLs will be hash-based: `#/`, `#/about`, `#/contact`
127
-
128
- **Key Points:**
129
- - Use `element={<Home />}` to render components
130
- - No configuration needed - just wrap and go
131
- - Hash-based URLs work everywhere
132
-
133
- ---
134
-
135
- ## Route Components
136
-
137
- ### Router Component
138
-
139
- The `<Router>` component is the top-level container for your app:
140
-
141
- ```jac
142
- <Router>
143
- {/* Your app content */}
144
- </Router>
145
- ```
146
-
147
- **Features:**
148
- - Hash-based URLs (e.g., `#/about`, `#/contact`)
149
- - No props needed - it just works!
150
- - Manages routing state automatically
151
- - Works in any environment
152
-
153
- ### Routes Component
154
-
155
- The `<Routes>` component groups multiple routes:
156
-
157
- ```jac
158
- <Routes>
159
- <Route path="/" element={<Home />} />
160
- <Route path="/about" element={<About />} />
161
- <Route path="/contact" element={<Contact />} />
162
- </Routes>
163
- ```
164
-
165
- ### Route Component
166
-
167
- Each `<Route>` defines a single route:
168
-
169
- ```jac
170
- <Route path="/todos" element={<TodoList />} />
171
- ```
172
-
173
- **Props:**
174
- - **`path`**: The URL path (must start with `/`)
175
- - **`element`**: The JSX element to render (note: call the component with `<>`)
176
- - **`index`**: Boolean for index routes (optional)
177
-
178
- **Important:** Use `element={<Component />}` not `component={Component}`
179
-
180
- ### Example: Index Routes
181
-
182
- ```jac
183
- <Routes>
184
- <Route index element={<Home />} /> {/* Matches parent route */}
185
- <Route path="/about" element={<About />} />
186
- </Routes>
187
- ```
188
-
189
- ---
190
-
191
- ## Navigation with Link
192
-
193
- ### The Link Component
194
-
195
- The `<Link>` component creates clickable navigation links:
196
-
197
- ```jac
198
- <Link to="/about">About Us</Link>
199
- ```
200
-
201
- **Props:**
202
- - **`to`**: The destination path (e.g., `"/"`, `"/about"`)
203
- - **`style`**: Optional CSS styles for the link
204
- - **`className`**: Optional CSS class name
205
-
206
- ### Basic Navigation
207
-
208
- ```jac
209
- cl import from "@jac-client/utils" { Router, Routes, Route, Link }
210
-
211
- cl {
212
- def Navigation() -> any {
213
- return <nav style={{"padding": "1rem", "backgroundColor": "#f0f0f0"}}>
214
- <Link to="/">Home</Link>
215
- {" | "}
216
- <Link to="/about">About</Link>
217
- {" | "}
218
- <Link to="/contact">Contact</Link>
219
- </nav>;
220
- }
221
- }
222
- ```
223
-
224
- ### Active Link Styling with useLocation
225
-
226
- ```jac
227
- cl import from "@jac-client/utils" { Link, useLocation }
228
-
229
- cl {
230
- def Navigation() -> any {
231
- let location = useLocation();
232
-
233
- def linkStyle(path: str) -> dict {
234
- isActive = location.pathname == path;
235
- return {
236
- "padding": "0.5rem 1rem",
237
- "textDecoration": "none",
238
- "color": "#0066cc" if isActive else "#333",
239
- "fontWeight": "bold" if isActive else "normal",
240
- "backgroundColor": "#e3f2fd" if isActive else "transparent",
241
- "borderRadius": "4px"
242
- };
243
- }
244
-
245
- return <nav style={{"display": "flex", "gap": "1rem", "padding": "1rem"}}>
246
- <Link to="/" style={linkStyle("/")}>Home</Link>
247
- <Link to="/about" style={linkStyle("/about")}>About</Link>
248
- <Link to="/contact" style={linkStyle("/contact")}>Contact</Link>
249
- </nav>;
250
- }
251
- }
252
- ```
253
-
254
- ### Link Component Features
255
-
256
- - **No Page Refresh**: Navigation happens without reloading the page
257
- - **Client-Side Routing**: Fast transitions between pages
258
- - **Browser History**: Works with browser back/forward buttons
259
- - **Styling Support**: Can be styled like any other element
260
- - **Battle-tested**: Reliable, production-ready navigation
261
-
262
- ---
263
-
264
- ## Programmatic Navigation with useNavigate
265
-
266
- For programmatic navigation (e.g., after form submission), use the `useNavigate()` hook:
267
-
268
- ```jac
269
- cl import from "@jac-client/utils" { useNavigate }
270
-
271
- cl {
272
- def LoginForm() -> any {
273
- let [username, setUsername] = useState("");
274
- let [password, setPassword] = useState("");
275
- let navigate = useNavigate();
276
-
277
- async def handleLogin(e: any) -> None {
278
- e.preventDefault();
279
- success = await jacLogin(username, password);
280
- if success {
281
- navigate("/dashboard"); # Navigate after successful login
282
- } else {
283
- alert("Login failed");
284
- }
285
- }
286
-
287
- return <form onSubmit={handleLogin}>
288
- <input
289
- type="text"
290
- value={username}
291
- onChange={lambda e: any -> None { setUsername(e.target.value); }}
292
- placeholder="Username"
293
- />
294
- <input
295
- type="password"
296
- value={password}
297
- onChange={lambda e: any -> None { setPassword(e.target.value); }}
298
- placeholder="Password"
299
- />
300
- <button type="submit">Login</button>
301
- </form>;
302
- }
303
- }
304
- ```
305
-
306
- **useNavigate() Features:**
307
- - **Hook-based API**: Modern React pattern
308
- - **Type-safe**: Works seamlessly with TypeScript/Jac types
309
- - **Replace option**: Use `navigate("/path", { replace: true })` to replace history entry
310
-
311
- **Common Use Cases:**
312
- - After form submission
313
- - After authentication
314
- - Conditional navigation based on logic
315
- - In button onClick handlers
316
- - Redirects after API calls
317
-
318
- ---
319
-
320
- ## URL Parameters with useParams
321
-
322
- Access dynamic URL parameters using the `useParams()` hook:
323
-
324
- ```jac
325
- cl import from "@jac-client/utils" { useParams, Link }
326
-
327
- cl {
328
- def UserProfile() -> any {
329
- let params = useParams();
330
- let userId = params.id;
331
-
332
- return <div>
333
- <h1>User Profile</h1>
334
- <p>Viewing profile for user ID: {userId}</p>
335
- <Link to="/">Back to Home</Link>
336
- </div>;
337
- }
338
-
339
- def app() -> any {
340
- return <Router>
341
- <Routes>
342
- <Route path="/" element={<Home />} />
343
- <Route path="/user/:id" element={<UserProfile />} />
344
- </Routes>
345
- </Router>;
346
- }
347
- }
348
- ```
349
-
350
- **URL Pattern Examples:**
351
- - `/user/:id` → Access via `params.id`
352
- - `/posts/:postId/comments/:commentId` → Access via `params.postId` and `params.commentId`
353
- - `/products/:category/:productId` → Multiple parameters
354
-
355
- ---
356
-
357
- ## Current Location with useLocation
358
-
359
- Access the current location object using `useLocation()`:
360
-
361
- ```jac
362
- cl import from "@jac-client/utils" { useLocation }
363
-
364
- cl {
365
- def CurrentPath() -> any {
366
- let location = useLocation();
367
-
368
- return <div>
369
- <p>Current pathname: {location.pathname}</p>
370
- <p>Current hash: {location.hash}</p>
371
- <p>Search params: {location.search}</p>
372
- </div>;
373
- }
374
- }
375
- ```
376
-
377
- **Location Object Properties:**
378
- - **`pathname`**: Current path (e.g., `/about`)
379
- - **`search`**: Query string (e.g., `?page=2`)
380
- - **`hash`**: URL hash (e.g., `#section1`)
381
- - **`state`**: Location state passed via navigate
382
-
383
- ---
384
-
385
- ## Protected Routes Pattern
386
-
387
- Use the `<Navigate>` component to protect routes that require authentication:
388
-
389
- ```jac
390
- cl import from "@jac-client/utils" { Navigate, useNavigate }
391
-
392
- cl {
393
- def Dashboard() -> any {
394
- # Check if user is logged in
395
- if not jacIsLoggedIn() {
396
- return <Navigate to="/login" />;
397
- }
398
-
399
- return <div>
400
- <h1> Dashboard</h1>
401
- <p>Welcome! You are logged in.</p>
402
- <p>This is protected content only visible to authenticated users.</p>
403
- </div>;
404
- }
405
-
406
- def LoginPage() -> any {
407
- let navigate = useNavigate();
408
-
409
- async def handleLogin(e: any) -> None {
410
- e.preventDefault();
411
- success = await jacLogin(username, password);
412
- if success {
413
- navigate("/dashboard");
414
- }
415
- }
416
-
417
- return <form onSubmit={handleLogin}>
418
- <h2>Login</h2>
419
- <input type="text" placeholder="Username" />
420
- <input type="password" placeholder="Password" />
421
- <button type="submit">Login</button>
422
- </form>;
423
- }
424
-
425
- def app() -> any {
426
- return <Router>
427
- <Routes>
428
- <Route path="/" element={<HomePage />} />
429
- <Route path="/login" element={<LoginPage />} />
430
- <Route path="/dashboard" element={<Dashboard />} />
431
- </Routes>
432
- </Router>;
433
- }
434
- }
435
- ```
436
-
437
- **Protected Route Pattern:**
438
- 1. Check authentication at the start of the component
439
- 2. Return `<Navigate to="/login" />` if not authenticated
440
- 3. Return protected content if authenticated
441
- 4. Use `useNavigate()` to redirect after successful login
442
-
443
- ---
444
-
445
- ## Complete Examples
446
-
447
- ### Example 1: Simple Multi-Page App
448
-
449
- ```jac
450
- cl import from react { useState, useEffect }
451
- cl import from "@jac-client/utils" { Router, Routes, Route, Link, useLocation }
452
-
453
- cl {
454
- def Navigation() -> any {
455
- let location = useLocation();
456
-
457
- def linkStyle(path: str) -> dict {
458
- isActive = location.pathname == path;
459
- return {
460
- "padding": "0.5rem 1rem",
461
- "textDecoration": "none",
462
- "color": "#0066cc" if isActive else "#333",
463
- "fontWeight": "bold" if isActive else "normal"
464
- };
465
- }
466
-
467
- return <nav style={{"padding": "1rem", "backgroundColor": "#f0f0f0"}}>
468
- <Link to="/" style={linkStyle("/")}>Home</Link>
469
- {" | "}
470
- <Link to="/about" style={linkStyle("/about")}>About</Link>
471
- {" | "}
472
- <Link to="/contact" style={linkStyle("/contact")}>Contact</Link>
473
- </nav>;
474
- }
475
-
476
- def Home() -> any {
477
- return <div>
478
- <h1> Home Page</h1>
479
- <p>Welcome to the home page!</p>
480
- </div>;
481
- }
482
-
483
- def About() -> any {
484
- return <div>
485
- <h1>ℹ About Page</h1>
486
- <p>Learn more about our application.</p>
487
- </div>;
488
- }
489
-
490
- def Contact() -> any {
491
- return <div>
492
- <h1> Contact Page</h1>
493
- <p>Email: contact@example.com</p>
494
- </div>;
495
- }
496
-
497
- def app() -> any {
498
- return <Router>
499
- <div>
500
- <Navigation />
501
- <div style={{"padding": "2rem"}}>
502
- <Routes>
503
- <Route path="/" element={<Home />} />
504
- <Route path="/about" element={<About />} />
505
- <Route path="/contact" element={<Contact />} />
506
- </Routes>
507
- </div>
508
- </div>
509
- </Router>;
510
- }
511
- }
512
- ```
513
-
514
- ### Example 2: App with URL Parameters
515
-
516
- ```jac
517
- cl import from "@jac-client/utils" { Router, Routes, Route, Link, useParams }
518
-
519
- cl {
520
- def UserList() -> any {
521
- users = ["Alice", "Bob", "Charlie"];
522
-
523
- return <div>
524
- <h1> User List</h1>
525
- {users.map(lambda user: any -> any {
526
- return <div key={user}>
527
- <Link to={"/user/" + user}>{user}</Link>
528
- </div>;
529
- })}
530
- </div>;
531
- }
532
-
533
- def UserProfile() -> any {
534
- let params = useParams();
535
- let username = params.id;
536
-
537
- return <div>
538
- <h1> Profile: {username}</h1>
539
- <p>Viewing profile for {username}</p>
540
- <Link to="/">← Back to User List</Link>
541
- </div>;
542
- }
543
-
544
- def app() -> any {
545
- return <Router>
546
- <Routes>
547
- <Route path="/" element={<UserList />} />
548
- <Route path="/user/:id" element={<UserProfile />} />
549
- </Routes>
550
- </Router>;
551
- }
552
- }
553
- ```
554
-
555
- ---
556
-
557
- ## Best Practices
558
-
559
- ### 1. **Use Correct Route Syntax**
560
- ```jac
561
- # CORRECT - Use element prop with JSX
562
- <Route path="/" element={<Home />} />
563
-
564
- # WRONG - Don't pass component without JSX
565
- <Route path="/" component={Home} />
566
- ```
567
-
568
- ### 2. **Import All Needed Components**
569
- ```jac
570
- cl import from "@jac-client/utils" {
571
- Router,
572
- Routes,
573
- Route,
574
- Link,
575
- Navigate,
576
- useNavigate,
577
- useLocation,
578
- useParams
579
- }
580
- ```
581
-
582
- ### 3. **Use Hooks for Navigation**
583
- ```jac
584
- # CORRECT - Use useNavigate hook
585
- def MyComponent() -> any {
586
- let navigate = useNavigate();
587
- navigate("/dashboard");
588
- }
589
-
590
- # OLD - Global navigate() function (still works for backward compatibility)
591
- navigate("/dashboard");
592
- ```
593
-
594
- ### 4. **Protected Routes Pattern**
595
- ```jac
596
- # CORRECT - Check auth in component
597
- def ProtectedPage() -> any {
598
- if not jacIsLoggedIn() {
599
- return <Navigate to="/login" />;
600
- }
601
- return <div>Protected content</div>;
602
- }
603
- ```
604
-
605
- ### 5. **Use Link for Navigation**
606
- ```jac
607
- # CORRECT - Use Link component
608
- <Link to="/about">About</Link>
609
-
610
- # WRONG - Regular anchor tags cause page reload
611
- <a href="#/about">About</a>
612
- ```
613
-
614
- ### 6. **Dynamic Routes with Parameters**
615
- ```jac
616
- # Define route with parameter
617
- <Route path="/user/:id" element={<UserProfile />} />
618
-
619
- # Access parameter in component
620
- def UserProfile() -> any {
621
- let params = useParams();
622
- let userId = params.id;
623
- return <div>User: {userId}</div>;
624
- }
625
- ```
626
-
627
- ### 7. **Active Link Styling**
628
- ```jac
629
- def Navigation() -> any {
630
- let location = useLocation();
631
-
632
- def isActive(path: str) -> bool {
633
- return location.pathname == path;
634
- }
635
-
636
- return <nav>
637
- <Link
638
- to="/"
639
- style={{"fontWeight": "bold" if isActive("/") else "normal"}}
640
- >
641
- Home
642
- </Link>
643
- </nav>;
644
- }
645
- ```
646
-
647
- ---
648
-
649
- ## Summary
650
-
651
- - **Simple & Declarative**: Use `<Router>`, `<Routes>`, `<Route>` components
652
- - **Hash-based URLs**: Uses `#/path` for maximum compatibility
653
- - **Modern Hooks**: `useNavigate()`, `useLocation()`, `useParams()`
654
- - **Protected Routes**: Use `<Navigate>` component for redirects
655
- - **URL Parameters**: Dynamic routes with `:param` syntax
656
- - **No Configuration**: Just wrap your app in `<Router>` and start routing!
657
- - **Production-ready**: Battle-tested routing for real applications
658
-
659
- Routing in Jac is simple, powerful, and production-ready!