jac-client 0.2.0__py3-none-any.whl → 0.2.3__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 (154) hide show
  1. jac_client/docs/README.md +50 -20
  2. jac_client/docs/advanced-state.md +13 -14
  3. jac_client/docs/asset-serving/intro.md +209 -0
  4. jac_client/docs/assets/pipe_line-v2.svg +32 -0
  5. jac_client/docs/file-system/app.jac.md +121 -0
  6. jac_client/docs/file-system/backend-frontend.md +217 -0
  7. jac_client/docs/file-system/intro.md +72 -0
  8. jac_client/docs/file-system/nested-imports.md +348 -0
  9. jac_client/docs/guide-example/intro.md +11 -13
  10. jac_client/docs/guide-example/step-01-setup.md +30 -20
  11. jac_client/docs/guide-example/step-02-components.md +24 -24
  12. jac_client/docs/guide-example/step-03-styling.md +24 -24
  13. jac_client/docs/guide-example/step-04-todo-ui.md +17 -17
  14. jac_client/docs/guide-example/step-05-local-state.md +23 -23
  15. jac_client/docs/guide-example/step-06-events.md +23 -24
  16. jac_client/docs/guide-example/step-07-effects.md +27 -28
  17. jac_client/docs/guide-example/step-08-walkers.md +23 -23
  18. jac_client/docs/guide-example/step-09-authentication.md +18 -18
  19. jac_client/docs/guide-example/step-10-routing.md +20 -21
  20. jac_client/docs/guide-example/step-11-final.md +34 -35
  21. jac_client/docs/imports.md +4 -5
  22. jac_client/docs/lifecycle-hooks.md +12 -13
  23. jac_client/docs/routing.md +21 -22
  24. jac_client/docs/styling/intro.md +249 -0
  25. jac_client/docs/styling/js-styling.md +367 -0
  26. jac_client/docs/styling/material-ui.md +341 -0
  27. jac_client/docs/styling/pure-css.md +299 -0
  28. jac_client/docs/styling/sass.md +403 -0
  29. jac_client/docs/styling/styled-components.md +395 -0
  30. jac_client/docs/styling/tailwind.md +298 -0
  31. jac_client/examples/all-in-one/.babelrc +9 -0
  32. jac_client/examples/all-in-one/README.md +16 -0
  33. jac_client/examples/all-in-one/app.jac +426 -0
  34. jac_client/examples/all-in-one/assets/burger.png +0 -0
  35. jac_client/examples/all-in-one/button.jac +7 -0
  36. jac_client/examples/all-in-one/components/button.jac +7 -0
  37. jac_client/examples/all-in-one/package.json +29 -0
  38. jac_client/examples/all-in-one/styles.css +26 -0
  39. jac_client/examples/all-in-one/vite.config.js +28 -0
  40. jac_client/examples/asset-serving/css-with-image/.babelrc +9 -0
  41. jac_client/examples/asset-serving/css-with-image/README.md +91 -0
  42. jac_client/examples/asset-serving/css-with-image/app.jac +88 -0
  43. jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
  44. jac_client/examples/asset-serving/css-with-image/package.json +28 -0
  45. jac_client/examples/asset-serving/css-with-image/styles.css +26 -0
  46. jac_client/examples/asset-serving/css-with-image/vite.config.js +28 -0
  47. jac_client/examples/asset-serving/image-asset/.babelrc +9 -0
  48. jac_client/examples/asset-serving/image-asset/README.md +119 -0
  49. jac_client/examples/asset-serving/image-asset/app.jac +55 -0
  50. jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
  51. jac_client/examples/asset-serving/image-asset/package.json +28 -0
  52. jac_client/examples/asset-serving/image-asset/styles.css +26 -0
  53. jac_client/examples/asset-serving/image-asset/vite.config.js +28 -0
  54. jac_client/examples/asset-serving/import-alias/.babelrc +9 -0
  55. jac_client/examples/asset-serving/import-alias/README.md +83 -0
  56. jac_client/examples/asset-serving/import-alias/app.jac +111 -0
  57. jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
  58. jac_client/examples/asset-serving/import-alias/package.json +28 -0
  59. jac_client/examples/asset-serving/import-alias/vite.config.js +28 -0
  60. jac_client/examples/basic/app.jac +14 -9
  61. jac_client/examples/basic/package.json +1 -1
  62. jac_client/examples/basic/vite.config.js +0 -1
  63. jac_client/examples/basic-auth/package.json +1 -1
  64. jac_client/examples/basic-auth/vite.config.js +0 -1
  65. jac_client/examples/basic-auth-with-router/package.json +1 -1
  66. jac_client/examples/basic-auth-with-router/vite.config.js +0 -1
  67. jac_client/examples/basic-full-stack/package.json +1 -1
  68. jac_client/examples/basic-full-stack/vite.config.js +0 -1
  69. jac_client/examples/css-styling/js-styling/.babelrc +9 -0
  70. jac_client/examples/css-styling/js-styling/README.md +183 -0
  71. jac_client/examples/css-styling/js-styling/app.jac +84 -0
  72. jac_client/examples/css-styling/js-styling/package.json +28 -0
  73. jac_client/examples/css-styling/js-styling/styles.js +100 -0
  74. jac_client/examples/css-styling/js-styling/vite.config.js +27 -0
  75. jac_client/examples/css-styling/material-ui/.babelrc +9 -0
  76. jac_client/examples/css-styling/material-ui/README.md +16 -0
  77. jac_client/examples/css-styling/material-ui/app.jac +122 -0
  78. jac_client/examples/css-styling/material-ui/package.json +32 -0
  79. jac_client/examples/css-styling/material-ui/vite.config.js +27 -0
  80. jac_client/examples/css-styling/pure-css/.babelrc +9 -0
  81. jac_client/examples/css-styling/pure-css/README.md +16 -0
  82. jac_client/examples/css-styling/pure-css/app.jac +64 -0
  83. jac_client/examples/css-styling/pure-css/package.json +28 -0
  84. jac_client/examples/css-styling/pure-css/styles.css +111 -0
  85. jac_client/examples/css-styling/pure-css/vite.config.js +27 -0
  86. jac_client/examples/css-styling/sass-example/.babelrc +9 -0
  87. jac_client/examples/css-styling/sass-example/README.md +16 -0
  88. jac_client/examples/css-styling/sass-example/app.jac +64 -0
  89. jac_client/examples/css-styling/sass-example/package.json +29 -0
  90. jac_client/examples/css-styling/sass-example/styles.scss +153 -0
  91. jac_client/examples/css-styling/sass-example/vite.config.js +27 -0
  92. jac_client/examples/css-styling/styled-components/.babelrc +9 -0
  93. jac_client/examples/css-styling/styled-components/README.md +16 -0
  94. jac_client/examples/css-styling/styled-components/app.jac +71 -0
  95. jac_client/examples/css-styling/styled-components/package.json +29 -0
  96. jac_client/examples/css-styling/styled-components/styled.js +90 -0
  97. jac_client/examples/css-styling/styled-components/vite.config.js +27 -0
  98. jac_client/examples/css-styling/tailwind-example/.babelrc +9 -0
  99. jac_client/examples/css-styling/tailwind-example/README.md +16 -0
  100. jac_client/examples/css-styling/tailwind-example/app.jac +63 -0
  101. jac_client/examples/css-styling/tailwind-example/global.css +1 -0
  102. jac_client/examples/css-styling/tailwind-example/package.json +30 -0
  103. jac_client/examples/css-styling/tailwind-example/vite.config.js +29 -0
  104. jac_client/examples/full-stack-with-auth/app.jac +20 -33
  105. jac_client/examples/full-stack-with-auth/package.json +1 -1
  106. jac_client/examples/full-stack-with-auth/vite.config.js +0 -1
  107. jac_client/examples/little-x/app.jac +327 -218
  108. jac_client/examples/little-x/submit-button.jac +1 -1
  109. jac_client/examples/nested-folders/nested-advance/.babelrc +9 -0
  110. jac_client/examples/nested-folders/nested-advance/ButtonRoot.jac +11 -0
  111. jac_client/examples/nested-folders/nested-advance/README.md +77 -0
  112. jac_client/examples/nested-folders/nested-advance/app.jac +35 -0
  113. jac_client/examples/nested-folders/nested-advance/level1/ButtonSecondL.jac +19 -0
  114. jac_client/examples/nested-folders/nested-advance/level1/Card.jac +43 -0
  115. jac_client/examples/nested-folders/nested-advance/level1/level2/ButtonThirdL.jac +25 -0
  116. jac_client/examples/nested-folders/nested-advance/package.json +29 -0
  117. jac_client/examples/nested-folders/nested-advance/vite.config.js +28 -0
  118. jac_client/examples/nested-folders/nested-basic/.babelrc +9 -0
  119. jac_client/examples/nested-folders/nested-basic/README.md +183 -0
  120. jac_client/examples/nested-folders/nested-basic/app.jac +13 -0
  121. jac_client/examples/nested-folders/nested-basic/app.js +7 -0
  122. jac_client/examples/nested-folders/nested-basic/button.jac +7 -0
  123. jac_client/examples/nested-folders/nested-basic/components/button.jac +7 -0
  124. jac_client/examples/nested-folders/nested-basic/package.json +28 -0
  125. jac_client/examples/nested-folders/nested-basic/vite.config.js +27 -0
  126. jac_client/examples/with-router/app.jac +1 -1
  127. jac_client/examples/with-router/package.json +1 -1
  128. jac_client/examples/with-router/vite.config.js +0 -1
  129. jac_client/plugin/cli.py +7 -2
  130. jac_client/plugin/client.py +68 -5
  131. jac_client/plugin/client_runtime.jac +1 -1
  132. jac_client/plugin/vite_client_bundle.py +162 -14
  133. jac_client/tests/__init__.py +0 -1
  134. jac_client/tests/fixtures/basic-app/app.jac +7 -2
  135. jac_client/tests/fixtures/cl_file/app.cl.jac +48 -0
  136. jac_client/tests/fixtures/cl_file/app.jac +15 -0
  137. jac_client/tests/fixtures/client_app_with_antd/app.jac +14 -8
  138. jac_client/tests/fixtures/js_import/app.jac +19 -15
  139. jac_client/tests/fixtures/js_import/utils.js +0 -1
  140. jac_client/tests/fixtures/package.json +1 -1
  141. jac_client/tests/fixtures/relative_import/app.jac +4 -6
  142. jac_client/tests/fixtures/relative_import/button.jac +7 -6
  143. jac_client/tests/fixtures/spawn_test/app.jac +1 -5
  144. jac_client/tests/fixtures/test_fragments_spread/app.jac +24 -10
  145. jac_client/tests/test_asset_examples.py +322 -0
  146. jac_client/tests/test_cl.py +480 -426
  147. jac_client/tests/test_create_jac_app.py +125 -133
  148. jac_client/tests/test_it.py +329 -0
  149. jac_client/tests/test_nested_file.py +374 -0
  150. {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/METADATA +11 -3
  151. jac_client-0.2.3.dist-info/RECORD +171 -0
  152. jac_client-0.2.0.dist-info/RECORD +0 -72
  153. {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/WHEEL +0 -0
  154. {jac_client-0.2.0.dist-info → jac_client-0.2.3.dist-info}/entry_points.txt +0 -0
@@ -1,12 +1,12 @@
1
1
  # Step 3: Styling Components
2
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!
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
4
 
5
5
  In this step, you'll learn how to style your components using inline CSS to make them look great!
6
6
 
7
7
  ---
8
8
 
9
- ## 🏗️ Part 1: Building the App
9
+ ## Part 1: Building the App
10
10
 
11
11
  ### Step 3.1: Style the TodoItem Component
12
12
 
@@ -162,11 +162,11 @@ cl {
162
162
 
163
163
  ---
164
164
 
165
- **⏭️ Want to skip the theory?** Jump to [Step 4: Todo UI](./step-04-todo-ui.md)
165
+ **⏭ Want to skip the theory?** Jump to [Step 4: Todo UI](./step-04-todo-ui.md)
166
166
 
167
167
  ---
168
168
 
169
- ## 💡 Part 2: Understanding the Concepts
169
+ ## Part 2: Understanding the Concepts
170
170
 
171
171
  ### What are Inline Styles?
172
172
 
@@ -223,14 +223,14 @@ text-align → "textAlign"
223
223
  **Examples:**
224
224
 
225
225
  ```jac
226
- #Correct (camelCase)
226
+ # Correct (camelCase)
227
227
  {
228
228
  "backgroundColor": "#ffffff",
229
229
  "fontSize": "16px",
230
230
  "borderRadius": "8px"
231
231
  }
232
232
 
233
- #Wrong (kebab-case won't work)
233
+ # Wrong (kebab-case won't work)
234
234
  {
235
235
  "background-color": "#ffffff", # Error!
236
236
  "font-size": "16px" # Error!
@@ -289,14 +289,14 @@ text-align → "textAlign"
289
289
  All CSS values must be **strings** (in quotes):
290
290
 
291
291
  ```jac
292
- #Correct
292
+ # Correct
293
293
  {
294
294
  "padding": "20px",
295
295
  "color": "#3b82f6",
296
296
  "fontSize": "16px"
297
297
  }
298
298
 
299
- #Wrong (missing quotes)
299
+ # Wrong (missing quotes)
300
300
  {
301
301
  "padding": 20px, # Error!
302
302
  "color": #3b82f6, # Error!
@@ -395,19 +395,19 @@ def app() -> any {
395
395
 
396
396
  ---
397
397
 
398
- ##What You've Learned
398
+ ## What You've Learned
399
399
 
400
- -How to write inline styles in Jac
401
- -Double curly braces `{{ }}` syntax
402
- -camelCase property names
403
- -Common CSS properties
404
- -Conditional styling with ternary operator
405
- -Flexbox basics for layout
406
- -Reusing styles with variables
400
+ - How to write inline styles in Jac
401
+ - Double curly braces `{{ }}` syntax
402
+ - camelCase property names
403
+ - Common CSS properties
404
+ - Conditional styling with ternary operator
405
+ - Flexbox basics for layout
406
+ - Reusing styles with variables
407
407
 
408
408
  ---
409
409
 
410
- ## 🐛 Common Issues
410
+ ## Common Issues
411
411
 
412
412
  ### Issue: Styles not applying
413
413
 
@@ -422,10 +422,10 @@ def app() -> any {
422
422
  **Cause**: Missing quotes around property names or values
423
423
 
424
424
  ```jac
425
- #Wrong
425
+ # Wrong
426
426
  {padding: 20px}
427
427
 
428
- #Correct
428
+ # Correct
429
429
  {"padding": "20px"}
430
430
  ```
431
431
 
@@ -434,16 +434,16 @@ def app() -> any {
434
434
  **Solution**: Convert kebab-case to camelCase
435
435
 
436
436
  ```jac
437
- #Wrong
437
+ # Wrong
438
438
  {"background-color": "#fff"}
439
439
 
440
- #Correct
440
+ # Correct
441
441
  {"backgroundColor": "#fff"}
442
442
  ```
443
443
 
444
444
  ---
445
445
 
446
- ## 🎯 Quick Exercise
446
+ ## Quick Exercise
447
447
 
448
448
  Try adding a container with centered content:
449
449
 
@@ -471,8 +471,8 @@ This creates:
471
471
 
472
472
  ---
473
473
 
474
- ## ➡️ Next Step
474
+ ## Next Step
475
475
 
476
476
  Great! Your components now look professional. Next, let's build the **complete Todo UI** with all the components working together!
477
477
 
478
- 👉 **[Continue to Step 4: Todo UI](./step-04-todo-ui.md)**
478
+ **[Continue to Step 4: Todo UI](./step-04-todo-ui.md)**
@@ -1,12 +1,12 @@
1
1
  # Step 4: Building the Complete Todo UI
2
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!
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
4
 
5
5
  In this step, you'll put all your components together to create the full todo application interface!
6
6
 
7
7
  ---
8
8
 
9
- ## 🏗️ Part 1: Building the App
9
+ ## Part 1: Building the App
10
10
 
11
11
  ### Step 4.1: Complete App with All Components
12
12
 
@@ -205,11 +205,11 @@ cl {
205
205
 
206
206
  ---
207
207
 
208
- **⏭️ Want to skip the theory?** Jump to [Step 5: Local State](./step-05-local-state.md)
208
+ **⏭ Want to skip the theory?** Jump to [Step 5: Local State](./step-05-local-state.md)
209
209
 
210
210
  ---
211
211
 
212
- ## 💡 Part 2: Understanding the Concepts
212
+ ## Part 2: Understanding the Concepts
213
213
 
214
214
  ### Component Hierarchy
215
215
 
@@ -365,19 +365,19 @@ Using consistent colors makes your app look polished!
365
365
 
366
366
  ---
367
367
 
368
- ##What You've Learned
368
+ ## What You've Learned
369
369
 
370
- -Building a complete UI by composing components
371
- -Component hierarchy and organization
372
- -Container components that render lists
373
- -Conditional rendering for empty states
374
- -Centered card layout pattern
375
- -Consistent spacing and colors
376
- -Props flow from parent to child
370
+ - Building a complete UI by composing components
371
+ - Component hierarchy and organization
372
+ - Container components that render lists
373
+ - Conditional rendering for empty states
374
+ - Centered card layout pattern
375
+ - Consistent spacing and colors
376
+ - Props flow from parent to child
377
377
 
378
378
  ---
379
379
 
380
- ## 🐛 Common Issues
380
+ ## Common Issues
381
381
 
382
382
  ### Issue: Components overlapping
383
383
 
@@ -410,7 +410,7 @@ return <div>Show todos</div>; # This only runs if hasTodos is true
410
410
 
411
411
  ---
412
412
 
413
- ## 🎯 Quick Exercise
413
+ ## Quick Exercise
414
414
 
415
415
  Try customizing your app:
416
416
 
@@ -448,7 +448,7 @@ def app() -> any {
448
448
  "color": "white",
449
449
  "marginBottom": "20px"
450
450
  }}>
451
- <h1 style={{"margin": "0"}}>📝 Todo App</h1>
451
+ <h1 style={{"margin": "0"}}> Todo App</h1>
452
452
  <p style={{"margin": "5px 0 0 0"}}>Stay organized!</p>
453
453
  </div>
454
454
 
@@ -468,10 +468,10 @@ def app() -> any {
468
468
 
469
469
  ---
470
470
 
471
- ## ➡️ Next Step
471
+ ## Next Step
472
472
 
473
473
  Excellent! Your UI is complete and looks great. But it's all static - clicking buttons does nothing!
474
474
 
475
475
  In the next step, we'll add **state** to make your app interactive!
476
476
 
477
- 👉 **[Continue to Step 5: Local State](./step-05-local-state.md)**
477
+ **[Continue to Step 5: Local State](./step-05-local-state.md)**
@@ -1,12 +1,12 @@
1
1
  # Step 5: Local State
2
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!
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
4
 
5
5
  In this step, you'll learn about **state** - the data that makes your app interactive and dynamic!
6
6
 
7
7
  ---
8
8
 
9
- ## 🏗️ Part 1: Building the App
9
+ ## Part 1: Building the App
10
10
 
11
11
  ### Step 5.1: First, Let's See Why Normal Variables Don't Work
12
12
 
@@ -267,11 +267,11 @@ cl {
267
267
 
268
268
  ---
269
269
 
270
- **⏭️ Want to skip the theory?** Jump to [Step 6: Event Handlers](./step-06-events.md)
270
+ **⏭ Want to skip the theory?** Jump to [Step 6: Event Handlers](./step-06-events.md)
271
271
 
272
272
  ---
273
273
 
274
- ## 💡 Part 2: Understanding the Concepts
274
+ ## Part 2: Understanding the Concepts
275
275
 
276
276
  ### What is State?
277
277
 
@@ -380,7 +380,7 @@ let [name, setName] = useState("");
380
380
  let [isOpen, setIsOpen] = useState(false);
381
381
  let [todos, setTodos] = useState([]);
382
382
 
383
- #Bad names
383
+ # Bad names
384
384
  let [count, updateCount] = useState(0); # Inconsistent
385
385
  let [x, y] = useState(0); # Not descriptive
386
386
  ```
@@ -413,11 +413,11 @@ items = [TodoItem(text=todo["text"]) for todo in todos]
413
413
  **Never modify state directly:**
414
414
 
415
415
  ```jac
416
- #WRONG - Never do this!
416
+ # WRONG - Never do this!
417
417
  let [todos, setTodos] = useState([]);
418
418
  todos.push(newTodo); # DON'T modify directly!
419
419
 
420
- #CORRECT - Create new array
420
+ # CORRECT - Create new array
421
421
  let [todos, setTodos] = useState([]);
422
422
  setTodos(todos.concat([newTodo])); # Create new array
423
423
  ```
@@ -446,29 +446,29 @@ The child receives state but **cannot modify** the parent's state directly (we'l
446
446
 
447
447
  ---
448
448
 
449
- ##What You've Learned
449
+ ## What You've Learned
450
450
 
451
- -What state is and why we need it
452
- -How to use the `useState` hook
453
- -Creating multiple state variables
454
- -State naming conventions
455
- -Using `.map()` to render lists
456
- -State is immutable (don't modify directly)
457
- -Passing state to child components via props
451
+ - What state is and why we need it
452
+ - How to use the `useState` hook
453
+ - Creating multiple state variables
454
+ - State naming conventions
455
+ - Using `.map()` to render lists
456
+ - State is immutable (don't modify directly)
457
+ - Passing state to child components via props
458
458
 
459
459
  ---
460
460
 
461
- ## 🐛 Common Issues
461
+ ## Common Issues
462
462
 
463
463
  ### Issue: UI not updating when state changes
464
464
 
465
465
  **Check:** Are you modifying state directly?
466
466
 
467
467
  ```jac
468
- #Wrong
468
+ # Wrong
469
469
  todos.push(newTodo);
470
470
 
471
- #Correct
471
+ # Correct
472
472
  setTodos(todos.concat([newTodo]));
473
473
  ```
474
474
 
@@ -477,10 +477,10 @@ setTodos(todos.concat([newTodo]));
477
477
  **Check:** Did you initialize state as an array?
478
478
 
479
479
  ```jac
480
- #Wrong
480
+ # Wrong
481
481
  let [todos, setTodos] = useState(); # undefined
482
482
 
483
- #Correct
483
+ # Correct
484
484
  let [todos, setTodos] = useState([]); # empty array
485
485
  ```
486
486
 
@@ -494,7 +494,7 @@ cl import from react {useState}
494
494
 
495
495
  ---
496
496
 
497
- ## 🎯 Quick Exercise
497
+ ## Quick Exercise
498
498
 
499
499
  Try adding more initial todos:
500
500
 
@@ -521,10 +521,10 @@ return <div>
521
521
 
522
522
  ---
523
523
 
524
- ## ➡️ Next Step
524
+ ## Next Step
525
525
 
526
526
  Great! You now have state in your app, but you can't change it yet. Clicking buttons does nothing!
527
527
 
528
528
  In the next step, we'll add **event handlers** to make your app fully interactive!
529
529
 
530
- 👉 **[Continue to Step 6: Event Handlers](./step-06-events.md)**
530
+ **[Continue to Step 6: Event Handlers](./step-06-events.md)**
@@ -1,12 +1,12 @@
1
1
  # Step 6: Event Handlers
2
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!
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
4
 
5
5
  In this step, you'll learn how to handle user interactions like clicks, typing, and key presses to make your app fully interactive!
6
6
 
7
7
  ---
8
8
 
9
- ## 🏗️ Part 1: Building the App
9
+ ## Part 1: Building the App
10
10
 
11
11
  ### Step 6.1: Handle Input Changes (onChange)
12
12
 
@@ -458,11 +458,11 @@ cl {
458
458
 
459
459
  ---
460
460
 
461
- **⏭️ Want to skip the theory?** Jump to [Step 7: Effects](./step-07-effects.md)
461
+ **⏭ Want to skip the theory?** Jump to [Step 7: Effects](./step-07-effects.md)
462
462
 
463
463
  ---
464
464
 
465
- ## 💡 Part 2: Understanding the Concepts
465
+ ## Part 2: Understanding the Concepts
466
466
 
467
467
  ### What are Event Handlers?
468
468
 
@@ -555,10 +555,10 @@ When state updates, React re-renders the component with the new value!
555
555
  **`.concat()` - Add items**
556
556
 
557
557
  ```jac
558
- #Correct way to add
558
+ # Correct way to add
559
559
  setTodos(todos.concat([newTodo]));
560
560
 
561
- #Wrong (modifies original)
561
+ # Wrong (modifies original)
562
562
  todos.push(newTodo);
563
563
  setTodos(todos);
564
564
  ```
@@ -659,20 +659,20 @@ def removeItem(id: any) -> None {
659
659
 
660
660
  ---
661
661
 
662
- ##What You've Learned
662
+ ## What You've Learned
663
663
 
664
- -What event handlers are
665
- -Common events (onClick, onChange, onKeyPress)
666
- -Event handler syntax with lambda functions
667
- -The event object (`e`)
668
- -Passing functions as props
669
- -Updating state in event handlers
670
- -Array methods (concat, map, filter)
671
- -Inline vs named functions
664
+ - What event handlers are
665
+ - Common events (onClick, onChange, onKeyPress)
666
+ - Event handler syntax with lambda functions
667
+ - The event object (`e`)
668
+ - Passing functions as props
669
+ - Updating state in event handlers
670
+ - Array methods (concat, map, filter)
671
+ - Inline vs named functions
672
672
 
673
673
  ---
674
674
 
675
- ## 🐛 Common Issues
675
+ ## Common Issues
676
676
 
677
677
  ### Issue: Event handler not firing
678
678
 
@@ -687,7 +687,7 @@ def removeItem(id: any) -> None {
687
687
  - Is `onChange` calling the state setter?
688
688
 
689
689
  ```jac
690
- #Correct
690
+ # Correct
691
691
  <input
692
692
  value={text}
693
693
  onChange={lambda e: any -> None {
@@ -695,7 +695,7 @@ def removeItem(id: any) -> None {
695
695
  }}
696
696
  />
697
697
 
698
- #Missing onChange
698
+ # Missing onChange
699
699
  <input value={text} />
700
700
  ```
701
701
 
@@ -704,17 +704,17 @@ def removeItem(id: any) -> None {
704
704
  **Check:** Are you creating a new array/object?
705
705
 
706
706
  ```jac
707
- #Wrong (modifying original)
707
+ # Wrong (modifying original)
708
708
  todos.push(newTodo);
709
709
  setTodos(todos);
710
710
 
711
- #Correct (creating new array)
711
+ # Correct (creating new array)
712
712
  setTodos(todos.concat([newTodo]));
713
713
  ```
714
714
 
715
715
  ---
716
716
 
717
- ## 🎯 Quick Exercise
717
+ ## Quick Exercise
718
718
 
719
719
  Try adding a "Clear All" button:
720
720
 
@@ -740,11 +740,10 @@ def clearCompleted() -> None {
740
740
 
741
741
  ---
742
742
 
743
- ## ➡️ Next Step
743
+ ## Next Step
744
744
 
745
745
  Excellent! Your app is now fully interactive with local state. But when you refresh the page, all your todos disappear!
746
746
 
747
747
  In the next step, we'll use **useEffect** to load data when the app starts!
748
748
 
749
- 👉 **[Continue to Step 7: Effects](./step-07-effects.md)**
750
-
749
+ **[Continue to Step 7: Effects](./step-07-effects.md)**
@@ -1,12 +1,12 @@
1
1
  # Step 7: Component Lifecycle with `useEffect`
2
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!
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
4
 
5
5
  In this step, you'll learn about **useEffect** - a way to run code when your component loads or when data changes!
6
6
 
7
7
  ---
8
8
 
9
- ## 🏗️ Part 1: Building the App
9
+ ## Part 1: Building the App
10
10
 
11
11
  ### Step 7.1: Understanding the Problem
12
12
 
@@ -91,7 +91,7 @@ cl {
91
91
  }
92
92
  ```
93
93
 
94
- **Try it!** Add some todos, then refresh the page - your todos persist! 🎉
94
+ **Try it!** Add some todos, then refresh the page - your todos persist!
95
95
 
96
96
  ### Step 7.5: Add Loading State
97
97
 
@@ -154,22 +154,22 @@ cl {
154
154
 
155
155
  ---
156
156
 
157
- **⏭️ Want to skip the theory?** Jump to [Step 8: Walkers](./step-08-walkers.md)
157
+ **⏭ Want to skip the theory?** Jump to [Step 8: Walkers](./step-08-walkers.md)
158
158
 
159
159
  ---
160
160
 
161
- ## 💡 Part 2: Understanding the Concepts
161
+ ## Part 2: Understanding the Concepts
162
162
 
163
163
  ### What is `useEffect`?
164
164
 
165
165
  `useEffect` lets you run **side effects** - code that affects things outside your component.
166
166
 
167
167
  **Common side effects:**
168
- - 📡 Fetching data from a server
169
- - 💾 Saving data to localStorage
168
+ - Fetching data from a server
169
+ - Saving data to localStorage
170
170
  - ⏰ Setting up timers
171
- - 📊 Logging analytics
172
- - 🔔 Subscribing to events
171
+ - Logging analytics
172
+ - Subscribing to events
173
173
 
174
174
  **Python analogy:**
175
175
 
@@ -368,31 +368,31 @@ useEffect(lambda -> None {
368
368
 
369
369
  ---
370
370
 
371
- ##What You've Learned
371
+ ## What You've Learned
372
372
 
373
- -What useEffect is and why we need it
374
- -How to run code when component mounts
375
- -Dependency arrays control when effects run
376
- -Multiple useEffect hooks for organization
377
- -Using localStorage to persist data
378
- -Adding loading states
379
- -Preventing unnecessary saves
373
+ - What useEffect is and why we need it
374
+ - How to run code when component mounts
375
+ - Dependency arrays control when effects run
376
+ - Multiple useEffect hooks for organization
377
+ - Using localStorage to persist data
378
+ - Adding loading states
379
+ - Preventing unnecessary saves
380
380
 
381
381
  ---
382
382
 
383
- ## 🐛 Common Issues
383
+ ## Common Issues
384
384
 
385
385
  ### Issue: Effect runs too many times
386
386
 
387
387
  **Check:** Is your dependency array correct?
388
388
 
389
389
  ```jac
390
- #Wrong - runs on every render
390
+ # Wrong - runs on every render
391
391
  useEffect(lambda -> None {
392
392
  console.log(todos);
393
393
  });
394
394
 
395
- #Correct - runs only when todos change
395
+ # Correct - runs only when todos change
396
396
  useEffect(lambda -> None {
397
397
  console.log(todos);
398
398
  }, [todos]);
@@ -403,12 +403,12 @@ useEffect(lambda -> None {
403
403
  **Check:** Did you include all dependencies?
404
404
 
405
405
  ```jac
406
- #Wrong - missing todos dependency
406
+ # Wrong - missing todos dependency
407
407
  useEffect(lambda -> None {
408
408
  console.log(todos.length);
409
409
  }, []);
410
410
 
411
- #Correct - includes todos
411
+ # Correct - includes todos
412
412
  useEffect(lambda -> None {
413
413
  console.log(todos.length);
414
414
  }, [todos]);
@@ -426,12 +426,12 @@ useEffect(lambda -> None {
426
426
  **Cause:** Effect updates state, which triggers effect again
427
427
 
428
428
  ```jac
429
- #Wrong - infinite loop!
429
+ # Wrong - infinite loop!
430
430
  useEffect(lambda -> None {
431
431
  setTodos([...]); # This triggers effect again!
432
432
  }, [todos]);
433
433
 
434
- #Correct - run only once
434
+ # Correct - run only once
435
435
  useEffect(lambda -> None {
436
436
  setTodos([...]);
437
437
  }, []);
@@ -439,7 +439,7 @@ useEffect(lambda -> None {
439
439
 
440
440
  ---
441
441
 
442
- ## 🎯 Quick Exercise
442
+ ## Quick Exercise
443
443
 
444
444
  Try adding a "last saved" timestamp:
445
445
 
@@ -459,11 +459,10 @@ useEffect(lambda -> None {
459
459
 
460
460
  ---
461
461
 
462
- ## ➡️ Next Step
462
+ ## Next Step
463
463
 
464
464
  Great! Your app now persists data with localStorage. But localStorage is only local to your browser!
465
465
 
466
466
  In the next step, we'll add **real backend** using **walkers** so your data is stored on a server!
467
467
 
468
- 👉 **[Continue to Step 8: Walkers](./step-08-walkers.md)**
469
-
468
+ **[Continue to Step 8: Walkers](./step-08-walkers.md)**