xote 4.4.2 → 4.5.0

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/src/Xote__JSX.res CHANGED
@@ -8,10 +8,10 @@ type component<'props> = 'props => element
8
8
 
9
9
  type componentLike<'props, 'return> = 'props => 'return
10
10
 
11
- /* JSX functions for component creation */
11
+ /* JSX functions for component creation - all delegate to the component function */
12
12
  let jsx = (component: component<'props>, props: 'props): element => component(props)
13
13
 
14
- let jsxs = (component: component<'props>, props: 'props): element => component(props)
14
+ let jsxs = jsx
15
15
 
16
16
  let jsxKeyed = (
17
17
  component: component<'props>,
@@ -20,18 +20,10 @@ let jsxKeyed = (
20
20
  _: unit,
21
21
  ): element => {
22
22
  let _ = key /* TODO: Implement key support for list reconciliation */
23
- component(props)
23
+ jsx(component, props)
24
24
  }
25
25
 
26
- let jsxsKeyed = (
27
- component: component<'props>,
28
- props: 'props,
29
- ~key: option<string>=?,
30
- _: unit,
31
- ): element => {
32
- let _ = key
33
- component(props)
34
- }
26
+ let jsxsKeyed = jsxKeyed
35
27
 
36
28
  /* Fragment support */
37
29
  type fragmentProps = {children?: element}
@@ -198,223 +190,72 @@ module Elements = {
198
190
  }
199
191
  }
200
192
 
