basefn 1.0.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.
Files changed (154) hide show
  1. package/README.md +104 -0
  2. package/package.json +82 -0
  3. package/rescript.json +32 -0
  4. package/src/Basefn.css +14 -0
  5. package/src/Basefn.res +105 -0
  6. package/src/Basefn.res.mjs +114 -0
  7. package/src/Basefn__Dom.res +9 -0
  8. package/src/Basefn__Dom.res.mjs +24 -0
  9. package/src/Basefn__Utils.res +15 -0
  10. package/src/Basefn__Utils.res.mjs +32 -0
  11. package/src/Demo.res +1417 -0
  12. package/src/Demo.res.mjs +2328 -0
  13. package/src/Eita.res.mjs +105 -0
  14. package/src/Eita__Accordion.res.mjs +77 -0
  15. package/src/Eita__Alert.res.mjs +81 -0
  16. package/src/Eita__AppLayout.res.mjs +100 -0
  17. package/src/Eita__Avatar.res.mjs +40 -0
  18. package/src/Eita__Badge.res.mjs +65 -0
  19. package/src/Eita__Breadcrumb.res.mjs +53 -0
  20. package/src/Eita__Button.res.mjs +47 -0
  21. package/src/Eita__Card.res.mjs +60 -0
  22. package/src/Eita__Checkbox.res.mjs +36 -0
  23. package/src/Eita__Dom.res.mjs +16 -0
  24. package/src/Eita__Drawer.res.mjs +112 -0
  25. package/src/Eita__Dropdown.res.mjs +96 -0
  26. package/src/Eita__Grid.res.mjs +24 -0
  27. package/src/Eita__Input.res.mjs +54 -0
  28. package/src/Eita__Kbd.res.mjs +42 -0
  29. package/src/Eita__Label.res.mjs +24 -0
  30. package/src/Eita__Modal.res.mjs +93 -0
  31. package/src/Eita__Progress.res.mjs +101 -0
  32. package/src/Eita__Radio.res.mjs +38 -0
  33. package/src/Eita__Select.res.mjs +40 -0
  34. package/src/Eita__Separator.res.mjs +70 -0
  35. package/src/Eita__Sidebar.res.mjs +103 -0
  36. package/src/Eita__Slider.res.mjs +89 -0
  37. package/src/Eita__Spinner.res.mjs +69 -0
  38. package/src/Eita__Stepper.res.mjs +114 -0
  39. package/src/Eita__Switch.res.mjs +84 -0
  40. package/src/Eita__Tabs.res.mjs +57 -0
  41. package/src/Eita__Textarea.res.mjs +39 -0
  42. package/src/Eita__Timeline.res.mjs +86 -0
  43. package/src/Eita__Toast.res.mjs +112 -0
  44. package/src/Eita__Tooltip.res.mjs +60 -0
  45. package/src/Eita__Topbar.res.mjs +96 -0
  46. package/src/Eita__Typography.res.mjs +183 -0
  47. package/src/Eita__Utils.res.mjs +32 -0
  48. package/src/Example.res +111 -0
  49. package/src/Example.res.mjs +176 -0
  50. package/src/components/Basefn__Accordion.css +70 -0
  51. package/src/components/Basefn__Accordion.res +79 -0
  52. package/src/components/Basefn__Accordion.res.mjs +77 -0
  53. package/src/components/Basefn__Alert.css +79 -0
  54. package/src/components/Basefn__Alert.res +68 -0
  55. package/src/components/Basefn__Alert.res.mjs +78 -0
  56. package/src/components/Basefn__AppLayout.css +100 -0
  57. package/src/components/Basefn__AppLayout.res +74 -0
  58. package/src/components/Basefn__AppLayout.res.mjs +100 -0
  59. package/src/components/Basefn__Avatar.css +25 -0
  60. package/src/components/Basefn__Avatar.res +23 -0
  61. package/src/components/Basefn__Avatar.res.mjs +40 -0
  62. package/src/components/Basefn__Badge.css +71 -0
  63. package/src/components/Basefn__Badge.res +43 -0
  64. package/src/components/Basefn__Badge.res.mjs +65 -0
  65. package/src/components/Basefn__Breadcrumb.css +36 -0
  66. package/src/components/Basefn__Breadcrumb.res +45 -0
  67. package/src/components/Basefn__Breadcrumb.res.mjs +53 -0
  68. package/src/components/Basefn__Button.css +83 -0
  69. package/src/components/Basefn__Button.res +32 -0
  70. package/src/components/Basefn__Button.res.mjs +54 -0
  71. package/src/components/Basefn__Card.css +50 -0
  72. package/src/components/Basefn__Card.res +45 -0
  73. package/src/components/Basefn__Card.res.mjs +60 -0
  74. package/src/components/Basefn__Checkbox.css +72 -0
  75. package/src/components/Basefn__Checkbox.res +25 -0
  76. package/src/components/Basefn__Checkbox.res.mjs +36 -0
  77. package/src/components/Basefn__Drawer.css +168 -0
  78. package/src/components/Basefn__Drawer.res +86 -0
  79. package/src/components/Basefn__Drawer.res.mjs +112 -0
  80. package/src/components/Basefn__Dropdown.css +76 -0
  81. package/src/components/Basefn__Dropdown.res +85 -0
  82. package/src/components/Basefn__Dropdown.res.mjs +96 -0
  83. package/src/components/Basefn__Grid.css +11 -0
  84. package/src/components/Basefn__Grid.res +296 -0
  85. package/src/components/Basefn__Grid.res.mjs +263 -0
  86. package/src/components/Basefn__Icon.css +12 -0
  87. package/src/components/Basefn__Icon.res +196 -0
  88. package/src/components/Basefn__Icon.res.mjs +183 -0
  89. package/src/components/Basefn__Input.css +44 -0
  90. package/src/components/Basefn__Input.res +48 -0
  91. package/src/components/Basefn__Input.res.mjs +63 -0
  92. package/src/components/Basefn__Kbd.css +65 -0
  93. package/src/components/Basefn__Kbd.res +27 -0
  94. package/src/components/Basefn__Kbd.res.mjs +42 -0
  95. package/src/components/Basefn__Label.css +22 -0
  96. package/src/components/Basefn__Label.res +18 -0
  97. package/src/components/Basefn__Label.res.mjs +24 -0
  98. package/src/components/Basefn__Modal.css +100 -0
  99. package/src/components/Basefn__Modal.res +74 -0
  100. package/src/components/Basefn__Modal.res.mjs +93 -0
  101. package/src/components/Basefn__Progress.css +69 -0
  102. package/src/components/Basefn__Progress.res +88 -0
  103. package/src/components/Basefn__Progress.res.mjs +101 -0
  104. package/src/components/Basefn__Radio.css +72 -0
  105. package/src/components/Basefn__Radio.res +35 -0
  106. package/src/components/Basefn__Radio.res.mjs +38 -0
  107. package/src/components/Basefn__Select.css +44 -0
  108. package/src/components/Basefn__Select.res +33 -0
  109. package/src/components/Basefn__Select.res.mjs +40 -0
  110. package/src/components/Basefn__Separator.css +85 -0
  111. package/src/components/Basefn__Separator.res +45 -0
  112. package/src/components/Basefn__Separator.res.mjs +70 -0
  113. package/src/components/Basefn__Sidebar.css +141 -0
  114. package/src/components/Basefn__Sidebar.res +95 -0
  115. package/src/components/Basefn__Sidebar.res.mjs +107 -0
  116. package/src/components/Basefn__Slider.css +97 -0
  117. package/src/components/Basefn__Slider.res +68 -0
  118. package/src/components/Basefn__Slider.res.mjs +89 -0
  119. package/src/components/Basefn__Spinner.css +63 -0
  120. package/src/components/Basefn__Spinner.res +44 -0
  121. package/src/components/Basefn__Spinner.res.mjs +69 -0
  122. package/src/components/Basefn__Stepper.css +141 -0
  123. package/src/components/Basefn__Stepper.res +86 -0
  124. package/src/components/Basefn__Stepper.res.mjs +114 -0
  125. package/src/components/Basefn__Switch.css +80 -0
  126. package/src/components/Basefn__Switch.res +62 -0
  127. package/src/components/Basefn__Switch.res.mjs +84 -0
  128. package/src/components/Basefn__Tabs.css +54 -0
  129. package/src/components/Basefn__Tabs.res +73 -0
  130. package/src/components/Basefn__Tabs.res.mjs +57 -0
  131. package/src/components/Basefn__Textarea.css +41 -0
  132. package/src/components/Basefn__Textarea.res +28 -0
  133. package/src/components/Basefn__Textarea.res.mjs +41 -0
  134. package/src/components/Basefn__ThemeToggle.css +5 -0
  135. package/src/components/Basefn__ThemeToggle.res +29 -0
  136. package/src/components/Basefn__ThemeToggle.res.mjs +49 -0
  137. package/src/components/Basefn__Timeline.css +144 -0
  138. package/src/components/Basefn__Timeline.res +70 -0
  139. package/src/components/Basefn__Timeline.res.mjs +86 -0
  140. package/src/components/Basefn__Toast.css +100 -0
  141. package/src/components/Basefn__Toast.res +92 -0
  142. package/src/components/Basefn__Toast.res.mjs +112 -0
  143. package/src/components/Basefn__Tooltip.css +84 -0
  144. package/src/components/Basefn__Tooltip.res +42 -0
  145. package/src/components/Basefn__Tooltip.res.mjs +60 -0
  146. package/src/components/Basefn__Topbar.css +130 -0
  147. package/src/components/Basefn__Topbar.res +92 -0
  148. package/src/components/Basefn__Topbar.res.mjs +91 -0
  149. package/src/components/Basefn__Typography.css +120 -0
  150. package/src/components/Basefn__Typography.res +96 -0
  151. package/src/components/Basefn__Typography.res.mjs +175 -0
  152. package/src/styles/Basefn__Theme.res +63 -0
  153. package/src/styles/Basefn__Theme.res.mjs +65 -0
  154. package/src/styles/variables.css +199 -0
