components.km 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. type Component
  2. Computed[Node]; // Observable<VNode>
  3. function StaticComponent:
  4. &(&() => Node) => Component
  5. native 'ui-static-component';
  6. const Empty: Component :=
  7. { StaticComponent &() =>
  8. { Node 'div' }
  9. . { with { Styles [('display','none')] } } };
  10. export function Element:
  11. &(Tag, List[Component]) => Component
  12. &(tag, children) =>
  13. if ((children.{length}) = 0):
  14. { StaticComponent &() => { Node tag } },
  15. else:
  16. { Node (tag, children) };
  17. export function Container:
  18. &(List[Component]) => Component
  19. &(children) => { Node ('div', children) };
  20. export function StyledContainer:
  21. &(List[String]) => &(List[Component]) => Component
  22. &(@class) => &(children) => { Container children }.{ with {Style @class} };
  23. export function Label:
  24. &(String) => Component
  25. &(text) => { StaticComponent &() => { Node ('div', text) } };
  26. export function Label:
  27. &(Computed[String]) => Component
  28. &(@text) => { map (@text, (&(text) => { Node ('div', text) })) };
  29. export function Input:
  30. &(Reactive[String]) => Component
  31. &(@text) =>
  32. let on-input := { EventHandler
  33. (@text, &(ev) => (ev get-string 'webuiValue')) },
  34. \ text := map { watch @text },
  35. { Node 'input' }
  36. . { with { Attrs [('type','text'),('value',text)] } }
  37. . { with { Events [('input',on-input)] } };
  38. export function Checkbox:
  39. &(Reactive[Bool]) => Component
  40. &(@checked) =>
  41. let on-change := { EventHandler
  42. (@checked, &(ev) => (ev get-bool 'webuiChecked')) },
  43. \ checked := map { watch @checked },
  44. { Node 'input' }
  45. . { with { Attrs
  46. if checked:
  47. ([('type','checkbox'), ('checked','checked')]),
  48. else:
  49. ([('type','checkbox')])
  50. } }
  51. . { with { Events
  52. [ ('change',on-change) ]
  53. } };
  54. export function Select:
  55. &(Reactive[String], List[(String,String)]) => Component
  56. &(@current, options) =>
  57. let on-change := { EventHandler
  58. (@current, &(ev) => (ev get-string 'webuiValue')) },
  59. let children := (options map &(name,desc) =>
  60. { Node ('option', desc) }
  61. . { with { Attrs [('value',name)] } }),
  62. \ current := map { watch @current },
  63. { Node 'select' }
  64. . { with { Attrs [('value',current)] } }
  65. . { with { Events [('change',on-change)] } }
  66. . { with { Content children } };
  67. export function Button:
  68. &(String, Async) => Component
  69. &(text, action) =>
  70. let handler := { trigger action }.{EventHandler},
  71. { StaticComponent &() =>
  72. { Node ('button', text) }
  73. . { with { Events [('click',handler)] } } };
  74. export function ListView:[T]
  75. &(Tag, Reactive[FlexList[T]], &(FlexListKey,Computed[Number],Reactive[T]) => Component) => Component
  76. &(tag, list, f) =>
  77. let children := (list consume &(item) => { f(item) }),
  78. { Node (tag, children) };
  79. export function ListView:[T]
  80. &(Reactive[FlexList[T]], &(FlexListKey,Computed[Number],Reactive[T]) => Component) => Component
  81. &(list, f) => { ListView ('div', list, f) };