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
jac_client/docs/README.md DELETED
@@ -1,689 +0,0 @@
1
- # Todo App - Beginner's Guide to Building with Jac
2
-
3
- Welcome to the Todo App example! This guide will walk you through building a full-stack web application with Jac, from setup to deployment. Jac simplifies web development by eliminating the need for separate frontend and backend technologies, HTTP clients, and complex build configurations.
4
-
5
- ---
6
-
7
- ## 1. Creating the Application
8
-
9
- ### Prerequisites
10
-
11
- Before installing Jac client, you need to have **Node.js** installed on your system.
12
-
13
- #### Installing Node.js
14
-
15
- **For Linux users:**
16
-
17
- Visit [https://nodejs.org/en/download](https://nodejs.org/en/download) and follow the instructions to install Node.js using **nvm** (Node Version Manager) with **npm**.
18
-
19
- Select:
20
- - **Platform**: Linux
21
- - **Package Manager**: nvm
22
- - **Package**: npm
23
-
24
- Then follow the installation commands provided on that page.
25
-
26
- **For macOS users:**
27
-
28
- Download and install Node.js from [https://nodejs.org/en/download](https://nodejs.org/en/download) by selecting your operating system.
29
-
30
- **Verify Installation:**
31
-
32
- After installation, verify Node.js and npm are installed correctly:
33
-
34
- ```bash
35
- node -v
36
- npm -v
37
- ```
38
-
39
- ### Installation
40
-
41
- Once Node.js is installed, install the Jac client package:
42
-
43
- ```bash
44
- pip install jac-client
45
- ```
46
-
47
- ### Create a New Jac App
48
-
49
- Use the `jac create_jac_app` command to scaffold a new application: (* we can name our app however we want, here we are using `todo-app)
50
-
51
- ```bash
52
- jac create_jac_app todo-app
53
- ```
54
-
55
- This command will:
56
- - Create a new directory with your project name
57
- - Set up the basic project structure
58
- - Initialize npm and install Vite (for development server)
59
- - Create a starter `app.jac` file with a sample component
60
-
61
- **What gets created:**
62
- ```
63
- my-app/
64
- ├── app.jac # Your main application file
65
- ├── package.json # Node.js dependencies
66
- └── node_modules/ # Dependencies (after npm install)
67
- ```
68
-
69
- ### Running Your App
70
-
71
- Navigate to your project directory and start the development server:
72
-
73
- ```bash
74
- cd todo-app
75
- jac serve app.jac
76
- ```
77
-
78
- This starts both:
79
- - **Backend server**: Handles your Jac graph operations and walkers
80
- - **Frontend development server**: Serves your React components
81
-
82
- You can access your app at `http://localhost:8000`
83
-
84
- ---
85
-
86
- ## 2. Entry Point of the App
87
-
88
- Every Jac client application needs an entry point function. This is where your app starts rendering.
89
-
90
- ### The `app()` Function
91
-
92
- Inside your `cl` block, define a function called `app()`:
93
-
94
- ```jac
95
- cl import from react {useState}
96
-
97
- cl {
98
- def app() -> any {
99
- let [count, setCount] = useState(0);
100
- return <div>
101
- <h1>Hello, World!</h1>
102
- <p>Count: {count}</p>
103
- <button onClick={lambda e: any -> None { setCount(count + 1); }}>
104
- Increment
105
- </button>
106
- </div>;
107
- }
108
- }
109
- ```
110
-
111
- **Key Points:**
112
- - `app()` is the **required entry point** that Jac looks for
113
- - It must be defined inside a `cl { }` block (client-side code)
114
- - The `cl` (client) block indicates this code runs in the browser
115
- - This function gets called automatically when the page loads
116
- - You can define other components and helper functions in the same `cl` block
117
-
118
- **Example with Multiple Components:**
119
- ```jac
120
- cl import from react {useState, useEffect}
121
-
122
- cl {
123
- def TodoList(todos: list) -> any {
124
- return <ul>
125
- {todos.map(lambda todo: any -> any {
126
- return <li key={todo._jac_id}>{todo.text}</li>;
127
- })}
128
- </ul>;
129
- }
130
-
131
- def app() -> any {
132
- let [todos, setTodos] = useState([]);
133
-
134
- useEffect(lambda -> None {
135
- async def loadTodos() -> None {
136
- result = root spawn read_todos();
137
- setTodos(result.reports if result.reports else []);
138
- }
139
- loadTodos();
140
- }, []);
141
-
142
- return <div>
143
- <h1>My Todos</h1>
144
- <TodoList todos={todos} />
145
- </div>;
146
- }
147
- }
148
- ```
149
-
150
- ---
151
-
152
- ## 3. Creating Components
153
-
154
- Components in Jac are functions that return JSX (JavaScript XML). They're similar to React components but written in pure Jac syntax.
155
-
156
- ### Basic Component Structure
157
-
158
- ```jac
159
- cl {
160
- def MyComponent() -> any {
161
- return <div>
162
- <h1>Hello from Jac!</h1>
163
- </div>;
164
- }
165
- }
166
- ```
167
-
168
- ### Component with Props
169
-
170
- Components can accept parameters (props):
171
-
172
- ```jac
173
- def TodoItem(item: dict) -> any {
174
- return <li key={item.id}>
175
- <span>{item.text}</span>
176
- <button onClick={lambda -> None { removeTodo(item.id); }}>
177
- Remove
178
- </button>
179
- </li>;
180
- }
181
- ```
182
-
183
- **Component Features:**
184
- - **JSX Syntax**: Write HTML-like syntax directly in Jac
185
- - **Inline Styles**: Use JavaScript objects for styling
186
- - **Event Handlers**: Attach functions to user interactions
187
- - **Reusability**: Components can call other components
188
-
189
- ### Example: TodoItem Component
190
-
191
- ```jac
192
- def TodoItem(item: dict) -> any {
193
- return <li key={item.id} style={{
194
- "display": "flex",
195
- "gap": "12px",
196
- "alignItems": "center",
197
- "padding": "12px",
198
- "background": "#FFFFFF",
199
- "borderRadius": "10px"
200
- }}>
201
- <input
202
- type="checkbox"
203
- checked={item.done}
204
- onChange={lambda -> None { toggleTodo(item.id); }}
205
- />
206
- <span style={{
207
- "textDecoration": ("line-through" if item.done else "none")
208
- }}>
209
- {item.text}
210
- </span>
211
- <button onClick={lambda -> None { removeTodo(item.id); }}>
212
- Remove
213
- </button>
214
- </li>;
215
- }
216
- ```
217
-
218
- **Breaking it down:**
219
- - `item: dict` - Component receives a dictionary (todo item) as a prop
220
- - `style={{...}}` - Inline styles using JavaScript objects
221
- - `checked={item.done}` - Dynamic attribute binding
222
- - `onChange={lambda -> None {...}}` - Event handler using lambda
223
- - `{item.text}` - Interpolation of JavaScript expressions in JSX
224
-
225
- ---
226
-
227
- ## 4. Adding State with React Hooks
228
-
229
- Jac uses React hooks for state management. You can use all standard React hooks by importing them:
230
-
231
- ```jac
232
- cl import from react { useState, useEffect }
233
-
234
- cl {
235
- def Counter() -> any {
236
- let [count, setCount] = useState(0);
237
-
238
- useEffect(lambda -> None {
239
- console.log("Count changed:", count);
240
- }, [count]);
241
-
242
- return <div>
243
- <h1>Count: {count}</h1>
244
- <button onClick={lambda e: any -> None {
245
- setCount(count + 1);
246
- }}>
247
- Increment
248
- </button>
249
- </div>;
250
- }
251
- }
252
- ```
253
-
254
- **Available React Hooks:**
255
- - `useState` - For state management
256
- - `useEffect` - For side effects
257
- - `useRef` - For refs
258
- - `useContext` - For context
259
- - `useCallback`, `useMemo` - For performance optimization
260
- - And more...
261
-
262
- ### State Management Example
263
-
264
- Here's a complete example showing state management in a todo app:
265
-
266
- ```jac
267
- cl import from react {useState, useEffect}
268
-
269
- cl {
270
- def app() -> any {
271
- let [todos, setTodos] = useState([]);
272
- let [input, setInput] = useState("");
273
- let [filter, setFilter] = useState("all");
274
-
275
- # Load todos on mount
276
- useEffect(lambda -> None {
277
- async def loadTodos() -> None {
278
- result = root spawn read_todos();
279
- setTodos(result.reports if result.reports else []);
280
- }
281
- loadTodos();
282
- }, []);
283
-
284
- # Add new todo
285
- async def addTodo() -> None {
286
- if not input.trim() { return; }
287
- response = root spawn create_todo(text=input.trim());
288
- new_todo = response.reports[0][0];
289
- setTodos(todos.concat([new_todo]));
290
- setInput("");
291
- }
292
-
293
- # Filter todos
294
- def getFilteredTodos() -> list {
295
- if filter == "active" {
296
- return todos.filter(lambda todo: any -> bool { return not todo.done; });
297
- } elif filter == "completed" {
298
- return todos.filter(lambda todo: any -> bool { return todo.done; });
299
- }
300
- return todos;
301
- }
302
-
303
- filteredTodos = getFilteredTodos();
304
-
305
- return <div>
306
- <h1>My Todos</h1>
307
- <input
308
- value={input}
309
- onChange={lambda e: any -> None { setInput(e.target.value); }}
310
- onKeyPress={lambda e: any -> None {
311
- if e.key == "Enter" { addTodo(); }
312
- }}
313
- />
314
- <button onClick={addTodo}>Add</button>
315
-
316
- <div>
317
- {filteredTodos.map(lambda todo: any -> any {
318
- return <div key={todo._jac_id}>
319
- <span>{todo.text}</span>
320
- </div>;
321
- })}
322
- </div>
323
- </div>;
324
- }
325
- }
326
- ```
327
-
328
- ---
329
-
330
- ## 5. Event Handling
331
-
332
- Event handling in Jac works just like React, but with Jac's lambda syntax.
333
-
334
- ### Basic Event Handlers
335
-
336
- ```jac
337
- def Button() -> any {
338
- return <button onClick={lambda -> None {
339
- console.log("Button clicked!");
340
- }}>
341
- Click Me
342
- </button>;
343
- }
344
- ```
345
-
346
- ### Event Handlers with Event Object
347
-
348
- ```jac
349
- def InputField() -> any {
350
- let [value, setValue] = useState("");
351
-
352
- return <input
353
- type="text"
354
- value={value}
355
- onChange={lambda e: any -> None {
356
- console.log("Input value:", e.target.value);
357
- setValue(e.target.value);
358
- }}
359
- />;
360
- }
361
- ```
362
-
363
- ### Form Submission
364
-
365
- ```jac
366
- def TodoForm() -> any {
367
- return <form onSubmit={onAddTodo}>
368
- <input id="todo-input" type="text" />
369
- <button type="submit">Add Todo</button>
370
- </form>;
371
- }
372
-
373
- async def onAddTodo(e: any) -> None {
374
- e.preventDefault(); # Prevent page refresh
375
- inputEl = document.getElementById("todo-input");
376
- text = inputEl.value.trim();
377
-
378
- if not text { return; }
379
-
380
- # Handle form submission
381
- response = root spawn create_todo(text=text);
382
- new_todo = response.reports[0][0];
383
- # ... update state
384
- }
385
- ```
386
-
387
- ### Common Event Types
388
-
389
- | Event | Syntax | Use Case |
390
- |-------|--------|----------|
391
- | `onClick` | `onClick={lambda -> None {...}}` | Button clicks |
392
- | `onChange` | `onChange={lambda e: any -> None {...}}` | Input changes |
393
- | `onSubmit` | `onSubmit={lambda e: any -> None {...}}` | Form submission |
394
- | `onKeyPress` | `onKeyPress={lambda e: any -> None {...}}` | Keyboard input |
395
-
396
- ### Advanced: Conditional Event Handlers
397
-
398
- ```jac
399
- def FilterButton(filterType: str, currentFilter: str, onFilterChange: any) -> any {
400
- isActive = currentFilter == filterType;
401
-
402
- return <button
403
- onClick={lambda -> None {
404
- onFilterChange(filterType);
405
- }}
406
- style={{
407
- "background": ("#7C3AED" if isActive else "#FFFFFF"),
408
- "color": ("#FFFFFF" if isActive else "#7C3AED")
409
- }}
410
- >
411
- {filterType}
412
- </button>;
413
- }
414
- ```
415
-
416
- ---
417
-
418
- ## 6. Magic: No More Axios/Fetch!
419
-
420
- One of Jac's most powerful features is **seamless backend communication** without writing HTTP requests, fetch calls, or axios code.
421
-
422
- ### The `spawn` Syntax
423
-
424
- Instead of writing:
425
- ```javascript
426
- // Traditional approach
427
- const response = await fetch('/api/todos', {
428
- method: 'POST',
429
- headers: { 'Content-Type': 'application/json' },
430
- body: JSON.stringify({ text: 'New todo' })
431
- });
432
- const data = await response.json();
433
- ```
434
-
435
- You simply write:
436
- ```jac
437
- response = root spawn create_todo(text="New todo");
438
- ```
439
-
440
- ### How `spawn` Works
441
-
442
- ```jac
443
- # Call a walker on a node
444
- result = node_reference spawn walker_name(parameters);
445
- ```
446
-
447
- **Syntax:**
448
- - `node_reference` - The node to spawn the walker on (commonly `root` for the root node, or a node ID)
449
- - `spawn` - The spawn keyword
450
- - `walker_name` - Name of the walker to execute
451
- - `parameters` - Parameters to pass to the walker (as function arguments)
452
-
453
- **Example from Todo App:**
454
- ```jac
455
- # Create a new todo (spawn on root node)
456
- response = root spawn create_todo(text=text);
457
-
458
- # Toggle todo status (spawn on specific todo node)
459
- id spawn toggle_todo();
460
-
461
- # Read all todos
462
- todos = root spawn read_todos();
463
- ```
464
-
465
- ### Backend Walkers
466
-
467
- Walkers are defined in the same `app.jac` file (outside the `cl` block):
468
-
469
- ```jac
470
- # Node definition (data model)
471
- node Todo {
472
- has text: str;
473
- has done: bool = False;
474
- }
475
-
476
- # Walker: Create a new todo
477
- walker create_todo {
478
- has text: str;
479
- can create with `root entry {
480
- new_todo = here ++> Todo(text=self.text);
481
- report new_todo;
482
- }
483
- }
484
-
485
- # Walker: Toggle todo status
486
- walker toggle_todo {
487
- can toggle with Todo entry {
488
- here.done = not here.done;
489
- report here;
490
- }
491
- }
492
-
493
- # Walker: Read all todos
494
- walker read_todos {
495
- can read with `root entry {
496
- visit [-->(`?Todo)];
497
- }
498
-
499
- can report_todos with exit {
500
- report here;
501
- }
502
- }
503
- ```
504
-
505
- ### Complete Example: Creating a Todo
506
-
507
- **Frontend (in `cl` block):**
508
- ```jac
509
- async def onAddTodo(e: any) -> None {
510
- e.preventDefault();
511
- text = document.getElementById("todo-input").value.trim();
512
- if not text { return; }
513
-
514
- # Call backend walker - no fetch/axios needed!
515
- response = root spawn create_todo(text=text);
516
- new_todo = response.reports[0][0];
517
-
518
- # Update frontend state
519
- s = todoState();
520
- newItem = {
521
- "id": new_todo._jac_id,
522
- "text": new_todo.text,
523
- "done": new_todo.done
524
- };
525
- setTodoState({"items": s.items.concat([newItem])});
526
- }
527
- ```
528
-
529
- **Backend (outside `cl` block):**
530
- ```jac
531
- walker create_todo {
532
- has text: str;
533
- can create with `root entry {
534
- # 'text' comes from the walker parameter
535
- new_todo = here ++> Todo(text=self.text);
536
- report new_todo;
537
- }
538
- }
539
- ```
540
-
541
- ### Benefits of `spawn`
542
-
543
- **No HTTP Configuration**: No need to set up API endpoints, CORS, or request/response formats
544
- **Type Safety**: Jac handles serialization automatically
545
- **Authentication**: Built-in token management via `jacLogin()` / `jacLogout()`
546
- **Error Handling**: Exceptions are properly propagated
547
- **Graph Operations**: Direct access to graph-based data operations
548
- **Less Code**: Eliminates boilerplate HTTP client code
549
- **Natural Syntax**: Call walkers on nodes using intuitive syntax
550
-
551
- ### Authentication Helpers
552
-
553
- Jac also provides built-in auth functions:
554
-
555
- ```jac
556
- # Sign up
557
- result = await jacSignup(username, password);
558
- if result["success"] {
559
- navigate("/todos");
560
- }
561
-
562
- # Log in
563
- success = await jacLogin(username, password);
564
- if success {
565
- navigate("/todos");
566
- }
567
-
568
- # Log out
569
- jacLogout();
570
- navigate("/login");
571
-
572
- # Check if logged in
573
- if jacIsLoggedIn() {
574
- return <div>Welcome!</div>;
575
- }
576
- ```
577
-
578
- ---
579
-
580
- ## Complete Example: Todo App Structure
581
-
582
- Here's how all the pieces fit together:
583
-
584
- ```jac
585
- # ============================================================================
586
- # BACKEND: Data Models and Walkers
587
- # ============================================================================
588
- node Todo {
589
- has text: str;
590
- has done: bool = False;
591
- }
592
-
593
- walker create_todo {
594
- has text: str;
595
- can create with `root entry {
596
- new_todo = here ++> Todo(text=self.text);
597
- report new_todo;
598
- }
599
- }
600
-
601
- # ============================================================================
602
- # FRONTEND: Components, State, and Events
603
- # ============================================================================
604
- cl import from react {useState}
605
-
606
- cl {
607
- def app() -> any {
608
- let [todos, setTodos] = useState([]);
609
- let [input, setInput] = useState("");
610
-
611
- # Event Handler
612
- async def addTodo() -> None {
613
- if not input.trim() { return; }
614
- response = root spawn create_todo(text=input.trim());
615
- new_todo = response.reports[0][0];
616
- setTodos(todos.concat([new_todo]));
617
- setInput("");
618
- }
619
-
620
- return <div>
621
- <h2>My Todos</h2>
622
- <input
623
- value={input}
624
- onChange={lambda e: any -> None { setInput(e.target.value); }}
625
- onKeyPress={lambda e: any -> None {
626
- if e.key == "Enter" { addTodo(); }
627
- }}
628
- />
629
- <button onClick={addTodo}>Add Todo</button>
630
-
631
- <div>
632
- {todos.map(lambda todo: any -> any {
633
- return <div key={todo._jac_id}>
634
- <span>{todo.text}</span>
635
- </div>;
636
- })}
637
- </div>
638
- </div>;
639
- }
640
- }
641
- ```
642
-
643
- ---
644
-
645
- ## Running the Todo App
646
-
647
- To run this example:
648
-
649
- ```bash
650
- # From the todo-app directory
651
- jac serve app.jac
652
- ```
653
-
654
- Then visit `http://localhost:8000` in your browser.
655
-
656
- ---
657
-
658
- ## Next Steps
659
-
660
- Ready to dive deeper? Explore these advanced topics:
661
-
662
- - **[Routing](routing.md)**: Build multi-page apps with declarative routing (`<Router>`, `<Routes>`, `<Route>`)
663
- - **[Lifecycle Hooks](lifecycle-hooks.md)**: Use `onMount()` and React hooks for initialization logic
664
- - **[Advanced State](advanced-state.md)**: Manage complex state with React hooks and context
665
- - **[Imports](imports.md)**: Import third-party libraries (React, Ant Design, Lodash), other Jac files, and JavaScript modules
666
- - **[Learn JAC](https://www.jac-lang.org)**: Explore Jac's graph-based data modeling
667
-
668
- ## Examples
669
-
670
- Check out the `examples/` directory for working applications:
671
-
672
- - **[basic](../../examples/basic/)**: Simple counter app using React hooks
673
- - **[with-router](../../examples/with-router/)**: Multi-page app with declarative routing
674
- - **[little-x](../../examples/little-x/)**: Social media app with third-party libraries
675
- - **[todo-app](../../examples/todo-app/)**: Full-featured todo app with authentication
676
- - **[basic-full-stack](../../examples/basic-full-stack/)**: Full-stack app with backend integration
677
-
678
- ---
679
-
680
- ## Key Takeaways
681
-
682
- 1. **Single Language**: Write frontend and backend in Jac
683
- 2. **No HTTP Client**: Use `spawn` syntax instead of fetch/axios
684
- 3. **Reactive State**: React hooks manage UI updates automatically
685
- 4. **Component-Based**: Build reusable UI components with JSX
686
- 5. **Type Safety**: Jac provides type checking across frontend and backend
687
- 6. **Graph Database**: Built-in graph data model eliminates need for SQL/NoSQL
688
-
689
- Happy coding with Jac!