@@ -0,0 +1,114 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Xote from "xote/src/Xote.res.mjs";
4
+ import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
+ import * as Core__Option from "@rescript/core/src/Core__Option.res.mjs";
6
+
7
+ import './Basefn__Stepper.css'
8
+ ;
9
+
10
+ function statusToString(status) {
11
+ switch (status) {
12
+ case "Inactive" :
13
+ return "inactive";
14
+ case "Active" :
15
+ return "active";
16
+ case "Completed" :
17
+ return "completed";
18
+ case "Error" :
19
+ return "error";
20
+ }
21
+ }
22
+
23
+ function Basefn__Stepper(props) {
24
+ let onStepClick = props.onStepClick;
25
+ let __orientation = props.orientation;
26
+ let orientation = __orientation !== undefined ? __orientation : "Horizontal";
27
+ let getStepperClass = () => {
28
+ let orientationClass;
29
+ orientationClass = orientation === "Horizontal" ? "basefn-stepper--horizontal" : "basefn-stepper--vertical";
30
+ return "basefn-stepper " + orientationClass;
31
+ };
32
+ let getStepClass = (status, clickable) => {
33
+ let statusClass = "basefn-stepper__step--" + statusToString(status);
34
+ let clickableClass = clickable ? " basefn-stepper__step--clickable" : "";
35
+ return "basefn-stepper__step " + statusClass + clickableClass;
36
+ };
37
+ return Xote__JSX.Elements.jsx("div", {
38
+ class: getStepperClass(),
39
+ children: Xote.Component.fragment(props.steps.map((step, index) => {
40
+ let isClickable = Core__Option.isSome(onStepClick) && (step.status === "Completed" || step.status === "Active");
41
+ let match = step.status;
42
+ let tmp;
43
+ let exit = 0;
44
+ switch (match) {
45
+ case "Inactive" :
46
+ case "Active" :
47
+ exit = 1;
48
+ break;
49
+ case "Completed" :
50
+ tmp = Xote.Component.text("\u2713");
51
+ break;
52
+ case "Error" :
53
+ tmp = Xote.Component.text("\u00d7");
54
+ break;
55
+ }
56
+ if (exit === 1) {
57
+ tmp = Xote.Component.text((index + 1 | 0).toString());
58
+ }
59
+ let desc = step.description;
60
+ return Xote__JSX.Elements.jsxsKeyed("div", {
61
+ class: getStepClass(step.status, isClickable),
62
+ children: Xote__JSX.array([
63
+ Xote__JSX.Elements.jsxs("div", {
64
+ class: "basefn-stepper__step-header",
65
+ onClick: param => {
66
+ let status = step.status;
67
+ if (onStepClick === undefined) {
68
+ return;
69
+ }
70
+ switch (status) {
71
+ case "Active" :
72
+ case "Completed" :
73
+ return onStepClick(index);
74
+ case "Inactive" :
75
+ case "Error" :
76
+ return;
77
+ }
78
+ },
79
+ children: Xote__JSX.array([
80
+ Xote__JSX.Elements.jsx("div", {
81
+ class: "basefn-stepper__step-indicator",
82
+ children: tmp
83
+ }),
84
+ Xote__JSX.Elements.jsxs("div", {
85
+ class: "basefn-stepper__step-content",
86
+ children: Xote__JSX.array([
87
+ Xote__JSX.Elements.jsx("div", {
88
+ class: "basefn-stepper__step-title",
89
+ children: Xote.Component.text(step.title)
90
+ }),
91
+ desc !== undefined ? Xote__JSX.Elements.jsx("div", {
92
+ class: "basefn-stepper__step-description",
93
+ children: Xote.Component.text(desc)
94
+ }) : Xote__JSX.jsx(Xote__JSX.jsxFragment, {})
95
+ ])
96
+ })
97
+ ])
98
+ }),
99
+ Xote__JSX.Elements.jsx("div", {
100
+ class: "basefn-stepper__connector"
101
+ })
102
+ ])
103
+ }, index.toString(), undefined);
104
+ }))
105
+ });
106
+ }
107
+
108
+ let make = Basefn__Stepper;
109
+
110
+ export {
111
+ statusToString,
112
+ make,
113
+ }
114
+ /* Not a pure module */
@@ -0,0 +1,80 @@
1
+ .basefn-switch-wrapper {
2
+ display: inline-flex;
3
+ align-items: center;
4
+ gap: 0.75rem;
5
+ cursor: pointer;
6
+ user-select: none;
7
+ }
8
+
9
+ .basefn-switch-wrapper--disabled {
10
+ opacity: 0.5;
11
+ cursor: not-allowed;
12
+ }
13
+
14
+ .basefn-switch {
15
+ position: relative;
16
+ width: 44px;
17
+ height: 24px;
18
+ background-color: #d1d5db;
19
+ border-radius: 9999px;
20
+ transition: background-color 0.2s;
21
+ cursor: pointer;
22
+ }
23
+
24
+ .basefn-switch--checked {
25
+ background-color: #3b82f6;
26
+ }
27
+
28
+ .basefn-switch--disabled {
29
+ cursor: not-allowed;
30
+ }
31
+
32
+ .basefn-switch__slider {
33
+ position: absolute;
34
+ top: 2px;
35
+ left: 2px;
36
+ width: 20px;
37
+ height: 20px;
38
+ background-color: white;
39
+ border-radius: 9999px;
40
+ transition: transform 0.2s;
41
+ box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
42
+ }
43
+
44
+ .basefn-switch--checked .basefn-switch__slider {
45
+ transform: translateX(20px);
46
+ }
47
+
48
+ .basefn-switch-label {
49
+ font-size: 0.875rem;
50
+ color: #374151;
51
+ }
52
+
53
+ /* Sizes */
54
+ .basefn-switch--sm {
55
+ width: 36px;
56
+ height: 20px;
57
+ }
58
+
59
+ .basefn-switch--sm .basefn-switch__slider {
60
+ width: 16px;
61
+ height: 16px;
62
+ }
63
+
64
+ .basefn-switch--sm.basefn-switch--checked .basefn-switch__slider {
65
+ transform: translateX(16px);
66
+ }
67
+
68
+ .basefn-switch--lg {
69
+ width: 52px;
70
+ height: 28px;
71
+ }
72
+
73
+ .basefn-switch--lg .basefn-switch__slider {
74
+ width: 24px;
75
+ height: 24px;
76
+ }
77
+
78
+ .basefn-switch--lg.basefn-switch--checked .basefn-switch__slider {
79
+ transform: translateX(24px);
80
+ }
@@ -0,0 +1,62 @@
1
+ %%raw(`import './Basefn__Switch.css'`)
2
+
3
+ open Xote
4
+
5
+ type size = Sm | Md | Lg
6
+
7
+ let sizeToString = (size: size) => {
8
+ switch size {
9
+ | Sm => "sm"
10
+ | Md => "md"
11
+ | Lg => "lg"
12
+ }
13
+ }
14
+
15
+ @jsx.component
16
+ let make = (
17
+ ~checked: Signal.t<bool>,
18
+ ~onChange: option<unit => unit>=?,
19
+ ~label: option<string>=?,
20
+ ~disabled: bool=false,
21
+ ~size: size=Md,
22
+ ) => {
23
+ let handleClick = _ => {
24
+ if !disabled {
25
+ Signal.update(checked, prev => !prev)
26
+ switch onChange {
27
+ | Some(callback) => callback()
28
+ | None => ()
29
+ }
30
+ }
31
+ }
32
+
33
+ let getWrapperClass = () => {
34
+ let baseClass = "basefn-switch-wrapper"
35
+ let disabledClass = disabled ? " basefn-switch-wrapper--disabled" : ""
36
+ baseClass ++ disabledClass
37
+ }
38
+
39
+ let getSwitchClass = () => {
40
+ let baseClass = "basefn-switch"
41
+ let sizeClass = size != Md ? " basefn-switch--" ++ sizeToString(size) : ""
42
+ let checkedClass = Computed.make(() => Signal.get(checked) ? " basefn-switch--checked" : "")
43
+ let disabledClass = disabled ? " basefn-switch--disabled" : ""
44
+ baseClass ++ sizeClass ++ disabledClass
45
+ }
46
+
47
+ <label class={getWrapperClass()}>
48
+ <div
49
+ class={Computed.make(() =>
50
+ getSwitchClass() ++
51
+ Signal.get(Computed.make(() => Signal.get(checked) ? " basefn-switch--checked" : ""))
52
+ )}
53
+ onClick={handleClick}
54
+ >
55
+ <div class="basefn-switch__slider" />
56
+ </div>
57
+ {switch label {
58
+ | Some(labelText) => <span class="basefn-switch-label"> {Component.text(labelText)} </span>
59
+ | None => <> </>
60
+ }}
61
+ </label>
62
+ }
@@ -0,0 +1,84 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Xote from "xote/src/Xote.res.mjs";
4
+ import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
+
6
+ import './Basefn__Switch.css'
7
+ ;
8
+
9
+ function sizeToString(size) {
10
+ switch (size) {
11
+ case "Sm" :
12
+ return "sm";
13
+ case "Md" :
14
+ return "md";
15
+ case "Lg" :
16
+ return "lg";
17
+ }
18
+ }
19
+
20
+ function Basefn__Switch(props) {
21
+ let __size = props.size;
22
+ let __disabled = props.disabled;
23
+ let label = props.label;
24
+ let onChange = props.onChange;
25
+ let checked = props.checked;
26
+ let disabled = __disabled !== undefined ? __disabled : false;
27
+ let size = __size !== undefined ? __size : "Md";
28
+ let handleClick = param => {
29
+ if (!disabled) {
30
+ Xote.Signal.update(checked, prev => !prev);
31
+ if (onChange !== undefined) {
32
+ return onChange();
33
+ } else {
34
+ return;
35
+ }
36
+ }
37
+ };
38
+ let getWrapperClass = () => {
39
+ let disabledClass = disabled ? " basefn-switch-wrapper--disabled" : "";
40
+ return "basefn-switch-wrapper" + disabledClass;
41
+ };
42
+ let getSwitchClass = () => {
43
+ let sizeClass = size !== "Md" ? " basefn-switch--" + sizeToString(size) : "";
44
+ Xote.Computed.make(() => {
45
+ if (Xote.Signal.get(checked)) {
46
+ return " basefn-switch--checked";
47
+ } else {
48
+ return "";
49
+ }
50
+ }, undefined);
51
+ let disabledClass = disabled ? " basefn-switch--disabled" : "";
52
+ return "basefn-switch" + sizeClass + disabledClass;
53
+ };
54
+ return Xote__JSX.Elements.jsxs("label", {
55
+ class: getWrapperClass(),
56
+ children: Xote__JSX.array([
57
+ Xote__JSX.Elements.jsx("div", {
58
+ class: Xote.Computed.make(() => getSwitchClass() + Xote.Signal.get(Xote.Computed.make(() => {
59
+ if (Xote.Signal.get(checked)) {
60
+ return " basefn-switch--checked";
61
+ } else {
62
+ return "";
63
+ }
64
+ }, undefined)), undefined),
65
+ onClick: handleClick,
66
+ children: Xote__JSX.Elements.jsx("div", {
67
+ class: "basefn-switch__slider"
68
+ })
69
+ }),
70
+ label !== undefined ? Xote__JSX.Elements.jsx("span", {
71
+ class: "basefn-switch-label",
72
+ children: Xote.Component.text(label)
73
+ }) : Xote__JSX.jsx(Xote__JSX.jsxFragment, {})
74
+ ])
75
+ });
76
+ }
77
+
78
+ let make = Basefn__Switch;
79
+
80
+ export {
81
+ sizeToString,
82
+ make,
83
+ }
84
+ /* Not a pure module */
@@ -0,0 +1,54 @@
1
+ .basefn-tabs {
2
+ width: 100%;
3
+ }
4
+
5
+ .basefn-tabs__list {
6
+ display: flex;
7
+ border-bottom: 2px solid #e5e7eb;
8
+ gap: 0.5rem;
9
+ margin-bottom: 1.5rem;
10
+ }
11
+
12
+ .basefn-tabs__trigger {
13
+ padding: 0.75rem 1.25rem;
14
+ background: none;
15
+ border: none;
16
+ border-bottom: 2px solid transparent;
17
+ margin-bottom: -2px;
18
+ font-size: 0.875rem;
19
+ font-weight: 500;
20
+ color: #6b7280;
21
+ cursor: pointer;
22
+ transition: all 0.2s;
23
+ white-space: nowrap;
24
+ }
25
+
26
+ .basefn-tabs__trigger:hover {
27
+ color: #374151;
28
+ background-color: #f9fafb;
29
+ }
30
+
31
+ .basefn-tabs__trigger--active {
32
+ color: #3b82f6;
33
+ border-bottom-color: #3b82f6;
34
+ }
35
+
36
+ .basefn-tabs__trigger:disabled {
37
+ opacity: 0.5;
38
+ cursor: not-allowed;
39
+ }
40
+
41
+ .basefn-tabs__content {
42
+ animation: basefn-tabs-fade-in 0.2s ease-in;
43
+ }
44
+
45
+ @keyframes basefn-tabs-fade-in {
46
+ from {
47
+ opacity: 0;
48
+ transform: translateY(-4px);
49
+ }
50
+ to {
51
+ opacity: 1;
52
+ transform: translateY(0);
53
+ }
54
+ }
@@ -0,0 +1,73 @@
1
+ %%raw(`import './Basefn__Tabs.css'`)
2
+
3
+ open Xote
4
+
5
+ type tab = {
6
+ value: string,
7
+ label: string,
8
+ content: Component.node,
9
+ disabled?: bool,
10
+ }
11
+
12
+ @jsx.component
13
+ let make = (~tabs: array<tab>, ~defaultValue: option<string>=?) => {
14
+ // Use provided signal or create internal one
15
+ let activeTabSignal = Signal.make(
16
+ switch defaultValue {
17
+ | Some(value) => value
18
+ | None =>
19
+ tabs
20
+ ->Array.get(0)
21
+ ->Option.map(tab => tab.value)
22
+ ->Option.getOr("")
23
+ },
24
+ )
25
+
26
+ let handleTabClick = (value: string, disabled: option<bool>) => {
27
+ switch disabled {
28
+ | Some(true) => ()
29
+ | _ => Signal.set(activeTabSignal, value)
30
+ }
31
+ }
32
+
33
+ let computed = Computed.make(() => {
34
+ [
35
+ <div class="basefn-tabs">
36
+ <div class="basefn-tabs__list">
37
+ {tabs
38
+ ->Array.map(tab => {
39
+ let isActive = Computed.make(() => Signal.get(activeTabSignal) == tab.value)
40
+ let className = Computed.make(
41
+ () => {
42
+ let baseClass = "basefn-tabs__trigger"
43
+ let activeClass = Signal.get(isActive) ? " basefn-tabs__trigger--active" : ""
44
+ baseClass ++ activeClass
45
+ },
46
+ )
47
+
48
+ <button
49
+ key={tab.value}
50
+ class={className}
51
+ onClick={_ => handleTabClick(tab.value, tab.disabled)}
52
+ disabled={tab.disabled->Option.getOr(false)}
53
+ >
54
+ {Component.text(tab.label)}
55
+ </button>
56
+ })
57
+ ->Component.fragment}
58
+ </div>
59
+ <div class="basefn-tabs__content">
60
+ {
61
+ let activeValue = Signal.get(activeTabSignal)
62
+ tabs
63
+ ->Array.find(tab => tab.value == activeValue)
64
+ ->Option.map(tab => tab.content)
65
+ ->Option.getOr(<> </>)
66
+ }
67
+ </div>
68
+ </div>,
69
+ ]
70
+ })
71
+
72
+ Component.signalFragment(computed)
73
+ }
@@ -0,0 +1,57 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Xote from "xote/src/Xote.res.mjs";
4
+ import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
+ import * as Core__Option from "@rescript/core/src/Core__Option.res.mjs";
6
+
7
+ import './Basefn__Tabs.css'
8
+ ;
9
+
10
+ function Basefn__Tabs(props) {
11
+ let defaultValue = props.defaultValue;
12
+ let tabs = props.tabs;
13
+ let activeTabSignal = Xote.Signal.make(defaultValue !== undefined ? defaultValue : Core__Option.getOr(Core__Option.map(tabs[0], tab => tab.value), ""), undefined, undefined);
14
+ return Xote.Component.signalFragment(Xote.Computed.make(() => {
15
+ let activeValue = Xote.Signal.get(activeTabSignal);
16
+ return [Xote__JSX.Elements.jsxs("div", {
17
+ class: "basefn-tabs",
18
+ children: Xote__JSX.array([
19
+ Xote__JSX.Elements.jsx("div", {
20
+ class: "basefn-tabs__list",
21
+ children: Xote.Component.fragment(tabs.map(tab => {
22
+ let isActive = Xote.Computed.make(() => Xote.Signal.get(activeTabSignal) === tab.value, undefined);
23
+ let className = Xote.Computed.make(() => {
24
+ let activeClass = Xote.Signal.get(isActive) ? " basefn-tabs__trigger--active" : "";
25
+ return "basefn-tabs__trigger" + activeClass;
26
+ }, undefined);
27
+ return Xote__JSX.Elements.jsxKeyed("button", {
28
+ class: className,
29
+ disabled: Core__Option.getOr(tab.disabled, false),
30
+ onClick: param => {
31
+ let value = tab.value;
32
+ let disabled = tab.disabled;
33
+ if (disabled !== undefined && disabled) {
34
+ return;
35
+ } else {
36
+ return Xote.Signal.set(activeTabSignal, value);
37
+ }
38
+ },
39
+ children: Xote.Component.text(tab.label)
40
+ }, tab.value, undefined);
41
+ }))
42
+ }),
43
+ Xote__JSX.Elements.jsx("div", {
44
+ class: "basefn-tabs__content",
45
+ children: Core__Option.getOr(Core__Option.map(tabs.find(tab => tab.value === activeValue), tab => tab.content), Xote__JSX.jsx(Xote__JSX.jsxFragment, {}))
46
+ })
47
+ ])
48
+ })];
49
+ }, undefined));
50
+ }
51
+
52
+ let make = Basefn__Tabs;
53
+
54
+ export {
55
+ make,
56
+ }
57
+ /* Not a pure module */
@@ -0,0 +1,41 @@
1
+ @import '../styles/variables.css';
2
+
3
+ .basefn-textarea {
4
+ display: block;
5
+ width: 100%;
6
+ font-family: var(--basefn-font-family);
7
+ font-size: var(--basefn-font-size-base);
8
+ font-weight: var(--basefn-font-weight-normal);
9
+ line-height: var(--basefn-line-height-normal);
10
+ min-height: calc(var(--basefn-form-input-height) * 2);
11
+ padding: var(--basefn-form-input-padding-y) var(--basefn-form-input-padding-x);
12
+ background-color: var(--basefn-form-input-bg);
13
+ color: var(--basefn-form-input-text);
14
+ border: var(--basefn-border-width) solid var(--basefn-form-input-border);
15
+ border-radius: var(--basefn-radius-md);
16
+ outline: none;
17
+ resize: vertical;
18
+ transition: border-color var(--basefn-transition-fast), box-shadow var(--basefn-transition-fast);
19
+ }
20
+
21
+ .basefn-textarea::placeholder {
22
+ color: var(--basefn-form-input-placeholder);
23
+ opacity: 1;
24
+ }
25
+
26
+ .basefn-textarea:focus {
27
+ border-color: var(--basefn-form-input-border-focus);
28
+ box-shadow: 0 0 0 var(--basefn-focus-ring-width) var(--basefn-focus-ring-color);
29
+ }
30
+
31
+ .basefn-textarea:disabled {
32
+ background-color: var(--basefn-form-input-disabled-bg);
33
+ border-color: var(--basefn-form-input-disabled-border);
34
+ color: var(--basefn-form-input-disabled-text);
35
+ cursor: not-allowed;
36
+ resize: none;
37
+ }
38
+
39
+ .basefn-textarea:disabled::placeholder {
40
+ color: var(--basefn-form-input-disabled-text);
41
+ }
@@ -0,0 +1,28 @@
1
+ %%raw(`import './Basefn__Textarea.css'`)
2
+
3
+ open Xote
4
+
5
+ @jsx.component
6
+ let make = (
7
+ ~value: ReactiveProp.t<string>,
8
+ ~onInput=?,
9
+ ~placeholder: string="",
10
+ ~disabled: bool=false,
11
+ ) => {
12
+ let onInput = (e: Dom.event) => {
13
+ let t = Basefn__Dom.target(e)
14
+ let v = t["value"]
15
+
16
+ switch value {
17
+ | Reactive(signal) => Signal.set(signal, v)
18
+ | _ => ()
19
+ }
20
+
21
+ switch onInput {
22
+ | Some(onInput) => onInput(v)
23
+ | None => ()
24
+ }
25
+ }
26
+
27
+ <textarea class="basefn-textarea" placeholder value disabled onInput />
28
+ }
@@ -0,0 +1,41 @@
1
+ // Generated by ReScript, PLEASE EDIT WITH CARE
2
+
3
+ import * as Xote from "xote/src/Xote.res.mjs";
4
+ import * as Xote__JSX from "xote/src/Xote__JSX.res.mjs";
5
+ import * as Basefn__Dom from "../Basefn__Dom.res.mjs";
6
+
7
+ import './Basefn__Textarea.css'
8
+ ;
9
+
10
+ function Basefn__Textarea(props) {
11
+ let __disabled = props.disabled;
12
+ let __placeholder = props.placeholder;
13
+ let onInput = props.onInput;
14
+ let value = props.value;
15
+ let placeholder = __placeholder !== undefined ? __placeholder : "";
16
+ let disabled = __disabled !== undefined ? __disabled : false;
17
+ let onInput$1 = e => {
18
+ let t = Basefn__Dom.target(e);
19
+ let v = t.value;
20
+ if (value.TAG === "Reactive") {
21
+ Xote.Signal.set(value._0, v);
22
+ }
23
+ if (onInput !== undefined) {
24
+ return onInput(v);
25
+ }
26
+ };
27
+ return Xote__JSX.Elements.jsx("textarea", {
28
+ class: "basefn-textarea",
29
+ value: value,
30
+ placeholder: placeholder,
31
+ disabled: disabled,
32
+ onInput: onInput$1
33
+ });
34
+ }
35
+
36
+ let make = Basefn__Textarea;
37
+
38
+ export {
39
+ make,
40
+ }
41
+ /* Not a pure module */
@@ -0,0 +1,5 @@
1
+ @import "../styles/variables.css";
2
+
3
+ .basefn-theme-toggle svg {
4
+ color: var(--basefn-text-tertiary);
5
+ }
@@ -0,0 +1,29 @@
1
+ %%raw(`import './Basefn__ThemeToggle.css'`)
2
+
3
+ open Xote
4
+
5
+ @jsx.component
6
+ let make = (~size: [#Sm | #Md | #Lg]=#Md) => {
7
+ let theme = Basefn__Theme.currentTheme
8
+
9
+ let handleClick = e => {
10
+ Basefn__Dom.preventDefault(e)->ignore
11
+ Basefn__Dom.stopPropagation(e)->ignore
12
+ Basefn__Theme.toggleTheme()
13
+ }
14
+
15
+ let icon = Computed.make(() => {
16
+ switch Signal.get(theme) {
17
+ | Light => [<Basefn__Icon name={Sun} />]
18
+ | Dark => [<Basefn__Icon name={Moon} />]
19
+ }
20
+ })
21
+
22
+ <Basefn__Tooltip content="Toggle theme" position={Bottom}>
23
+ <Basefn__Button
24
+ variant=Ghost onClick={handleClick} class={"basefn-theme-toggle"->ReactiveProp.static}
25
+ >
26
+ {Component.signalFragment(icon)}
27
+ </Basefn__Button>
28
+ </Basefn__Tooltip>
29
+ }