@minejs/jsx 0.0.4 → 0.0.6
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 +3 -658
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -163
- package/dist/index.d.ts +2 -163
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/jsx-dev-runtime.cjs +2 -0
- package/dist/jsx-dev-runtime.cjs.map +1 -0
- package/dist/jsx-dev-runtime.d.cts +1 -0
- package/dist/jsx-dev-runtime.d.ts +1 -0
- package/dist/jsx-dev-runtime.js +2 -0
- package/dist/jsx-dev-runtime.js.map +1 -0
- package/dist/jsx-runtime.cjs +2 -0
- package/dist/jsx-runtime.cjs.map +1 -0
- package/dist/jsx-runtime.d.cts +1 -0
- package/dist/jsx-runtime.d.ts +1 -0
- package/dist/jsx-runtime.js +2 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/package.json +14 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
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.6-black"/>
|
|
12
12
|
<img src="https://img.shields.io/badge/🔥-@minejs-black"/>
|
|
13
13
|
<br>
|
|
14
14
|
<img src="https://img.shields.io/badge/coverage-97.59%25-brightgreen" alt="Test Coverage" />
|
|
@@ -23,661 +23,6 @@
|
|
|
23
23
|
|
|
24
24
|
<!-- ╔══════════════════════════════ DOC ══════════════════════════════╗ -->
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
> Moved to [@minejsx](https://github.com/minejsx-org).
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
- ### Setup
|
|
31
|
-
|
|
32
|
-
> install [`hmm`](https://github.com/minejs-org/hmm) first.
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
hmm i @minejs/jsx
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
39
|
-
|
|
40
|
-
- ### Usage
|
|
41
|
-
|
|
42
|
-
```ts
|
|
43
|
-
import { jsx, Fragment, Show, For, render, mount, createRoot } from '@minejs/jsx'
|
|
44
|
-
import { signal } from '@minejs/signals'
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
- ### 1. Basic JSX Elements
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
// Create simple element
|
|
51
|
-
const el = jsx('div', {
|
|
52
|
-
className: 'container',
|
|
53
|
-
children: 'Hello World'
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
// Create with attributes
|
|
57
|
-
const button = jsx('button', {
|
|
58
|
-
id: 'submit',
|
|
59
|
-
children: 'Click me',
|
|
60
|
-
onClick: () => console.log('Clicked!')
|
|
61
|
-
})
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
- ### 2. Reactive Content with Signals
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
const count = signal(0)
|
|
68
|
-
|
|
69
|
-
const el = jsx('div', {
|
|
70
|
-
children: `Count: ${count()}`
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
render(el, '#app')
|
|
74
|
-
|
|
75
|
-
count.set(5) // Updates DOM automatically!
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
- ### 3. Event Handling
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
const counter = signal(0)
|
|
82
|
-
|
|
83
|
-
const button = jsx('button', {
|
|
84
|
-
children: 'Increment',
|
|
85
|
-
onClick: () => {
|
|
86
|
-
counter.set(counter() + 1)
|
|
87
|
-
}
|
|
88
|
-
})
|
|
89
|
-
```
|
|
90
|
-
|
|
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
|
-
<br>
|
|
112
|
-
|
|
113
|
-
- ## API Reference 🔥
|
|
114
|
-
|
|
115
|
-
- #### `jsx<P = any>(type: string | ComponentFunction, props: JSXProps | null): JSXElement`
|
|
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)
|
|
379
|
-
|
|
380
|
-
const app = jsx('div', {
|
|
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)
|
|
641
|
-
|
|
642
|
-
```tsx
|
|
643
|
-
import { signal } from '@minejs/signals'
|
|
644
|
-
import { JSXElement } from '@minejs/jsx'
|
|
645
|
-
|
|
646
|
-
export function Counter(): JSXElement {
|
|
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
|
-
```
|
|
668
|
-
|
|
669
|
-
<!-- ╚═════════════════════════════════════════════════════════════════╝ -->
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
<!-- ╔══════════════════════════════ END ══════════════════════════════╗ -->
|
|
674
|
-
|
|
675
|
-
<br>
|
|
676
|
-
|
|
677
|
-
---
|
|
678
|
-
|
|
679
|
-
<div align="center">
|
|
680
|
-
<a href="https://github.com/maysara-elshewehy"><img src="https://img.shields.io/badge/by-Maysara-black"/></a>
|
|
681
|
-
</div>
|
|
682
|
-
|
|
683
|
-
<!-- ╚═════════════════════════════════════════════════════════════════╝ -->
|
|
28
|
+
<!-- ╚═════════════════════════════════════════════════════════════════╝ -->
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var render=require('@minejsx/render'),runtime=require('@minejsx/runtime');Object.keys(render).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return render[k]}})});Object.keys(runtime).forEach(function(k){if(k!=='default'&&!Object.prototype.hasOwnProperty.call(exports,k))Object.defineProperty(exports,k,{enumerable:true,get:function(){return runtime[k]}})});//# sourceMappingURL=index.cjs.map
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|