jac-client 0.2.0__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 (72) hide show
  1. jac_client/docs/README.md +659 -0
  2. jac_client/docs/advanced-state.md +1266 -0
  3. jac_client/docs/assets/pipe_line.png +0 -0
  4. jac_client/docs/guide-example/intro.md +117 -0
  5. jac_client/docs/guide-example/step-01-setup.md +260 -0
  6. jac_client/docs/guide-example/step-02-components.md +416 -0
  7. jac_client/docs/guide-example/step-03-styling.md +478 -0
  8. jac_client/docs/guide-example/step-04-todo-ui.md +477 -0
  9. jac_client/docs/guide-example/step-05-local-state.md +530 -0
  10. jac_client/docs/guide-example/step-06-events.md +750 -0
  11. jac_client/docs/guide-example/step-07-effects.md +469 -0
  12. jac_client/docs/guide-example/step-08-walkers.md +534 -0
  13. jac_client/docs/guide-example/step-09-authentication.md +586 -0
  14. jac_client/docs/guide-example/step-10-routing.md +540 -0
  15. jac_client/docs/guide-example/step-11-final.md +964 -0
  16. jac_client/docs/imports.md +1142 -0
  17. jac_client/docs/lifecycle-hooks.md +774 -0
  18. jac_client/docs/routing.md +660 -0
  19. jac_client/examples/basic/.babelrc +9 -0
  20. jac_client/examples/basic/README.md +16 -0
  21. jac_client/examples/basic/app.jac +16 -0
  22. jac_client/examples/basic/package.json +27 -0
  23. jac_client/examples/basic/vite.config.js +28 -0
  24. jac_client/examples/basic-auth/.babelrc +9 -0
  25. jac_client/examples/basic-auth/README.md +16 -0
  26. jac_client/examples/basic-auth/app.jac +308 -0
  27. jac_client/examples/basic-auth/package.json +27 -0
  28. jac_client/examples/basic-auth/vite.config.js +28 -0
  29. jac_client/examples/basic-auth-with-router/.babelrc +9 -0
  30. jac_client/examples/basic-auth-with-router/README.md +60 -0
  31. jac_client/examples/basic-auth-with-router/app.jac +464 -0
  32. jac_client/examples/basic-auth-with-router/package.json +28 -0
  33. jac_client/examples/basic-auth-with-router/vite.config.js +28 -0
  34. jac_client/examples/basic-full-stack/.babelrc +9 -0
  35. jac_client/examples/basic-full-stack/README.md +18 -0
  36. jac_client/examples/basic-full-stack/app.jac +320 -0
  37. jac_client/examples/basic-full-stack/package.json +28 -0
  38. jac_client/examples/basic-full-stack/vite.config.js +28 -0
  39. jac_client/examples/full-stack-with-auth/.babelrc +9 -0
  40. jac_client/examples/full-stack-with-auth/README.md +16 -0
  41. jac_client/examples/full-stack-with-auth/app.jac +735 -0
  42. jac_client/examples/full-stack-with-auth/package.json +28 -0
  43. jac_client/examples/full-stack-with-auth/vite.config.js +30 -0
  44. jac_client/examples/little-x/app.jac +615 -0
  45. jac_client/examples/little-x/package.json +23 -0
  46. jac_client/examples/little-x/submit-button.jac +8 -0
  47. jac_client/examples/with-router/.babelrc +9 -0
  48. jac_client/examples/with-router/README.md +17 -0
  49. jac_client/examples/with-router/app.jac +323 -0
  50. jac_client/examples/with-router/package.json +28 -0
  51. jac_client/examples/with-router/vite.config.js +28 -0
  52. jac_client/plugin/cli.py +239 -0
  53. jac_client/plugin/client.py +89 -0
  54. jac_client/plugin/client_runtime.jac +234 -0
  55. jac_client/plugin/vite_client_bundle.py +355 -0
  56. jac_client/tests/__init__.py +2 -0
  57. jac_client/tests/fixtures/basic-app/app.jac +18 -0
  58. jac_client/tests/fixtures/client_app_with_antd/app.jac +28 -0
  59. jac_client/tests/fixtures/js_import/app.jac +30 -0
  60. jac_client/tests/fixtures/js_import/utils.js +22 -0
  61. jac_client/tests/fixtures/package-lock.json +329 -0
  62. jac_client/tests/fixtures/package.json +11 -0
  63. jac_client/tests/fixtures/relative_import/app.jac +13 -0
  64. jac_client/tests/fixtures/relative_import/button.jac +6 -0
  65. jac_client/tests/fixtures/spawn_test/app.jac +133 -0
  66. jac_client/tests/fixtures/test_fragments_spread/app.jac +53 -0
  67. jac_client/tests/test_cl.py +476 -0
  68. jac_client/tests/test_create_jac_app.py +139 -0
  69. jac_client-0.2.0.dist-info/METADATA +182 -0
  70. jac_client-0.2.0.dist-info/RECORD +72 -0
  71. jac_client-0.2.0.dist-info/WHEEL +4 -0
  72. jac_client-0.2.0.dist-info/entry_points.txt +4 -0
