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.
- jac_client/examples/all-in-one/assets/workers/worker.py +5 -0
- jac_client/examples/all-in-one/src/app.jac +841 -0
- jac_client/examples/all-in-one/{button.jac → src/button.jac} +1 -1
- jac_client/examples/all-in-one/{components → src/components}/button.jac +1 -1
- jac_client/examples/asset-serving/css-with-image/{app.jac → src/app.jac} +2 -2
- jac_client/examples/asset-serving/image-asset/{app.jac → src/app.jac} +2 -2
- jac_client/examples/asset-serving/import-alias/{app.jac → src/app.jac} +7 -7
- jac_client/examples/basic/{app.jac → src/app.jac} +2 -2
- jac_client/examples/basic-auth/src/app.jac +377 -0
- jac_client/examples/basic-auth-with-router/{app.jac → src/app.jac} +18 -18
- jac_client/examples/basic-full-stack/{app.jac → src/app.jac} +175 -130
- jac_client/examples/css-styling/js-styling/{app.jac → src/app.jac} +6 -6
- jac_client/examples/css-styling/material-ui/{app.jac → src/app.jac} +5 -5
- jac_client/examples/css-styling/pure-css/{app.jac → src/app.jac} +6 -6
- jac_client/examples/css-styling/sass-example/{app.jac → src/app.jac} +6 -6
- jac_client/examples/css-styling/styled-components/{app.jac → src/app.jac} +5 -5
- jac_client/examples/css-styling/tailwind-example/{app.jac → src/app.jac} +6 -6
- jac_client/examples/full-stack-with-auth/{app.jac → src/app.jac} +37 -37
- jac_client/examples/little-x/{app.jac → src/app.jac} +27 -32
- jac_client/examples/little-x/src/submit-button.jac +16 -0
- jac_client/examples/nested-folders/nested-advance/{ButtonRoot.jac → src/ButtonRoot.jac} +1 -1
- jac_client/examples/nested-folders/nested-advance/{app.jac → src/app.jac} +1 -1
- jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/ButtonSecondL.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/Card.jac +1 -1
- jac_client/examples/nested-folders/nested-advance/{level1 → src/level1}/level2/ButtonThirdL.jac +1 -1
- jac_client/examples/nested-folders/nested-basic/{app.jac → src/app.jac} +2 -2
- jac_client/examples/nested-folders/nested-basic/{button.jac → src/button.jac} +1 -1
- jac_client/examples/nested-folders/nested-basic/{components → src/components}/button.jac +1 -1
- jac_client/examples/ts-support/src/app.jac +35 -0
- jac_client/examples/with-router/{app.jac → src/app.jac} +11 -11
- jac_client/plugin/cli.jac +547 -0
- jac_client/plugin/client.jac +52 -0
- jac_client/plugin/client_runtime.cl.jac +38 -0
- jac_client/plugin/impl/client.impl.jac +134 -0
- jac_client/plugin/impl/client_runtime.impl.jac +177 -0
- jac_client/plugin/impl/vite_client_bundle.impl.jac +72 -0
- jac_client/plugin/plugin_config.jac +195 -0
- jac_client/plugin/src/__init__.jac +20 -0
- jac_client/plugin/src/asset_processor.jac +33 -0
- jac_client/plugin/src/babel_processor.jac +18 -0
- jac_client/plugin/src/compiler.jac +66 -0
- jac_client/plugin/src/config_loader.jac +32 -0
- jac_client/plugin/src/impl/asset_processor.impl.jac +127 -0
- jac_client/plugin/src/impl/babel_processor.impl.jac +84 -0
- jac_client/plugin/src/impl/compiler.impl.jac +251 -0
- jac_client/plugin/src/impl/config_loader.impl.jac +119 -0
- jac_client/plugin/src/impl/import_processor.impl.jac +33 -0
- jac_client/plugin/src/impl/jac_to_js.impl.jac +41 -0
- jac_client/plugin/src/impl/package_installer.impl.jac +105 -0
- jac_client/plugin/src/impl/vite_bundler.impl.jac +513 -0
- jac_client/plugin/src/import_processor.jac +19 -0
- jac_client/plugin/src/jac_to_js.jac +35 -0
- jac_client/plugin/src/package_installer.jac +26 -0
- jac_client/plugin/src/vite_bundler.jac +36 -0
- jac_client/plugin/vite_client_bundle.jac +31 -0
- jac_client/tests/conftest.py +281 -0
- jac_client/tests/fixtures/basic-app/app.jac +2 -2
- jac_client/tests/fixtures/cl_file/app.cl.jac +2 -2
- jac_client/tests/fixtures/client_app_with_antd/app.jac +1 -1
- jac_client/tests/fixtures/js_import/app.jac +5 -5
- jac_client/tests/fixtures/spawn_test/app.jac +7 -7
- jac_client/tests/fixtures/with-ts/app.jac +35 -0
- jac_client/tests/test_cli.py +755 -0
- jac_client/tests/test_it.py +347 -67
- {jac_client-0.2.2.dist-info → jac_client-0.2.6.dist-info}/METADATA +30 -24
- jac_client-0.2.6.dist-info/RECORD +74 -0
- {jac_client-0.2.2.dist-info → jac_client-0.2.6.dist-info}/WHEEL +2 -1
- jac_client-0.2.6.dist-info/entry_points.txt +4 -0
- jac_client-0.2.6.dist-info/top_level.txt +1 -0
- jac_client/docs/README.md +0 -689
- jac_client/docs/advanced-state.md +0 -1265
- jac_client/docs/asset-serving/intro.md +0 -209
- jac_client/docs/assets/pipe_line-v2.svg +0 -32
- jac_client/docs/assets/pipe_line.png +0 -0
- jac_client/docs/file-system/app.jac.md +0 -121
- jac_client/docs/file-system/backend-frontend.md +0 -217
- jac_client/docs/file-system/intro.md +0 -72
- jac_client/docs/file-system/nested-imports.md +0 -348
- jac_client/docs/guide-example/intro.md +0 -115
- jac_client/docs/guide-example/step-01-setup.md +0 -270
- jac_client/docs/guide-example/step-02-components.md +0 -416
- jac_client/docs/guide-example/step-03-styling.md +0 -478
- jac_client/docs/guide-example/step-04-todo-ui.md +0 -477
- jac_client/docs/guide-example/step-05-local-state.md +0 -530
- jac_client/docs/guide-example/step-06-events.md +0 -749
- jac_client/docs/guide-example/step-07-effects.md +0 -468
- jac_client/docs/guide-example/step-08-walkers.md +0 -534
- jac_client/docs/guide-example/step-09-authentication.md +0 -586
- jac_client/docs/guide-example/step-10-routing.md +0 -539
- jac_client/docs/guide-example/step-11-final.md +0 -963
- jac_client/docs/imports.md +0 -1141
- jac_client/docs/lifecycle-hooks.md +0 -773
- jac_client/docs/routing.md +0 -659
- jac_client/docs/styling/intro.md +0 -249
- jac_client/docs/styling/js-styling.md +0 -367
- jac_client/docs/styling/material-ui.md +0 -341
- jac_client/docs/styling/pure-css.md +0 -299
- jac_client/docs/styling/sass.md +0 -403
- jac_client/docs/styling/styled-components.md +0 -395
- jac_client/docs/styling/tailwind.md +0 -298
- jac_client/examples/all-in-one/.babelrc +0 -9
- jac_client/examples/all-in-one/README.md +0 -16
- jac_client/examples/all-in-one/app.jac +0 -426
- jac_client/examples/all-in-one/assets/burger.png +0 -0
- jac_client/examples/all-in-one/package.json +0 -29
- jac_client/examples/all-in-one/styles.css +0 -26
- jac_client/examples/all-in-one/vite.config.js +0 -28
- jac_client/examples/asset-serving/css-with-image/.babelrc +0 -9
- jac_client/examples/asset-serving/css-with-image/README.md +0 -91
- jac_client/examples/asset-serving/css-with-image/assets/burger.png +0 -0
- jac_client/examples/asset-serving/css-with-image/package.json +0 -28
- jac_client/examples/asset-serving/css-with-image/styles.css +0 -26
- jac_client/examples/asset-serving/css-with-image/vite.config.js +0 -28
- jac_client/examples/asset-serving/image-asset/.babelrc +0 -9
- jac_client/examples/asset-serving/image-asset/README.md +0 -119
- jac_client/examples/asset-serving/image-asset/assets/burger.png +0 -0
- jac_client/examples/asset-serving/image-asset/package.json +0 -28
- jac_client/examples/asset-serving/image-asset/styles.css +0 -26
- jac_client/examples/asset-serving/image-asset/vite.config.js +0 -28
- jac_client/examples/asset-serving/import-alias/.babelrc +0 -9
- jac_client/examples/asset-serving/import-alias/README.md +0 -83
- jac_client/examples/asset-serving/import-alias/assets/burger.png +0 -0
- jac_client/examples/asset-serving/import-alias/package.json +0 -28
- jac_client/examples/asset-serving/import-alias/vite.config.js +0 -28
- jac_client/examples/basic/.babelrc +0 -9
- jac_client/examples/basic/README.md +0 -16
- jac_client/examples/basic/package.json +0 -27
- jac_client/examples/basic/vite.config.js +0 -27
- jac_client/examples/basic-auth/.babelrc +0 -9
- jac_client/examples/basic-auth/README.md +0 -16
- jac_client/examples/basic-auth/app.jac +0 -308
- jac_client/examples/basic-auth/package.json +0 -27
- jac_client/examples/basic-auth/vite.config.js +0 -27
- jac_client/examples/basic-auth-with-router/.babelrc +0 -9
- jac_client/examples/basic-auth-with-router/README.md +0 -60
- jac_client/examples/basic-auth-with-router/package.json +0 -28
- jac_client/examples/basic-auth-with-router/vite.config.js +0 -27
- jac_client/examples/basic-full-stack/.babelrc +0 -9
- jac_client/examples/basic-full-stack/README.md +0 -18
- jac_client/examples/basic-full-stack/package.json +0 -28
- jac_client/examples/basic-full-stack/vite.config.js +0 -27
- jac_client/examples/css-styling/js-styling/.babelrc +0 -9
- jac_client/examples/css-styling/js-styling/README.md +0 -183
- jac_client/examples/css-styling/js-styling/package.json +0 -28
- jac_client/examples/css-styling/js-styling/styles.js +0 -100
- jac_client/examples/css-styling/js-styling/vite.config.js +0 -27
- jac_client/examples/css-styling/material-ui/.babelrc +0 -9
- jac_client/examples/css-styling/material-ui/README.md +0 -16
- jac_client/examples/css-styling/material-ui/package.json +0 -32
- jac_client/examples/css-styling/material-ui/vite.config.js +0 -27
- jac_client/examples/css-styling/pure-css/.babelrc +0 -9
- jac_client/examples/css-styling/pure-css/README.md +0 -16
- jac_client/examples/css-styling/pure-css/package.json +0 -28
- jac_client/examples/css-styling/pure-css/styles.css +0 -111
- jac_client/examples/css-styling/pure-css/vite.config.js +0 -27
- jac_client/examples/css-styling/sass-example/.babelrc +0 -9
- jac_client/examples/css-styling/sass-example/README.md +0 -16
- jac_client/examples/css-styling/sass-example/package.json +0 -29
- jac_client/examples/css-styling/sass-example/styles.scss +0 -153
- jac_client/examples/css-styling/sass-example/vite.config.js +0 -27
- jac_client/examples/css-styling/styled-components/.babelrc +0 -9
- jac_client/examples/css-styling/styled-components/README.md +0 -16
- jac_client/examples/css-styling/styled-components/package.json +0 -29
- jac_client/examples/css-styling/styled-components/styled.js +0 -90
- jac_client/examples/css-styling/styled-components/vite.config.js +0 -27
- jac_client/examples/css-styling/tailwind-example/.babelrc +0 -9
- jac_client/examples/css-styling/tailwind-example/README.md +0 -16
- jac_client/examples/css-styling/tailwind-example/global.css +0 -1
- jac_client/examples/css-styling/tailwind-example/package.json +0 -30
- jac_client/examples/css-styling/tailwind-example/vite.config.js +0 -29
- jac_client/examples/full-stack-with-auth/.babelrc +0 -9
- jac_client/examples/full-stack-with-auth/README.md +0 -16
- jac_client/examples/full-stack-with-auth/package.json +0 -28
- jac_client/examples/full-stack-with-auth/vite.config.js +0 -29
- jac_client/examples/little-x/package.json +0 -23
- jac_client/examples/little-x/submit-button.jac +0 -8
- jac_client/examples/nested-folders/nested-advance/.babelrc +0 -9
- jac_client/examples/nested-folders/nested-advance/README.md +0 -77
- jac_client/examples/nested-folders/nested-advance/package.json +0 -29
- jac_client/examples/nested-folders/nested-advance/vite.config.js +0 -28
- jac_client/examples/nested-folders/nested-basic/.babelrc +0 -9
- jac_client/examples/nested-folders/nested-basic/README.md +0 -183
- jac_client/examples/nested-folders/nested-basic/app.js +0 -7
- jac_client/examples/nested-folders/nested-basic/package.json +0 -28
- jac_client/examples/nested-folders/nested-basic/vite.config.js +0 -27
- jac_client/examples/with-router/.babelrc +0 -9
- jac_client/examples/with-router/README.md +0 -17
- jac_client/examples/with-router/package.json +0 -28
- jac_client/examples/with-router/vite.config.js +0 -27
- jac_client/plugin/cli.py +0 -244
- jac_client/plugin/client.py +0 -152
- jac_client/plugin/client_runtime.jac +0 -234
- jac_client/plugin/vite_client_bundle.py +0 -503
- jac_client/tests/fixtures/js_import/utils.js +0 -21
- jac_client/tests/fixtures/package-lock.json +0 -329
- jac_client/tests/fixtures/package.json +0 -11
- jac_client/tests/test_asset_examples.py +0 -322
- jac_client/tests/test_cl.py +0 -530
- jac_client/tests/test_create_jac_app.py +0 -131
- jac_client/tests/test_nested_file.py +0 -374
- jac_client-0.2.2.dist-info/RECORD +0 -171
- jac_client-0.2.2.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)**
|