stargazer-ui 1.2.0 → 1.2.1

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 (349) hide show
  1. package/.babelrc.json +10 -0
  2. package/.eslintrc.cjs +18 -0
  3. package/.gitattributes +2 -0
  4. package/LICENSE +21 -0
  5. package/dev/index.html +12 -0
  6. package/dev/index.jsx +49 -0
  7. package/dev/index.scss +59 -0
  8. package/dev/pages/ButtonPage.jsx +44 -0
  9. package/dev/pages/CardPage.jsx +81 -0
  10. package/dev/pages/DropdownPage.jsx +31 -0
  11. package/dev/pages/FormPage.jsx +130 -0
  12. package/dev/pages/ListPage.jsx +52 -0
  13. package/dev/pages/ModalPage.jsx +37 -0
  14. package/dev/pages/OverlayPage.jsx +35 -0
  15. package/dev/pages/components.jsx +19 -0
  16. package/{styles → dev}/stargazerui.css +392 -3075
  17. package/dev/stargazerui.css.map +1 -0
  18. package/dev/test.jsx +88 -0
  19. package/package.json +79 -1
  20. package/rollup.config.js +140 -0
  21. package/scripts/writePackageJsons.js +42 -0
  22. package/src/Bar/Bar.tsx +0 -0
  23. package/src/Bar/Bar.type.ts +9 -0
  24. package/src/Bar/index.ts +0 -0
  25. package/src/Button/Button.tsx +17 -0
  26. package/src/Button/Button.types.ts +8 -0
  27. package/src/Button/index.ts +3 -0
  28. package/src/ButtonGroup/ButtonGroup.tsx +14 -0
  29. package/src/ButtonGroup/ButtonGroup.types.ts +8 -0
  30. package/src/ButtonGroup/index.ts +3 -0
  31. package/src/Card/Card.tsx +70 -0
  32. package/src/Card/Card.types.ts +33 -0
  33. package/src/Card/index.ts +3 -0
  34. package/src/CloseButton/CloseButton.tsx +14 -0
  35. package/src/CloseButton/CloseButton.types.ts +6 -0
  36. package/src/CloseButton/index.ts +3 -0
  37. package/src/Dropdown/Dropdown.tsx +358 -0
  38. package/src/Dropdown/Dropdown.types.ts +52 -0
  39. package/src/Dropdown/index.ts +4 -0
  40. package/src/FileUploadButton/FileUploadButton.tsx +27 -0
  41. package/src/FileUploadButton/FileUploadButton.types.ts +9 -0
  42. package/src/FileUploadButton/index.ts +3 -0
  43. package/src/FloatingLabel/FloatingLabel.tsx +22 -0
  44. package/src/FloatingLabel/FloatingLabel.types.ts +11 -0
  45. package/src/FloatingLabel/index.ts +3 -0
  46. package/src/Form/Form.tsx +445 -0
  47. package/src/Form/Form.types.ts +117 -0
  48. package/src/Form/index.ts +4 -0
  49. package/src/InputGroup/InputGroup.tsx +46 -0
  50. package/src/InputGroup/InputGroup.types.ts +21 -0
  51. package/src/InputGroup/index.ts +4 -0
  52. package/src/List/List.tsx +112 -0
  53. package/src/List/List.types.ts +34 -0
  54. package/src/List/index.ts +4 -0
  55. package/src/Modal/Modal.tsx +220 -0
  56. package/src/Modal/Modal.types.ts +49 -0
  57. package/src/Modal/index.ts +4 -0
  58. package/src/Nav/Nav.tsx +43 -0
  59. package/src/Nav/Nav.types.ts +21 -0
  60. package/src/Nav/index.ts +4 -0
  61. package/src/NavBar/Navbar.tsx +57 -0
  62. package/src/NavBar/Navbar.types.ts +24 -0
  63. package/src/NavBar/index.ts +4 -0
  64. package/src/NavDropdown/NavDropdown.tsx +93 -0
  65. package/src/NavDropdown/NavDropdown.types.ts +6 -0
  66. package/src/NavDropdown/index.ts +3 -0
  67. package/src/Overlay/Overlay.tsx +277 -0
  68. package/src/Overlay/Overlay.types.ts +20 -0
  69. package/{Overlay/index.d.ts → src/Overlay/index.ts} +3 -3
  70. package/src/Popout/Popout.tsx +155 -0
  71. package/src/Popout/Popout.types.ts +42 -0
  72. package/src/Popout/index.ts +3 -0
  73. package/src/Spinner/Spinner.tsx +15 -0
  74. package/src/Spinner/Spinner.types.ts +7 -0
  75. package/src/Spinner/index.ts +3 -0
  76. package/src/Table/Table.tsx +16 -0
  77. package/src/Table/Table.types.ts +9 -0
  78. package/src/Table/index.ts +3 -0
  79. package/src/Tabs/Tabs.tsx +215 -0
  80. package/src/Tabs/Tabs.types.ts +49 -0
  81. package/src/Tabs/index.ts +3 -0
  82. package/src/ToggleButton/ToggleButton.tsx +21 -0
  83. package/src/ToggleButton/ToggleButton.types.ts +8 -0
  84. package/src/ToggleButton/index.ts +3 -0
  85. package/{hooks/index.d.ts → src/hooks/index.ts} +6 -5
  86. package/src/hooks/useClassname.ts +5 -0
  87. package/src/hooks/useDraggable.ts +186 -0
  88. package/src/hooks/useKeepElementFocused.ts +37 -0
  89. package/src/hooks/useScreenSize.ts +24 -0
  90. package/src/index.ts +21 -0
  91. package/src/styles/_Card.scss +166 -0
  92. package/src/styles/_CloseButton.scss +51 -0
  93. package/src/styles/_CustomButton.scss +132 -0
  94. package/src/styles/_Dropdown.scss +120 -0
  95. package/src/styles/_FloatingLabel.scss +56 -0
  96. package/src/styles/_Forms.scss +7 -0
  97. package/src/styles/_Grid.scss +178 -0
  98. package/src/styles/_InputGroup.scss +71 -0
  99. package/src/styles/_List.scss +62 -0
  100. package/src/styles/_Modal.scss +234 -0
  101. package/src/styles/_ModalOld.scss +242 -0
  102. package/src/styles/_Nav.scss +36 -0
  103. package/src/styles/_NavBar.scss +116 -0
  104. package/src/styles/_NavDropdown.scss +34 -0
  105. package/src/styles/_OffCanvas.scss +260 -0
  106. package/src/styles/_OverLay.scss +56 -0
  107. package/src/styles/_Popout.scss +75 -0
  108. package/src/styles/_Spinner.scss +19 -0
  109. package/src/styles/_Table.scss +34 -0
  110. package/src/styles/_Tabs.scss +129 -0
  111. package/src/styles/_colors.scss +510 -0
  112. package/src/styles/_components.scss +40 -0
  113. package/src/styles/_functions.scss +134 -0
  114. package/src/styles/_mixins.scss +26 -0
  115. package/src/styles/_reset.scss +231 -0
  116. package/src/styles/_utilities.scss +2480 -0
  117. package/src/styles/_variables.scss +146 -0
  118. package/src/styles/forms/_FormCheck.scss +269 -0
  119. package/src/styles/forms/_FormControl.scss +102 -0
  120. package/src/styles/forms/_FormGroup.scss +21 -0
  121. package/src/styles/forms/_FormLabel.scss +3 -0
  122. package/src/styles/forms/_FormSelect.scss +164 -0
  123. package/src/styles/forms/_FormSlider.scss +116 -0
  124. package/src/styles/forms/_FormText.scss +6 -0
  125. package/{utils/BaseTypes.d.ts → src/utils/BaseTypes.ts} +30 -23
  126. package/src/utils/ContrastingColor.ts +25 -0
  127. package/src/utils/FileImportExport.js +50 -0
  128. package/src/utils/MergeClassnames.ts +5 -0
  129. package/src/utils/MergeRefs.ts +12 -0
  130. package/src/vite-env.d.ts +1 -0
  131. package/tsconfig-build.json +4 -0
  132. package/tsconfig.json +79 -0
  133. package/tsconfig.node.json +10 -0
  134. package/types/BaseTypes.d.ts +19 -0
  135. package/{Button → types/components/Button}/Button.types.d.ts +2 -1
  136. package/types/components/Button/index.d.ts +1 -0
  137. package/{Card → types/components/Card}/Card.types.d.ts +1 -3
  138. package/types/components/Card/index.d.ts +1 -0
  139. package/{CloseButton → types/components/CloseButton}/CloseButton.types.d.ts +1 -1
  140. package/types/components/CloseButton/index.d.ts +1 -0
  141. package/{Dropdown → types/components/Dropdown}/Dropdown.types.d.ts +10 -3
  142. package/types/components/Dropdown/index.d.ts +1 -0
  143. package/{FloatingLabel → types/components/FloatingLabel}/FloatingLabel.types.d.ts +1 -1
  144. package/types/components/FloatingLabel/index.d.ts +1 -0
  145. package/types/components/Form/Form.d.ts +17 -0
  146. package/types/components/Form/Form.types.d.ts +50 -0
  147. package/types/components/Form/index.d.ts +1 -0
  148. package/types/components/InputGroup/InputGroup.d.ts +6 -0
  149. package/types/components/InputGroup/InputGroup.types.d.ts +10 -0
  150. package/types/components/InputGroup/index.d.ts +1 -0
  151. package/{Modal → types/components/Modal}/Modal.d.ts +1 -1
  152. package/{Modal → types/components/Modal}/Modal.types.d.ts +2 -3
  153. package/types/components/Modal/index.d.ts +1 -0
  154. package/{Nav → types/components/Nav}/Nav.types.d.ts +1 -1
  155. package/types/components/Nav/index.d.ts +1 -0
  156. package/{NavBar → types/components/NavBar}/Navbar.d.ts +2 -1
  157. package/{NavBar → types/components/NavBar}/Navbar.types.d.ts +1 -2
  158. package/types/components/NavBar/index.d.ts +1 -0
  159. package/{NavDropdown → types/components/NavDropdown}/NavDropdown.d.ts +2 -2
  160. package/types/components/NavDropdown/index.d.ts +1 -0
  161. package/{Popout → types/components/Popout}/Popout.types.d.ts +1 -1
  162. package/types/components/Popout/index.d.ts +1 -0
  163. package/types/components/Spinner/index.d.ts +1 -0
  164. package/{Table → types/components/Table}/Table.types.d.ts +1 -1
  165. package/types/components/Table/index.d.ts +1 -0
  166. package/{Tabs → types/components/Tabs}/Tabs.types.d.ts +1 -9
  167. package/types/components/Tabs/index.d.ts +1 -0
  168. package/types/components/ToggleButton/ToggleButton.d.ts +9 -0
  169. package/types/components/ToggleButton/ToggleButton.types.d.ts +0 -0
  170. package/types/components/ToggleButton/index.d.ts +1 -0
  171. package/types/components/index.d.ts +16 -0
  172. package/types/index.d.ts +1 -0
  173. package/vite.config.js +57 -0
  174. package/vite.config.js.timestamp-1708777378490-e94428ceb2bf9.mjs +42 -0
  175. package/Bar/Bar.type.d.ts +0 -6
  176. package/Bar/index.js +0 -2
  177. package/Bar/index.js.map +0 -1
  178. package/Bar/package.json +0 -1
  179. package/Button/Button.js +0 -12
  180. package/Button/Button.js.map +0 -1
  181. package/Button/index.d.ts +0 -3
  182. package/Button/index.js +0 -7
  183. package/Button/index.js.map +0 -1
  184. package/Button/package.json +0 -1
  185. package/ButtonGroup/ButtonGroup.d.ts +0 -4
  186. package/ButtonGroup/ButtonGroup.js +0 -10
  187. package/ButtonGroup/ButtonGroup.js.map +0 -1
  188. package/ButtonGroup/ButtonGroup.types.d.ts +0 -7
  189. package/ButtonGroup/index.d.ts +0 -3
  190. package/ButtonGroup/index.js +0 -7
  191. package/ButtonGroup/index.js.map +0 -1
  192. package/ButtonGroup/package.json +0 -1
  193. package/Card/Card.js +0 -41
  194. package/Card/Card.js.map +0 -1
  195. package/Card/index.d.ts +0 -3
  196. package/Card/index.js +0 -7
  197. package/Card/index.js.map +0 -1
  198. package/Card/package.json +0 -1
  199. package/CloseButton/CloseButton.js +0 -11
  200. package/CloseButton/CloseButton.js.map +0 -1
  201. package/CloseButton/index.d.ts +0 -3
  202. package/CloseButton/index.js +0 -7
  203. package/CloseButton/index.js.map +0 -1
  204. package/CloseButton/package.json +0 -1
  205. package/Dropdown/Dropdown.js +0 -292
  206. package/Dropdown/Dropdown.js.map +0 -1
  207. package/Dropdown/index.d.ts +0 -4
  208. package/Dropdown/index.js +0 -8
  209. package/Dropdown/index.js.map +0 -1
  210. package/Dropdown/package.json +0 -1
  211. package/FileUploadButton/FileUploadButton.d.ts +0 -4
  212. package/FileUploadButton/FileUploadButton.js +0 -21
  213. package/FileUploadButton/FileUploadButton.js.map +0 -1
  214. package/FileUploadButton/FileUploadButton.types.d.ts +0 -7
  215. package/FileUploadButton/index.d.ts +0 -3
  216. package/FileUploadButton/index.js +0 -7
  217. package/FileUploadButton/index.js.map +0 -1
  218. package/FileUploadButton/package.json +0 -1
  219. package/FloatingLabel/FloatingLabel.js +0 -17
  220. package/FloatingLabel/FloatingLabel.js.map +0 -1
  221. package/FloatingLabel/index.d.ts +0 -3
  222. package/FloatingLabel/index.js +0 -7
  223. package/FloatingLabel/index.js.map +0 -1
  224. package/FloatingLabel/package.json +0 -1
  225. package/Form/Form.d.ts +0 -38
  226. package/Form/Form.js +0 -308
  227. package/Form/Form.js.map +0 -1
  228. package/Form/Form.types.d.ts +0 -105
  229. package/Form/index.d.ts +0 -4
  230. package/Form/index.js +0 -8
  231. package/Form/index.js.map +0 -1
  232. package/Form/package.json +0 -1
  233. package/InputGroup/InputGroup.d.ts +0 -7
  234. package/InputGroup/InputGroup.js +0 -31
  235. package/InputGroup/InputGroup.js.map +0 -1
  236. package/InputGroup/InputGroup.types.d.ts +0 -16
  237. package/InputGroup/index.d.ts +0 -4
  238. package/InputGroup/index.js +0 -7
  239. package/InputGroup/index.js.map +0 -1
  240. package/InputGroup/package.json +0 -1
  241. package/List/List.d.ts +0 -14
  242. package/List/List.js +0 -76
  243. package/List/List.js.map +0 -1
  244. package/List/List.types.d.ts +0 -28
  245. package/List/index.d.ts +0 -3
  246. package/List/index.js +0 -7
  247. package/List/index.js.map +0 -1
  248. package/List/package.json +0 -1
  249. package/Modal/Modal.js +0 -160
  250. package/Modal/Modal.js.map +0 -1
  251. package/Modal/index.d.ts +0 -3
  252. package/Modal/index.js +0 -7
  253. package/Modal/index.js.map +0 -1
  254. package/Modal/package.json +0 -1
  255. package/Nav/Nav.js +0 -28
  256. package/Nav/Nav.js.map +0 -1
  257. package/Nav/index.d.ts +0 -4
  258. package/Nav/index.js +0 -7
  259. package/Nav/index.js.map +0 -1
  260. package/Nav/package.json +0 -1
  261. package/NavBar/Navbar.js +0 -36
  262. package/NavBar/Navbar.js.map +0 -1
  263. package/NavBar/index.d.ts +0 -4
  264. package/NavBar/index.js +0 -8
  265. package/NavBar/index.js.map +0 -1
  266. package/NavBar/package.json +0 -1
  267. package/NavDropdown/NavDropdown.js +0 -77
  268. package/NavDropdown/NavDropdown.js.map +0 -1
  269. package/NavDropdown/index.d.ts +0 -3
  270. package/NavDropdown/index.js +0 -7
  271. package/NavDropdown/index.js.map +0 -1
  272. package/NavDropdown/package.json +0 -1
  273. package/Overlay/Overlay.d.ts +0 -4
  274. package/Overlay/Overlay.js +0 -228
  275. package/Overlay/Overlay.js.map +0 -1
  276. package/Overlay/Overlay.types.d.ts +0 -18
  277. package/Overlay/index.js +0 -7
  278. package/Overlay/index.js.map +0 -1
  279. package/Overlay/package.json +0 -1
  280. package/Popout/Popout.js +0 -110
  281. package/Popout/Popout.js.map +0 -1
  282. package/Popout/index.d.ts +0 -3
  283. package/Popout/index.js +0 -7
  284. package/Popout/index.js.map +0 -1
  285. package/Popout/package.json +0 -1
  286. package/Spinner/Spinner.js +0 -12
  287. package/Spinner/Spinner.js.map +0 -1
  288. package/Spinner/index.d.ts +0 -3
  289. package/Spinner/index.js +0 -7
  290. package/Spinner/index.js.map +0 -1
  291. package/Spinner/package.json +0 -1
  292. package/Table/Table.js +0 -11
  293. package/Table/Table.js.map +0 -1
  294. package/Table/index.d.ts +0 -3
  295. package/Table/index.js +0 -7
  296. package/Table/index.js.map +0 -1
  297. package/Table/package.json +0 -1
  298. package/Tabs/Tabs.js +0 -158
  299. package/Tabs/Tabs.js.map +0 -1
  300. package/Tabs/index.d.ts +0 -3
  301. package/Tabs/index.js +0 -7
  302. package/Tabs/index.js.map +0 -1
  303. package/Tabs/package.json +0 -1
  304. package/ToggleButton/ToggleButton.d.ts +0 -4
  305. package/ToggleButton/ToggleButton.js +0 -17
  306. package/ToggleButton/ToggleButton.js.map +0 -1
  307. package/ToggleButton/ToggleButton.types.d.ts +0 -7
  308. package/ToggleButton/index.d.ts +0 -3
  309. package/ToggleButton/index.js +0 -7
  310. package/ToggleButton/index.js.map +0 -1
  311. package/ToggleButton/package.json +0 -1
  312. package/hooks/index.js +0 -6
  313. package/hooks/index.js.map +0 -1
  314. package/hooks/package.json +0 -1
  315. package/hooks/useClassname.d.ts +0 -2
  316. package/hooks/useClassname.js +0 -7
  317. package/hooks/useClassname.js.map +0 -1
  318. package/hooks/useDraggable.d.ts +0 -23
  319. package/hooks/useDraggable.js +0 -147
  320. package/hooks/useDraggable.js.map +0 -1
  321. package/hooks/useKeepElementFocused.d.ts +0 -2
  322. package/hooks/useKeepElementFocused.js +0 -37
  323. package/hooks/useKeepElementFocused.js.map +0 -1
  324. package/hooks/useScreenSize.d.ts +0 -5
  325. package/hooks/useScreenSize.js +0 -21
  326. package/hooks/useScreenSize.js.map +0 -1
  327. package/index.d.ts +0 -18
  328. package/index.js +0 -19
  329. package/index.js.map +0 -1
  330. package/styles/stargazerui.css.map +0 -1
  331. package/utils/ContrastingColor.d.ts +0 -1
  332. package/utils/MergeClassnames.d.ts +0 -2
  333. package/utils/MergeClassnames.js +0 -7
  334. package/utils/MergeClassnames.js.map +0 -1
  335. package/utils/MergeRefs.d.ts +0 -2
  336. package/utils/MergeRefs.js +0 -16
  337. package/utils/MergeRefs.js.map +0 -1
  338. /package/{Button → types/components/Button}/Button.d.ts +0 -0
  339. /package/{Card → types/components/Card}/Card.d.ts +0 -0
  340. /package/{CloseButton → types/components/CloseButton}/CloseButton.d.ts +0 -0
  341. /package/{Dropdown → types/components/Dropdown}/Dropdown.d.ts +0 -0
  342. /package/{FloatingLabel → types/components/FloatingLabel}/FloatingLabel.d.ts +0 -0
  343. /package/{Nav → types/components/Nav}/Nav.d.ts +0 -0
  344. /package/{NavDropdown → types/components/NavDropdown}/NavDropdown.types.d.ts +0 -0
  345. /package/{Popout → types/components/Popout}/Popout.d.ts +0 -0
  346. /package/{Spinner → types/components/Spinner}/Spinner.d.ts +0 -0
  347. /package/{Spinner → types/components/Spinner}/Spinner.types.d.ts +0 -0
  348. /package/{Table → types/components/Table}/Table.d.ts +0 -0
  349. /package/{Tabs → types/components/Tabs}/Tabs.d.ts +0 -0
