@thecb/components 2.2.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 (308) hide show
  1. package/.eslintrc.json +29 -0
  2. package/.github/PULL_REQUEST_TEMPLATE.md +18 -0
  3. package/.github/stale.yml +17 -0
  4. package/.prettierignore +3 -0
  5. package/.tool-versions +1 -0
  6. package/README.md +149 -0
  7. package/dist/cb-components.cjs.js +77 -0
  8. package/package.json +96 -0
  9. package/rollup.config.js +35 -0
  10. package/src/components/atoms/alert/Alert.js +67 -0
  11. package/src/components/atoms/alert/Alert.theme.js +71 -0
  12. package/src/components/atoms/alert/index.js +3 -0
  13. package/src/components/atoms/amount-callout/AmountCallout.js +27 -0
  14. package/src/components/atoms/amount-callout/AmountCallout.theme.js +19 -0
  15. package/src/components/atoms/amount-callout/index.js +3 -0
  16. package/src/components/atoms/breadcrumb/Breadcrumb.js +50 -0
  17. package/src/components/atoms/breadcrumb/Breadcrumb.theme.js +25 -0
  18. package/src/components/atoms/breadcrumb/index.js +3 -0
  19. package/src/components/atoms/button-with-action/ButtonWithAction.js +128 -0
  20. package/src/components/atoms/button-with-action/ButtonWithAction.stories.js +125 -0
  21. package/src/components/atoms/button-with-action/ButtonWithAction.theme.js +360 -0
  22. package/src/components/atoms/button-with-action/index.js +3 -0
  23. package/src/components/atoms/button-with-link/ButtonWithLink.js +40 -0
  24. package/src/components/atoms/button-with-link/index.js +3 -0
  25. package/src/components/atoms/checkbox/Checkbox.js +143 -0
  26. package/src/components/atoms/checkbox/Checkbox.theme.js +54 -0
  27. package/src/components/atoms/checkbox/index.js +3 -0
  28. package/src/components/atoms/checkbox-list/CheckboxList.js +129 -0
  29. package/src/components/atoms/checkbox-list/CheckboxList.theme.js +42 -0
  30. package/src/components/atoms/checkbox-list/index.js +3 -0
  31. package/src/components/atoms/country-dropdown/CountryDropdown.js +24 -0
  32. package/src/components/atoms/country-dropdown/index.js +1 -0
  33. package/src/components/atoms/country-dropdown/options.js +249 -0
  34. package/src/components/atoms/display-box/DisplayBox.js +22 -0
  35. package/src/components/atoms/display-box/DisplayBox.theme.js +9 -0
  36. package/src/components/atoms/display-box/index.js +3 -0
  37. package/src/components/atoms/display-card/DisplayCard.js +65 -0
  38. package/src/components/atoms/display-card/index.js +3 -0
  39. package/src/components/atoms/dropdown/Dropdown.js +299 -0
  40. package/src/components/atoms/dropdown/Dropdown.theme.js +9 -0
  41. package/src/components/atoms/dropdown/DropdownIcon.js +31 -0
  42. package/src/components/atoms/dropdown/index.js +3 -0
  43. package/src/components/atoms/form-layouts/FormContainer.js +28 -0
  44. package/src/components/atoms/form-layouts/FormInput.js +218 -0
  45. package/src/components/atoms/form-layouts/FormInputColumn.js +15 -0
  46. package/src/components/atoms/form-layouts/FormInputRow.js +26 -0
  47. package/src/components/atoms/form-layouts/FormLayouts.theme.js +52 -0
  48. package/src/components/atoms/form-layouts/index.js +6 -0
  49. package/src/components/atoms/form-select/FormSelect.js +62 -0
  50. package/src/components/atoms/form-select/FormSelect.styled.js +65 -0
  51. package/src/components/atoms/form-select/index.js +3 -0
  52. package/src/components/atoms/formatted-address/FormattedAddress.js +53 -0
  53. package/src/components/atoms/formatted-address/FormattedAddress.theme.js +11 -0
  54. package/src/components/atoms/formatted-address/index.js +3 -0
  55. package/src/components/atoms/hamburger-button/HamburgerButton.js +113 -0
  56. package/src/components/atoms/hamburger-button/index.js +3 -0
  57. package/src/components/atoms/heading/Heading.js +37 -0
  58. package/src/components/atoms/heading/Heading.styled.js +14 -0
  59. package/src/components/atoms/heading/Heading.theme.js +18 -0
  60. package/src/components/atoms/heading/index.js +3 -0
  61. package/src/components/atoms/icons/AccountsAddIcon.js +42 -0
  62. package/src/components/atoms/icons/AccountsIcon.js +37 -0
  63. package/src/components/atoms/icons/AccountsIconSmall.js +63 -0
  64. package/src/components/atoms/icons/ChevronIcon.js +51 -0
  65. package/src/components/atoms/icons/ForgotPasswordIcon.js +46 -0
  66. package/src/components/atoms/icons/GoToEmailIcon.js +31 -0
  67. package/src/components/atoms/icons/Icons.theme.js +38 -0
  68. package/src/components/atoms/icons/PaymentMethodIcon.js +42 -0
  69. package/src/components/atoms/icons/PaymentsIconSmall.js +63 -0
  70. package/src/components/atoms/icons/ProfileIconSmall.js +44 -0
  71. package/src/components/atoms/icons/PropertiesAddIcon.js +70 -0
  72. package/src/components/atoms/icons/PropertiesIconSmall.js +32 -0
  73. package/src/components/atoms/icons/SettingsIconSmall.js +63 -0
  74. package/src/components/atoms/icons/VerifiedEmailIcon.js +53 -0
  75. package/src/components/atoms/icons/index.js +28 -0
  76. package/src/components/atoms/index.js +33 -0
  77. package/src/components/atoms/labeled-amount/LabeledAmount.js +35 -0
  78. package/src/components/atoms/labeled-amount/LabeledAmount.theme.js +10 -0
  79. package/src/components/atoms/labeled-amount/index.js +3 -0
  80. package/src/components/atoms/layouts/Box.js +83 -0
  81. package/src/components/atoms/layouts/Box.styled.js +131 -0
  82. package/src/components/atoms/layouts/Center.js +28 -0
  83. package/src/components/atoms/layouts/Center.styled.js +18 -0
  84. package/src/components/atoms/layouts/Cluster.js +37 -0
  85. package/src/components/atoms/layouts/Cluster.styled.js +21 -0
  86. package/src/components/atoms/layouts/Cover.js +49 -0
  87. package/src/components/atoms/layouts/Cover.styled.js +29 -0
  88. package/src/components/atoms/layouts/Frame.js +28 -0
  89. package/src/components/atoms/layouts/Frame.styled.js +27 -0
  90. package/src/components/atoms/layouts/Grid.js +38 -0
  91. package/src/components/atoms/layouts/Grid.styled.js +22 -0
  92. package/src/components/atoms/layouts/Imposter.js +52 -0
  93. package/src/components/atoms/layouts/Imposter.styled.js +19 -0
  94. package/src/components/atoms/layouts/Motion.js +51 -0
  95. package/src/components/atoms/layouts/Motion.styled.js +41 -0
  96. package/src/components/atoms/layouts/Reel.js +28 -0
  97. package/src/components/atoms/layouts/Reel.styled.js +17 -0
  98. package/src/components/atoms/layouts/Sidebar.js +42 -0
  99. package/src/components/atoms/layouts/Sidebar.styled.js +38 -0
  100. package/src/components/atoms/layouts/Stack.js +36 -0
  101. package/src/components/atoms/layouts/Stack.styled.js +30 -0
  102. package/src/components/atoms/layouts/Switcher.js +64 -0
  103. package/src/components/atoms/layouts/Switcher.styled.js +44 -0
  104. package/src/components/atoms/layouts/examples/FixedSizeContainer.js +22 -0
  105. package/src/components/atoms/layouts/examples/FixedSizeContainer.styled.js +20 -0
  106. package/src/components/atoms/layouts/examples/LayoutContentBlock.js +27 -0
  107. package/src/components/atoms/layouts/examples/LayoutContentBlock.styled.js +15 -0
  108. package/src/components/atoms/layouts/examples/ResizingContainer.js +49 -0
  109. package/src/components/atoms/layouts/examples/ResizingContainer.styled.js +39 -0
  110. package/src/components/atoms/layouts/examples/cluster-example/ClusterExample.js +10 -0
  111. package/src/components/atoms/layouts/examples/cluster-example/ClusterExample.stories.js +97 -0
  112. package/src/components/atoms/layouts/examples/grid-example/GridExample.js +49 -0
  113. package/src/components/atoms/layouts/examples/grid-example/GridExample.stories.js +44 -0
  114. package/src/components/atoms/layouts/examples/sidebar-example/SidebarExample.js +11 -0
  115. package/src/components/atoms/layouts/examples/sidebar-example/SidebarExample.stories.js +87 -0
  116. package/src/components/atoms/layouts/examples/stack-example/StackExample.js +27 -0
  117. package/src/components/atoms/layouts/examples/stack-example/StackExample.stories.js +69 -0
  118. package/src/components/atoms/layouts/examples/switcher-example/SwitcherExample.js +38 -0
  119. package/src/components/atoms/layouts/examples/switcher-example/SwitcherExample.stories.js +65 -0
  120. package/src/components/atoms/layouts/index.js +27 -0
  121. package/src/components/atoms/line-item/LineItem.js +30 -0
  122. package/src/components/atoms/line-item/LineItem.theme.js +7 -0
  123. package/src/components/atoms/line-item/index.js +3 -0
  124. package/src/components/atoms/link/ExternalLink.js +50 -0
  125. package/src/components/atoms/link/ExternalLink.styled.js +26 -0
  126. package/src/components/atoms/link/InternalLink.js +51 -0
  127. package/src/components/atoms/link/InternalLink.styled.js +39 -0
  128. package/src/components/atoms/link/Link.theme.js +8 -0
  129. package/src/components/atoms/link/index.js +4 -0
  130. package/src/components/atoms/nav-footer/NavFooter.js +57 -0
  131. package/src/components/atoms/nav-footer/index.js +3 -0
  132. package/src/components/atoms/nav-header/NavHeader.js +36 -0
  133. package/src/components/atoms/nav-header/index.js +3 -0
  134. package/src/components/atoms/paragraph/Paragraph.js +31 -0
  135. package/src/components/atoms/paragraph/Paragraph.styled.js +13 -0
  136. package/src/components/atoms/paragraph/Paragraph.theme.js +18 -0
  137. package/src/components/atoms/paragraph/index.js +3 -0
  138. package/src/components/atoms/password-requirements/PasswordRequirements.js +116 -0
  139. package/src/components/atoms/password-requirements/index.js +3 -0
  140. package/src/components/atoms/placeholder/Placeholder.js +122 -0
  141. package/src/components/atoms/placeholder/Placeholder.theme.js +9 -0
  142. package/src/components/atoms/placeholder/index.js +3 -0
  143. package/src/components/atoms/processing-fee/ProcessingFee.js +43 -0
  144. package/src/components/atoms/processing-fee/ProcessingFee.theme.js +7 -0
  145. package/src/components/atoms/processing-fee/index.js +3 -0
  146. package/src/components/atoms/radio-button/RadioButton.js +101 -0
  147. package/src/components/atoms/radio-button/RadioButton.theme.js +9 -0
  148. package/src/components/atoms/radio-button/index.js +3 -0
  149. package/src/components/atoms/solid-divider/SolidDivider.js +22 -0
  150. package/src/components/atoms/solid-divider/SolidDivider.theme.js +8 -0
  151. package/src/components/atoms/solid-divider/index.js +3 -0
  152. package/src/components/atoms/spinner/Spinner.js +61 -0
  153. package/src/components/atoms/spinner/Spinner.theme.js +5 -0
  154. package/src/components/atoms/spinner/index.js +3 -0
  155. package/src/components/atoms/state-province-dropdown/StateProvinceDropdown.js +28 -0
  156. package/src/components/atoms/state-province-dropdown/index.js +3 -0
  157. package/src/components/atoms/state-province-dropdown/options.js +3837 -0
  158. package/src/components/atoms/text/Text.js +37 -0
  159. package/src/components/atoms/text/Text.styled.js +32 -0
  160. package/src/components/atoms/text/Text.theme.js +22 -0
  161. package/src/components/atoms/text/index.js +3 -0
  162. package/src/components/atoms/toggle-switch/ToggleSwitch.js +212 -0
  163. package/src/components/atoms/toggle-switch/ToggleSwitch.theme.js +36 -0
  164. package/src/components/atoms/toggle-switch/index.js +3 -0
  165. package/src/components/index.js +3 -0
  166. package/src/components/molecules/address-form/AddressForm.js +110 -0
  167. package/src/components/molecules/address-form/AddressForm.state.js +52 -0
  168. package/src/components/molecules/address-form/index.js +11 -0
  169. package/src/components/molecules/change-password-form/ChangePasswordForm.js +92 -0
  170. package/src/components/molecules/change-password-form/ChangePasswordForm.state.js +33 -0
  171. package/src/components/molecules/change-password-form/index.js +11 -0
  172. package/src/components/molecules/collapsible-section/CollapsibleSection.js +126 -0
  173. package/src/components/molecules/collapsible-section/CollapsibleSection.theme.js +11 -0
  174. package/src/components/molecules/collapsible-section/index.js +3 -0
  175. package/src/components/molecules/edit-name-form/EditNameForm.js +51 -0
  176. package/src/components/molecules/edit-name-form/EditNameForm.state.js +14 -0
  177. package/src/components/molecules/edit-name-form/index.js +11 -0
  178. package/src/components/molecules/email-form/EmailForm.js +55 -0
  179. package/src/components/molecules/email-form/EmailForm.state.js +19 -0
  180. package/src/components/molecules/email-form/index.js +11 -0
  181. package/src/components/molecules/forgot-password-form/ForgotPasswordForm.js +32 -0
  182. package/src/components/molecules/forgot-password-form/ForgotPasswordForm.state.js +11 -0
  183. package/src/components/molecules/forgot-password-form/index.js +11 -0
  184. package/src/components/molecules/highlight-tab-row/HighlightTabRow.js +62 -0
  185. package/src/components/molecules/highlight-tab-row/HighlightTabRow.theme.js +7 -0
  186. package/src/components/molecules/highlight-tab-row/index.js +8 -0
  187. package/src/components/molecules/index.js +24 -0
  188. package/src/components/molecules/login-form/LoginForm.js +46 -0
  189. package/src/components/molecules/login-form/LoginForm.state.js +14 -0
  190. package/src/components/molecules/login-form/index.js +11 -0
  191. package/src/components/molecules/modal/Modal.js +138 -0
  192. package/src/components/molecules/modal/index.js +3 -0
  193. package/src/components/molecules/module/Module.js +42 -0
  194. package/src/components/molecules/module/Module.theme.js +30 -0
  195. package/src/components/molecules/module/index.js +8 -0
  196. package/src/components/molecules/nav-menu/NavMenu.theme.js +5 -0
  197. package/src/components/molecules/nav-menu/NavMenuDesktop.js +39 -0
  198. package/src/components/molecules/nav-menu/NavMenuMobile.js +63 -0
  199. package/src/components/molecules/nav-menu/index.js +4 -0
  200. package/src/components/molecules/obligation/Obligation.js +69 -0
  201. package/src/components/molecules/obligation/icons/AccountBillIcon.js +89 -0
  202. package/src/components/molecules/obligation/icons/AccountConstructionIcon.js +99 -0
  203. package/src/components/molecules/obligation/icons/AccountDentalIcon.js +94 -0
  204. package/src/components/molecules/obligation/icons/AccountElectricIcon.js +99 -0
  205. package/src/components/molecules/obligation/icons/AccountGarbageIcon.js +94 -0
  206. package/src/components/molecules/obligation/icons/AccountGasIcon.js +94 -0
  207. package/src/components/molecules/obligation/icons/AccountGenericIcon.js +89 -0
  208. package/src/components/molecules/obligation/icons/AccountMedicalIcon.js +94 -0
  209. package/src/components/molecules/obligation/icons/AccountWaterIcon.js +94 -0
  210. package/src/components/molecules/obligation/icons/PropertyApartmentIcon.js +99 -0
  211. package/src/components/molecules/obligation/icons/PropertyBusinessIcon.js +94 -0
  212. package/src/components/molecules/obligation/icons/PropertyCarIcon.js +99 -0
  213. package/src/components/molecules/obligation/icons/PropertyCommercialVehicleIcon.js +100 -0
  214. package/src/components/molecules/obligation/icons/PropertyGarageIcon.js +96 -0
  215. package/src/components/molecules/obligation/icons/PropertyLandIcon.js +99 -0
  216. package/src/components/molecules/obligation/icons/PropertyMotorcycleIcon.js +99 -0
  217. package/src/components/molecules/obligation/icons/PropertyPersonalIcon.js +94 -0
  218. package/src/components/molecules/obligation/icons/PropertyStorefrontIcon.js +100 -0
  219. package/src/components/molecules/obligation/icons/index.js +60 -0
  220. package/src/components/molecules/obligation/index.js +3 -0
  221. package/src/components/molecules/obligation/modules/AmountModule.js +36 -0
  222. package/src/components/molecules/obligation/modules/IconModule.js +29 -0
  223. package/src/components/molecules/obligation/modules/PaymentDetailsActions.js +67 -0
  224. package/src/components/molecules/obligation/modules/TitleModule.js +25 -0
  225. package/src/components/molecules/obligation/modules/index.js +6 -0
  226. package/src/components/molecules/payment-button-bar/PaymentButtonBar.js +80 -0
  227. package/src/components/molecules/payment-button-bar/index.js +3 -0
  228. package/src/components/molecules/payment-details/PaymentDetails.js +158 -0
  229. package/src/components/molecules/payment-details/PaymentDetails.theme.js +11 -0
  230. package/src/components/molecules/payment-details/index.js +1 -0
  231. package/src/components/molecules/phone-form/PhoneForm.js +44 -0
  232. package/src/components/molecules/phone-form/PhoneForm.state.js +17 -0
  233. package/src/components/molecules/phone-form/index.js +11 -0
  234. package/src/components/molecules/radio-section/RadioSection.js +205 -0
  235. package/src/components/molecules/radio-section/RadioSection.theme.js +15 -0
  236. package/src/components/molecules/radio-section/index.js +3 -0
  237. package/src/components/molecules/registration-form/RegistrationForm.js +104 -0
  238. package/src/components/molecules/registration-form/RegistrationForm.state.js +40 -0
  239. package/src/components/molecules/registration-form/index.js +11 -0
  240. package/src/components/molecules/reset-confirmation-form/ResetConfirmationForm.js +56 -0
  241. package/src/components/molecules/reset-confirmation-form/index.js +3 -0
  242. package/src/components/molecules/reset-password-form/ResetPasswordForm.js +67 -0
  243. package/src/components/molecules/reset-password-form/ResetPasswordForm.state.js +30 -0
  244. package/src/components/molecules/reset-password-form/index.js +11 -0
  245. package/src/components/molecules/reset-password-success/ResetPasswordSuccess.js +55 -0
  246. package/src/components/molecules/reset-password-success/index.js +3 -0
  247. package/src/components/molecules/tab-sidebar/TabSidebar.js +92 -0
  248. package/src/components/molecules/tab-sidebar/TabSidebar.theme.js +9 -0
  249. package/src/components/molecules/tab-sidebar/index.js +3 -0
  250. package/src/components/molecules/terms-and-conditions/TermsAndConditions.js +73 -0
  251. package/src/components/molecules/terms-and-conditions/index.js +3 -0
  252. package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.js +64 -0
  253. package/src/components/molecules/terms-and-conditions-modal/TermsAndConditionsModal.theme.js +28 -0
  254. package/src/components/molecules/terms-and-conditions-modal/index.js +3 -0
  255. package/src/components/molecules/workflow-tile/WorkflowTile.js +58 -0
  256. package/src/components/molecules/workflow-tile/index.js +3 -0
  257. package/src/components/templates/center-single/CenterSingle.js +61 -0
  258. package/src/components/templates/center-single/index.js +3 -0
  259. package/src/components/templates/center-stack/CenterStack.js +49 -0
  260. package/src/components/templates/center-stack/index.js +3 -0
  261. package/src/components/templates/default-page-template/DefaultPageTemplate.js +49 -0
  262. package/src/components/templates/default-page-template/index.js +3 -0
  263. package/src/components/templates/index.js +5 -0
  264. package/src/components/templates/sidebar-single-content/SidebarSingleContent.js +60 -0
  265. package/src/components/templates/sidebar-single-content/index.js +3 -0
  266. package/src/components/templates/sidebar-stack-content/SidebarStackContent.js +81 -0
  267. package/src/components/templates/sidebar-stack-content/index.js +3 -0
  268. package/src/components/templates/templates.theme.js +5 -0
  269. package/src/components/withWindowSize.js +50 -0
  270. package/src/constants/colors.js +178 -0
  271. package/src/constants/regex_constants.js +1 -0
  272. package/src/constants/style_constants.js +21 -0
  273. package/src/deprecated/colors.js +154 -0
  274. package/src/deprecated/components/radio-button/index.js +3 -0
  275. package/src/deprecated/components/radio-button/radio-button.js +44 -0
  276. package/src/deprecated/icons/AlertErrorIcon.js +42 -0
  277. package/src/deprecated/icons/AlertInfoIcon.js +42 -0
  278. package/src/deprecated/icons/AlertSuccessIcon.js +42 -0
  279. package/src/deprecated/icons/AlertWarningIcon.js +36 -0
  280. package/src/deprecated/icons/BankIcon.js +82 -0
  281. package/src/deprecated/icons/GenericCard.js +39 -0
  282. package/src/deprecated/icons/IconAdd.js +44 -0
  283. package/src/deprecated/icons/IconCheck.js +23 -0
  284. package/src/deprecated/icons/IconCheckEmail.js +46 -0
  285. package/src/deprecated/icons/IconChevron.js +35 -0
  286. package/src/deprecated/icons/IconEmailVerified.js +62 -0
  287. package/src/deprecated/icons/IconEye.js +32 -0
  288. package/src/deprecated/icons/IconEyeSlash.js +48 -0
  289. package/src/deprecated/icons/IconInvalid.js +69 -0
  290. package/src/deprecated/icons/IconNeutral.js +27 -0
  291. package/src/deprecated/icons/IconQuit.js +32 -0
  292. package/src/deprecated/icons/IconValid.js +72 -0
  293. package/src/deprecated/icons/IconWarn.js +28 -0
  294. package/src/deprecated/icons/index.js +40 -0
  295. package/src/deprecated/index.js +1 -0
  296. package/src/deprecated/spinner/Spinner.js +68 -0
  297. package/src/deprecated/spinner/index.js +1 -0
  298. package/src/deprecated/utility/__tests__/safeConcat.spec.js +59 -0
  299. package/src/deprecated/utility/__tests__/validateKeyType.spec.js +116 -0
  300. package/src/deprecated/utility/index.js +2 -0
  301. package/src/deprecated/utility/safeConcat.js +10 -0
  302. package/src/deprecated/utility/validateKeyType.js +19 -0
  303. package/src/index.js +2 -0
  304. package/src/util/formats.js +30 -0
  305. package/src/util/general.js +15 -0
  306. package/src/util/inputValidationUtils.js +257 -0
  307. package/src/util/router-utils.js +23 -0
  308. package/src/util/themeUtils.js +144 -0
