round-core 0.0.1

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.
package/README.md ADDED
@@ -0,0 +1,354 @@
1
+ <h1 align="center">Round Framework</h1>
2
+
3
+ <p align="center">
4
+ <img src="https://raw.githubusercontent.com/ZtaMDev/RoundJS/main/Round.png" alt="Dars Framework Logo" width="200" />
5
+ </p>
6
+
7
+ <p align="center">
8
+ <img src="https://img.shields.io/npm/v/round-core?color=brightgreen" alt="PyPI Version" />
9
+ </p>
10
+
11
+ <p align="center">
12
+ <em>Round is a lightweight frontend framework focused on building <b>single-page applications (SPAs)</b> with <b>fine‑grained reactivity.</b></em>
13
+ </p>
14
+
15
+ ```bash
16
+ npm install round-core
17
+ ```
18
+
19
+ Instead of a Virtual DOM diff, Round updates the UI by subscribing DOM updates directly to reactive primitives (**signals**). This keeps rendering predictable, small, and fast for interactive apps.
20
+
21
+ ## What Round is focused on
22
+
23
+ - **SPA-first**: client-side navigation and UI updates.
24
+ - **Fine-grained reactivity**: update only what depends on the changed signal.
25
+ - **Ergonomic bindings**: built-in two-way bindings with `bind:*` directives.
26
+ - **A JSX superset**: `.round` files support extra control-flow syntax that compiles to JavaScript.
27
+ - **Minimal runtime**: DOM-first runtime (no VDOM diffing).
28
+
29
+ ## Concepts
30
+
31
+ ### SPA
32
+
33
+ A **Single Page Application (SPA)** loads one HTML page and then updates the UI dynamically as the user navigates and interacts—without full page reloads.
34
+
35
+ ### Fine-grained reactivity (signals)
36
+
37
+ A **signal** is a small reactive container.
38
+
39
+ - Reading a signal inside an `effect()` tracks a dependency.
40
+ - Writing to a signal triggers only the subscribed computations.
41
+
42
+
43
+ ## Normal Installation
44
+
45
+ Simply install the `round-core` package
46
+
47
+ ```bash
48
+ bun add round-core
49
+ ```
50
+
51
+ Or:
52
+
53
+ ```bash
54
+ npm install round-core
55
+ ```
56
+
57
+ ## Repo Installation
58
+
59
+ > Round is currently in active development. If you are using the repository directly, install dependencies and run the CLI locally.
60
+
61
+ ```bash
62
+ bun install
63
+ ```
64
+
65
+ Or:
66
+
67
+ ```bash
68
+ npm install
69
+ ```
70
+
71
+ ## Quick start (create a new app)
72
+
73
+ Round includes a CLI with a project initializer.
74
+
75
+ ```bash
76
+ round init myapp
77
+ cd myapp
78
+ npm install
79
+ npm run dev
80
+ ```
81
+
82
+ This scaffolds a minimal Round app with `src/app.round` and an example `src/counter.round`.
83
+
84
+ ## `.round` files
85
+
86
+ A `.round` file is a JSX-based component module (ESM) compiled by the Round toolchain.
87
+
88
+ Example `src/app.round`:
89
+
90
+ ```jsx
91
+ import { Route } from 'round-core';
92
+ import { Counter } from './counter';
93
+
94
+ export default function App() {
95
+ return (
96
+ <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
97
+ <Route route="/" title="Home">
98
+ <Counter />
99
+ </Route>
100
+ </div>
101
+ );
102
+ }
103
+ ```
104
+
105
+ ## Core API
106
+
107
+ ### `signal(initialValue)`
108
+
109
+ Create a reactive signal.
110
+
111
+ - Call with no arguments to **read**.
112
+ - Call with one argument to **write**.
113
+ - Use `.value` to read/write the current value in a non-subscribing way (static access).
114
+
115
+ ```jsx
116
+ import { signal } from 'round-core';
117
+
118
+ export function Counter() {
119
+ const count = signal(0);
120
+
121
+ return (
122
+ <div>
123
+ <h1>Count: {count()}</h1>
124
+ <button onClick={() => count(count() + 1)}>Increment</button>
125
+ </div>
126
+ );
127
+ }
128
+ ```
129
+
130
+ ### `effect(fn)`
131
+
132
+ Run `fn` whenever the signals it reads change.
133
+
134
+ ```js
135
+ import { signal, effect } from 'round-core';
136
+
137
+ const name = signal('Ada');
138
+
139
+ effect(() => {
140
+ console.log('Name changed:', name());
141
+ });
142
+
143
+ name('Grace');
144
+ ```
145
+
146
+ ### `bindable(initialValue)`
147
+
148
+ `bindable()` creates a signal intended for **two-way DOM bindings**.
149
+
150
+ ```jsx
151
+ import { bindable } from 'round-core';
152
+
153
+ export function Example() {
154
+ const email = bindable('');
155
+
156
+ return (
157
+ <div>
158
+ <input bind:value={email} placeholder="Email" />
159
+ <div>Typed: {email()}</div>
160
+ </div>
161
+ );
162
+ }
163
+ ```
164
+
165
+ ### `bindable.object(initialObject)` and deep binding
166
+
167
+ Round supports object-shaped state with ergonomic deep bindings via proxies.
168
+
169
+ ```jsx
170
+ import { bindable } from 'round-core';
171
+
172
+ export function Profile() {
173
+ const user = bindable.object({
174
+ profile: { bio: '' },
175
+ flags: { newsletter: false }
176
+ });
177
+
178
+ return (
179
+ <div>
180
+ <textarea bind:value={user.profile.bio} />
181
+ <label>
182
+ <input type="checkbox" bind:checked={user.flags.newsletter} />
183
+ Subscribe
184
+ </label>
185
+ </div>
186
+ );
187
+ }
188
+ ```
189
+
190
+ ### `$pick(path)`
191
+
192
+ Create a view signal from a signal/bindable that holds an object.
193
+
194
+ ```js
195
+ import { bindable } from 'round-core';
196
+
197
+ const user = bindable({ profile: { bio: 'Hello' } });
198
+ const bio = user.$pick('profile.bio');
199
+
200
+ console.log(bio());
201
+ ```
202
+
203
+ ### `.transform(fromInput, toOutput)`
204
+
205
+ Transform a signal/bindable to adapt between DOM values (often strings) and your internal representation.
206
+
207
+ ```jsx
208
+ import { bindable } from 'round-core';
209
+
210
+ export function AgeField() {
211
+ const age = bindable('18')
212
+ .transform(
213
+ (str) => Math.max(0, parseInt(str, 10) || 0),
214
+ (num) => String(num)
215
+ );
216
+
217
+ return <input type="number" bind:value={age} />;
218
+ }
219
+ ```
220
+
221
+ ### `.validate(validator, options)`
222
+
223
+ Attach validation to a signal/bindable.
224
+
225
+ - Invalid writes do not update the underlying value.
226
+ - `signal.error` is itself a signal (reactive) containing the current error message or `null`.
227
+ - `options.validateOn` can be `'input'` (default) or `'blur'`.
228
+ - `options.validateInitial` can trigger validation on startup.
229
+
230
+ ```jsx
231
+ import { bindable } from 'round-core';
232
+
233
+ export function EmailField() {
234
+ const email = bindable('')
235
+ .validate(
236
+ (v) => v.includes('@') || 'Invalid email',
237
+ { validateOn: 'blur' }
238
+ );
239
+
240
+ return (
241
+ <div>
242
+ <input bind:value={email} placeholder="name@example.com" />
243
+ <div style={() => ({ color: email.error() ? 'crimson' : '#666' })}>
244
+ {email.error}
245
+ </div>
246
+ </div>
247
+ );
248
+ }
249
+ ```
250
+
251
+ ## DOM binding directives
252
+
253
+ Round supports two-way bindings via props:
254
+
255
+ - `bind:value={someBindable}` for text-like inputs, `<textarea>`, and `<select>`.
256
+ - `bind:checked={someBindable}` for `<input type="checkbox">` and `<input type="radio">`.
257
+
258
+ Round will warn if the value is not signal-like, and will warn if you bind a plain `signal()` instead of a `bindable()`.
259
+
260
+ ## JSX superset control flow
261
+
262
+ Round extends JSX inside `.round` files with a control-flow syntax that compiles to JavaScript.
263
+
264
+ ### `if / else if / else`
265
+
266
+ ```jsx
267
+ {if(user.loggedIn){
268
+ <Dashboard />
269
+ } else if(user.loading){
270
+ <div>Loading...</div>
271
+ } else {
272
+ <Login />
273
+ }}
274
+ ```
275
+
276
+ Notes:
277
+
278
+ - Conditions may be normal JS expressions.
279
+ - For *simple paths* like `flags.showCounter` (identifier/member paths), Round will auto-unwrap signal-like values (call them) so the condition behaves as expected.
280
+
281
+ ### `for (... in ...)`
282
+
283
+ ```jsx
284
+ {for(item in items){
285
+ <div className="row">{item}</div>
286
+ }}
287
+ ```
288
+
289
+ This compiles roughly to a `.map(...)` under the hood.
290
+
291
+ ## Rendering model (no VDOM)
292
+
293
+ Round renders to the DOM directly using a small runtime:
294
+
295
+ - Elements are created with `document.createElement(...)`.
296
+ - Dynamic children and reactive props are updated via `effect()` subscriptions.
297
+ - Components are functions returning DOM nodes (or arrays of nodes).
298
+
299
+ This is a **DOM-first, fine-grained reactive model**, rather than a Virtual DOM diffing renderer.
300
+
301
+ ## Routing
302
+
303
+ Round includes router primitives intended for SPA navigation.
304
+
305
+ Typical usage:
306
+
307
+ ```jsx
308
+ import { Route } from 'round-core';
309
+
310
+ export default function App() {
311
+ return (
312
+ <div>
313
+ <Route route="/" title="Home">
314
+ <div>Home</div>
315
+ </Route>
316
+ <Route route="/about" title="About">
317
+ <div>About</div>
318
+ </Route>
319
+ </div>
320
+ );
321
+ }
322
+ ```
323
+
324
+ ## Suspense and lazy loading
325
+
326
+ Round supports `Suspense` for promise-based rendering and `lazy()` for code splitting.
327
+
328
+ (These APIs are evolving; expect improvements as Round’s compiler and runtime expand.)
329
+
330
+ ## Error handling
331
+
332
+ Round aims to provide strong developer feedback:
333
+
334
+ - Runtime error reporting with safe boundaries.
335
+ - `ErrorBoundary` to catch render-time errors and show a fallback.
336
+
337
+ ## CLI
338
+
339
+ The CLI is intended for day-to-day development:
340
+
341
+ - `round dev`
342
+ - `round build`
343
+ - `round preview`
344
+ - `round init <name>`
345
+
346
+ Run `round -h` to see available commands.
347
+
348
+ ## Status
349
+
350
+ Round is under active development and the API is still stabilizing. The README is currently the primary documentation; a dedicated documentation site will be built later using Round itself.
351
+
352
+ ## License
353
+
354
+ MIT
package/Round.png ADDED
Binary file