@@ -0,0 +1,445 @@
1
+ import React, { forwardRef, useContext, createContext, useMemo, useState, useRef, useEffect, InvalidEvent } from "react";
2
+
3
+ import { FormCheckType, FormContextType, FormControlType, FormGroupType, FormLabelType, FormSliderType, FormTextType, FormType, FormSelectType, FormSelectControlType, FormSelectInputType, FormSelectListType, FormSelectListItemType, SelectContextType, SliderContextType } from "./Form.types";
4
+ import useClassname from "../hooks/useClassname";
5
+ import mergeRefs from "../utils/MergeRefs";
6
+ import contrastingColor from "../utils/ContrastingColor";
7
+ import { debounce } from "lodash";
8
+
9
+ export const FormContext = createContext<FormContextType | null>(null)
10
+ export const FormContextProvider = ({children, value} : {children: React.ReactNode, value:FormContextType}) => {
11
+ return (
12
+ <FormContext.Provider value={value}>
13
+ {children}
14
+ </FormContext.Provider>
15
+ )
16
+ }
17
+ export const useFormContext = () => {
18
+ const context = useContext(FormContext)
19
+ if(!context) {
20
+ return { controlId: null}
21
+ }
22
+ return context
23
+ }
24
+
25
+
26
+ const Form = forwardRef<HTMLFormElement, FormType>(({children, ...restProps}, ref) => {
27
+ return (
28
+ <form ref={ref} {...restProps}>
29
+ {children}
30
+ </form>
31
+ )
32
+ })
33
+ Form.displayName = "Form"
34
+
35
+
36
+ const Control = forwardRef<HTMLInputElement, FormControlType>( (
37
+ {as = "input", className = "", plaintext = false, id="", type = "text", autoFocus=false, ...restProps}, ref
38
+ ) => {
39
+ let Component = as
40
+
41
+ const { controlId } = useFormContext()
42
+
43
+ let elementId = controlId ?? id
44
+
45
+ let computedClassName = (plaintext ? "sg-form-control-plaintext" : "sg-form-control") + (className != "" ? " "+className : "") + (type == "color" ? " sg-form-control-color" : "")
46
+
47
+ return (
48
+ <Component autoFocus={autoFocus} ref={ref} id={elementId} type={type} className={computedClassName} {...restProps} />
49
+ )
50
+ })
51
+ Control.displayName = "FormControl"
52
+
53
+ const Group = forwardRef<HTMLDivElement, FormGroupType>( ({children, className, controlId, vertical, ...restProps}, ref) => {
54
+ const context = useMemo(() => {
55
+ return {controlId: controlId}
56
+ }, [controlId])
57
+ return (
58
+ <div ref={ref} className={`sg-form-group${className ? " "+className : ""}${vertical ? " sg-form-group-vertical":""}`} {...restProps}>
59
+ <FormContextProvider value={context}>
60
+ {children}
61
+ </FormContextProvider>
62
+ </div>
63
+ )
64
+ })
65
+ Group.displayName = "FormGroup"
66
+
67
+ const Label = forwardRef<HTMLLabelElement, FormLabelType>( ({children, className, htmlFor}, ref) => {
68
+ const { controlId } = useFormContext()
69
+
70
+ let elementHtmlFor = controlId ?? htmlFor
71
+ return (
72
+ <label ref={ref} htmlFor={elementHtmlFor} className={`sg-form-label${className ? " "+className : ""}`}>
73
+ {children}
74
+ </label>
75
+ )
76
+ })
77
+ Label.displayName = "FormLabel"
78
+
79
+ const Check = forwardRef<HTMLInputElement, FormCheckType>( ({ children,
80
+ classNameContainer, containerRef, containerId, styleContainer,
81
+ classNameLabel, labelRef, label, labelId, styleLabel,
82
+ className, type="checkbox", id, reverse=false, style, onChange, ...restProps
83
+ } , ref) => {
84
+ const { controlId } = useFormContext()
85
+
86
+ const typeComputed = !["radio", "checkbox", "color"].includes(type) ? "checkbox" : type
87
+
88
+ const [contrastColor, setContrastColor] = useState<React.CSSProperties>({})
89
+ const onChangeInternal = (event: React.ChangeEvent<HTMLInputElement>) => {
90
+ //setContrastColor({backgroundColor: "#"+contrastingColor(event.target.value)})
91
+ if(onChange) onChange(event)
92
+ }
93
+
94
+
95
+ return (
96
+ <div ref={containerRef} id={containerId} style={styleContainer} className={`sg-form-check${reverse ? " sg-form-check-reverse":""}${classNameContainer ? " "+classNameContainer : ""}${type === "switch" ? " sg-form-switch":""}`} >
97
+ {
98
+ controlId ?
99
+ <input id={controlId} ref={ref} type={typeComputed} style={style} className={`sg-form-check-input${className ? " "+className : ""}`} onChange={event => onChangeInternal(event)} {...restProps} />
100
+ :
101
+ <label ref={labelRef} id={labelId} style={styleLabel} className={`sg-form-check-label${classNameLabel ? " "+classNameLabel : ""}`}>
102
+ {reverse ?
103
+ <>
104
+ <span>{children ?? label}</span>
105
+ <input ref={ref} type={typeComputed} style={style} className={`sg-form-check-input${className ? " "+className : ""}`} onChange={event => onChangeInternal(event)} {...restProps} />
106
+ </>
107
+ :
108
+ <>
109
+ <input ref={ref} type={typeComputed} style={style} className={`sg-form-check-input${className ? " "+className : ""}`} onChange={event => onChangeInternal(event)} {...restProps} />
110
+ <span>{children ?? label}</span>
111
+ </>
112
+ }
113
+ </label>
114
+ }
115
+ </div>
116
+ )
117
+ })
118
+ Check.displayName = "FormCheck"
119
+
120
+ const Text = forwardRef<HTMLElement, FormTextType>( ({children, className, ...restProps}, ref) => {
121
+ return (
122
+ <small ref={ref} className={`sg-form-text${className ? " "+className:""}`} {...restProps}>
123
+ {children}
124
+ </small>
125
+ )
126
+ })
127
+ Check.displayName = "FormText"
128
+
129
+ export const SliderContext = createContext<SliderContextType | null>(null)
130
+ export const SliderContextProvider = ({children, value} : {children: React.ReactNode, value:SliderContextType}) => {
131
+ return (
132
+ <SliderContext.Provider value={value}>
133
+ {children}
134
+ </SliderContext.Provider>
135
+ )
136
+ }
137
+ export const useSliderContext = () => {
138
+ const context = useContext(SliderContext)
139
+ if(!context) {
140
+ throw new Error("UseSliderContext must be used within a SliderContextProvider!")
141
+ }
142
+ return context
143
+ }
144
+
145
+ const Slider = forwardRef<HTMLSpanElement, FormSliderType>( ({className, style, controlId, min=1, max=10, step=1, defaultValue=6, value, onChange, ...restProps}, ref) => {
146
+ const internalRef = useRef<HTMLDivElement>(null)
147
+ //if(internalRef.current) console.log(internalRef.current)
148
+ const trackEmpty = useRef<HTMLDivElement>(null)
149
+ const trackFilled = useRef<HTMLDivElement>(null)
150
+ const thumbRef = useRef<HTMLSpanElement>(null)
151
+ const [ internalValue, setInternalValue ] = useState(value ? value + 1 - min : defaultValue - min)
152
+ if(value && value != internalValue + min) {
153
+ setInternalValue(value - min)
154
+ }
155
+ const internalMin = min < 1 ? 1 : min
156
+ const internalMax = min < 1 ? max + 1 - min : max
157
+
158
+ const [ isGrabbing, setIsGrabbing ] = useState(false)
159
+ const updateValue = (value: number) => {
160
+ let parsedValue = value < internalMin - 1 ? internalMin - 1 : value
161
+ parsedValue = parsedValue > internalMax - internalMin ? internalMax - internalMin : parsedValue
162
+ if(parsedValue === internalValue) return
163
+
164
+ setInternalValue(parsedValue)
165
+ if(onChange) {
166
+ onChange(Math.abs(parsedValue) + min)
167
+ }
168
+ }
169
+ const getNearestStep = (event: React.PointerEvent, targetElement: HTMLElement) => {
170
+ const { pageX } = event
171
+ const paddingLeft = parseFloat(window.getComputedStyle(targetElement, null).getPropertyValue('padding-left'))
172
+ const leftEdge = targetElement.getBoundingClientRect().left + paddingLeft
173
+
174
+ const width = targetElement.scrollWidth - 2*paddingLeft
175
+ const thresholdDeltaX = width*(step)/(internalMax-internalMin)
176
+
177
+ const relativeMousePositionX = (pageX - leftEdge)/thresholdDeltaX < 0 ? 0 : (pageX - leftEdge)/thresholdDeltaX
178
+ const nearestStep = Math.round((pageX - leftEdge)/thresholdDeltaX)
179
+ return { relativeMousePositionX, nearestStep }
180
+ }
181
+
182
+ const onPointerDownTrack = (event: React.PointerEvent) => {
183
+ if(!internalRef.current) return
184
+ const { nearestStep } = getNearestStep(event, internalRef.current)
185
+ updateValue(nearestStep*step)
186
+ }
187
+ const onPointerDown = (event: React.PointerEvent) => {
188
+ (event.target as HTMLElement).setPointerCapture(event.pointerId)
189
+ setIsGrabbing(true)
190
+ if(!thumbRef.current) return
191
+
192
+ }
193
+
194
+ const onPointerMove = (event: React.PointerEvent) => {
195
+ if(!isGrabbing) return
196
+ if(!internalRef.current) return
197
+ const { relativeMousePositionX, nearestStep } = getNearestStep(event, internalRef.current)
198
+ //console.log(nearestStep)
199
+ const lowerBoundary = nearestStep === 0 || relativeMousePositionX === 0? -0.05 : 0.95*nearestStep
200
+ const upperBoundary = nearestStep === 0 || relativeMousePositionX === 0? 0.05 : 1.05*nearestStep
201
+ if(lowerBoundary < relativeMousePositionX && relativeMousePositionX < upperBoundary) {
202
+ updateValue(nearestStep*step)
203
+ }
204
+
205
+ }
206
+
207
+ const onPointerUp = (event: React.PointerEvent) => {
208
+ setIsGrabbing(false)
209
+ }
210
+
211
+ const onKeyDown = (event: React.KeyboardEvent) => {
212
+ let caseTrue = false
213
+ switch (event.key) {
214
+ case "ArrowLeft":
215
+ case "ArrowDown":
216
+ updateValue(internalValue - 1)
217
+ event.preventDefault()
218
+ break
219
+ case "ArrowRight":
220
+ case "ArrowUp":
221
+ updateValue(internalValue + 1)
222
+ event.preventDefault()
223
+ break
224
+ case "End":
225
+ updateValue(internalMax - 1)
226
+ event.preventDefault()
227
+ break
228
+ case "Home":
229
+ updateValue(internalMin - 1)
230
+ event.preventDefault()
231
+ break
232
+ }
233
+ }
234
+ const filled = (internalValue)/(internalMax-internalMin)
235
+ const pointerActions = {onPointerDown, onPointerMove, onPointerUp}
236
+ return (
237
+ <div onPointerDown={onPointerDownTrack} ref={mergeRefs([ref, internalRef])} id={controlId} style={{...style, "--filled":filled*100+"%"} as React.CSSProperties} className={useClassname("sg-form-slider", className)}>
238
+ <span ref={trackFilled} className="sg-form-slider-filled" id={controlId+"-track-filled"}></span>
239
+ <span
240
+ role="slider" tabIndex={0} ref={thumbRef} data-grabbing={isGrabbing} id={controlId+"-track-thumb"}
241
+ {...pointerActions} onKeyDown={onKeyDown} className="sg-form-slider-thumb"
242
+ aria-valuenow={internalValue + min} aria-valuemax={max} aria-valuemin={min} {...restProps}
243
+ ></span>
244
+ <span ref={trackEmpty} className="sg-form-slider-empty" id={controlId+"-track-empty"}></span>
245
+ </div>
246
+ )
247
+ })
248
+ Slider.displayName = "FormSlider"
249
+
250
+ export const SelectContext = createContext<SelectContextType | null>(null)
251
+ export const SelectContextProvider = ({children, value} : {children: React.ReactNode, value:SelectContextType}) => {
252
+ return (
253
+ <SelectContext.Provider value={value}>
254
+ {children}
255
+ </SelectContext.Provider>
256
+ )
257
+ }
258
+ export const useSelectContext = () => {
259
+ const context = useContext(SelectContext)
260
+ if(!context) {
261
+ throw new Error("UseSelectContext must be used within a SelectContextProvider!")
262
+ }
263
+ return context
264
+ }
265
+
266
+ const SelectTag = forwardRef<HTMLSelectElement, FormSelectType>( ({children, className, id, ...restProps}, ref) => {
267
+ const { controlId } = useFormContext()
268
+ const elementId = controlId ?? id
269
+ const classNames = ["sg-form-select-tag", className]
270
+ return (
271
+ <select ref={ref} className={`sg-form-select-tag${className ? " "+className : ""}`} id={elementId} {...restProps}>
272
+ {children}
273
+ </select>
274
+ )
275
+ })
276
+ SelectTag.displayName = "FormSelectTag"
277
+
278
+ const Select = forwardRef<HTMLDivElement, FormSelectType>( ({children, className, id, required="false", ...restProps}, ref) => {
279
+ const { controlId } = useFormContext()
280
+
281
+ const internalSelectRef = useRef<HTMLDivElement>(null)
282
+
283
+ const [ showList, setShowList ] = useState<boolean>(false)
284
+ const [ activeDescendant, setActiveDescendant ] = useState<string>("")
285
+ const [ inputValue, setInputValue ] = useState<string>("")
286
+
287
+ let elementId = controlId ?? id
288
+
289
+ const context = useMemo(() => ({
290
+ internalId: elementId,
291
+ showList,
292
+ setShowList,
293
+ activeDescendant,
294
+ setActiveDescendant,
295
+ inputValue,
296
+ setInputValue
297
+ }), [showList, activeDescendant, inputValue])
298
+
299
+ useEffect(() => {
300
+ const selectElement = internalSelectRef.current
301
+ const handleClick = (event: MouseEvent) => {
302
+ if(!selectElement!.contains(event.target as HTMLElement)) {
303
+ setShowList(false)
304
+ document.querySelectorAll(".sg-select-control.focus").forEach(element => {
305
+ element.classList.remove("focus")
306
+ })
307
+ }
308
+ }
309
+ if(selectElement) {
310
+ document.addEventListener("click", handleClick, true)
311
+ }
312
+ const handleSubmit = (event: any) => {
313
+ console.log(event.target)
314
+ }
315
+ document.addEventListener("invalid", handleSubmit, true)
316
+ return function cleanup() {
317
+ if(selectElement) {
318
+ document.removeEventListener("click", handleClick, true)
319
+ }
320
+ document.removeEventListener("invalid", handleSubmit, true)
321
+ }
322
+ }, [internalSelectRef.current])
323
+
324
+ return (
325
+ <div ref={mergeRefs([ref, internalSelectRef])} className={`sg-form-select${className ? " "+className : ""}`} id={elementId} {...restProps} >
326
+ <SelectContextProvider value={context}>
327
+ {children}
328
+ </SelectContextProvider>
329
+ </div>
330
+ )
331
+ })
332
+ Select.displayName = "FormSelect"
333
+
334
+ const SelectControl = forwardRef<HTMLDivElement, FormSelectControlType>( ({children, className, placeholder="Placeholder...", searchable=false, inputRef, inputOptions, ...restProps}, ref) => {
335
+ const { setShowList, internalId } = useSelectContext()
336
+ const selectControlRef = useRef<HTMLDivElement>(null)
337
+
338
+ const handlePointerUp = (event: React.MouseEvent) => {
339
+ setShowList(prev => !prev);
340
+ const selectControl = selectControlRef.current
341
+ if(selectControl) {
342
+ selectControl.classList.add("focus")
343
+ const eventTargetChildren = selectControl.children[0] as HTMLElement
344
+ if(eventTargetChildren) { eventTargetChildren.focus() }
345
+ }
346
+ }
347
+ const inputParams = {...inputOptions, disabled:searchable, placeholder:placeholder, ref:inputRef}
348
+
349
+ return (
350
+ <div ref={mergeRefs([ref, selectControlRef])} onPointerUp={handlePointerUp} className={useClassname("sg-select-control", className)} {...restProps}>
351
+ <SelectInput {...inputParams}/>
352
+ </div>
353
+ )
354
+ })
355
+ SelectControl.displayName = "FormSelectControl"
356
+
357
+ const SelectInput = forwardRef<HTMLInputElement, FormSelectInputType>( ({className, id, value, onChange, ...restProps}, ref ) => {
358
+ const { showList, setShowList, inputValue, setInputValue, internalId } = useSelectContext()
359
+
360
+ const debouncedInput = (value: string) => {
361
+ setTimeout(()=>{
362
+ setInputValue(value)
363
+ }, 300)
364
+ }
365
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
366
+ console.log(event)
367
+ if(!showList) { setShowList(true) }
368
+ if(onChange) { onChange(event) }
369
+ //debouncedInput(event.target.value)
370
+ setInputValue(event.target.value)
371
+ }
372
+ const handleKeyUp = (event: React.KeyboardEvent) => {
373
+ const key = event.key
374
+ switch(key) {
375
+ case "ArrowDown":
376
+ console.log("down arrow")
377
+ break
378
+ case "ArrowUp":
379
+ console.log("up arrow")
380
+ break
381
+ }
382
+ }
383
+
384
+
385
+ return (
386
+ <input value={inputValue} ref={ref}
387
+ onKeyUp={handleKeyUp} onChange={handleChange}
388
+ className={useClassname("sg-select-input", className)}
389
+ {...restProps}
390
+ />
391
+ )
392
+ })
393
+ SelectInput.displayName = "FormSelectInput"
394
+
395
+ const SelectList = forwardRef<HTMLUListElement, FormSelectListType>( ({children, className, id, ...restProps}, ref) => {
396
+ const { showList, internalId } = useSelectContext()
397
+
398
+ const listRef = useRef<HTMLUListElement>(null)
399
+
400
+ return (
401
+ <ul ref={mergeRefs([ref, listRef])} className={useClassname("sg-select-list", className)} style={showList ? undefined : {display:"none"}} {...restProps}>
402
+ {children}
403
+ </ul>
404
+ )
405
+ })
406
+ SelectList.displayName = "FormSelectList"
407
+
408
+ const SelectOption = forwardRef<HTMLLIElement, FormSelectListItemType>(({children, className, id, value,...restProps}, ref) => {
409
+ const { internalId } = useSelectContext()
410
+ const handlePointerEnter = (event: React.MouseEvent) => {
411
+ if(!event.target) return
412
+
413
+ let element = event.target as HTMLElement
414
+ let focusElement = document.querySelectorAll(".sg-select-list-item.focus")
415
+ //console.log(element, focusElement)
416
+ focusElement.forEach(element => element.classList.remove("focus"))
417
+ element.classList.add("focus")
418
+ }
419
+ const handlePointerUp = (event: React.MouseEvent) => {
420
+ console.log((event.target as HTMLElement).id)
421
+ }
422
+ return (
423
+ <li onPointerDown={handlePointerUp} onPointerOver={handlePointerEnter} id={value ?? id} className={useClassname("sg-select-list-item", className)} {...restProps}>
424
+ {children}
425
+ </li>
426
+ )
427
+ })
428
+ SelectOption.displayName = "FormSelectOption"
429
+
430
+
431
+ export default Object.assign(Form, {
432
+ Control: Control,
433
+ Select: Object.assign(Select, {
434
+ Control: SelectControl,
435
+ Input: SelectInput,
436
+ Options: SelectList,
437
+ Option: SelectOption
438
+ }),
439
+ SelectTag: SelectTag,
440
+ Group: Group,
441
+ Label: Label,
442
+ Check: Check,
443
+ Text: Text,
444
+ Slider: Slider
445
+ })
@@ -0,0 +1,117 @@
1
+ import { ReactNode, Dispatch, Children } from "react";
2
+
3
+ import { BaseDivType, BaseFormType, BaseInputType, BaseLabelType, BaseLItemType, BaseSelectType, BaseSpanType, BaseSliderType, BaseSmallType, BaseUListType } from "../utils/BaseTypes";
4
+
5
+ export type FormContextType = {
6
+ controlId: string
7
+ }
8
+
9
+ export type FormType = {
10
+ children: ReactNode
11
+ } & BaseFormType
12
+
13
+ export type FormControlType = {
14
+ as?: React.ElementType,
15
+ className?: string,
16
+ plaintext?: boolean,
17
+ id?: string,
18
+ type?: string,
19
+ autoFocus?: boolean
20
+ } & BaseInputType
21
+
22
+ // Form Select types
23
+ export type SelectContextType = {
24
+ internalId?:string,
25
+ showList: boolean,
26
+ setShowList: Dispatch<React.SetStateAction<boolean>>,
27
+ activeDescendant: string,
28
+ setActiveDescendant: Dispatch<React.SetStateAction<string>>,
29
+ inputValue: string,
30
+ setInputValue: Dispatch<React.SetStateAction<string>>
31
+ }
32
+ export type FormSelectType = {
33
+ children: ReactNode,
34
+ className?: string,
35
+ id?: string,
36
+ required?: boolean
37
+ } & (BaseSelectType & BaseDivType)
38
+ export type FormSelectControlType = {
39
+ children?: ReactNode,
40
+ className?: string,
41
+ placeholder?: string,
42
+ searchable?: boolean,
43
+ inputRef?: React.Ref<HTMLInputElement>,
44
+ inputOptions?: FormSelectInputType
45
+ } & BaseDivType
46
+ export type FormSelectInputType = {
47
+ className?: string,
48
+ id?: string
49
+ } & BaseInputType
50
+ export type FormSelectListType = {
51
+ children: ReactNode,
52
+ className?: string,
53
+ id?: string
54
+ } & BaseUListType
55
+ export type FormSelectListItemType = {
56
+ children: ReactNode,
57
+ className?: string,
58
+ id?: string,
59
+ value?: string
60
+ } & BaseLItemType
61
+
62
+
63
+ export type FormGroupType = {
64
+ children: ReactNode,
65
+ className?: string,
66
+ controlId: string,
67
+ vertical?: boolean
68
+ } & BaseDivType
69
+
70
+ export type FormLabelType = {
71
+ children: ReactNode,
72
+ className?: string,
73
+ htmlFor?: string
74
+ } & BaseLabelType
75
+
76
+ export type FormCheckType = {
77
+ children?: ReactNode,
78
+ style?: React.CSSProperties,
79
+ classNameContainer?:string,
80
+ containerRef?:React.LegacyRef<HTMLDivElement>,
81
+ containerId?: string,
82
+ styleContainer?: React.CSSProperties,
83
+ classNameLabel?: string,
84
+ labelRef?: React.LegacyRef<HTMLLabelElement>,
85
+ label?: string,
86
+ labelId?: string,
87
+ styleLabel?: React.CSSProperties,
88
+ className?: string,
89
+ type?: string,
90
+ controlId?: string,
91
+ reverse?: boolean,
92
+ } & BaseInputType
93
+
94
+ export type FormTextType = {
95
+ children: ReactNode,
96
+ className?: string,
97
+ } & BaseSmallType
98
+
99
+ export type FormSliderType = {
100
+ children?: ReactNode,
101
+ className?: string,
102
+ style?: React.CSSProperties,
103
+ controlId: string,
104
+ min?: number,
105
+ max?: number,
106
+ step?: number,
107
+ defaultValue?: number,
108
+ value: number,
109
+ onChange(value :number): () => any
110
+ } & BaseSpanType // BaseSliderType
111
+ export type SliderContextType = {
112
+ children: ReactNode,
113
+ controlId: string,
114
+ min?: number,
115
+ max?: number,
116
+ step?: number
117
+ }
@@ -0,0 +1,4 @@
1
+ import Form from "./Form"
2
+ export default Form
3
+ export {FormContextProvider, useFormContext} from "./Form"
4
+ export type {FormCheckType, FormContextType, FormControlType, FormGroupType, FormLabelType, FormSelectType, FormTextType, FormType} from "./Form.types"
@@ -0,0 +1,46 @@
1
+ import React, { forwardRef, useMemo } from "react"
2
+
3
+ import { InputGroupText, InputGroupType, InputGroupGridType } from "./InputGroup.types"
4
+
5
+ import { FormContextProvider, useFormContext } from "../Form"
6
+ import { useClassname } from "../hooks"
7
+
8
+ const InputGroup = forwardRef<HTMLDivElement, InputGroupType>(({children, className, controlId, ...restProps}, ref) => {
9
+ const context = useMemo(() => {
10
+ return {controlId: controlId}
11
+ }, [controlId])
12
+ return (
13
+ <div ref={ref} className={useClassname("sg-input-group", className)} {...restProps}>
14
+ <FormContextProvider value={context}>
15
+ {children}
16
+ </FormContextProvider>
17
+ </div>
18
+ )
19
+ })
20
+ InputGroup.displayName = "InputGroup"
21
+
22
+ const Grid = forwardRef<HTMLDivElement, InputGroupGridType>( ({children, className, ...restProps}, ref) => {
23
+ return (
24
+ <div ref={ref} className={useClassname("sg-input-group-grid", className)}>
25
+ {children}
26
+ </div>
27
+ )
28
+ })
29
+ Grid.displayName = "InputGroupGrid"
30
+
31
+ const Text = forwardRef<HTMLLabelElement, InputGroupText>( ({children, className, htmlFor, ...restProps}, ref) => {
32
+ const { controlId } = useFormContext()
33
+
34
+ const computedHtmlFor = controlId ?? htmlFor
35
+ return (
36
+ <label ref={ref} htmlFor={computedHtmlFor} className={useClassname("sg-input-group-text", className)} {...restProps}>
37
+ {children}
38
+ </label>
39
+ )
40
+ })
41
+ Text.displayName = "InputGroupText"
42
+
43
+ export default Object.assign(InputGroup, {
44
+ Text: Text,
45
+ Grid: Grid
46
+ })
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from "react";
2
+
3
+ import { BaseDivType, BaseLabelType } from "../utils/BaseTypes";
4
+
5
+ export type InputGroupType = {
6
+ children: ReactNode,
7
+ className?: string,
8
+ controlId: string
9
+ } & BaseDivType
10
+
11
+ export type InputGroupText = {
12
+ children: ReactNode,
13
+ className?: string,
14
+ htmlFor?: string
15
+ } & BaseLabelType
16
+
17
+ export type InputGroupGridType = {
18
+ children: ReactNode,
19
+ className?:string,
20
+
21
+ } & BaseDivType
@@ -0,0 +1,4 @@
1
+ import InputGroup from "./InputGroup"
2
+ export default InputGroup
3
+ export * from "./InputGroup"
4
+ export type { InputGroupText, InputGroupType} from "./InputGroup.types"