@health-samurai/react-components 0.0.0-alpha.4 → 0.0.0-alpha.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.
Files changed (304) hide show
  1. package/dist/bundle.css +1375 -484
  2. package/dist/src/components/code-editor/http/grammar/http.d.ts +3 -0
  3. package/dist/src/components/code-editor/http/grammar/http.d.ts.map +1 -0
  4. package/dist/src/components/code-editor/http/grammar/http.grammar +74 -0
  5. package/dist/src/components/code-editor/http/grammar/http.js +38 -0
  6. package/dist/src/components/code-editor/http/grammar/http.js.map +1 -0
  7. package/dist/src/components/code-editor/http/grammar/http.terms.d.ts +2 -0
  8. package/dist/src/components/code-editor/http/grammar/http.terms.d.ts.map +1 -0
  9. package/dist/src/components/code-editor/http/grammar/http.terms.js +4 -0
  10. package/dist/src/components/code-editor/http/grammar/http.terms.js.map +1 -0
  11. package/dist/src/components/code-editor/http/grammar/http.test.d.ts +2 -0
  12. package/dist/src/components/code-editor/http/grammar/http.test.d.ts.map +1 -0
  13. package/dist/src/components/code-editor/http/grammar/http.test.js +80 -0
  14. package/dist/src/components/code-editor/http/grammar/http.test.js.map +1 -0
  15. package/dist/src/components/code-editor/http/index.d.ts +4 -0
  16. package/dist/src/components/code-editor/http/index.d.ts.map +1 -0
  17. package/dist/src/components/code-editor/http/index.js +66 -0
  18. package/dist/src/components/code-editor/http/index.js.map +1 -0
  19. package/dist/src/components/code-editor/index.d.ts +14 -2
  20. package/dist/src/components/code-editor/index.d.ts.map +1 -1
  21. package/dist/src/components/code-editor/index.js +309 -20
  22. package/dist/src/components/code-editor/index.js.map +1 -1
  23. package/dist/src/components/code-editor.stories.d.ts +1 -0
  24. package/dist/src/components/code-editor.stories.d.ts.map +1 -1
  25. package/dist/src/components/code-editor.stories.js +255 -2
  26. package/dist/src/components/code-editor.stories.js.map +1 -1
  27. package/dist/src/components/copy-icon.d.ts +5 -1
  28. package/dist/src/components/copy-icon.d.ts.map +1 -1
  29. package/dist/src/components/copy-icon.js +41 -3
  30. package/dist/src/components/copy-icon.js.map +1 -1
  31. package/dist/src/components/data-table.d.ts +8 -0
  32. package/dist/src/components/data-table.d.ts.map +1 -0
  33. package/dist/src/components/data-table.js +65 -0
  34. package/dist/src/components/data-table.js.map +1 -0
  35. package/dist/src/components/data-table.stories.d.ts +7 -0
  36. package/dist/src/components/data-table.stories.d.ts.map +1 -0
  37. package/dist/src/components/data-table.stories.js +44 -0
  38. package/dist/src/components/data-table.stories.js.map +1 -0
  39. package/dist/src/components/fhir-structure-view.d.ts +34 -0
  40. package/dist/src/components/fhir-structure-view.d.ts.map +1 -0
  41. package/dist/src/components/fhir-structure-view.js +229 -0
  42. package/dist/src/components/fhir-structure-view.js.map +1 -0
  43. package/dist/src/components/fhir-structure-view.stories.d.ts +7 -0
  44. package/dist/src/components/fhir-structure-view.stories.d.ts.map +1 -0
  45. package/dist/src/components/fhir-structure-view.stories.js +447 -0
  46. package/dist/src/components/fhir-structure-view.stories.js.map +1 -0
  47. package/dist/src/components/patient-table.d.ts +73 -0
  48. package/dist/src/components/patient-table.d.ts.map +1 -0
  49. package/dist/src/components/patient-table.js +921 -0
  50. package/dist/src/components/patient-table.js.map +1 -0
  51. package/dist/src/components/patient-table.stories.d.ts +111 -0
  52. package/dist/src/components/patient-table.stories.d.ts.map +1 -0
  53. package/dist/src/components/patient-table.stories.js +172 -0
  54. package/dist/src/components/patient-table.stories.js.map +1 -0
  55. package/dist/src/components/request-line-editor.d.ts +13 -35
  56. package/dist/src/components/request-line-editor.d.ts.map +1 -1
  57. package/dist/src/components/request-line-editor.js +72 -49
  58. package/dist/src/components/request-line-editor.js.map +1 -1
  59. package/dist/src/components/request-line-editor.stories.d.ts.map +1 -1
  60. package/dist/src/components/request-line-editor.stories.js +17 -53
  61. package/dist/src/components/request-line-editor.stories.js.map +1 -1
  62. package/dist/src/components/segment-control.d.ts +16 -0
  63. package/dist/src/components/segment-control.d.ts.map +1 -0
  64. package/dist/src/components/segment-control.js +48 -0
  65. package/dist/src/components/segment-control.js.map +1 -0
  66. package/dist/src/components/segment-control.stories.d.ts +15 -0
  67. package/dist/src/components/segment-control.stories.d.ts.map +1 -0
  68. package/dist/src/components/segment-control.stories.js +33 -0
  69. package/dist/src/components/segment-control.stories.js.map +1 -0
  70. package/dist/src/components/split-button.d.ts +5 -0
  71. package/dist/src/components/split-button.d.ts.map +1 -0
  72. package/dist/src/components/split-button.js +12 -0
  73. package/dist/src/components/split-button.js.map +1 -0
  74. package/dist/src/components/split-button.stories.d.ts +7 -0
  75. package/dist/src/components/split-button.stories.d.ts.map +1 -0
  76. package/dist/src/components/split-button.stories.js +57 -0
  77. package/dist/src/components/split-button.stories.js.map +1 -0
  78. package/dist/src/components/tree-view.d.ts +22 -0
  79. package/dist/src/components/tree-view.d.ts.map +1 -0
  80. package/dist/src/components/tree-view.js +101 -0
  81. package/dist/src/components/tree-view.js.map +1 -0
  82. package/dist/src/components/tree-view.stories.d.ts +13 -0
  83. package/dist/src/components/tree-view.stories.d.ts.map +1 -0
  84. package/dist/src/components/tree-view.stories.js +274 -0
  85. package/dist/src/components/tree-view.stories.js.map +1 -0
  86. package/dist/src/icons.d.ts +9 -0
  87. package/dist/src/icons.d.ts.map +1 -0
  88. package/dist/src/icons.js +279 -0
  89. package/dist/src/icons.js.map +1 -0
  90. package/dist/src/index.css +42 -3
  91. package/dist/src/index.d.ts +9 -1
  92. package/dist/src/index.d.ts.map +1 -1
  93. package/dist/src/index.js +9 -1
  94. package/dist/src/index.js.map +1 -1
  95. package/dist/src/shadcn/components/ui/accordion.d.ts.map +1 -1
  96. package/dist/src/shadcn/components/ui/accordion.js +23 -5
  97. package/dist/src/shadcn/components/ui/accordion.js.map +1 -1
  98. package/dist/src/shadcn/components/ui/alert-dialog.d.ts +3 -1
  99. package/dist/src/shadcn/components/ui/alert-dialog.d.ts.map +1 -1
  100. package/dist/src/shadcn/components/ui/alert-dialog.js +5 -2
  101. package/dist/src/shadcn/components/ui/alert-dialog.js.map +1 -1
  102. package/dist/src/shadcn/components/ui/alert.d.ts.map +1 -1
  103. package/dist/src/shadcn/components/ui/alert.js +12 -5
  104. package/dist/src/shadcn/components/ui/alert.js.map +1 -1
  105. package/dist/src/shadcn/components/ui/avatar.d.ts.map +1 -1
  106. package/dist/src/shadcn/components/ui/avatar.js +4 -3
  107. package/dist/src/shadcn/components/ui/avatar.js.map +1 -1
  108. package/dist/src/shadcn/components/ui/badge.d.ts.map +1 -1
  109. package/dist/src/shadcn/components/ui/badge.js +16 -5
  110. package/dist/src/shadcn/components/ui/badge.js.map +1 -1
  111. package/dist/src/shadcn/components/ui/breadcrumb.d.ts.map +1 -1
  112. package/dist/src/shadcn/components/ui/breadcrumb.js +6 -6
  113. package/dist/src/shadcn/components/ui/breadcrumb.js.map +1 -1
  114. package/dist/src/shadcn/components/ui/button.d.ts.map +1 -1
  115. package/dist/src/shadcn/components/ui/button.js +19 -11
  116. package/dist/src/shadcn/components/ui/button.js.map +1 -1
  117. package/dist/src/shadcn/components/ui/card.d.ts.map +1 -1
  118. package/dist/src/shadcn/components/ui/card.js +14 -6
  119. package/dist/src/shadcn/components/ui/card.js.map +1 -1
  120. package/dist/src/shadcn/components/ui/checkbox.d.ts.map +1 -1
  121. package/dist/src/shadcn/components/ui/checkbox.js +20 -5
  122. package/dist/src/shadcn/components/ui/checkbox.js.map +1 -1
  123. package/dist/src/shadcn/components/ui/checkbox.stories.d.ts.map +1 -1
  124. package/dist/src/shadcn/components/ui/checkbox.stories.js +44 -35
  125. package/dist/src/shadcn/components/ui/checkbox.stories.js.map +1 -1
  126. package/dist/src/shadcn/components/ui/combobox.d.ts +18 -0
  127. package/dist/src/shadcn/components/ui/combobox.d.ts.map +1 -0
  128. package/dist/src/shadcn/components/ui/combobox.js +121 -0
  129. package/dist/src/shadcn/components/ui/combobox.js.map +1 -0
  130. package/dist/src/shadcn/components/ui/combobox.stories.d.ts +11 -0
  131. package/dist/src/shadcn/components/ui/combobox.stories.d.ts.map +1 -0
  132. package/dist/src/shadcn/components/ui/combobox.stories.js +16 -0
  133. package/dist/src/shadcn/components/ui/combobox.stories.js.map +1 -0
  134. package/dist/src/shadcn/components/ui/command.d.ts.map +1 -1
  135. package/dist/src/shadcn/components/ui/command.js +73 -12
  136. package/dist/src/shadcn/components/ui/command.js.map +1 -1
  137. package/dist/src/shadcn/components/ui/command.stories.js +0 -1
  138. package/dist/src/shadcn/components/ui/command.stories.js.map +1 -1
  139. package/dist/src/shadcn/components/ui/dialog.d.ts.map +1 -1
  140. package/dist/src/shadcn/components/ui/dialog.js +35 -7
  141. package/dist/src/shadcn/components/ui/dialog.js.map +1 -1
  142. package/dist/src/shadcn/components/ui/drawer.d.ts.map +1 -1
  143. package/dist/src/shadcn/components/ui/drawer.js +26 -5
  144. package/dist/src/shadcn/components/ui/drawer.js.map +1 -1
  145. package/dist/src/shadcn/components/ui/dropdown-menu.d.ts.map +1 -1
  146. package/dist/src/shadcn/components/ui/dropdown-menu.js +12 -1
  147. package/dist/src/shadcn/components/ui/dropdown-menu.js.map +1 -1
  148. package/dist/src/shadcn/components/ui/form.d.ts.map +1 -1
  149. package/dist/src/shadcn/components/ui/form.js +12 -4
  150. package/dist/src/shadcn/components/ui/form.js.map +1 -1
  151. package/dist/src/shadcn/components/ui/input.d.ts +3 -1
  152. package/dist/src/shadcn/components/ui/input.d.ts.map +1 -1
  153. package/dist/src/shadcn/components/ui/input.js +126 -17
  154. package/dist/src/shadcn/components/ui/input.js.map +1 -1
  155. package/dist/src/shadcn/components/ui/label.d.ts.map +1 -1
  156. package/dist/src/shadcn/components/ui/label.js +8 -1
  157. package/dist/src/shadcn/components/ui/label.js.map +1 -1
  158. package/dist/src/shadcn/components/ui/menubar.d.ts.map +1 -1
  159. package/dist/src/shadcn/components/ui/menubar.js +35 -13
  160. package/dist/src/shadcn/components/ui/menubar.js.map +1 -1
  161. package/dist/src/shadcn/components/ui/pagination.d.ts.map +1 -1
  162. package/dist/src/shadcn/components/ui/pagination.js +6 -6
  163. package/dist/src/shadcn/components/ui/pagination.js.map +1 -1
  164. package/dist/src/shadcn/components/ui/popover.d.ts.map +1 -1
  165. package/dist/src/shadcn/components/ui/popover.js +12 -1
  166. package/dist/src/shadcn/components/ui/popover.js.map +1 -1
  167. package/dist/src/shadcn/components/ui/progress.d.ts.map +1 -1
  168. package/dist/src/shadcn/components/ui/progress.js +6 -2
  169. package/dist/src/shadcn/components/ui/progress.js.map +1 -1
  170. package/dist/src/shadcn/components/ui/radio-group.d.ts.map +1 -1
  171. package/dist/src/shadcn/components/ui/radio-group.js +11 -6
  172. package/dist/src/shadcn/components/ui/radio-group.js.map +1 -1
  173. package/dist/src/shadcn/components/ui/radio-group.stories.d.ts.map +1 -1
  174. package/dist/src/shadcn/components/ui/radio-group.stories.js +57 -34
  175. package/dist/src/shadcn/components/ui/radio-group.stories.js.map +1 -1
  176. package/dist/src/shadcn/components/ui/scroll-area.d.ts.map +1 -1
  177. package/dist/src/shadcn/components/ui/scroll-area.js +9 -3
  178. package/dist/src/shadcn/components/ui/scroll-area.js.map +1 -1
  179. package/dist/src/shadcn/components/ui/select.d.ts.map +1 -1
  180. package/dist/src/shadcn/components/ui/select.js +49 -14
  181. package/dist/src/shadcn/components/ui/select.js.map +1 -1
  182. package/dist/src/shadcn/components/ui/select.stories.d.ts.map +1 -1
  183. package/dist/src/shadcn/components/ui/select.stories.js +1 -4
  184. package/dist/src/shadcn/components/ui/select.stories.js.map +1 -1
  185. package/dist/src/shadcn/components/ui/separator.d.ts.map +1 -1
  186. package/dist/src/shadcn/components/ui/separator.js +7 -1
  187. package/dist/src/shadcn/components/ui/separator.js.map +1 -1
  188. package/dist/src/shadcn/components/ui/sidebar.d.ts.map +1 -1
  189. package/dist/src/shadcn/components/ui/sidebar.js +20 -6
  190. package/dist/src/shadcn/components/ui/sidebar.js.map +1 -1
  191. package/dist/src/shadcn/components/ui/skeleton.d.ts.map +1 -1
  192. package/dist/src/shadcn/components/ui/skeleton.js +3 -1
  193. package/dist/src/shadcn/components/ui/skeleton.js.map +1 -1
  194. package/dist/src/shadcn/components/ui/slider.d.ts.map +1 -1
  195. package/dist/src/shadcn/components/ui/slider.js +34 -4
  196. package/dist/src/shadcn/components/ui/slider.js.map +1 -1
  197. package/dist/src/shadcn/components/ui/sonner.d.ts +16 -1
  198. package/dist/src/shadcn/components/ui/sonner.d.ts.map +1 -1
  199. package/dist/src/shadcn/components/ui/sonner.js +23 -3
  200. package/dist/src/shadcn/components/ui/sonner.js.map +1 -1
  201. package/dist/src/shadcn/components/ui/sonner.stories.d.ts.map +1 -1
  202. package/dist/src/shadcn/components/ui/sonner.stories.js +19 -11
  203. package/dist/src/shadcn/components/ui/sonner.stories.js.map +1 -1
  204. package/dist/src/shadcn/components/ui/switch.d.ts.map +1 -1
  205. package/dist/src/shadcn/components/ui/switch.js +18 -2
  206. package/dist/src/shadcn/components/ui/switch.js.map +1 -1
  207. package/dist/src/shadcn/components/ui/table.d.ts.map +1 -1
  208. package/dist/src/shadcn/components/ui/table.js +12 -8
  209. package/dist/src/shadcn/components/ui/table.js.map +1 -1
  210. package/dist/src/shadcn/components/ui/tabs.d.ts +21 -3
  211. package/dist/src/shadcn/components/ui/tabs.d.ts.map +1 -1
  212. package/dist/src/shadcn/components/ui/tabs.js +315 -9
  213. package/dist/src/shadcn/components/ui/tabs.js.map +1 -1
  214. package/dist/src/shadcn/components/ui/tabs.stories.d.ts.map +1 -1
  215. package/dist/src/shadcn/components/ui/tabs.stories.js +50 -1
  216. package/dist/src/shadcn/components/ui/tabs.stories.js.map +1 -1
  217. package/dist/src/shadcn/components/ui/textarea.d.ts.map +1 -1
  218. package/dist/src/shadcn/components/ui/textarea.js +15 -1
  219. package/dist/src/shadcn/components/ui/textarea.js.map +1 -1
  220. package/dist/src/shadcn/components/ui/toggle-group.d.ts.map +1 -1
  221. package/dist/src/shadcn/components/ui/toggle-group.js +6 -2
  222. package/dist/src/shadcn/components/ui/toggle-group.js.map +1 -1
  223. package/dist/src/shadcn/components/ui/toggle.d.ts.map +1 -1
  224. package/dist/src/shadcn/components/ui/toggle.js +18 -6
  225. package/dist/src/shadcn/components/ui/toggle.js.map +1 -1
  226. package/dist/src/shadcn/components/ui/tooltip.d.ts.map +1 -1
  227. package/dist/src/shadcn/components/ui/tooltip.js +11 -1
  228. package/dist/src/shadcn/components/ui/tooltip.js.map +1 -1
  229. package/dist/src/shadcn/components/ui/tree.d.ts +28 -0
  230. package/dist/src/shadcn/components/ui/tree.d.ts.map +1 -0
  231. package/dist/src/shadcn/components/ui/tree.js +122 -0
  232. package/dist/src/shadcn/components/ui/tree.js.map +1 -0
  233. package/dist/src/typography.css +12 -0
  234. package/package.json +13 -2
  235. package/src/components/code-editor/http/grammar/http.grammar +74 -0
  236. package/src/components/code-editor/http/grammar/http.terms.ts +9 -0
  237. package/src/components/code-editor/http/grammar/http.test.ts +110 -0
  238. package/src/components/code-editor/http/grammar/http.ts +21 -0
  239. package/src/components/code-editor/http/index.ts +87 -0
  240. package/src/components/code-editor/index.tsx +307 -21
  241. package/src/components/code-editor.stories.tsx +295 -1
  242. package/src/components/copy-icon.tsx +57 -3
  243. package/src/components/data-table.stories.tsx +38 -0
  244. package/src/components/data-table.tsx +117 -0
  245. package/src/components/fhir-structure-view.stories.tsx +439 -0
  246. package/src/components/fhir-structure-view.tsx +231 -0
  247. package/src/components/patient-table.stories.tsx +111 -0
  248. package/src/components/patient-table.tsx +1301 -0
  249. package/src/components/request-line-editor.stories.tsx +17 -27
  250. package/src/components/request-line-editor.tsx +98 -61
  251. package/src/components/segment-control.stories.tsx +29 -0
  252. package/src/components/segment-control.tsx +80 -0
  253. package/src/components/split-button.stories.tsx +49 -0
  254. package/src/components/split-button.tsx +17 -0
  255. package/src/components/tree-view.stories.tsx +259 -0
  256. package/src/components/tree-view.tsx +172 -0
  257. package/src/icons.tsx +287 -0
  258. package/src/index.css +42 -3
  259. package/src/index.tsx +9 -2
  260. package/src/shadcn/components/ui/accordion.tsx +66 -8
  261. package/src/shadcn/components/ui/alert-dialog.tsx +6 -2
  262. package/src/shadcn/components/ui/alert.tsx +53 -15
  263. package/src/shadcn/components/ui/avatar.tsx +17 -6
  264. package/src/shadcn/components/ui/badge.tsx +67 -18
  265. package/src/shadcn/components/ui/breadcrumb.tsx +35 -7
  266. package/src/shadcn/components/ui/button.tsx +118 -57
  267. package/src/shadcn/components/ui/card.tsx +44 -13
  268. package/src/shadcn/components/ui/checkbox.stories.tsx +20 -24
  269. package/src/shadcn/components/ui/checkbox.tsx +45 -4
  270. package/src/shadcn/components/ui/combobox.stories.tsx +19 -0
  271. package/src/shadcn/components/ui/combobox.tsx +142 -0
  272. package/src/shadcn/components/ui/command.stories.tsx +1 -1
  273. package/src/shadcn/components/ui/command.tsx +192 -36
  274. package/src/shadcn/components/ui/dialog.tsx +101 -13
  275. package/src/shadcn/components/ui/drawer.tsx +93 -18
  276. package/src/shadcn/components/ui/dropdown-menu.tsx +37 -9
  277. package/src/shadcn/components/ui/form.tsx +16 -4
  278. package/src/shadcn/components/ui/input.tsx +400 -29
  279. package/src/shadcn/components/ui/label.tsx +21 -4
  280. package/src/shadcn/components/ui/menubar.tsx +188 -43
  281. package/src/shadcn/components/ui/pagination.tsx +12 -6
  282. package/src/shadcn/components/ui/popover.tsx +35 -4
  283. package/src/shadcn/components/ui/progress.tsx +21 -5
  284. package/src/shadcn/components/ui/radio-group.stories.tsx +22 -14
  285. package/src/shadcn/components/ui/radio-group.tsx +42 -5
  286. package/src/shadcn/components/ui/scroll-area.tsx +33 -5
  287. package/src/shadcn/components/ui/select.stories.tsx +0 -2
  288. package/src/shadcn/components/ui/select.tsx +184 -33
  289. package/src/shadcn/components/ui/separator.tsx +15 -5
  290. package/src/shadcn/components/ui/sidebar.tsx +68 -26
  291. package/src/shadcn/components/ui/skeleton.tsx +4 -1
  292. package/src/shadcn/components/ui/slider.tsx +82 -11
  293. package/src/shadcn/components/ui/sonner.stories.tsx +19 -15
  294. package/src/shadcn/components/ui/sonner.tsx +53 -3
  295. package/src/shadcn/components/ui/switch.tsx +53 -7
  296. package/src/shadcn/components/ui/table.tsx +38 -11
  297. package/src/shadcn/components/ui/tabs.stories.tsx +32 -0
  298. package/src/shadcn/components/ui/tabs.tsx +456 -17
  299. package/src/shadcn/components/ui/textarea.tsx +42 -4
  300. package/src/shadcn/components/ui/toggle-group.tsx +27 -5
  301. package/src/shadcn/components/ui/toggle.tsx +59 -18
  302. package/src/shadcn/components/ui/tooltip.tsx +33 -8
  303. package/src/shadcn/components/ui/tree.tsx +233 -0
  304. package/src/typography.css +12 -0
