@minejs/jsx 0.0.5 → 0.0.7
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 +11 -574
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/{jsx-dev-runtime-Cf8gl1gB.d.cts → jsx-dev-runtime-BcuwRgdf.d.cts} +7 -9
- package/dist/{jsx-dev-runtime-Cf8gl1gB.d.ts → jsx-dev-runtime-BcuwRgdf.d.ts} +7 -9
- package/dist/jsx-dev-runtime.cjs +1 -1
- package/dist/jsx-dev-runtime.cjs.map +1 -1
- package/dist/jsx-dev-runtime.d.cts +1 -1
- package/dist/jsx-dev-runtime.d.ts +1 -1
- package/dist/jsx-dev-runtime.js +1 -1
- package/dist/jsx-dev-runtime.js.map +1 -1
- package/dist/jsx-runtime.cjs +1 -1
- package/dist/jsx-runtime.cjs.map +1 -1
- package/dist/jsx-runtime.d.cts +1 -1
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/dist/jsx-runtime.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
</div>
|
|
9
9
|
|
|
10
10
|
<div align="center">
|
|
11
|
-
<img src="https://img.shields.io/badge/v-0.0.
|
|
11
|
+
<img src="https://img.shields.io/badge/v-0.0.7-black"/>
|
|
12
12
|
<img src="https://img.shields.io/badge/🔥-@minejs-black"/>
|
|
13
13
|
<br>
|
|
14
|
-
<img src="https://img.shields.io/badge/coverage-
|
|
14
|
+
<img src="https://img.shields.io/badge/coverage-98.78%25-brightgreen" alt="Test Coverage" />
|
|
15
15
|
<img src="https://img.shields.io/github/issues/minejs-org/jsx?style=flat" alt="Github Repo Issues" />
|
|
16
16
|
<img src="https://img.shields.io/github/stars/minejs-org/jsx?style=social" alt="GitHub Repo stars" />
|
|
17
17
|
</div>
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
- ## Quick Start 🔥
|
|
27
27
|
|
|
28
|
-
>
|
|
28
|
+
> Lightweight JSX runtime with fine-grained reactivity..
|
|
29
29
|
|
|
30
30
|
- ### Setup
|
|
31
31
|
|
|
@@ -40,7 +40,10 @@
|
|
|
40
40
|
- ### Usage
|
|
41
41
|
|
|
42
42
|
```ts
|
|
43
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
jsx, Fragment,
|
|
45
|
+
Show, For, render, mount, createRoot
|
|
46
|
+
} from '@minejs/jsx'
|
|
44
47
|
import { signal } from '@minejs/signals'
|
|
45
48
|
```
|
|
46
49
|
|
|
@@ -88,583 +91,17 @@
|
|
|
88
91
|
})
|
|
89
92
|
```
|
|
90
93
|
|
|
91
|
-
- ### 4. Control Flow Components
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
const isVisible = signal(true)
|
|
95
|
-
const items = signal(['Apple', 'Banana', 'Orange'])
|
|
96
|
-
|
|
97
|
-
// Conditional rendering
|
|
98
|
-
const conditional = Show({
|
|
99
|
-
when: isVisible(),
|
|
100
|
-
children: jsx('div', { children: 'Visible!' })
|
|
101
|
-
})
|
|
102
|
-
|
|
103
|
-
// List rendering
|
|
104
|
-
const list = For({
|
|
105
|
-
each: items(),
|
|
106
|
-
children: (item) => jsx('li', { children: item })
|
|
107
|
-
})
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
|
|
111
94
|
<br>
|
|
112
95
|
|
|
113
96
|
- ## API Reference 🔥
|
|
114
97
|
|
|
115
|
-
- #### `
|
|
116
|
-
> Create a DOM element from JSX or component function.
|
|
117
|
-
|
|
118
|
-
```typescript
|
|
119
|
-
// HTML element
|
|
120
|
-
const div = jsx('div', {
|
|
121
|
-
className: 'box',
|
|
122
|
-
children: 'Content'
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
// Component
|
|
126
|
-
const Greeting = (props) => jsx('h1', { children: `Hello, ${props.name}!` })
|
|
127
|
-
const greeting = jsx(Greeting, { name: 'John' })
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
- #### `jsxs(type: string | ComponentFunction, props: JSXProps | null): JSXElement`
|
|
131
|
-
|
|
132
|
-
> Alias for jsx(). Used by TypeScript JSX transform for multiple children.
|
|
133
|
-
|
|
134
|
-
```typescript
|
|
135
|
-
const el = jsxs('div', {
|
|
136
|
-
children: [
|
|
137
|
-
jsx('h1', { children: 'Title' }),
|
|
138
|
-
jsx('p', { children: 'Paragraph' })
|
|
139
|
-
]
|
|
140
|
-
})
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
- #### `Fragment(props: { children?: any }): DocumentFragment`
|
|
144
|
-
|
|
145
|
-
> Create a DocumentFragment to group elements without wrapper.
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
const frag = Fragment({
|
|
149
|
-
children: [
|
|
150
|
-
jsx('div', { children: 'First' }),
|
|
151
|
-
jsx('div', { children: 'Second' })
|
|
152
|
-
]
|
|
153
|
-
})
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
- #### `component<P = any>(fn: (props: P) => JSXElement | null): ComponentFunction<P>`
|
|
157
|
-
|
|
158
|
-
> Create a component from a function.
|
|
159
|
-
|
|
160
|
-
```typescript
|
|
161
|
-
const Button = component<{ label: string }>((props) => {
|
|
162
|
-
return jsx('button', { children: props.label })
|
|
163
|
-
})
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
- #### `defineComponent<P = any>(setup: (props: P) => () => JSXElement | null): ComponentFunction<P>`
|
|
167
|
-
|
|
168
|
-
> Create a component with setup function (like Vue Composition API).
|
|
169
|
-
|
|
170
|
-
```typescript
|
|
171
|
-
const Counter = defineComponent((props) => {
|
|
172
|
-
const count = signal(0)
|
|
173
|
-
|
|
174
|
-
return () => jsx('div', {
|
|
175
|
-
children: `Count: ${count()}`
|
|
176
|
-
})
|
|
177
|
-
})
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
- #### `Show(props: { when: boolean | Signal<boolean>, children: any }): JSXElement | null`
|
|
181
|
-
|
|
182
|
-
> Conditional rendering based on boolean condition.
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
const isLoggedIn = signal(false)
|
|
186
|
-
|
|
187
|
-
Show({
|
|
188
|
-
when: isLoggedIn(),
|
|
189
|
-
children: jsx('div', { children: 'Welcome back!' })
|
|
190
|
-
})
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
- #### `Switch(props: { children: { when: boolean | Signal<boolean>, children: any }[] }): JSXElement | null`
|
|
194
|
-
|
|
195
|
-
> Render first matching condition.
|
|
196
|
-
|
|
197
|
-
```typescript
|
|
198
|
-
const status = signal('loading')
|
|
199
|
-
|
|
200
|
-
Switch({
|
|
201
|
-
children: [
|
|
202
|
-
{ when: status() === 'loading', children: jsx('div', { children: 'Loading...' }) },
|
|
203
|
-
{ when: status() === 'error', children: jsx('div', { children: 'Error!' }) },
|
|
204
|
-
{ when: status() === 'success', children: jsx('div', { children: 'Success!' }) }
|
|
205
|
-
]
|
|
206
|
-
})
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
- #### `For<T>(props: { each: T[] | Signal<T[]>, children: (item: T, index: number) => JSXElement }): JSXElement`
|
|
210
|
-
|
|
211
|
-
> Render list of items.
|
|
212
|
-
|
|
213
|
-
```typescript
|
|
214
|
-
const todos = signal([
|
|
215
|
-
{ id: 1, text: 'Learn JSX' },
|
|
216
|
-
{ id: 2, text: 'Build app' }
|
|
217
|
-
])
|
|
218
|
-
|
|
219
|
-
For({
|
|
220
|
-
each: todos(),
|
|
221
|
-
children: (todo) => jsx('li', { children: todo.text })
|
|
222
|
-
})
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
- #### `createElements(elements: any[]): DocumentFragment`
|
|
226
|
-
|
|
227
|
-
> Create multiple elements at once.
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
const fragment = createElements([
|
|
231
|
-
jsx('div', null),
|
|
232
|
-
jsx('span', null),
|
|
233
|
-
jsx('button', null)
|
|
234
|
-
])
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
- #### `render(component: JSXElement | (() => JSXElement), container: HTMLElement | string, options?: RenderOptions): MountedComponent`
|
|
238
|
-
|
|
239
|
-
> Render component to DOM.
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
const el = jsx('div', { children: 'Content' })
|
|
243
|
-
|
|
244
|
-
const mounted = render(el, '#app', {
|
|
245
|
-
mode: 'replace',
|
|
246
|
-
onMount: () => console.log('Mounted!'),
|
|
247
|
-
onUnmount: () => console.log('Unmounted!')
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
mounted.unmount()
|
|
251
|
-
mounted.update(newElement)
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
- #### `mount(component: JSXElement | (() => JSXElement), container: HTMLElement | string): MountedComponent`
|
|
255
|
-
|
|
256
|
-
> Shorthand for render with replace mode.
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
mount(jsx('div', { children: 'App' }), '#app')
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
- #### `createRoot(container: HTMLElement | string): { render: (component) => void, unmount: () => void }`
|
|
263
|
-
|
|
264
|
-
> Create a root for multiple renders.
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
const root = createRoot('#app')
|
|
268
|
-
root.render(jsx('div', { children: 'First' }))
|
|
269
|
-
root.render(jsx('div', { children: 'Second' }))
|
|
270
|
-
root.unmount()
|
|
271
|
-
```
|
|
272
|
-
|
|
273
|
-
- #### `hydrate(component: JSXElement | (() => JSXElement), container: HTMLElement | string): MountedComponent`
|
|
274
|
-
|
|
275
|
-
> Hydrate server-rendered HTML with client-side interactivity.
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
hydrate(jsx('div', { children: 'Content' }), '#app')
|
|
279
|
-
```
|
|
280
|
-
|
|
281
|
-
- #### `createPortal(children: JSXElement, container: HTMLElement | string): JSXElement`
|
|
282
|
-
|
|
283
|
-
> Render element to different DOM node.
|
|
284
|
-
|
|
285
|
-
```typescript
|
|
286
|
-
const modal = createPortal(
|
|
287
|
-
jsx('div', { className: 'modal', children: 'Modal content' }),
|
|
288
|
-
document.body
|
|
289
|
-
)
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
- #### `Teleport(props: { to: string | HTMLElement, children: JSXElement }): JSXElement`
|
|
293
|
-
|
|
294
|
-
> Alias for createPortal with component syntax.
|
|
295
|
-
|
|
296
|
-
```typescript
|
|
297
|
-
Teleport({
|
|
298
|
-
to: '#portal',
|
|
299
|
-
children: jsx('div', { children: 'Teleported!' })
|
|
300
|
-
})
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
- #### `lazy<P = any>(loader: () => Promise<{ default: (props: P) => JSXElement }>, fallback?: JSXElement): (props: P) => JSXElement`
|
|
304
|
-
|
|
305
|
-
> Lazy load component with dynamic import.
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
const HeavyComponent = lazy(
|
|
309
|
-
() => import('./HeavyComponent'),
|
|
310
|
-
jsx('div', { children: 'Loading...' })
|
|
311
|
-
)
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
- #### `ErrorBoundary(props: { fallback: (error: Error) => JSXElement, children: JSXElement }): JSXElement`
|
|
315
|
-
|
|
316
|
-
> Catch errors in component tree.
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
ErrorBoundary({
|
|
320
|
-
fallback: (error) => jsx('div', { children: `Error: ${error.message}` }),
|
|
321
|
-
children: jsx('div', { children: 'Content' })
|
|
322
|
-
})
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
- #### `Suspense(props: { fallback: JSXElement, children: JSXElement | Promise<JSXElement> }): JSXElement`
|
|
326
|
-
|
|
327
|
-
> Handle async content with fallback.
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
Suspense({
|
|
331
|
-
fallback: jsx('div', { children: 'Loading...' }),
|
|
332
|
-
children: Promise.resolve(jsx('div', { children: 'Loaded!' }))
|
|
333
|
-
})
|
|
334
|
-
```
|
|
335
|
-
|
|
336
|
-
- #### `queueUpdate(fn: () => void): void`
|
|
337
|
-
|
|
338
|
-
> Queue DOM update to be batched.
|
|
339
|
-
|
|
340
|
-
```typescript
|
|
341
|
-
queueUpdate(() => {
|
|
342
|
-
// DOM update
|
|
343
|
-
})
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
- #### `onDOMReady(callback: () => void): void`
|
|
347
|
-
|
|
348
|
-
> Execute callback when DOM is ready.
|
|
349
|
-
|
|
350
|
-
```typescript
|
|
351
|
-
onDOMReady(() => {
|
|
352
|
-
console.log('DOM ready!')
|
|
353
|
-
})
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
- #### `isBrowser(): boolean`
|
|
357
|
-
|
|
358
|
-
> Check if running in browser environment.
|
|
359
|
-
|
|
360
|
-
```typescript
|
|
361
|
-
if (isBrowser()) {
|
|
362
|
-
console.log('Running in browser!')
|
|
363
|
-
}
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
<br>
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
- ## Real-World Examples
|
|
370
|
-
|
|
371
|
-
- #### Counter Component
|
|
372
|
-
|
|
373
|
-
```typescript
|
|
374
|
-
import { jsx } from '@minejs/jsx'
|
|
375
|
-
import { render } from '@minejs/jsx'
|
|
376
|
-
import { signal } from '@minejs/signals'
|
|
377
|
-
|
|
378
|
-
const count = signal(0)
|
|
98
|
+
- #### [`Render`](./docs/render.md)
|
|
379
99
|
|
|
380
|
-
|
|
381
|
-
className: 'counter',
|
|
382
|
-
children: [
|
|
383
|
-
jsx('h1', { children: `Count: ${count()}` }),
|
|
384
|
-
jsx('button', {
|
|
385
|
-
children: 'Increment',
|
|
386
|
-
onClick: () => count.set(count() + 1)
|
|
387
|
-
})
|
|
388
|
-
]
|
|
389
|
-
})
|
|
390
|
-
|
|
391
|
-
render(app, '#app')
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
- #### Todo App
|
|
395
|
-
|
|
396
|
-
```typescript
|
|
397
|
-
import { jsx, For, Show } from '@minejs/jsx'
|
|
398
|
-
import { render } from '@minejs/jsx'
|
|
399
|
-
import { signal, computed } from '@minejs/signals'
|
|
400
|
-
|
|
401
|
-
interface Todo {
|
|
402
|
-
id: number
|
|
403
|
-
text: string
|
|
404
|
-
done: boolean
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
const todos = signal<Todo[]>([])
|
|
408
|
-
const input = signal('')
|
|
409
|
-
const filter = signal<'all' | 'active' | 'completed'>('all')
|
|
410
|
-
|
|
411
|
-
const filteredTodos = computed(() => {
|
|
412
|
-
const f = filter()
|
|
413
|
-
const t = todos()
|
|
414
|
-
|
|
415
|
-
if (f === 'active') return t.filter(todo => !todo.done)
|
|
416
|
-
if (f === 'completed') return t.filter(todo => todo.done)
|
|
417
|
-
return t
|
|
418
|
-
})
|
|
419
|
-
|
|
420
|
-
const addTodo = () => {
|
|
421
|
-
if (input().trim()) {
|
|
422
|
-
todos.update(list => [
|
|
423
|
-
...list,
|
|
424
|
-
{ id: Date.now(), text: input(), done: false }
|
|
425
|
-
])
|
|
426
|
-
input.set('')
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
const app = jsx('div', {
|
|
431
|
-
className: 'todo-app',
|
|
432
|
-
children: [
|
|
433
|
-
jsx('h1', { children: 'Todos' }),
|
|
434
|
-
jsx('div', {
|
|
435
|
-
className: 'input-group',
|
|
436
|
-
children: [
|
|
437
|
-
jsx('input', {
|
|
438
|
-
type: 'text',
|
|
439
|
-
value: input(),
|
|
440
|
-
onInput: (e) => input.set((e.target as HTMLInputElement).value),
|
|
441
|
-
placeholder: 'Add todo...'
|
|
442
|
-
}),
|
|
443
|
-
jsx('button', {
|
|
444
|
-
children: 'Add',
|
|
445
|
-
onClick: addTodo
|
|
446
|
-
})
|
|
447
|
-
]
|
|
448
|
-
}),
|
|
449
|
-
jsx('ul', {
|
|
450
|
-
children: For({
|
|
451
|
-
each: filteredTodos(),
|
|
452
|
-
children: (todo) => jsx('li', {
|
|
453
|
-
children: [
|
|
454
|
-
jsx('input', {
|
|
455
|
-
type: 'checkbox',
|
|
456
|
-
checked: todo.done
|
|
457
|
-
}),
|
|
458
|
-
jsx('span', { children: todo.text })
|
|
459
|
-
]
|
|
460
|
-
})
|
|
461
|
-
})
|
|
462
|
-
})
|
|
463
|
-
]
|
|
464
|
-
})
|
|
465
|
-
|
|
466
|
-
render(app, '#app')
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
- #### Form with Validation
|
|
470
|
-
|
|
471
|
-
```typescript
|
|
472
|
-
import { jsx, Show } from '@minejs/jsx'
|
|
473
|
-
import { render } from '@minejs/jsx'
|
|
474
|
-
import { signal, computed } from '@minejs/signals'
|
|
475
|
-
|
|
476
|
-
const email = signal('')
|
|
477
|
-
const password = signal('')
|
|
478
|
-
|
|
479
|
-
const isEmailValid = computed(() => {
|
|
480
|
-
return email().includes('@') && email().length > 3
|
|
481
|
-
})
|
|
482
|
-
|
|
483
|
-
const isPasswordValid = computed(() => {
|
|
484
|
-
return password().length >= 8
|
|
485
|
-
})
|
|
486
|
-
|
|
487
|
-
const canSubmit = computed(() => {
|
|
488
|
-
return isEmailValid() && isPasswordValid()
|
|
489
|
-
})
|
|
490
|
-
|
|
491
|
-
const form = jsx('form', {
|
|
492
|
-
children: [
|
|
493
|
-
jsx('div', {
|
|
494
|
-
children: [
|
|
495
|
-
jsx('input', {
|
|
496
|
-
type: 'email',
|
|
497
|
-
value: email(),
|
|
498
|
-
onInput: (e) => email.set((e.target as HTMLInputElement).value),
|
|
499
|
-
placeholder: 'Email'
|
|
500
|
-
}),
|
|
501
|
-
Show({
|
|
502
|
-
when: !isEmailValid() && email(),
|
|
503
|
-
children: jsx('span', {
|
|
504
|
-
style: { color: 'red' },
|
|
505
|
-
children: 'Invalid email'
|
|
506
|
-
})
|
|
507
|
-
})
|
|
508
|
-
]
|
|
509
|
-
}),
|
|
510
|
-
jsx('div', {
|
|
511
|
-
children: [
|
|
512
|
-
jsx('input', {
|
|
513
|
-
type: 'password',
|
|
514
|
-
value: password(),
|
|
515
|
-
onInput: (e) => password.set((e.target as HTMLInputElement).value),
|
|
516
|
-
placeholder: 'Password'
|
|
517
|
-
}),
|
|
518
|
-
Show({
|
|
519
|
-
when: !isPasswordValid() && password(),
|
|
520
|
-
children: jsx('span', {
|
|
521
|
-
style: { color: 'red' },
|
|
522
|
-
children: 'Password must be 8+ characters'
|
|
523
|
-
})
|
|
524
|
-
})
|
|
525
|
-
]
|
|
526
|
-
}),
|
|
527
|
-
jsx('button', {
|
|
528
|
-
type: 'submit',
|
|
529
|
-
disabled: !canSubmit(),
|
|
530
|
-
children: 'Submit'
|
|
531
|
-
})
|
|
532
|
-
]
|
|
533
|
-
})
|
|
534
|
-
|
|
535
|
-
render(form, '#app')
|
|
536
|
-
```
|
|
537
|
-
|
|
538
|
-
- #### Dynamic List with Filtering
|
|
539
|
-
|
|
540
|
-
```typescript
|
|
541
|
-
import { jsx, For, Show } from '@minejs/jsx'
|
|
542
|
-
import { render } from '@minejs/jsx'
|
|
543
|
-
import { signal, computed } from '@minejs/signals'
|
|
544
|
-
|
|
545
|
-
const items = signal(['React', 'Vue', 'Svelte', 'SolidJS'])
|
|
546
|
-
const searchTerm = signal('')
|
|
547
|
-
|
|
548
|
-
const filtered = computed(() => {
|
|
549
|
-
const term = searchTerm().toLowerCase()
|
|
550
|
-
return items().filter(item => item.toLowerCase().includes(term))
|
|
551
|
-
})
|
|
552
|
-
|
|
553
|
-
const app = jsx('div', {
|
|
554
|
-
children: [
|
|
555
|
-
jsx('input', {
|
|
556
|
-
type: 'text',
|
|
557
|
-
value: searchTerm(),
|
|
558
|
-
onInput: (e) => searchTerm.set((e.target as HTMLInputElement).value),
|
|
559
|
-
placeholder: 'Search...'
|
|
560
|
-
}),
|
|
561
|
-
jsx('ul', {
|
|
562
|
-
children: For({
|
|
563
|
-
each: filtered(),
|
|
564
|
-
children: (item) => jsx('li', { children: item })
|
|
565
|
-
})
|
|
566
|
-
}),
|
|
567
|
-
Show({
|
|
568
|
-
when: filtered().length === 0,
|
|
569
|
-
children: jsx('p', { children: 'No results found' })
|
|
570
|
-
})
|
|
571
|
-
]
|
|
572
|
-
})
|
|
573
|
-
|
|
574
|
-
render(app, '#app')
|
|
575
|
-
```
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
- ## More 🔥
|
|
579
|
-
|
|
580
|
-
- ### Vanilla Setup (No Framework)
|
|
581
|
-
|
|
582
|
-
- #### HTML :
|
|
583
|
-
|
|
584
|
-
```html
|
|
585
|
-
<!DOCTYPE html>
|
|
586
|
-
<html>
|
|
587
|
-
<head>
|
|
588
|
-
<title>My App</title>
|
|
589
|
-
</head>
|
|
590
|
-
<body>
|
|
591
|
-
<div id="app"></div>
|
|
592
|
-
<script type="module" src="./app.ts"></script>
|
|
593
|
-
</body>
|
|
594
|
-
</html>
|
|
595
|
-
```
|
|
596
|
-
|
|
597
|
-
- #### TypeScript/JavaScript (app.ts)
|
|
598
|
-
|
|
599
|
-
```typescript
|
|
600
|
-
import { jsx } from '@minejs/jsx'
|
|
601
|
-
import { mount } from '@minejs/jsx'
|
|
602
|
-
import { signal } from '@minejs/signals'
|
|
603
|
-
|
|
604
|
-
// Create reactive state
|
|
605
|
-
const count = signal(0)
|
|
606
|
-
|
|
607
|
-
// Create UI
|
|
608
|
-
const app = jsx('div', {
|
|
609
|
-
className: 'container',
|
|
610
|
-
children: [
|
|
611
|
-
jsx('h1', { children: `Count: ${count()}` }),
|
|
612
|
-
jsx('button', {
|
|
613
|
-
children: 'Increment',
|
|
614
|
-
onClick: () => count.set(count() + 1)
|
|
615
|
-
})
|
|
616
|
-
]
|
|
617
|
-
})
|
|
618
|
-
|
|
619
|
-
// Mount to DOM
|
|
620
|
-
mount(app, '#app')
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
624
|
-
|
|
625
|
-
- ### Using JSX Syntax (.tsx/.jsx files)
|
|
626
|
-
|
|
627
|
-
- #### TypeScript Configuration (tsconfig.json)
|
|
628
|
-
|
|
629
|
-
```json
|
|
630
|
-
{
|
|
631
|
-
"compilerOptions": {
|
|
632
|
-
"jsx" : "react-jsx",
|
|
633
|
-
"jsxImportSource" : "@minejs/jsx",
|
|
634
|
-
"target" : "ES2020",
|
|
635
|
-
"module" : "ESNext"
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
```
|
|
639
|
-
|
|
640
|
-
- #### Component File (Counter.tsx)
|
|
100
|
+
> Lightweight DOM rendering library for JSX elements.
|
|
641
101
|
|
|
642
|
-
|
|
643
|
-
import { signal } from '@minejs/signals'
|
|
644
|
-
import { JSXElement } from '@minejs/jsx'
|
|
102
|
+
- #### [`Runtime`](./docs/runtime.md)
|
|
645
103
|
|
|
646
|
-
|
|
647
|
-
const count = signal(0)
|
|
648
|
-
|
|
649
|
-
return (
|
|
650
|
-
<div className="counter">
|
|
651
|
-
<h1>Count: {count()}</h1>
|
|
652
|
-
<button onClick={() => count.set(count() + 1)}>
|
|
653
|
-
Increment
|
|
654
|
-
</button>
|
|
655
|
-
</div>
|
|
656
|
-
)
|
|
657
|
-
}
|
|
658
|
-
```
|
|
659
|
-
|
|
660
|
-
- #### Main App (app.tsx)
|
|
661
|
-
|
|
662
|
-
```tsx
|
|
663
|
-
import { mount } from '@minejs/jsx'
|
|
664
|
-
import { Counter } from './Counter'
|
|
665
|
-
|
|
666
|
-
mount(<Counter />, '#app')
|
|
667
|
-
```
|
|
104
|
+
> Lightweight JSX runtime with fine-grained reactivity.
|
|
668
105
|
|
|
669
106
|
<!-- ╚═════════════════════════════════════════════════════════════════╝ -->
|
|
670
107
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var signals=require('@minejs/signals');function
|
|
1
|
+
'use strict';var signals=require('@minejs/signals');var d=[],u=false;function f(e,n,t={}){let o=typeof n=="string"?document.querySelector(n):n;if(!o)throw new Error(`Container not found: ${n}`);let r=typeof e=="function"?e():e;if(!r)throw new Error("Component returned null or undefined");switch(t.mode||"replace"){case "replace":o.innerHTML="",o.appendChild(r);break;case "append":o.appendChild(r);break;case "prepend":o.insertBefore(r,o.firstChild);break;default:o.innerHTML="",o.appendChild(r);}return t.onMount?.(),{element:r,unmount:()=>{if(r instanceof Element)r.remove();else if(r instanceof DocumentFragment)for(;r.firstChild;)r.removeChild(r.firstChild);t.onUnmount?.();},update:l=>{r instanceof Element&&l instanceof Element?r.replaceWith(l):l instanceof Element&&r instanceof DocumentFragment&&r.parentNode&&r.parentNode.replaceChild(l,r);}}}function N(e,n){return f(e,n,{mode:"replace"})}function S(e,n){let t=typeof n=="string"?document.querySelector(n):n;if(!t)throw new Error(`Portal container not found: ${n}`);let o=document.createComment("portal");return e instanceof Node&&t.appendChild(e),o}function v(e,n){let t=typeof n=="string"?document.querySelector(n):n,o=t instanceof HTMLElement?t:null;if(!o)throw new Error(`Container not found: ${n}`);return f(e,o,{mode:"replace"})}function b(e,n){let t=null,o=false,r=null;return i=>{if(t)return t(i);if(r){let l=document.createElement("div");return l.className="crux-lazy-error",l.textContent=`Error loading component: ${r.message}`,l.style.color="red",l}return o||(o=true,e().then(l=>{t=l.default;}).catch(l=>{r=l instanceof Error?l:new Error(String(l));})),n||y()}}function y(){let e=document.createElement("div");return e.textContent="Loading...",e}function P(e){try{return e.children}catch(n){return e.fallback(n)}}function H(e){if(e.children instanceof Promise){let n=document.createElement("div");return n.style.display="contents",e.fallback instanceof Node&&n.appendChild(e.fallback),e.children.then(t=>{n.innerHTML="",t instanceof Node&&n.appendChild(t);}),n}else return e.children}function F(e){return S(e.children,e.to)}function D(e){d.push(e),u||(u=true,queueMicrotask(g));}function g(){let e=d;d=[],u=false,e.forEach(n=>n());}function C(){return typeof window<"u"&&typeof document<"u"}function A(e){C()&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e):e());}function R(e){let n=typeof e=="string"?document.querySelector(e):e;if(!n||!(n instanceof HTMLElement))throw new Error(`Root container not found: ${e}`);let t=null;return {render(o){t&&t.unmount(),t=f(o,n);},unmount(){t&&(t.unmount(),t=null);}}}function m(e,n){return typeof e=="function"?e(n||{}):J(e,n||{})}var O=m;function h(e){let n=document.createDocumentFragment();return s(e.children).forEach(o=>{o instanceof Node&&n.appendChild(o);}),n}function J(e,n){let t=document.createElement(e);for(let[o,r]of Object.entries(n))o==="children"?X(t,r):o==="ref"?x(t,r):o.startsWith("on")?M(t,o,r):o==="className"||o==="class"?T(t,r):o==="style"?w(t,r):signals.isSignal(r)?L(t,o,r):typeof r=="boolean"?r&&t.setAttribute(o,""):r!=null&&t.setAttribute(o,String(r));return t}function X(e,n){s(n).forEach(o=>{if(o instanceof Node)e.appendChild(o);else if(signals.isSignal(o)){let r=document.createTextNode("");signals.effect(()=>{r.textContent=String(o());}),e.appendChild(r);}else o!=null&&o!==false&&e.appendChild(document.createTextNode(String(o)));});}function s(e){return e==null||e===false?[]:Array.isArray(e)?e.flatMap(s):[e]}function x(e,n){signals.isSignal(n)?n.set(e):typeof n=="function"&&n(e);}function M(e,n,t){if(typeof t!="function")return;let o=n.slice(2).toLowerCase();e.addEventListener(o,t);}function T(e,n){signals.isSignal(n)?signals.effect(()=>{let t=n();t!=null&&(e.className=String(t));}):n!=null&&(e.className=String(n));}function w(e,n){signals.isSignal(n)?signals.effect(()=>{let t=n();E(e,t);}):E(e,n);}function E(e,n){typeof n=="string"?e.style.cssText=n:typeof n=="object"&&n!=null&&Object.entries(n).forEach(([t,o])=>{if(o!=null){let r=t.replace(/[A-Z]/g,i=>`-${i.toLowerCase()}`);e.style.setProperty(r,String(o));}});}function L(e,n,t){signals.effect(()=>{let o=t();o!=null?n in e?e[n]=o:e.setAttribute(n,String(o)):e.removeAttribute(n);});}function $(e){return e}function j(e){return n=>e(n)()}function z(e){let n=document.createDocumentFragment();return e.forEach(t=>{t instanceof Node&&n.appendChild(t);}),n}function B(e){if(signals.isSignal(e.when)){let n=document.createComment("show"),t=document.createDocumentFragment();t.appendChild(n);let o=null;return signals.effect(()=>{let r=e.when,i=r();i&&!o?(o=s(e.children)[0],o instanceof Node&&n.parentNode?.insertBefore(o,n)):!i&&o&&(o.remove(),o=null);}),t}else return e.when?m(h,{children:e.children}):null}function U(e){for(let n of e.children)if(signals.isSignal(n.when)?n.when():n.when)return m(h,{children:n.children});return null}function W(e){let n=document.createDocumentFragment();if(signals.isSignal(e.each)){let t=document.createElement("div");t.style.display="contents",signals.effect(()=>{let o=e.each,r=o();t.innerHTML="",r.forEach((i,l)=>{let p=e.children(i,l);p instanceof Node&&t.appendChild(p);});}),n.appendChild(t);}else e.each.forEach((o,r)=>{let i=e.children(o,r);i instanceof Node&&n.appendChild(i);});return n}exports.ErrorBoundary=P;exports.For=W;exports.Fragment=h;exports.Show=B;exports.Suspense=H;exports.Switch=U;exports.Teleport=F;exports.component=$;exports.createElements=z;exports.createPortal=S;exports.createRoot=R;exports.defineComponent=j;exports.hydrate=v;exports.isBrowser=C;exports.jsx=m;exports.jsxs=O;exports.lazy=b;exports.mount=N;exports.onDOMReady=A;exports.queueUpdate=D;exports.render=f;//# sourceMappingURL=index.cjs.map
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|