201
- /* Convert props to attrs array */
202
- let propsToAttrs = (
203
- props: props<
204
- 'id,
205
- 'class,
206
- 'style,
207
- 'typ,
208
- 'name,
209
- 'value,
210
- 'placeholder,
211
- 'min,
212
- 'max,
213
- 'step,
214
- 'pattern,
215
- 'autoComplete,
216
- 'accept,
217
- 'forAttr,
218
- 'href,
219
- 'target,
220
- 'src,
221
- 'alt,
222
- 'width,
223
- 'height,
224
- 'role,
225
- 'ariaLabel,
226
- 'disabled,
227
- 'checked,
228
- 'required,
229
- 'readOnly,
230
- 'multiple,
231
- 'ariaHidden,
232
- 'ariaExpanded,
233
- 'ariaSelected,
234
- >,
235
- ): array<(string, Component.attrValue)> => {
236
- let attrs = []
237
-
238
- /* Standard attributes */
239
- switch props.id {
240
- | Some(v) => attrs->Array.push(convertAttrValue("id", v))
241
- | None => ()
242
- }
243
-
244
- switch props.class {
245
- | Some(v) => attrs->Array.push(convertAttrValue("class", v))
246
- | None => ()
247
- }
248
-
249
- switch props.style {
250
- | Some(v) => attrs->Array.push(convertAttrValue("style", v))
251
- | None => ()
252
- }
253
-
254
- /* Form/Input attributes */
255
- switch props.type_ {
256
- | Some(v) => attrs->Array.push(convertAttrValue("type", v))
257
- | None => ()
258
- }
259
-
260
- switch props.name {
261
- | Some(v) => attrs->Array.push(convertAttrValue("name", v))
262
- | None => ()
263
- }
264
-
265
- switch props.value {
266
- | Some(v) => attrs->Array.push(convertAttrValue("value", v))
267
- | None => ()
268
- }
269
-
270
- switch props.placeholder {
271
- | Some(v) => attrs->Array.push(convertAttrValue("placeholder", v))
272
- | None => ()
273
- }
274
-
275
- switch props.disabled {
276
- | Some(v) => attrs->Array.push(convertBoolAttrValue("disabled", v))
277
- | None => ()
278
- }
279
-
280
- switch props.checked {
281
- | Some(v) => attrs->Array.push(convertBoolAttrValue("checked", v))
282
- | None => ()
283
- }
284
-
285
- switch props.required {
286
- | Some(v) => attrs->Array.push(convertBoolAttrValue("required", v))
287
- | None => ()
288
- }
289
-
290
- switch props.readOnly {
291
- | Some(v) => attrs->Array.push(convertBoolAttrValue("readonly", v))
292
- | None => ()
293
- }
294
-
295
- switch props.maxLength {
296
- | Some(v) => attrs->Array.push(Component.attr("maxlength", Int.toString(v)))
297
- | None => ()
298
- }
299
-
300
- switch props.minLength {
301
- | Some(v) => attrs->Array.push(Component.attr("minlength", Int.toString(v)))
302
- | None => ()
303
- }
304
-
305
- switch props.min {
306
- | Some(v) => attrs->Array.push(convertAttrValue("min", v))
307
- | None => ()
308
- }
309
-
310
- switch props.max {
311
- | Some(v) => attrs->Array.push(convertAttrValue("max", v))
312
- | None => ()
313
- }
314
-
315
- switch props.step {
316
- | Some(v) => attrs->Array.push(convertAttrValue("step", v))
317
- | None => ()
318
- }
319
-
320
- switch props.pattern {
321
- | Some(v) => attrs->Array.push(convertAttrValue("pattern", v))
322
- | None => ()
323
- }
324
-
325
- switch props.autoComplete {
326
- | Some(v) => attrs->Array.push(convertAttrValue("autocomplete", v))
193
+ /* Helper to add optional attribute to attrs array */
194
+ let addAttr = (attrs, opt, key, converter) => {
195
+ switch opt {
196
+ | Some(v) => attrs->Array.push(converter(key, v))
327
197
  | None => ()
328
198
  }
199
+ }
329
200
 
330
- switch props.multiple {
331
- | Some(v) => attrs->Array.push(convertBoolAttrValue("multiple", v))
201
+ /* Helper to add optional int attribute */
202
+ let addIntAttr = (attrs, opt, key) => {
203
+ switch opt {
204
+ | Some(v) => attrs->Array.push(Component.attr(key, Int.toString(v)))
332
205
  | None => ()
333
206
  }
207
+ }
334
208
 
335
- switch props.accept {
336
- | Some(v) => attrs->Array.push(convertAttrValue("accept", v))
337
- | None => ()
338
- }
209
+ /* Convert props to attrs array - uses wildcard types to accept any prop types */
210
+ let propsToAttrs = (props: props<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>): array<(string, Component.attrValue)> => {
211
+ let attrs = []
339
212
 
340
- switch props.rows {
341
- | Some(v) => attrs->Array.push(Component.attr("rows", Int.toString(v)))
342
- | None => ()
343
- }
213
+ /* Standard attributes */
214
+ addAttr(attrs, props.id, "id", convertAttrValue)
215
+ addAttr(attrs, props.class, "class", convertAttrValue)
216
+ addAttr(attrs, props.style, "style", convertAttrValue)
344
217
 
345
- switch props.cols {
346
- | Some(v) => attrs->Array.push(Component.attr("cols", Int.toString(v)))
347
- | None => ()
348
- }
218
+ /* Form/Input attributes */
219
+ addAttr(attrs, props.type_, "type", convertAttrValue)
220
+ addAttr(attrs, props.name, "name", convertAttrValue)
221
+ addAttr(attrs, props.value, "value", convertAttrValue)
222
+ addAttr(attrs, props.placeholder, "placeholder", convertAttrValue)
223
+ addAttr(attrs, props.disabled, "disabled", convertBoolAttrValue)
224
+ addAttr(attrs, props.checked, "checked", convertBoolAttrValue)
225
+ addAttr(attrs, props.required, "required", convertBoolAttrValue)
226
+ addAttr(attrs, props.readOnly, "readonly", convertBoolAttrValue)
227
+ addIntAttr(attrs, props.maxLength, "maxlength")
228
+ addIntAttr(attrs, props.minLength, "minlength")
229
+ addAttr(attrs, props.min, "min", convertAttrValue)
230
+ addAttr(attrs, props.max, "max", convertAttrValue)
231
+ addAttr(attrs, props.step, "step", convertAttrValue)
232
+ addAttr(attrs, props.pattern, "pattern", convertAttrValue)
233
+ addAttr(attrs, props.autoComplete, "autocomplete", convertAttrValue)
234
+ addAttr(attrs, props.multiple, "multiple", convertBoolAttrValue)
235
+ addAttr(attrs, props.accept, "accept", convertAttrValue)
236
+ addIntAttr(attrs, props.rows, "rows")
237
+ addIntAttr(attrs, props.cols, "cols")
349
238
 
350
239
  /* Label attributes */
351
- switch props.for_ {
352
- | Some(v) => attrs->Array.push(convertAttrValue("for", v))
353
- | None => ()
354
- }
240
+ addAttr(attrs, props.for_, "for", convertAttrValue)
355
241
 
356
242
  /* Link attributes */
357
- switch props.href {
358
- | Some(v) => attrs->Array.push(convertAttrValue("href", v))
359
- | None => ()
360
- }
361
-
362
- switch props.target {
363
- | Some(v) => attrs->Array.push(convertAttrValue("target", v))
364
- | None => ()
365
- }
243
+ addAttr(attrs, props.href, "href", convertAttrValue)
244
+ addAttr(attrs, props.target, "target", convertAttrValue)
366
245
 
367
246
  /* Image attributes */
368
- switch props.src {
369
- | Some(v) => attrs->Array.push(convertAttrValue("src", v))
370
- | None => ()
371
- }
372
-
373
- switch props.alt {
374
- | Some(v) => attrs->Array.push(convertAttrValue("alt", v))
375
- | None => ()
376
- }
377
-
378
- switch props.width {
379
- | Some(v) => attrs->Array.push(convertAttrValue("width", v))
380
- | None => ()
381
- }
382
-
383
- switch props.height {
384
- | Some(v) => attrs->Array.push(convertAttrValue("height", v))
385
- | None => ()
386
- }
247
+ addAttr(attrs, props.src, "src", convertAttrValue)
248
+ addAttr(attrs, props.alt, "alt", convertAttrValue)
249
+ addAttr(attrs, props.width, "width", convertAttrValue)
250
+ addAttr(attrs, props.height, "height", convertAttrValue)
387
251
 
388
252
  /* Accessibility attributes */
389
- switch props.role {
390
- | Some(v) => attrs->Array.push(convertAttrValue("role", v))
391
- | None => ()
392
- }
393
-
394
- switch props.tabIndex {
395
- | Some(v) => attrs->Array.push(Component.attr("tabindex", Int.toString(v)))
396
- | None => ()
397
- }
398
-
399
- switch props.ariaLabel {
400
- | Some(v) => attrs->Array.push(convertAttrValue("aria-label", v))
401
- | None => ()
402
- }
403
-
404
- switch props.ariaHidden {
405
- | Some(v) => attrs->Array.push(convertBoolAttrValue("aria-hidden", v))
406
- | None => ()
407
- }
408
-
409
- switch props.ariaExpanded {
410
- | Some(v) => attrs->Array.push(convertBoolAttrValue("aria-expanded", v))
411
- | None => ()
412
- }
413
-
414
- switch props.ariaSelected {
415
- | Some(v) => attrs->Array.push(convertBoolAttrValue("aria-selected", v))
416
- | None => ()
417
- }
253
+ addAttr(attrs, props.role, "role", convertAttrValue)
254
+ addIntAttr(attrs, props.tabIndex, "tabindex")
255
+ addAttr(attrs, props.ariaLabel, "aria-label", convertAttrValue)
256
+ addAttr(attrs, props.ariaHidden, "aria-hidden", convertBoolAttrValue)
257
+ addAttr(attrs, props.ariaExpanded, "aria-expanded", convertBoolAttrValue)
258
+ addAttr(attrs, props.ariaSelected, "aria-selected", convertBoolAttrValue)
418
259
 
419
260
  /* Data attributes */
420
261
  switch props.data {
@@ -431,131 +272,34 @@ module Elements = {
431
272
  attrs
432
273
  }
433
274
 
434
- /* Convert props to events array */
435
- let propsToEvents = (
436
- props: props<
437
- 'id,
438
- 'class,
439
- 'style,
440
- 'typ,
441
- 'name,
442
- 'value,
443
- 'placeholder,
444
- 'min,
445
- 'max,
446
- 'step,
447
- 'pattern,
448
- 'autoComplete,
449
- 'accept,
450
- 'forAttr,
451
- 'href,
452
- 'target,
453
- 'src,
454
- 'alt,
455
- 'width,
456
- 'height,
457
- 'role,
458
- 'ariaLabel,
459
- 'disabled,
460
- 'checked,
461
- 'required,
462
- 'readOnly,
463
- 'multiple,
464
- 'ariaHidden,
465
- 'ariaExpanded,
466
- 'ariaSelected,
467
- >,
468
- ): array<(string, Dom.event => unit)> => {
469
- let events = []
470
-
471
- switch props.onClick {
472
- | Some(handler) => events->Array.push(("click", handler))
473
- | None => ()
474
- }
475
-
476
- switch props.onInput {
477
- | Some(handler) => events->Array.push(("input", handler))
478
- | None => ()
479
- }
480
-
481
- switch props.onChange {
482
- | Some(handler) => events->Array.push(("change", handler))
483
- | None => ()
484
- }
485
-
486
- switch props.onSubmit {
487
- | Some(handler) => events->Array.push(("submit", handler))
488
- | None => ()
489
- }
490
-
491
- switch props.onFocus {
492
- | Some(handler) => events->Array.push(("focus", handler))
493
- | None => ()
494
- }
495
-
496
- switch props.onBlur {
497
- | Some(handler) => events->Array.push(("blur", handler))
498
- | None => ()
499
- }
500
-
501
- switch props.onKeyDown {
502
- | Some(handler) => events->Array.push(("keydown", handler))
503
- | None => ()
504
- }
505
-
506
- switch props.onKeyUp {
507
- | Some(handler) => events->Array.push(("keyup", handler))
275
+ /* Helper to add optional event handler to events array */
276
+ let addEvent = (events, opt, eventName) => {
277
+ switch opt {
278
+ | Some(handler) => events->Array.push((eventName, handler))
508
279
  | None => ()
509
280
  }
281
+ }
510
282
 
511
- switch props.onMouseEnter {
512
- | Some(handler) => events->Array.push(("mouseenter", handler))
513
- | None => ()
514
- }
283
+ /* Convert props to events array - uses wildcard types to accept any prop types */
284
+ let propsToEvents = (props: props<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>): array<(string, Dom.event => unit)> => {
285
+ let events = []
515
286
 
516
- switch props.onMouseLeave {
517
- | Some(handler) => events->Array.push(("mouseleave", handler))
518
- | None => ()
519
- }
287
+ addEvent(events, props.onClick, "click")
288
+ addEvent(events, props.onInput, "input")
289
+ addEvent(events, props.onChange, "change")
290
+ addEvent(events, props.onSubmit, "submit")
291
+ addEvent(events, props.onFocus, "focus")
292
+ addEvent(events, props.onBlur, "blur")
293
+ addEvent(events, props.onKeyDown, "keydown")
294
+ addEvent(events, props.onKeyUp, "keyup")
295
+ addEvent(events, props.onMouseEnter, "mouseenter")
296
+ addEvent(events, props.onMouseLeave, "mouseleave")
520
297
 
521
298
  events
522
299
  }
523
300
 
524
301
  /* Extract children from props */
525
- let getChildren = (
526
- props: props<
527
- 'id,
528
- 'class,
529
- 'style,
530
- 'typ,
531
- 'name,
532
- 'value,
533
- 'placeholder,
534
- 'min,
535
- 'max,
536
- 'step,
537
- 'pattern,
538
- 'autoComplete,
539
- 'accept,
540
- 'forAttr,
541
- 'href,
542
- 'target,
543
- 'src,
544
- 'alt,
545
- 'width,
546
- 'height,
547
- 'role,
548
- 'ariaLabel,
549
- 'disabled,
550
- 'checked,
551
- 'required,
552
- 'readOnly,
553
- 'multiple,
554
- 'ariaHidden,
555
- 'ariaExpanded,
556
- 'ariaSelected,
557
- >,
558
- ): array<element> => {
302
+ let getChildren = (props: props<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>): array<element> => {
559
303
  switch props.children {
560
304
  | Some(Fragment(children)) => children
561
305
  | Some(child) => [child]
@@ -564,41 +308,7 @@ module Elements = {
564
308
  }
565
309
 
566
310
  /* Create an element from a tag string and props */
567
- let createElement = (
568
- tag: string,
569
- props: props<
570
- 'id,
571
- 'class,
572
- 'style,
573
- 'typ,
574
- 'name,
575
- 'value,
576
- 'placeholder,
577
- 'min,
578
- 'max,
579
- 'step,
580
- 'pattern,
581
- 'autoComplete,
582
- 'accept,
583
- 'forAttr,
584
- 'href,
585
- 'target,
586
- 'src,
587
- 'alt,
588
- 'width,
589
- 'height,
590
- 'role,
591
- 'ariaLabel,
592
- 'disabled,
593
- 'checked,
594
- 'required,
595
- 'readOnly,
596
- 'multiple,
597
- 'ariaHidden,
598
- 'ariaExpanded,
599
- 'ariaSelected,
600
- >,
601
- ): element => {
311
+ let createElement = (tag: string, props: props<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>): element => {
602
312
  Component.Element({
603
313
  tag,
604
314
  attrs: propsToAttrs(props),
@@ -607,161 +317,18 @@ module Elements = {
607
317
  })
608
318
  }
609
319
 
610
- /* JSX functions for HTML elements */
611
- let jsx = (
612
- tag: string,
613
- props: props<
614
- 'id,
615
- 'class,
616
- 'style,
617
- 'typ,
618
- 'name,
619
- 'value,
620
- 'placeholder,
621
- 'min,
622
- 'max,
623
- 'step,
624
- 'pattern,
625
- 'autoComplete,
626
- 'accept,
627
- 'forAttr,
628
- 'href,
629
- 'target,
630
- 'src,
631
- 'alt,
632
- 'width,
633
- 'height,
634
- 'role,
635
- 'ariaLabel,
636
- 'disabled,
637
- 'checked,
638
- 'required,
639
- 'readOnly,
640
- 'multiple,
641
- 'ariaHidden,
642
- 'ariaExpanded,
643
- 'ariaSelected,
644
- >,
645
- ): element => createElement(tag, props)
646
-
647
- let jsxs = (
648
- tag: string,
649
- props: props<
650
- 'id,
651
- 'class,
652
- 'style,
653
- 'typ,
654
- 'name,
655
- 'value,
656
- 'placeholder,
657
- 'min,
658
- 'max,
659
- 'step,
660
- 'pattern,
661
- 'autoComplete,
662
- 'accept,
663
- 'forAttr,
664
- 'href,
665
- 'target,
666
- 'src,
667
- 'alt,
668
- 'width,
669
- 'height,
670
- 'role,
671
- 'ariaLabel,
672
- 'disabled,
673
- 'checked,
674
- 'required,
675
- 'readOnly,
676
- 'multiple,
677
- 'ariaHidden,
678
- 'ariaExpanded,
679
- 'ariaSelected,
680
- >,
681
- ): element => createElement(tag, props)
682
-
683
- let jsxKeyed = (
684
- tag: string,
685
- props: props<
686
- 'id,
687
- 'class,
688
- 'style,
689
- 'typ,
690
- 'name,
691
- 'value,
692
- 'placeholder,
693
- 'min,
694
- 'max,
695
- 'step,
696
- 'pattern,
697
- 'autoComplete,
698
- 'accept,
699
- 'forAttr,
700
- 'href,
701
- 'target,
702
- 'src,
703
- 'alt,
704
- 'width,
705
- 'height,
706
- 'role,
707
- 'ariaLabel,
708
- 'disabled,
709
- 'checked,
710
- 'required,
711
- 'readOnly,
712
- 'multiple,
713
- 'ariaHidden,
714
- 'ariaExpanded,
715
- 'ariaSelected,
716
- >,
717
- ~key: option<string>=?,
718
- _: unit,
719
- ): element => {
720
- let _ = key
721
- createElement(tag, props)
722
- }
320
+ /* JSX functions for HTML elements - all delegate to createElement */
321
+ let jsx = (tag: string, props: props<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>): element => createElement(tag, props)
723
322
 
724
- let jsxsKeyed = (
725
- tag: string,
726
- props: props<
727
- 'id,
728
- 'class,
729
- 'style,
730
- 'typ,
731
- 'name,
732
- 'value,
733
- 'placeholder,
734
- 'min,
735
- 'max,
736
- 'step,
737
- 'pattern,
738
- 'autoComplete,
739
- 'accept,
740
- 'forAttr,
741
- 'href,
742
- 'target,
743
- 'src,
744
- 'alt,
745
- 'width,
746
- 'height,
747
- 'role,
748
- 'ariaLabel,
749
- 'disabled,
750
- 'checked,
751
- 'required,
752
- 'readOnly,
753
- 'multiple,
754
- 'ariaHidden,
755
- 'ariaExpanded,
756
- 'ariaSelected,
757
- >,
758
- ~key: option<string>=?,
759
- _: unit,
760
- ): element => {
323
+ let jsxs = jsx
324
+
325
+ let jsxKeyed = (tag: string, props: props<_, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _>, ~key: option<string>=?, _: unit): element => {
761
326
  let _ = key
762
- createElement(tag, props)
327
+ jsx(tag, props)
763
328
  }
764
329
 
330
+ let jsxsKeyed = jsxKeyed
331
+
765
332
  /* Element helper for ReScript JSX type checking */
766
333
  external someElement: element => option<element> = "%identity"
767
334
  }