@@ -6,6 +6,8 @@ import {
6
6
  } from "@codemirror/autocomplete";
7
7
  import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
8
8
  import { json, jsonParseLinter } from "@codemirror/lang-json";
9
+ import { SQLDialect, sql } from "@codemirror/lang-sql";
10
+ import { yaml } from "@codemirror/lang-yaml";
9
11
  import {
10
12
  bracketMatching,
11
13
  foldGutter,
@@ -16,7 +18,7 @@ import {
16
18
  } from "@codemirror/language";
17
19
  import { linter, lintGutter, lintKeymap } from "@codemirror/lint";
18
20
  import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
19
- import { EditorState } from "@codemirror/state";
21
+ import { Compartment, EditorState } from "@codemirror/state";
20
22
  import {
21
23
  crosshairCursor,
22
24
  drawSelection,
@@ -28,10 +30,13 @@ import {
28
30
  keymap,
29
31
  lineNumbers,
30
32
  rectangularSelection,
33
+ type ViewUpdate,
31
34
  } from "@codemirror/view";
32
35
  import { tags } from "@lezer/highlight";
33
36
  import * as React from "react";
34
37
 
38
+ import { http } from "./http";
39
+
35
40
  const baseTheme = EditorView.baseTheme({
36
41
  "&": {
37
42
  backgroundColor: "var(--color-bg-primary)",
@@ -70,33 +75,229 @@ const baseTheme = EditorView.baseTheme({
70
75
  },
71
76
  });
72
77
 
78
+ const readOnlyTheme = EditorView.theme({
79
+ "&": {
80
+ backgroundColor: "var(--color-bg-secondary)",
81
+ height: "100%",
82
+ width: "100%",
83
+ fontSize: "14px",
84
+ paddingTop: "8px",
85
+ paddingBottom: "8px",
86
+ },
87
+ ".cm-scroller": {
88
+ overflow: "auto",
89
+ },
90
+ ".cm-content": {
91
+ fontFamily: "var(--font-family-mono)",
92
+ padding: "0",
93
+ },
94
+ "&.cm-focused": {
95
+ outline: "none",
96
+ },
97
+ ".cm-gutter": {
98
+ fontFamily: "var(--font-family-mono)",
99
+ },
100
+ ".cm-gutters": {
101
+ backgroundColor: "var(--color-bg-secondary)",
102
+ border: "none",
103
+ },
104
+ ".cm-lineNumbers": {
105
+ paddingLeft: "16px",
106
+ },
107
+ ".cm-activeLineGutter": {
108
+ backgroundColor: "var(--color-bg-secondary)",
109
+ color: "var(--color-text-primary)",
110
+ },
111
+ ".cm-activeLine": {
112
+ backgroundColor: "rgba(255, 255, 255, 0)",
113
+ },
114
+ });
115
+
73
116
  const customHighlightStyle = HighlightStyle.define([
74
117
  { tag: tags.propertyName, color: "#EA4A35" },
75
118
  { tag: tags.string, color: "#405CBF" },
76
119
  { tag: tags.number, color: "#00A984" },
77
120
  { tag: tags.bool, color: "#569cd6" },
78
121
  { tag: tags.null, color: "#569cd6" },
122
+ { tag: tags.keyword, color: "#569cd6" },
123
+ { tag: tags.operatorKeyword, color: "#405CBF" },
124
+ { tag: tags.controlKeyword, color: "#EA4A35" },
125
+ { tag: tags.typeName, color: "#00A984" },
126
+ { tag: tags.variableName, color: "#EA4A35" },
127
+ { tag: tags.operator, color: "#405CBF" },
128
+ { tag: tags.comment, color: "#00A984" },
129
+ { tag: tags.lineComment, color: "#00A984" },
130
+ { tag: tags.blockComment, color: "#00A984" },
79
131
  ]);
80
132
 
133
+ const SQL_KEYWORDS = [
134
+ "select",
135
+ "from",
136
+ "where",
137
+ "and",
138
+ "or",
139
+ "not",
140
+ "in",
141
+ "between",
142
+ "like",
143
+ "insert",
144
+ "update",
145
+ "delete",
146
+ "create",
147
+ "drop",
148
+ "alter",
149
+ "table",
150
+ "index",
151
+ "join",
152
+ "inner",
153
+ "left",
154
+ "right",
155
+ "outer",
156
+ "on",
157
+ "as",
158
+ "order",
159
+ "by",
160
+ "group",
161
+ "having",
162
+ "limit",
163
+ "offset",
164
+ "union",
165
+ "intersect",
166
+ "except",
167
+ "distinct",
168
+ "all",
169
+ "exists",
170
+ "case",
171
+ "when",
172
+ "then",
173
+ "else",
174
+ "end",
175
+ "null",
176
+ "true",
177
+ "false",
178
+ "is",
179
+ "asc",
180
+ "desc",
181
+ ];
182
+
183
+ const SQL_BUILTIN = [
184
+ "varchar",
185
+ "char",
186
+ "text",
187
+ "integer",
188
+ "int",
189
+ "bigint",
190
+ "decimal",
191
+ "numeric",
192
+ "float",
193
+ "real",
194
+ "boolean",
195
+ "date",
196
+ "time",
197
+ "timestamp",
198
+ "uuid",
199
+ "count",
200
+ "sum",
201
+ "avg",
202
+ "min",
203
+ "max",
204
+ "coalesce",
205
+ "concat",
206
+ "substring",
207
+ "upper",
208
+ "lower",
209
+ "trim",
210
+ "length",
211
+ "now",
212
+ "current_date",
213
+ "current_time",
214
+ ];
215
+
216
+ const customSQLDialect = SQLDialect.define({
217
+ keywords: SQL_KEYWORDS.join(" "),
218
+ builtin: SQL_BUILTIN.join(" "),
219
+ });
220
+
221
+ type LanguageMode = "json" | "http" | "sql" | "yaml";
222
+
223
+ function languageExtensions(mode: LanguageMode) {
224
+ if (mode === "http") {
225
+ const jsonLang = json();
226
+ const yamlLang = yaml();
227
+ return [
228
+ http((ct) =>
229
+ ct === "application/json"
230
+ ? jsonLang.language
231
+ : ct === "text/yaml"
232
+ ? yamlLang.language
233
+ : null,
234
+ ),
235
+ syntaxHighlighting(customHighlightStyle),
236
+ ];
237
+ } else if (mode === "sql") {
238
+ return [
239
+ sql({ dialect: customSQLDialect }),
240
+ syntaxHighlighting(customHighlightStyle),
241
+ ];
242
+ } else if (mode === "yaml") {
243
+ return [yaml(), syntaxHighlighting(customHighlightStyle)];
244
+ } else {
245
+ return [
246
+ json(),
247
+ linter(jsonParseLinter(), { delay: 300 }),
248
+ syntaxHighlighting(customHighlightStyle),
249
+ ];
250
+ }
251
+ }
252
+
253
+ type CodeEditorProps = {
254
+ readOnly?: boolean;
255
+ isReadOnlyTheme?: boolean;
256
+ defaultValue?: string;
257
+ currentValue?: string;
258
+ onChange?: (value: string) => void;
259
+ onUpdate?: (update: ViewUpdate) => void;
260
+ id?: string;
261
+ mode?: LanguageMode;
262
+ viewCallback?: (view: EditorView) => void;
263
+ };
264
+
265
+ export type CodeEditorView = EditorView;
266
+
81
267
  export function CodeEditor({
82
268
  defaultValue,
269
+ currentValue,
83
270
  onChange,
84
- }: {
85
- defaultValue?: string;
86
- onChange?: (value: string) => void;
87
- }) {
88
- const editorRef = React.useRef(null);
271
+ onUpdate,
272
+ viewCallback,
273
+ readOnly = false,
274
+ id,
275
+ mode = "json",
276
+ isReadOnlyTheme = false,
277
+ }: CodeEditorProps) {
278
+ const domRef = React.useRef(null);
279
+ const [view, setView] = React.useState<EditorView | null>(null);
280
+
281
+ const initialValue = React.useRef(defaultValue ?? "");
282
+
283
+ const onChangeComparment = React.useRef(new Compartment());
284
+ const onUpdateComparment = React.useRef(new Compartment());
285
+ const languageCompartment = React.useRef(new Compartment());
286
+ const readOnlyCompartment = React.useRef(new Compartment());
287
+ const themeCompartment = React.useRef(new Compartment());
89
288
 
90
289
  React.useEffect(() => {
91
- if (!editorRef.current) {
290
+ if (!domRef.current) {
92
291
  return;
93
292
  }
94
293
 
95
294
  const view = new EditorView({
96
- parent: editorRef.current,
295
+ parent: domRef.current,
97
296
  state: EditorState.create({
98
- doc: defaultValue ?? "",
297
+ doc: initialValue.current,
99
298
  extensions: [
299
+ EditorView.contentAttributes.of({ "data-gramm": "false" }),
300
+ readOnlyCompartment.current.of(EditorState.readOnly.of(false)),
100
301
  lineNumbers(),
101
302
  foldGutter(),
102
303
  highlightSpecialChars(),
@@ -105,8 +306,7 @@ export function CodeEditor({
105
306
  dropCursor(),
106
307
  EditorState.allowMultipleSelections.of(true),
107
308
  indentOnInput(),
108
- json(),
109
- syntaxHighlighting(customHighlightStyle),
309
+ languageCompartment.current.of([]),
110
310
  bracketMatching(),
111
311
  closeBrackets(),
112
312
  autocompletion(),
@@ -115,7 +315,7 @@ export function CodeEditor({
115
315
  highlightActiveLine(),
116
316
  highlightActiveLineGutter(),
117
317
  highlightSelectionMatches(),
118
- baseTheme,
318
+ themeCompartment.current.of(baseTheme),
119
319
  keymap.of([
120
320
  ...closeBracketsKeymap,
121
321
  ...defaultKeymap,
@@ -125,19 +325,105 @@ export function CodeEditor({
125
325
  ...completionKeymap,
126
326
  ...lintKeymap,
127
327
  ]),
128
- linter(jsonParseLinter(), { delay: 300 }),
129
328
  lintGutter(),
130
- EditorView.updateListener.of((update) => {
131
- if (update.docChanged && onChange) {
132
- onChange(update.view.state.doc.toString());
133
- }
134
- }),
329
+ onChangeComparment.current.of([]),
330
+ onUpdateComparment.current.of([]),
135
331
  ],
136
332
  }),
137
333
  });
138
334
 
139
- return () => view.destroy();
140
- }, [defaultValue, onChange]);
335
+ setView(() => view);
336
+
337
+ return () => {
338
+ view.destroy();
339
+ setView(() => null);
340
+ };
341
+ }, []);
342
+
343
+ React.useEffect(() => {
344
+ if (viewCallback && view) {
345
+ viewCallback(view);
346
+ }
347
+ }, [view, viewCallback]);
348
+
349
+ React.useEffect(() => {
350
+ view?.dispatch({
351
+ effects: onChangeComparment.current.reconfigure([
352
+ EditorView.updateListener.of((update) => {
353
+ if (update.docChanged && onChange) {
354
+ onChange(update.view.state.doc.toString());
355
+ }
356
+ }),
357
+ ]),
358
+ });
359
+ }, [view, onChange]);
360
+
361
+ React.useEffect(() => {
362
+ view?.dispatch({
363
+ effects: onUpdateComparment.current.reconfigure([
364
+ EditorView.updateListener.of((update) => {
365
+ if (onUpdate) {
366
+ onUpdate(update);
367
+ }
368
+ }),
369
+ ]),
370
+ });
371
+ }, [view, onUpdate]);
372
+
373
+ // FIXME: it is probably better to have CM manage its state.
374
+ React.useEffect(() => {
375
+ if (!view || currentValue === undefined) {
376
+ return;
377
+ }
378
+
379
+ const currentDoc = view.state.doc.toString();
380
+ if (currentDoc !== currentValue) {
381
+ view.dispatch({
382
+ changes: {
383
+ from: 0,
384
+ to: currentDoc.length,
385
+ insert: currentValue,
386
+ },
387
+ });
388
+ }
389
+ }, [currentValue, view]);
390
+
391
+ React.useEffect(() => {
392
+ if (view === null) {
393
+ return;
394
+ }
395
+ view.dispatch({
396
+ effects: languageCompartment.current.reconfigure(
397
+ languageExtensions(mode),
398
+ ),
399
+ });
400
+ }, [mode, view]);
401
+
402
+ React.useEffect(() => {
403
+ if (view === null) {
404
+ return;
405
+ }
406
+ view.dispatch({
407
+ effects: [
408
+ readOnlyCompartment.current.reconfigure(
409
+ EditorState.readOnly.of(readOnly),
410
+ ),
411
+ ],
412
+ });
413
+ }, [readOnly, view]);
414
+
415
+ React.useEffect(() => {
416
+ if (view === null) {
417
+ return;
418
+ }
419
+ view.dispatch({
420
+ effects: [
421
+ themeCompartment.current.reconfigure(
422
+ isReadOnlyTheme ? readOnlyTheme : baseTheme,
423
+ ),
424
+ ],
425
+ });
426
+ }, [isReadOnlyTheme, view]);
141
427
 
142
- return <div className="h-full w-full" ref={editorRef} />;
428
+ return <div className="h-full w-full" ref={domRef} id={id} />;
143
429
  }
@@ -1,4 +1,7 @@
1
+ import type { EditorView } from "@codemirror/view";
1
2
  import type { Meta, StoryObj } from "@storybook/react-vite";
3
+ import React from "react";
4
+ import { Input } from "#shadcn/components/ui/input.js";
2
5
  import { CodeEditor } from "./code-editor";
3
6
 
4
7
  const meta: Meta<typeof CodeEditor> = {
@@ -28,7 +31,298 @@ export const Default: Story = {
28
31
  },
29
32
  render: () => (
30
33
  <div className="h-[500px] w-[500px]">
31
- <CodeEditor />
34
+ <CodeEditor mode="http" />
32
35
  </div>
33
36
  ),
34
37
  };
38
+
39
+ type ParsedHeader = {
40
+ name: string;
41
+ nameTrivia: string;
42
+ value: string;
43
+ valueTrivia: string;
44
+ };
45
+
46
+ type Parsed = {
47
+ method: string;
48
+ methodTrivia: string;
49
+ path: string;
50
+ pathTrivia: string;
51
+ headers: ParsedHeader[];
52
+ headersTrivia: string;
53
+ };
54
+
55
+ function parse(query: string): Parsed {
56
+ let hi = 0;
57
+ let lo = 0;
58
+ const res: Parsed = {
59
+ method: "",
60
+ methodTrivia: "",
61
+ path: "",
62
+ pathTrivia: "",
63
+ headers: [],
64
+ headersTrivia: "",
65
+ };
66
+
67
+ // Note that we iterate by code units, but it doesn't change correctness.
68
+ // method
69
+ for (hi = 0; hi < query.length; ++hi) {
70
+ const c = query[hi];
71
+ if (c === " " || c === "\t" || c === "\n") {
72
+ break;
73
+ }
74
+ }
75
+ res.method = query.substring(lo, hi);
76
+ lo = hi;
77
+ if (lo >= query.length) {
78
+ return res;
79
+ }
80
+
81
+ // method trivia
82
+ for (hi = lo; hi < query.length; ++hi) {
83
+ const c = query[hi];
84
+ if (!(c === " " || c === "\t")) {
85
+ break;
86
+ }
87
+ }
88
+ res.methodTrivia = query.substring(lo, hi);
89
+ lo = hi;
90
+ if (lo >= query.length) {
91
+ return res;
92
+ }
93
+
94
+ // path
95
+ for (hi = lo; hi < query.length; ++hi) {
96
+ const c = query[hi];
97
+ if (c === "\n") {
98
+ break;
99
+ }
100
+ }
101
+ res.path = query.substring(lo, hi);
102
+ lo = hi;
103
+ if (lo >= query.length) {
104
+ return res;
105
+ }
106
+
107
+ // path trivia
108
+ if (query[hi] === "\n") {
109
+ hi += 1;
110
+ res.pathTrivia = query.substring(lo, hi);
111
+ }
112
+ lo = hi;
113
+ if (lo >= query.length) {
114
+ return res;
115
+ }
116
+
117
+ // headers
118
+ let header: ParsedHeader = {
119
+ name: "",
120
+ nameTrivia: "",
121
+ value: "",
122
+ valueTrivia: "",
123
+ };
124
+ let headerReady = false;
125
+ // SAFETY: don't decrease hi inside this loop.
126
+ for (hi = lo; hi < query.length; ++hi) {
127
+ if (headerReady) {
128
+ res.headers.push(header);
129
+ }
130
+ header = { name: "", nameTrivia: "", value: "", valueTrivia: "" };
131
+ headerReady = false;
132
+
133
+ if (query[hi] === "\n") {
134
+ // end of headers
135
+ break;
136
+ }
137
+
138
+ // header name
139
+ for (lo = hi; hi <= query.length; ++hi) {
140
+ const c = query[hi];
141
+ if (c === " " || c === "\t" || c === "\n" || c === ":") {
142
+ break;
143
+ }
144
+ }
145
+ headerReady = true;
146
+ header.name = query.substring(lo, hi);
147
+ lo = hi;
148
+ if (lo >= query.length) {
149
+ break;
150
+ }
151
+
152
+ // header name trivia
153
+ let colonFound = false;
154
+ for (lo = hi; hi <= query.length; ++hi) {
155
+ const c = query[hi];
156
+ if (c === ":" && !colonFound) {
157
+ colonFound = true;
158
+ } else if (!(c === " " || c === "\t")) {
159
+ break;
160
+ }
161
+ }
162
+ header.nameTrivia = query.substring(lo, hi);
163
+ lo = hi;
164
+ if (lo >= query.length) {
165
+ break;
166
+ }
167
+
168
+ // header value
169
+ for (hi = lo; hi < query.length; ++hi) {
170
+ const c = query[hi];
171
+ if (c === "\n") {
172
+ break;
173
+ }
174
+ }
175
+ header.value = query.substring(lo, hi);
176
+ lo = hi;
177
+ if (lo >= query.length) {
178
+ break;
179
+ }
180
+
181
+ // header value trivia
182
+ if (query[hi] === "\n") {
183
+ header.valueTrivia = query.substring(lo, hi + 1);
184
+ }
185
+ lo = hi + 1;
186
+ if (lo >= query.length) {
187
+ break;
188
+ }
189
+ }
190
+ if (headerReady) {
191
+ res.headers.push(header);
192
+ }
193
+
194
+ if (query[hi] === "\n") {
195
+ res.headersTrivia = query.substring(lo, hi + 1);
196
+ }
197
+
198
+ return res;
199
+ }
200
+
201
+ const MethodInput = React.memo(function MethodInput({
202
+ method,
203
+ onMethodChange,
204
+ }: {
205
+ method: string;
206
+ onMethodChange: (ev: React.ChangeEvent<HTMLInputElement>) => void;
207
+ }) {
208
+ return (
209
+ <div className="flex justify-center items-baseline">
210
+ Method:
211
+ <Input
212
+ type="text"
213
+ className="inline"
214
+ value={method}
215
+ onChange={onMethodChange}
216
+ />
217
+ </div>
218
+ );
219
+ });
220
+
221
+ const PathInput = React.memo(function PathInput({
222
+ path,
223
+ onPathChange,
224
+ }: {
225
+ path: string;
226
+ onPathChange: (ev: React.ChangeEvent<HTMLInputElement>) => void;
227
+ }) {
228
+ return (
229
+ <div className="flex justify-center items-baseline">
230
+ {"Path: "}
231
+ <Input
232
+ type="text"
233
+ className="inline"
234
+ value={path}
235
+ onChange={onPathChange}
236
+ />
237
+ </div>
238
+ );
239
+ });
240
+
241
+ function ComplexComp() {
242
+ const [rawQuery, setRawQuery] = React.useState("");
243
+ const parsed = React.useMemo(() => parse(rawQuery), [rawQuery]);
244
+ const parsedRef = React.useRef(parsed);
245
+ React.useEffect(() => {
246
+ parsedRef.current = parsed;
247
+ }, [parsed]);
248
+ const method = React.useMemo(() => parsed.method, [parsed.method]);
249
+ const path = React.useMemo(() => parsed.path, [parsed.path]);
250
+
251
+ const viewRef = React.useRef<EditorView | null>(null);
252
+
253
+ const onMethodChange = React.useCallback(
254
+ (ev: React.ChangeEvent<HTMLInputElement>) => {
255
+ let newVal = ev.target.value;
256
+
257
+ if (newVal.indexOf(" ") !== -1) {
258
+ newVal = newVal.replaceAll(" ", "").replaceAll("\t", "");
259
+ }
260
+
261
+ const view = viewRef.current;
262
+ if (view === null) {
263
+ return null;
264
+ }
265
+
266
+ const from = 0;
267
+ const to = parsedRef.current.method.length;
268
+
269
+ view.dispatch({
270
+ changes: {
271
+ from: from,
272
+ to: to,
273
+ insert: newVal,
274
+ },
275
+ });
276
+ },
277
+ [],
278
+ );
279
+
280
+ const onPathChange = React.useCallback(
281
+ (ev: React.ChangeEvent<HTMLInputElement>) => {
282
+ const newVal = ev.target.value;
283
+
284
+ const view = viewRef.current;
285
+ if (view === null) {
286
+ return null;
287
+ }
288
+
289
+ const from =
290
+ parsedRef.current.method.length + parsedRef.current.methodTrivia.length;
291
+ const to = from + parsedRef.current.path.length;
292
+ console.log(from, to);
293
+
294
+ view.dispatch({
295
+ changes: {
296
+ from: from,
297
+ to: to,
298
+ insert: newVal,
299
+ },
300
+ });
301
+ },
302
+ [],
303
+ );
304
+
305
+ return (
306
+ <>
307
+ <MethodInput method={method} onMethodChange={onMethodChange} />
308
+ <PathInput path={path} onPathChange={onPathChange} />
309
+ <div className="h-[500px] w-[500px] border-black border-2">
310
+ <CodeEditor
311
+ mode="http"
312
+ onUpdate={(update) => {
313
+ if (update.docChanged) {
314
+ setRawQuery(update.state.doc.toString());
315
+ }
316
+ }}
317
+ viewCallback={(view) => {
318
+ viewRef.current = view;
319
+ }}
320
+ />
321
+ </div>
322
+ </>
323
+ );
324
+ }
325
+
326
+ export const Complex: Story = {
327
+ render: () => ComplexComp(),
328
+ };