@@ -0,0 +1,2 @@
1
+ export { default as safeConcat } from './safeConcat';
2
+ export { default as validateKeyType } from './validateKeyType';
@@ -0,0 +1,10 @@
1
+ //
2
+
3
+ export default function safeConcat(values , concatinator ) {
4
+ if (!Array.isArray(values)) {
5
+ console.error(`'values' needs to be an array. Recieved ${typeof values}`);
6
+ return;
7
+ }
8
+
9
+ return values.filter((val ) => !!val).join(String(concatinator));
10
+ }
@@ -0,0 +1,19 @@
1
+ //
2
+
3
+ export default function validateKeyType(obj ,
4
+ expectedKey ,
5
+ expectedType ) {
6
+ if (!(expectedKey in obj)) {
7
+ return false;
8
+ }
9
+
10
+ if (expectedType === 'object' && Array.isArray(obj[expectedKey])) {
11
+ return false;
12
+ }
13
+
14
+ if (expectedType === 'array' && Array.isArray(obj[expectedKey])) {
15
+ return true;
16
+ }
17
+
18
+ return typeof obj[expectedKey] === expectedType;
19
+ }
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ // export * from "./deprecated";
2
+ export * from "./components";
@@ -0,0 +1,30 @@
1
+ import { createFormat } from "formatted-input";
2
+ export const formatDelimiter = "_";
3
+
4
+ export const phoneFormats = [
5
+ "",
6
+ "_",
7
+ "__",
8
+ "(___) ",
9
+ "(___) _",
10
+ "(___) __",
11
+ "(___) ___-",
12
+ "(___) ___-_",
13
+ "(___) ___-__",
14
+ "(___) ___-___",
15
+ "(___) ___-____",
16
+ ];
17
+
18
+ const zipFormats = [
19
+ "",
20
+ "_",
21
+ "__",
22
+ "___",
23
+ "____",
24
+ "_____",
25
+ "______",
26
+ "_____-__",
27
+ "_____-___",
28
+ "_____-____",
29
+ ];
30
+ export const zipFormat = createFormat(zipFormats, formatDelimiter);
@@ -0,0 +1,15 @@
1
+ import numeral from "numeral";
2
+
3
+ export const noop = () => {};
4
+
5
+ const formatMoneyString = (s) => numeral(s).format("$0,0.00");
6
+ const convertCentsToMoneyDecimal = (n) => (n / 100).toFixed(2);
7
+ export const displayCurrency = (cents) =>
8
+ formatMoneyString(convertCentsToMoneyDecimal(cents));
9
+
10
+ export const safeChildren = (children, replacement = []) => {
11
+ if (children && children instanceof Array) {
12
+ return children.map((child) => (!child ? replacement : child));
13
+ }
14
+ return !children ? replacement : children;
15
+ };
@@ -0,0 +1,257 @@
1
+ import * as S from "sanctuary";
2
+ import * as $ from "sanctuary-def";
3
+ import * as R from "ramda";
4
+
5
+ // FormInput :: { form :: Object String any, keyName :: String }
6
+
7
+ // String -> Maybe String
8
+ const getsMaybeString = keyName => S.gets(S.is($.String))([keyName, "value"]);
9
+
10
+ // String, String, Regex -> FormInput -> Either String String
11
+ const regexTest = (keyName, errorMsg, regex) =>
12
+ S.pipe([
13
+ getsMaybeString(keyName),
14
+ S.maybeToEither("Invalid string entered"),
15
+ S.chain(string =>
16
+ S.test(regex)(string) ? S.Right(string) : S.Left(errorMsg)
17
+ )
18
+ ]);
19
+
20
+ // Constants to reprsent input error types
21
+ export const MIN_LENGTH_ERROR = "error/HAS_LENGTH";
22
+ export const MAX_LENGTH_ERROR = "max_length_error";
23
+ export const EXACT_LENGTH_ERROR = "exact_length_error";
24
+ export const MULTIPLE_LENGTHS_ERROR = "multiple_lengths_error";
25
+ export const EMAIL_ERROR = "email_error";
26
+ export const HAS_NUMBER_ERROR = "error/HAS_NUMBER";
27
+ export const HAS_UPPERCASE_LETTER_ERROR = "error/HAS_UPPERCASE_LETTER";
28
+ export const HAS_LOWERCASE_LETTER_ERROR = "error/HAS_LOWERCASE_LETTER";
29
+ export const HAS_SPECIAL_CHARACTER_ERROR = "error/HAS_SPECIAL_CHARACTER";
30
+ export const ONLY_NUMBERS_ERROR = "only_numbers_error";
31
+ export const ONLY_LETTERS_ERROR = "only_letters_error";
32
+ export const REQUIRED_FIELD_ERROR = "required_field_error";
33
+ export const NUM_GREATER_THAN_ERROR = "num_greater_than_error";
34
+ export const NUM_LESS_THAN_ERROR = "num_less_than_error";
35
+ export const MATCHES_FIELD_ERROR = "matches_field_error";
36
+ export const VALID_SELECT_OPTION_ERROR = "valid_select_option_error";
37
+
38
+ // Array<String>, Array<String> -> Object -> String
39
+ const genErrorMessage = (strings, ...argKeys) => inputState =>
40
+ strings.reduce(
41
+ (accum, current, index) =>
42
+ `${accum}${current}${
43
+ argKeys[index] ? R.pathOr("", [argKeys[index]], inputState) : ""
44
+ }`,
45
+ []
46
+ );
47
+
48
+ /*
49
+ What's going on here? This looks weird, you may ask...
50
+ DEFAULT_ERROR_MESSAGES is a map between the error constants (which are returned by validators)
51
+ and some tagged template literals.
52
+ In this case, the template tag function is curried and returns a function which accepts an args object
53
+ I'm calling that object inputState, but it could really be anything.
54
+ When the error message string fucntion is called with that arg, it's reduced to produce a custom error message
55
+ with interpolation.
56
+ */
57
+ export const DEFAULT_ERROR_MESSAGES = {
58
+ [MIN_LENGTH_ERROR]: genErrorMessage`${`fieldLabel`} is too short`,
59
+ [MAX_LENGTH_ERROR]: genErrorMessage`${`fieldLabel`} is too long`,
60
+ [EXACT_LENGTH_ERROR]: genErrorMessage`${`fieldLabel`} is not the right length`,
61
+ [MULTIPLE_LENGTHS_ERROR]: genErrorMessage`${`fieldLabel`} is not a valid length`,
62
+ [EMAIL_ERROR]: genErrorMessage`${`fieldLabel`} is not a valid email address`,
63
+ [HAS_NUMBER_ERROR]: genErrorMessage`${`fieldLabel`} needs a number`,
64
+ [HAS_UPPERCASE_LETTER_ERROR]: genErrorMessage`${`fieldLabel`} needs an uppercase letter`,
65
+ [HAS_LOWERCASE_LETTER_ERROR]: genErrorMessage`${`fieldLabel`} needs a lowercase letter`,
66
+ [HAS_SPECIAL_CHARACTER_ERROR]: genErrorMessage`${`fieldLabel`} needs a special character`,
67
+ [ONLY_NUMBERS_ERROR]: genErrorMessage`${`fieldLabel`} must be only numbers`,
68
+ [ONLY_LETTERS_ERROR]: genErrorMessage`${`fieldLabel`} must be only letters`,
69
+ [REQUIRED_FIELD_ERROR]: genErrorMessage`${`fieldLabel`} is required`,
70
+ [NUM_GREATER_THAN_ERROR]: genErrorMessage`${`fieldLabel`} is too high`,
71
+ [NUM_LESS_THAN_ERROR]: genErrorMessage`${`fieldLabel`} is too low`,
72
+ [MATCHES_FIELD_ERROR]: genErrorMessage`${`fieldLabel`} must match ${`matchField`}`,
73
+ [VALID_SELECT_OPTION_ERROR]: genErrorMessage`${`fieldLabel`} is not a valid option`
74
+ };
75
+
76
+ // Constants to represent an input's state
77
+ // Neutral - has not been validated
78
+ // Invalid - has been validated and has an error
79
+ // Valid - has been validated and has no error
80
+ export const INPUT_STATE_NEUTRAL = "NEUTRAL";
81
+ export const INPUT_STATE_INVALID = "INVALID";
82
+ export const INPUT_STATE_VALID = "VALID";
83
+
84
+ // Function to check the state of an input
85
+ // This function is intended to be used with inputs that have multiple validators
86
+ // Takes an input's state value, destructures for the input's error and showError booleans, list of errors
87
+ // Also takes a list of the specific error constants to look for
88
+ // If the input's showError property is false, the input has not been validated, and input state is NEUTRAL
89
+ // If the input has an error, and showError is true, check if the errors we care about are in the input's error list
90
+ // If yes, input state is INVALID
91
+ // If input has no error and showError is true, or the errors we're looking for aren't present in the list
92
+ // then input state is VALID
93
+ // { error: Boolean, showError: Boolean, errorsList: Array<String> }, Array<String> -> String
94
+ export const getInputState = (
95
+ { dirty, hasErrors, errors, rawValue },
96
+ errorsToCheck = []
97
+ ) => {
98
+ if (!dirty) {
99
+ return INPUT_STATE_NEUTRAL;
100
+ } else if (
101
+ (dirty && rawValue === "") ||
102
+ (hasErrors && errorsToCheck.some(error => errors.includes(error)))
103
+ ) {
104
+ return INPUT_STATE_INVALID;
105
+ }
106
+ return INPUT_STATE_VALID;
107
+ };
108
+
109
+ // Number -> FormInput -> Either String String
110
+ export const stringHasMinLength = minLength => ({ form, keyName }) =>
111
+ S.pipe([
112
+ getsMaybeString(keyName),
113
+ S.maybeToEither("Invalid string entered"),
114
+ S.chain(string =>
115
+ string.length >= minLength ? S.Right(string) : S.Left(MIN_LENGTH_ERROR)
116
+ )
117
+ ])(form);
118
+
119
+ // Number -> FormInput -> Either String String
120
+ // This function is INCLUSIVE of the maxLength arg supplied to it
121
+ export const stringHasMaxLength = maxLength => ({ form, keyName }) =>
122
+ S.pipe([
123
+ getsMaybeString(keyName),
124
+ S.maybeToEither("Invalid string entered"),
125
+ S.chain(string =>
126
+ string.length <= maxLength ? S.Right(string) : S.Left(MAX_LENGTH_ERROR)
127
+ )
128
+ ])(form);
129
+
130
+ // Number -> FormInput -> Either String String
131
+ export const stringHasExactLength = exactLength => ({ form, keyName }) =>
132
+ S.pipe([
133
+ getsMaybeString(keyName),
134
+ S.maybeToEither("Invalid string entered"),
135
+ S.chain(string =>
136
+ string.length == exactLength
137
+ ? S.Right(string)
138
+ : S.Left(EXACT_LENGTH_ERROR)
139
+ )
140
+ ])(form);
141
+
142
+ // Array(Number) -> FormInput -> Either String String
143
+ export const stringHasMultipleValidLengths = validLengths => ({
144
+ form,
145
+ keyName
146
+ }) =>
147
+ S.pipe([
148
+ getsMaybeString(keyName),
149
+ S.maybeToEither("Form is missing key or value is not a string"),
150
+ S.chain(string =>
151
+ R.contains(string.length, validLengths)
152
+ ? S.Right(string)
153
+ : S.Left(MULTIPLE_LENGTHS_ERROR)
154
+ )
155
+ ])(form);
156
+
157
+ // FormInput -> Either String String
158
+ /* NOTE: this is not a foolproof email validation check
159
+ It will likely fail on edge cases such as " "@foo.com
160
+ It also cannot tell you if the particular email entered is valid for the given domain
161
+ Or if the email account actually exists
162
+ Only use this to help indicate to a user that they may have entered their email incorrectly
163
+ Real validation should be accomplished on the server by sending an email to
164
+ the provided email address
165
+ */
166
+ export const isProbablyAnEmail = ({ form, keyName }) =>
167
+ regexTest(keyName, EMAIL_ERROR, /^[^\s@]+@[^\s@]+\.[^\s@]+$/)(form);
168
+
169
+ // FormInput -> Either String String
170
+ export const stringHasNumber = ({ form, keyName }) =>
171
+ regexTest(keyName, HAS_NUMBER_ERROR, /[0-9]/)(form);
172
+
173
+ // FormInput -> Either String String
174
+ export const stringHasUppercaseLetter = ({ form, keyName }) =>
175
+ regexTest(keyName, HAS_UPPERCASE_LETTER_ERROR, /[A-Z]/)(form);
176
+
177
+ // FormInput -> Either String String
178
+ export const stringHasLowercaseLetter = ({ form, keyName }) =>
179
+ regexTest(keyName, HAS_LOWERCASE_LETTER_ERROR, /[a-z]/)(form);
180
+
181
+ // FormInput -> Either String String
182
+ export const stringHasSpecialCharacter = ({ form, keyName }) =>
183
+ regexTest(keyName, HAS_SPECIAL_CHARACTER_ERROR, /[!@#$%^&*.?]/)(form);
184
+
185
+ // FormInput -> Either String String
186
+ export const stringIsOnlyNumbers = ({ form, keyName }) =>
187
+ regexTest(keyName, ONLY_NUMBERS_ERROR, /^[0-9]+$/)(form);
188
+
189
+ // FormInput -> Either String String
190
+ export const stringIsOnlyLetters = ({ form, keyName }) =>
191
+ regexTest(keyName, ONLY_LETTERS_ERROR, /^[a-zA-Z]+$/)(form);
192
+
193
+ // fieldIsRequired asks for only one character,
194
+ // which can be a letter (a-z) or (A-Z), a digit (0-9), or one of the special characters (!@#$%^&*.?)
195
+ // If you need only letters or numbers use one of the more specific string checks above
196
+ // If you need the string to exceed a specificed length, use stringHasMinLength
197
+ // FormInput -> Either String String
198
+ export const fieldIsRequired = ({ form, keyName }) =>
199
+ S.pipe([
200
+ getsMaybeString(keyName),
201
+ S.maybeToEither("Invalid string entered"),
202
+ S.chain(string =>
203
+ string.replace(/\s/g, "").length === 0
204
+ ? S.Left(REQUIRED_FIELD_ERROR)
205
+ : S.Right(string)
206
+ )
207
+ ])(form);
208
+
209
+ // Number -> FormInput -> Either String String
210
+ export const numberIsGreaterThan = minValue => ({ form, keyName }) =>
211
+ S.pipe([
212
+ getsMaybeString(keyName),
213
+ S.maybeToEither("Invalid string entered"),
214
+ S.chain(n =>
215
+ parseInt(n, 10) > minValue
216
+ ? S.Right(n.toString())
217
+ : S.Left(NUM_GREATER_THAN_ERROR)
218
+ )
219
+ ])(form);
220
+
221
+ // Number -> FormInput -> Either String String
222
+ export const numberIsLessThan = maxValue => ({ form, keyName }) =>
223
+ S.pipe([
224
+ getsMaybeString(keyName),
225
+ S.maybeToEither("Invalid string entered"),
226
+ S.chain(n =>
227
+ parseInt(n, 10) < maxValue
228
+ ? S.Right(n.toString())
229
+ : S.Left(NUM_LESS_THAN_ERROR)
230
+ )
231
+ ])(form);
232
+
233
+ // Error message splits the keyname on capital letters, joins with a space, and lower cases, so "accountNumber" becomes "account number"
234
+ // Eq a => FormInput -> String -> Either String a
235
+ export const matchesOtherField = matchKey => ({ form, keyName }) =>
236
+ S.equals(S.props([keyName, "value"])(form))(
237
+ S.props([matchKey, "value"])(form)
238
+ )
239
+ ? S.Right(S.props([keyName, "value"])(form))
240
+ : S.Left(MATCHES_FIELD_ERROR);
241
+
242
+ // Array(String) -> FormInput -> Either String String
243
+ export const selectIsValid = validOptions => ({ form, keyName }) =>
244
+ S.pipe([
245
+ getsMaybeString(keyName),
246
+ S.maybeToEither("Invalid string entered"),
247
+ S.chain(string =>
248
+ R.contains(S.toUpper(string), validOptions)
249
+ ? S.Right(string)
250
+ : S.Left(VALID_SELECT_OPTION_ERROR)
251
+ )
252
+ ])(form);
253
+
254
+ export const isInputInvalid = input => input.error && input.showError;
255
+
256
+ export const inputErrorMessage = input =>
257
+ input.showError ? input.errorMsg : "";
@@ -0,0 +1,23 @@
1
+ import * as R from "ramda";
2
+
3
+ // todo: remove ramda dep
4
+ // maybe move logic to Header as that's the only component using this
5
+ const getTabs = R.anyPass([
6
+ R.equals("settings"),
7
+ R.equals("accounts"),
8
+ R.equals("properties")
9
+ ]);
10
+ const configureTabNavigation = subRoute =>
11
+ subRoute.split("/").filter(route => getTabs(route));
12
+ const getSubRoute = route => route.topLevel;
13
+ const buildTabNavigation = R.compose(
14
+ R.map(configureTabNavigation),
15
+ R.map(getSubRoute)
16
+ );
17
+ const sortRoutes = R.compose(R.sortBy(R.toLower), R.flatten);
18
+ const configureRoutes = R.compose(
19
+ sortRoutes,
20
+ R.compose(buildTabNavigation, R.flatten)
21
+ );
22
+
23
+ export { configureRoutes };
@@ -0,0 +1,144 @@
1
+ import theme from "styled-theming";
2
+ import { useContext } from "react";
3
+ import { ThemeContext } from "styled-components";
4
+ /*
5
+ themeContext: { name: "default", values: {JSON_THEME_VALUES_HERE} }
6
+
7
+ fallbackValues: {
8
+ padding: {
9
+ primary: "2rem 1rem",
10
+ secondary: "1rem 0.5rem"
11
+ },
12
+ fontWeight: "600"
13
+ }
14
+
15
+ componentName: "Button"
16
+
17
+ Iterates over a component's fallback values, checks to see if any of those values
18
+ are present in the theme values available in the app's theme context.
19
+ If they are, those values override the fallback value.
20
+
21
+ We use the resuting values as an argument to the styled-theming lib functions
22
+ to create new functions that can be called with theme props to produce values.
23
+ Typically, those functions are passed back to components and used in styled-component files.
24
+ We do things a bit differently...
25
+
26
+ Before returning, we call the styled-theming functions with relevant theme props (name, variant...)
27
+ The styled-theming API then returns the value
28
+ Ultimately, an object of property values ({ color: "red", fontWeight: "600" })
29
+ is returned to the component, which can be passed
30
+ to whatever layout atoms / other atoms the component is using to build itself
31
+
32
+ Why do things this way? It's powerful. Right now we're always using "default" as our theme name
33
+ And only expecting one set of theme value in our context (one theme per client)
34
+
35
+ However, this function can easily be modified to allow for multiple themes per client and
36
+ allow for toggling those themes on the fly via state values
37
+
38
+ Future use cases for the above:
39
+ -Different themes per agency/sub-division of client
40
+ -Extra themes designed for accessibility (high contrast / color blindness)
41
+ -Superfluous extra themes (dark mode)
42
+ -Toggling between many client themes / proposed client themes in a live demo
43
+
44
+ The above functionality is not available right now, but it is trivial to enable it with this approach.
45
+ */
46
+ export const createThemeValues = (
47
+ themeContext,
48
+ fallbackValues,
49
+ componentName,
50
+ variant
51
+ ) => {
52
+ const { values: themeValues } = themeContext;
53
+ const themeProps = { theme: { name: "default", ...themeContext }, variant };
54
+
55
+ const mergedValues = Object.entries(fallbackValues).reduce(
56
+ (acc, [propName, propValue]) => {
57
+ if (typeof propValue === "object") {
58
+ const mergedPropValues = Object.entries(propValue).reduce(
59
+ (innerAcc, [variantName, defaultVariantValue]) => {
60
+ const variantValue =
61
+ themeValues?.[componentName]?.[propName]?.[variantName] ??
62
+ defaultVariantValue;
63
+ return {
64
+ ...innerAcc,
65
+ [variantName]: {
66
+ default: variantValue
67
+ }
68
+ };
69
+ },
70
+ {}
71
+ );
72
+ // Always using "default" as our theme name right now
73
+ // In the future if we want to toggle themes on the fly, change this
74
+ return {
75
+ ...acc,
76
+ [propName]: mergedPropValues
77
+ };
78
+ }
79
+ const mergedSinglePropValue =
80
+ themeValues?.[componentName]?.[propName] ?? propValue;
81
+ return {
82
+ ...acc,
83
+ [propName]: { default: mergedSinglePropValue }
84
+ };
85
+ },
86
+ {}
87
+ );
88
+
89
+ const createdTheme = Object.entries(mergedValues).reduce(
90
+ (acc, [propName, propValue]) => {
91
+ if (propValue[variant]) {
92
+ return {
93
+ ...acc,
94
+ [propName]: theme.variants("name", "variant", propValue)(themeProps)
95
+ };
96
+ }
97
+ return {
98
+ ...acc,
99
+ [propName]: theme("name", propValue)(themeProps)
100
+ };
101
+ },
102
+ {}
103
+ );
104
+ return createdTheme;
105
+ };
106
+
107
+ export const themeComponent = (
108
+ component,
109
+ componentThemeId,
110
+ fallbackValues,
111
+ defaultVariant
112
+ ) => ({ variant = defaultVariant, ...props }) => {
113
+ const themeContext = useContext(ThemeContext);
114
+ const metadata = themeContext?.metadata ?? {};
115
+ const themeValues = themeContext
116
+ ? createThemeValues(themeContext, fallbackValues, componentThemeId, variant)
117
+ : fallbackValues;
118
+
119
+ return component({
120
+ ...props,
121
+ themeValues,
122
+ variant,
123
+ metadata
124
+ });
125
+ };
126
+
127
+ /*
128
+ Keeping this around for now in case we need it later...
129
+
130
+ export const generateImgSrc = (
131
+ configAssetsEndpoint,
132
+ clientSlug,
133
+ agency = ""
134
+ ) => filename => {
135
+ if (configAssetsEndpoint === "http://localhost:8080/assets") {
136
+ return agency !== ""
137
+ ? `${configAssetsEndpoint}/${clientSlug}/${agency}/${filename}`
138
+ : `${configAssetsEndpoint}/${clientSlug}/${filename}`;
139
+ }
140
+ return agency !== ""
141
+ ? `${configAssetsEndpoint}/${agency}/${filename}`
142
+ : `${configAssetsEndpoint}/${filename}`;
143
+ };
144
+ */