@@ -0,0 +1,477 @@
1
+ # Step 4: Building the Complete Todo UI
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 put all your components together to create the full todo application interface!
6
+
7
+ ---
8
+
9
+ ## 🏗️ Part 1: Building the App
10
+
11
+ ### Step 4.1: Complete App with All Components
12
+
13
+ Let's build the complete UI. Replace your entire `app.jac` with:
14
+
15
+ ```jac
16
+ cl {
17
+ # Component 1: Todo Input
18
+ def TodoInput(props: any) -> any {
19
+ return <div style={{
20
+ "display": "flex",
21
+ "gap": "8px",
22
+ "marginBottom": "16px"
23
+ }}>
24
+ <input
25
+ type="text"
26
+ placeholder="What needs to be done?"
27
+ style={{
28
+ "flex": "1",
29
+ "padding": "8px",
30
+ "border": "1px solid #ddd",
31
+ "borderRadius": "4px"
32
+ }}
33
+ />
34
+ <button style={{
35
+ "padding": "8px 16px",
36
+ "background": "#3b82f6",
37
+ "color": "#ffffff",
38
+ "border": "none",
39
+ "borderRadius": "4px",
40
+ "cursor": "pointer",
41
+ "fontWeight": "600"
42
+ }}>
43
+ Add
44
+ </button>
45
+ </div>;
46
+ }
47
+
48
+ # Component 2: Filter Buttons
49
+ def TodoFilters(props: any) -> any {
50
+ return <div style={{
51
+ "display": "flex",
52
+ "gap": "8px",
53
+ "marginBottom": "16px"
54
+ }}>
55
+ <button style={{
56
+ "padding": "6px 12px",
57
+ "background": "#3b82f6",
58
+ "color": "#ffffff",
59
+ "border": "none",
60
+ "borderRadius": "4px",
61
+ "cursor": "pointer",
62
+ "fontSize": "14px"
63
+ }}>
64
+ All
65
+ </button>
66
+ <button style={{
67
+ "padding": "6px 12px",
68
+ "background": "#e5e7eb",
69
+ "color": "#000000",
70
+ "border": "none",
71
+ "borderRadius": "4px",
72
+ "cursor": "pointer",
73
+ "fontSize": "14px"
74
+ }}>
75
+ Active
76
+ </button>
77
+ <button style={{
78
+ "padding": "6px 12px",
79
+ "background": "#e5e7eb",
80
+ "color": "#000000",
81
+ "border": "none",
82
+ "borderRadius": "4px",
83
+ "cursor": "pointer",
84
+ "fontSize": "14px"
85
+ }}>
86
+ Completed
87
+ </button>
88
+ </div>;
89
+ }
90
+
91
+ # Component 3: Single Todo Item
92
+ def TodoItem(props: any) -> any {
93
+ return <div style={{
94
+ "display": "flex",
95
+ "alignItems": "center",
96
+ "gap": "10px",
97
+ "padding": "10px",
98
+ "borderBottom": "1px solid #e5e7eb"
99
+ }}>
100
+ <input
101
+ type="checkbox"
102
+ checked={props.done}
103
+ style={{"cursor": "pointer"}}
104
+ />
105
+ <span style={{
106
+ "flex": "1",
107
+ "textDecoration": ("line-through" if props.done else "none"),
108
+ "color": ("#999" if props.done else "#000")
109
+ }}>
110
+ {props.text}
111
+ </span>
112
+ <button style={{
113
+ "padding": "4px 8px",
114
+ "background": "#ef4444",
115
+ "color": "#ffffff",
116
+ "border": "none",
117
+ "borderRadius": "4px",
118
+ "cursor": "pointer",
119
+ "fontSize": "12px"
120
+ }}>
121
+ Delete
122
+ </button>
123
+ </div>;
124
+ }
125
+
126
+ # Component 4: Todo List (renders multiple TodoItems)
127
+ def TodoList(props: any) -> any {
128
+ return <div>
129
+ <TodoItem text="Learn Jac basics" done={true} />
130
+ <TodoItem text="Build a todo app" done={false} />
131
+ <TodoItem text="Deploy to production" done={false} />
132
+ </div>;
133
+ }
134
+
135
+ # Main App
136
+ def app() -> any {
137
+ return <div style={{
138
+ "maxWidth": "600px",
139
+ "margin": "20px auto",
140
+ "padding": "20px",
141
+ "background": "#ffffff",
142
+ "borderRadius": "8px",
143
+ "boxShadow": "0 2px 4px rgba(0,0,0,0.1)"
144
+ }}>
145
+ <h1 style={{"marginBottom": "20px"}}>My Todos</h1>
146
+ <TodoInput />
147
+ <TodoFilters />
148
+ <TodoList />
149
+
150
+ # Stats footer
151
+ <div style={{
152
+ "marginTop": "16px",
153
+ "padding": "10px",
154
+ "background": "#f9fafb",
155
+ "borderRadius": "4px",
156
+ "fontSize": "14px",
157
+ "color": "#666"
158
+ }}>
159
+ 2 items left
160
+ </div>
161
+ </div>;
162
+ }
163
+ }
164
+ ```
165
+
166
+ **Try it!** You should now see a complete todo application interface!
167
+
168
+ It looks like a real app, but clicking buttons won't do anything yet (we'll add that next).
169
+
170
+ ### Step 4.2: Add Empty State
171
+
172
+ What if there are no todos? Let's handle that:
173
+
174
+ ```jac
175
+ cl {
176
+ # ... (keep all previous components)
177
+
178
+ # Updated TodoList with empty state
179
+ def TodoList(props: any) -> any {
180
+ # For now, we'll manually control this
181
+ let hasTodos = true; # Change to false to see empty state
182
+
183
+ if not hasTodos {
184
+ return <div style={{
185
+ "padding": "20px",
186
+ "textAlign": "center",
187
+ "color": "#999"
188
+ }}>
189
+ No todos yet. Add one above!
190
+ </div>;
191
+ }
192
+
193
+ return <div>
194
+ <TodoItem text="Learn Jac basics" done={true} />
195
+ <TodoItem text="Build a todo app" done={false} />
196
+ <TodoItem text="Deploy to production" done={false} />
197
+ </div>;
198
+ }
199
+
200
+ # ... (rest of the code stays the same)
201
+ }
202
+ ```
203
+
204
+ **Try it!** Change `hasTodos = true` to `hasTodos = false` and see the empty state message.
205
+
206
+ ---
207
+
208
+ **⏭️ Want to skip the theory?** Jump to [Step 5: Local State](./step-05-local-state.md)
209
+
210
+ ---
211
+
212
+ ## 💡 Part 2: Understanding the Concepts
213
+
214
+ ### Component Hierarchy
215
+
216
+ Your app now has a clear structure:
217
+
218
+ ```
219
+ app (main container)
220
+ ├── h1 (title)
221
+ ├── TodoInput (input field + button)
222
+ ├── TodoFilters (All/Active/Completed buttons)
223
+ ├── TodoList (container)
224
+ │ ├── TodoItem (Learn Jac)
225
+ │ ├── TodoItem (Build app)
226
+ │ └── TodoItem (Deploy)
227
+ └── div (stats footer)
228
+ ```
229
+
230
+ ### Container Component Pattern
231
+
232
+ `TodoList` is a **container component** - it manages and renders multiple child components:
233
+
234
+ ```jac
235
+ def TodoList() -> any {
236
+ return <div>
237
+ <TodoItem text="Task 1" done={false} />
238
+ <TodoItem text="Task 2" done={true} />
239
+ <TodoItem text="Task 3" done={false} />
240
+ </div>;
241
+ }
242
+ ```
243
+
244
+ This pattern makes it easy to:
245
+ - Add/remove todos (just add/remove `<TodoItem>` components)
246
+ - Style the list container separately from items
247
+ - Handle empty states
248
+
249
+ ### Props Flow (Top-Down)
250
+
251
+ Data flows **down** from parent to child through props:
252
+
253
+ ```
254
+ app
255
+ └─> passes nothing to TodoList
256
+ └─> passes {text, done} to each TodoItem
257
+ ```
258
+
259
+ Right now, data is hard-coded. Later, we'll use **state** to make it dynamic.
260
+
261
+ ### Conditional Rendering
262
+
263
+ We used a simple `if` statement to show/hide content:
264
+
265
+ ```jac
266
+ if not hasTodos {
267
+ return <div>No todos yet!</div>;
268
+ }
269
+
270
+ return <div>
271
+ # Show todos
272
+ </div>;
273
+ ```
274
+
275
+ This is called **conditional rendering** - showing different UI based on conditions.
276
+
277
+ **Other ways to do this:**
278
+
279
+ **Method 1: If/Else in component**
280
+
281
+ ```jac
282
+ def TodoList() -> any {
283
+ if hasTodos {
284
+ return <div>Show todos</div>;
285
+ } else {
286
+ return <div>Empty state</div>;
287
+ }
288
+ }
289
+ ```
290
+
291
+ **Method 2: Ternary operator in JSX**
292
+
293
+ ```jac
294
+ return <div>
295
+ {(
296
+ <div>Show todos</div>
297
+ ) if hasTodos else (
298
+ <div>Empty state</div>
299
+ )}
300
+ </div>;
301
+ ```
302
+
303
+ **Method 3: And operator (&&)**
304
+
305
+ ```jac
306
+ return <div>
307
+ {(<div>Empty state</div>) if not hasTodos else None}
308
+ # Shows only when hasTodos is false
309
+ </div>;
310
+ ```
311
+
312
+ Use whichever feels clearest to you!
313
+
314
+ ### Layout Strategy
315
+
316
+ Our app uses a centered card layout:
317
+
318
+ ```jac
319
+ <div style={{
320
+ "maxWidth": "600px", # Don't get too wide
321
+ "margin": "20px auto", # Center horizontally
322
+ "padding": "20px", # Inner spacing
323
+ "background": "#ffffff", # White card
324
+ "borderRadius": "8px", # Rounded corners
325
+ "boxShadow": "0 2px 4px rgba(0,0,0,0.1)" # Subtle shadow
326
+ }}>
327
+ ```
328
+
329
+ This creates a "card" effect that looks modern and professional.
330
+
331
+ ### Spacing Between Components
332
+
333
+ We use `marginBottom` to add space between components:
334
+
335
+ ```jac
336
+ <h1 style={{"marginBottom": "20px"}}>My Todos</h1>
337
+ # 20px gap here
338
+ <TodoInput /> # Has marginBottom: "16px" in its style
339
+ # 16px gap here
340
+ <TodoFilters /> # Has marginBottom: "16px" in its style
341
+ # 16px gap here
342
+ <TodoList />
343
+ ```
344
+
345
+ This creates consistent vertical rhythm in your design.
346
+
347
+ ### Color Scheme
348
+
349
+ Our app uses a consistent color palette:
350
+
351
+ ```jac
352
+ {
353
+ "primary": "#3b82f6", # Blue (buttons, accents)
354
+ "danger": "#ef4444", # Red (delete button)
355
+ "background": "#ffffff", # White (main background)
356
+ "lightGray": "#f9fafb", # Light gray (stats footer)
357
+ "border": "#e5e7eb", # Gray border
358
+ "text": "#000", # Black text
359
+ "textMuted": "#999", # Gray text (completed todos)
360
+ "textLight": "#666" # Medium gray (stats)
361
+ }
362
+ ```
363
+
364
+ Using consistent colors makes your app look polished!
365
+
366
+ ---
367
+
368
+ ## ✅ What You've Learned
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
377
+
378
+ ---
379
+
380
+ ## 🐛 Common Issues
381
+
382
+ ### Issue: Components overlapping
383
+
384
+ **Solution**: Check that each component has proper margins/padding:
385
+
386
+ ```jac
387
+ <TodoInput /> # Add marginBottom
388
+ <TodoFilters /> # Add marginBottom
389
+ <TodoList />
390
+ ```
391
+
392
+ ### Issue: Layout looks broken
393
+
394
+ **Check:**
395
+ - Is `maxWidth` set on the container?
396
+ - Is `margin: "0 auto"` used for centering?
397
+ - Does the container have `padding`?
398
+
399
+ ### Issue: Empty state not showing
400
+
401
+ **Check**: Make sure you're returning ONLY the empty state when there are no todos:
402
+
403
+ ```jac
404
+ if not hasTodos {
405
+ return <div>Empty state</div>; # Return here, don't continue
406
+ }
407
+
408
+ return <div>Show todos</div>; # This only runs if hasTodos is true
409
+ ```
410
+
411
+ ---
412
+
413
+ ## 🎯 Quick Exercise
414
+
415
+ Try customizing your app:
416
+
417
+ **1. Change the color scheme:**
418
+
419
+ ```jac
420
+ # Change primary color from blue to purple
421
+ "background": "#8b5cf6" # Instead of "#3b82f6"
422
+ ```
423
+
424
+ **2. Add more mock todos:**
425
+
426
+ ```jac
427
+ def TodoList() -> any {
428
+ return <div>
429
+ <TodoItem text="Task 1" done={false} />
430
+ <TodoItem text="Task 2" done={true} />
431
+ <TodoItem text="Task 3" done={false} />
432
+ <TodoItem text="Task 4" done={false} />
433
+ <TodoItem text="Task 5" done={true} />
434
+ </div>;
435
+ }
436
+ ```
437
+
438
+ **3. Add a header:**
439
+
440
+ ```jac
441
+ def app() -> any {
442
+ return <div>
443
+ # Add a header
444
+ <div style={{
445
+ "textAlign": "center",
446
+ "padding": "20px",
447
+ "background": "#3b82f6",
448
+ "color": "white",
449
+ "marginBottom": "20px"
450
+ }}>
451
+ <h1 style={{"margin": "0"}}>📝 Todo App</h1>
452
+ <p style={{"margin": "5px 0 0 0"}}>Stay organized!</p>
453
+ </div>
454
+
455
+ # Main content
456
+ <div style={{
457
+ "maxWidth": "600px",
458
+ "margin": "0 auto",
459
+ "padding": "20px"
460
+ }}>
461
+ <TodoInput />
462
+ <TodoFilters />
463
+ <TodoList />
464
+ </div>
465
+ </div>;
466
+ }
467
+ ```
468
+
469
+ ---
470
+
471
+ ## ➡️ Next Step
472
+
473
+ Excellent! Your UI is complete and looks great. But it's all static - clicking buttons does nothing!
474
+
475
+ In the next step, we'll add **state** to make your app interactive!
476
+
477
+ 👉 **[Continue to Step 5: Local State](./step-05-local-state.md)**