jac-client 0.2.3__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} +3 -3
  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.3.dist-info → jac_client-0.2.6.dist-info}/METADATA +28 -30
  66. jac_client-0.2.6.dist-info/RECORD +74 -0
  67. {jac_client-0.2.3.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.3.dist-info/RECORD +0 -171
  202. jac_client-0.2.3.dist-info/entry_points.txt +0 -4
@@ -1,270 +0,0 @@
1
- # Step 1: Project Setup
2
-
3
- > ** Quick Tip:** Each step has two parts. **Part 1** shows you what to build. **Part 2** explains why it works. Want to just build? Skip all Part 2 sections!
4
-
5
- In this first step, you'll create your Jac project and understand the basic file structure.
6
-
7
- ---
8
-
9
- ## Part 1: Building the App
10
-
11
- ### Step 1.1: Create Your Project
12
-
13
- Open your terminal and run:
14
-
15
- ```bash
16
- jac create_jac_app todo-app
17
- ```
18
-
19
- This creates a new directory called `todo-app` with everything you need.
20
-
21
- ### Step 1.2: Navigate to Your Project
22
-
23
- ```bash
24
- cd todo-app
25
- ```
26
-
27
- ### Step 1.3: Understand the Structure
28
-
29
- Your project now has these files:
30
-
31
- ```
32
- todo-app/
33
- ├── app.jac # Your main application file (we'll work here!)
34
- ├── package.json # Node.js dependencies (auto-managed)
35
- ├── vite.config.js # Build configuration (you can ignore this)
36
- └── README.md # Basic instructions
37
- ```
38
-
39
- **Important**: We'll write ALL our code in `app.jac` - that's it!
40
-
41
- ### Step 1.4: Create Your First App
42
-
43
- Open `app.jac` in your code editor and replace everything with this:
44
-
45
- ```jac
46
- cl {
47
- def app() -> any {
48
- return <div>
49
- <h1>Hello, Jac!</h1>
50
- <p>My first full-stack app</p>
51
- </div>;
52
- }
53
- }
54
- ```
55
-
56
- ### Step 1.5: Run Your App
57
-
58
- In your terminal, run:
59
-
60
- ```bash
61
- jac serve app.jac
62
- ```
63
-
64
- You'll see output like:
65
-
66
- ```
67
- INFO: Started server process [12345]
68
- INFO: Waiting for application startup.
69
- INFO: Application startup complete.
70
- INFO: Uvicorn running on http://127.0.0.1:8000
71
- ```
72
-
73
- ### Step 1.6: View in Browser
74
-
75
- Open your browser and go to:
76
-
77
- ```
78
- http://localhost:8000/page/app
79
- ```
80
-
81
- You should see "Hello, Jac!" and "My first full-stack app"
82
-
83
- ---
84
-
85
- **⏭ Want to skip the theory?** Jump to [Step 2: First Component](./step-02-components.md)
86
-
87
- ---
88
-
89
- ## Part 2: Understanding the Concepts
90
-
91
- ### What is `cl { ... }`?
92
-
93
- `cl` stands for "client" - it means this code runs in the **browser** (frontend).
94
-
95
- ```jac
96
- cl {
97
- # Everything here runs on the client-side (browser)
98
- }
99
- ```
100
-
101
- Think of it like this:
102
-
103
- - Code **inside** `cl { }` → Runs in the browser (frontend)
104
- - Code **outside** `cl { }` → Runs on the server (backend)
105
-
106
- ### What is `def app() -> any`?
107
-
108
- This is your **main entry point** - the function that Jac calls first.
109
-
110
- ```jac
111
- def app() -> any {
112
- return <div>...</div>;
113
- }
114
- ```
115
-
116
- **Requirements:**
117
-
118
- - Must be named `app` (by convention)
119
- - Must return JSX (HTML-like syntax)
120
- - Located inside `cl { }` block
121
-
122
- **Python analogy:**
123
-
124
- ```python
125
- # Python
126
- if __name__ == "__main__":
127
- run_app()
128
-
129
- # Jac
130
- def app() -> any {
131
- # Start here
132
- }
133
- ```
134
-
135
- ### What is JSX?
136
-
137
- JSX lets you write HTML directly in your Jac code:
138
-
139
- ```jac
140
- return <div>
141
- <h1>This is HTML!</h1>
142
- <p>But written in Jac code</p>
143
- </div>;
144
- ```
145
-
146
- **Key rules:**
147
-
148
- 1. Must have **one root element**
149
-
150
- ```jac
151
- # Correct
152
- return <div><h1>Title</h1><p>Text</p></div>;
153
-
154
- # Wrong (two root elements)
155
- return <h1>Title</h1><p>Text</p>;
156
- ```
157
-
158
- 2. Self-closing tags need `/`
159
-
160
- ```jac
161
- <img src="photo.jpg" /> # Correct
162
- <img src="photo.jpg"> # Wrong
163
- ```
164
-
165
- 3. Use `{}` to insert Jac code
166
- ```jac
167
- let name = "Alice";
168
- return <h1>Hello, {name}!</h1>; # Shows: Hello, Alice!
169
- ```
170
-
171
- ### How `jac serve` Works
172
-
173
- When you run `jac serve app.jac`:
174
-
175
- 1. **Jac compiler** reads your `.jac` file
176
- 2. **Frontend code** (inside `cl`) → Compiled to JavaScript
177
- 3. **Backend code** (outside `cl`) → Stays as Python-like backend code
178
- 4. **Single server** serves both on port 8000
179
- 5. **Auto-reload** watches for file changes (coming soon...)
180
-
181
- It's like running a Flask/FastAPI server, but it ALSO compiles and serves your React frontend - all in one command!
182
-
183
- ### File Organization
184
-
185
- For now, everything goes in `app.jac`. As your app grows, you can split into multiple files:
186
-
187
- ```
188
- todo-app/
189
- ├── app.jac # Main app
190
- ├── components.jac # Reusable components
191
- └── walkers.jac # Backend logic
192
- ```
193
-
194
- But for this tutorial, we'll keep everything in one file for simplicity.
195
-
196
- ---
197
-
198
- ## What You've Learned
199
-
200
- - How to create a Jac project
201
- - Project structure basics
202
- - What `cl { }` means (client-side code)
203
- - The `def app()` entry point
204
- - JSX basics (HTML in code)
205
- - Running your app with `jac serve`
206
-
207
- ---
208
-
209
- ## Common Issues
210
-
211
- ### Issue: `jac: command not found`
212
-
213
- **Solution**: Install jac-client:
214
-
215
- ```bash
216
- pip install jac-client
217
- ```
218
-
219
- ### Issue: Port 8000 already in use
220
-
221
- **Solution**: Use a different port:
222
-
223
- ```bash
224
- jac serve app.jac --port 8080
225
- ```
226
-
227
- Then visit `http://localhost:8080/page/app`
228
-
229
- ### Issue: Blank page in browser
230
-
231
- **Check:**
232
-
233
- - Did you visit `/page/app` (not just `/`)?
234
- - Check terminal for errors
235
- - Make sure `app()` has a `return` statement
236
-
237
- ### Issue: Changes not showing
238
-
239
- **Solution**:
240
-
241
- - Stop the server (Ctrl+C)
242
- - Restart: `jac serve app.jac`
243
- - Refresh browser
244
-
245
- ---
246
-
247
- ## Quick Exercise
248
-
249
- Before moving on, try changing the text:
250
-
251
- ```jac
252
- cl {
253
- def app() -> any {
254
- return <div>
255
- <h1>My Todo App</h1>
256
- <p>Built with Jac</p>
257
- </div>;
258
- }
259
- }
260
- ```
261
-
262
- Save, refresh your browser, and see the changes!
263
-
264
- ---
265
-
266
- ## Next Step
267
-
268
- Great! You have a running Jac app. Now let's learn about **components** - the building blocks of any UI.
269
-
270
- **[Continue to Step 2: First Component](./step-02-components.md)**
@@ -1,416 +0,0 @@
1
- # Step 2: First Component
2
-
3
- > ** Quick Tip:** Each step has two parts. **Part 1** shows you what to build. **Part 2** explains why it works. Want to just build? Skip all Part 2 sections!
4
-
5
- In this step, you'll create your first reusable component - a **TodoItem** that displays a single todo.
6
-
7
- ---
8
-
9
- ## Part 1: Building the App
10
-
11
- ### Step 2.1: Create a TodoItem Component
12
-
13
- Update your `app.jac`:
14
-
15
- ```jac
16
- cl {
17
- # A component to display a single todo
18
- def TodoItem(props: any) -> any {
19
- return <div>
20
- <input type="checkbox" />
21
- <span>Learn Jac basics</span>
22
- <button>Delete</button>
23
- </div>;
24
- }
25
-
26
- def app() -> any {
27
- return <div>
28
- <h1>My Todos</h1>
29
- <TodoItem />
30
- </div>;
31
- }
32
- }
33
- ```
34
-
35
- **Try it!** Save and refresh your browser. You should see a todo item with a checkbox, text, and delete button.
36
-
37
- ### Step 2.2: Make It Reusable with Props
38
-
39
- Now let's make the TodoItem display different text:
40
-
41
- ```jac
42
- cl {
43
- # Component that accepts data via props
44
- def TodoItem(props: any) -> any {
45
- return <div>
46
- <input type="checkbox" checked={props.done} />
47
- <span>{props.text}</span>
48
- <button>Delete</button>
49
- </div>;
50
- }
51
-
52
- def app() -> any {
53
- return <div>
54
- <h1>My Todos</h1>
55
- <TodoItem text="Learn Jac basics" done={false} />
56
- <TodoItem text="Build a todo app" done={false} />
57
- <TodoItem text="Deploy to production" done={true} />
58
- </div>;
59
- }
60
- }
61
- ```
62
-
63
- **Try it!** You should now see three different todos. Notice how the third one has the checkbox checked!
64
-
65
- ### Step 2.3: Create Multiple Components
66
-
67
- Let's add more components to organize our app:
68
-
69
- ```jac
70
- cl {
71
- # Component 1: TodoInput (input field + Add button)
72
- def TodoInput(props: any) -> any {
73
- return <div>
74
- <input type="text" placeholder="What needs to be done?" />
75
- <button>Add</button>
76
- </div>;
77
- }
78
-
79
- # Component 2: TodoFilters (filter buttons)
80
- def TodoFilters(props: any) -> any {
81
- return <div>
82
- <button>All</button>
83
- <button>Active</button>
84
- <button>Completed</button>
85
- </div>;
86
- }
87
-
88
- # Component 3: TodoItem (single todo)
89
- def TodoItem(props: any) -> any {
90
- return <div>
91
- <input type="checkbox" checked={props.done} />
92
- <span>{props.text}</span>
93
- <button>Delete</button>
94
- </div>;
95
- }
96
-
97
- # Component 4: TodoList (list of todos)
98
- def TodoList(props: any) -> any {
99
- return <div>
100
- <TodoItem text="Learn Jac basics" done={true} />
101
- <TodoItem text="Build a todo app" done={false} />
102
- <TodoItem text="Deploy to production" done={false} />
103
- </div>;
104
- }
105
-
106
- # Main app - combines all components
107
- def app() -> any {
108
- return <div>
109
- <h1>My Todos</h1>
110
- <TodoInput />
111
- <TodoFilters />
112
- <TodoList />
113
- </div>;
114
- }
115
- }
116
- ```
117
-
118
- **Try it!** Your app now has a clear structure with separate components.
119
-
120
- ---
121
-
122
- **⏭ Want to skip the theory?** Jump to [Step 3: Styling](./step-03-styling.md)
123
-
124
- ---
125
-
126
- ## Part 2: Understanding the Concepts
127
-
128
- ### What is a Component?
129
-
130
- A component is a **function that returns UI (JSX)**.
131
-
132
- Think of components like Python functions:
133
-
134
- ```python
135
- # Python - returns text
136
- def greet_user(name):
137
- return f"Hello, {name}!"
138
-
139
- print(greet_user("Alice")) # Hello, Alice!
140
- print(greet_user("Bob")) # Hello, Bob!
141
- ```
142
-
143
- ```jac
144
- # Jac - returns UI
145
- def TodoItem(props: any) -> any {
146
- return <div>{props.text}</div>;
147
- }
148
-
149
- # Usage
150
- <TodoItem text="Learn Jac" />
151
- <TodoItem text="Build app" />
152
- ```
153
-
154
- ### Why Use Components?
155
-
156
- **1. Reusability** - Write once, use many times
157
-
158
- ```jac
159
- <TodoItem text="Task 1" done={false} />
160
- <TodoItem text="Task 2" done={true} />
161
- <TodoItem text="Task 3" done={false} />
162
- ```
163
-
164
- **2. Organization** - Break complex UI into manageable pieces
165
-
166
- ```jac
167
- app
168
- ├── TodoInput
169
- ├── TodoFilters
170
- └── TodoList
171
- ├── TodoItem
172
- ├── TodoItem
173
- └── TodoItem
174
- ```
175
-
176
- **3. Maintainability** - Easy to find and fix bugs
177
-
178
- If there's a bug in how todos display, you know to check `TodoItem`.
179
-
180
- ### Component Naming Rules
181
-
182
- **1. Use PascalCase** (first letter capitalized)
183
-
184
- ```jac
185
- # Correct
186
- def TodoItem() -> any { ... }
187
- def UserProfile() -> any { ... }
188
- def NavigationBar() -> any { ... }
189
-
190
- # Wrong
191
- def todoItem() -> any { ... } # camelCase
192
- def user_profile() -> any { ... } # snake_case
193
- def navigation-bar() -> any { ... } # kebab-case
194
- ```
195
-
196
- **2. Name describes what it does**
197
-
198
- ```jac
199
- # Good names
200
- def TodoItem() -> any { ... }
201
- def LoginForm() -> any { ... }
202
- def ProductCard() -> any { ... }
203
-
204
- # Bad names
205
- def Component1() -> any { ... }
206
- def Thing() -> any { ... }
207
- def X() -> any { ... }
208
- ```
209
-
210
- ### Understanding Props
211
-
212
- **Props** = "Properties" = Data passed to a component
213
-
214
- ```jac
215
- # Passing props (like function arguments)
216
- <TodoItem text="Learn Jac" done={false} />
217
-
218
- # Receiving props (in the component)
219
- def TodoItem(props: any) -> any {
220
- let text = props.text; # "Learn Jac"
221
- let done = props.done; # false
222
- return <div>{text}</div>;
223
- }
224
- ```
225
-
226
- **Important**: In React (which Jac uses), components receive props as a **single object**, not individual parameters.
227
-
228
- ```jac
229
- # Correct way
230
- def TodoItem(props: any) -> any {
231
- let text = props.text;
232
- let done = props.done;
233
- # ...
234
- }
235
-
236
- # Wrong way (won't work)
237
- def TodoItem(text: str, done: bool) -> any {
238
- # This doesn't work in React!
239
- }
240
- ```
241
-
242
- ### Accessing Props
243
-
244
- Three ways to access props:
245
-
246
- **Method 1: Direct access**
247
-
248
- ```jac
249
- def TodoItem(props: any) -> any {
250
- return <span>{props.text}</span>;
251
- }
252
- ```
253
-
254
- **Method 2: Extract to variables**
255
-
256
- ```jac
257
- def TodoItem(props: any) -> any {
258
- let text = props.text;
259
- let done = props.done;
260
- return <span>{text}</span>;
261
- }
262
- ```
263
-
264
- **Method 3: Dictionary access (explicit)**
265
-
266
- ```jac
267
- def TodoItem(props: any) -> any {
268
- let text = props["text"];
269
- let done = props["done"];
270
- return <span>{text}</span>;
271
- }
272
- ```
273
-
274
- All three ways work! Use whichever feels clearest to you.
275
-
276
- ### Composing Components
277
-
278
- You can nest components inside other components:
279
-
280
- ```jac
281
- # TodoList uses TodoItem
282
- def TodoList() -> any {
283
- return <div>
284
- <TodoItem text="Task 1" done={false} />
285
- <TodoItem text="Task 2" done={true} />
286
- </div>;
287
- }
288
-
289
- # App uses TodoList
290
- def app() -> any {
291
- return <div>
292
- <h1>My Todos</h1>
293
- <TodoList />
294
- </div>;
295
- }
296
- ```
297
-
298
- This creates a hierarchy:
299
-
300
- ```
301
- app
302
- └── TodoList
303
- ├── TodoItem
304
- └── TodoItem
305
- ```
306
-
307
- ### Using JSX in Props
308
-
309
- You can pass any value as props:
310
-
311
- ```jac
312
- # String
313
- <TodoItem text="Hello" />
314
-
315
- # Number
316
- <TodoItem count={42} />
317
-
318
- # Boolean
319
- <TodoItem done={true} />
320
-
321
- # Variable
322
- let myText = "Learn Jac";
323
- <TodoItem text={myText} />
324
-
325
- # Expression
326
- <TodoItem priority={5 + 3} />
327
- ```
328
-
329
- ---
330
-
331
- ## What You've Learned
332
-
333
- - Components are functions that return UI
334
- - How to create a component
335
- - PascalCase naming convention
336
- - Passing data to components with props
337
- - Receiving props as a single object
338
- - Composing components (nesting)
339
- - Organizing app into multiple components
340
-
341
- ---
342
-
343
- ## Common Issues
344
-
345
- ### Issue: Component not showing up
346
-
347
- **Check:**
348
- - Is the name in PascalCase? `TodoItem` not `todoItem`
349
- - Did you use `<TodoItem />` (with angle brackets)?
350
- - Does it have a `return` statement?
351
-
352
- ### Issue: "object with keys {text, done}"
353
-
354
- **Cause**: Using individual parameters instead of props object
355
-
356
- ```jac
357
- # Wrong
358
- def TodoItem(text: str, done: bool) -> any {
359
- # ...
360
- }
361
-
362
- # Correct
363
- def TodoItem(props: any) -> any {
364
- let text = props.text;
365
- # ...
366
- }
367
- ```
368
-
369
- ### Issue: Props are undefined
370
-
371
- **Check:**
372
- - Did you pass the props when using the component?
373
- - Are the prop names spelled the same in both places?
374
-
375
- ```jac
376
- # Passing props
377
- <TodoItem text="Learn" done={false} />
378
-
379
- # Receiving props (names must match!)
380
- def TodoItem(props: any) -> any {
381
- props.text # "Learn"
382
- props.done # false
383
- }
384
- ```
385
-
386
- ---
387
-
388
- ## Quick Exercise
389
-
390
- Try adding a new component:
391
-
392
- ```jac
393
- def TodoStats(props: any) -> any {
394
- return <div>
395
- <p>Total: {props.total}</p>
396
- <p>Completed: {props.completed}</p>
397
- </div>;
398
- }
399
-
400
- # Use it in app
401
- def app() -> any {
402
- return <div>
403
- <h1>My Todos</h1>
404
- <TodoStats total={3} completed={1} />
405
- # ... rest of your components
406
- </div>;
407
- }
408
- ```
409
-
410
- ---
411
-
412
- ## Next Step
413
-
414
- Great! You can now create and organize components. But they look plain. Let's make them beautiful with **styling**!
415
-
416
- **[Continue to Step 3: Styling](./step-03-styling.md)**