@bloom-housing/ui-components 4.2.2 → 4.3.1-alpha.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 (67) hide show
  1. package/CHANGELOG.md +736 -2
  2. package/README.md +10 -4
  3. package/index.ts +14 -10
  4. package/package.json +6 -4
  5. package/scripts/generate-translations.ts +60 -0
  6. package/src/actions/Button.docs.mdx +76 -0
  7. package/src/actions/Button.scss +58 -61
  8. package/src/authentication/timeout.tsx +1 -0
  9. package/src/blocks/DashBlock.tsx +5 -3
  10. package/src/blocks/DashBlocks.scss +4 -1
  11. package/src/blocks/FormCard.tsx +1 -1
  12. package/src/forms/FieldGroup.tsx +18 -17
  13. package/src/global/app-css.scss +7 -0
  14. package/src/global/markdown.scss +20 -0
  15. package/src/global/mixins.scss +66 -49
  16. package/src/global/tables.scss +236 -58
  17. package/src/global/text.scss +11 -3
  18. package/src/global/tokens/borders.scss +15 -0
  19. package/src/global/tokens/colors.scss +64 -0
  20. package/src/global/tokens/fonts.scss +45 -0
  21. package/src/global/tokens/screens.scss +6 -0
  22. package/src/global/tokens/sizes.scss +48 -0
  23. package/src/headers/Heading.tsx +2 -0
  24. package/src/headers/PageHeader.docs.mdx +45 -0
  25. package/src/headers/PageHeader.scss +30 -17
  26. package/src/headers/PageHeader.tsx +2 -10
  27. package/src/headers/SiteHeader.tsx +7 -1
  28. package/src/helpers/MultiLineAddress.tsx +37 -0
  29. package/src/helpers/OneLineAddress.tsx +21 -0
  30. package/src/helpers/tableSummaries.tsx +34 -23
  31. package/src/locales/es.json +165 -33
  32. package/src/locales/general.json +19 -9
  33. package/src/locales/tl.json +655 -1
  34. package/src/locales/vi.json +164 -37
  35. package/src/locales/zh.json +165 -33
  36. package/src/navigation/FooterNav.scss +8 -3
  37. package/src/overlays/Drawer.tsx +11 -3
  38. package/src/overlays/Modal.tsx +16 -7
  39. package/src/overlays/Overlay.tsx +4 -3
  40. package/src/page_components/ApplicationTimeline.scss +36 -0
  41. package/src/page_components/ApplicationTimeline.tsx +33 -0
  42. package/src/page_components/forgot-password/FormForgotPassword.tsx +5 -4
  43. package/src/page_components/listing/AdditionalFees.tsx +38 -31
  44. package/src/page_components/listing/ListingCard.scss +12 -0
  45. package/src/page_components/listing/ListingCard.tsx +5 -3
  46. package/src/page_components/listing/ListingMap.tsx +7 -2
  47. package/src/page_components/listing/UnitTables.tsx +19 -18
  48. package/src/page_components/listing/listing_sidebar/Contact.tsx +110 -0
  49. package/src/page_components/listing/listing_sidebar/ContactAddress.tsx +41 -0
  50. package/src/page_components/listing/listing_sidebar/GetApplication.tsx +35 -15
  51. package/src/page_components/listing/listing_sidebar/QuantityRowSection.tsx +46 -0
  52. package/src/page_components/listing/listing_sidebar/SubmitApplication.tsx +52 -57
  53. package/src/page_components/listing/listing_sidebar/events/EventSection.tsx +3 -2
  54. package/src/page_components/sign-in/FormSignIn.tsx +2 -1
  55. package/src/page_components/sign-in/ResendConfirmationModal.tsx +106 -0
  56. package/src/prototypes/Swatch.tsx +10 -0
  57. package/src/tables/CategoryTable.tsx +33 -0
  58. package/src/tables/GroupedTable.tsx +5 -5
  59. package/src/tables/MinimalTable.tsx +12 -2
  60. package/src/tables/StackedTable.tsx +38 -26
  61. package/src/tables/StandardTable.tsx +26 -10
  62. package/tailwind.config.js +76 -81
  63. package/tailwind.tosass.js +2 -1
  64. package/src/helpers/address.tsx +0 -46
  65. package/src/page_components/listing/listing_sidebar/LeasingAgent.tsx +0 -72
  66. package/src/page_components/listing/listing_sidebar/SidebarAddress.tsx +0 -56
  67. package/src/page_components/listing/listing_sidebar/Waitlist.tsx +0 -49
@@ -0,0 +1,6 @@
1
+ :root {
2
+ --bloom-screen-sm: #{$screen-sm};
3
+ --bloom-screen-md: #{$screen-md};
4
+ --bloom-screen-lg: #{$screen-lg};
5
+ --bloom-screen-xl: #{$screen-xl};
6
+ }
@@ -0,0 +1,48 @@
1
+ :root {
2
+ --bloom-s0_5: 0.125rem;
3
+ --bloom-s1: 0.25rem;
4
+ --bloom-s1_5: 0.375rem;
5
+ --bloom-s2: 0.5rem;
6
+ --bloom-s2_5: 0.625rem;
7
+ --bloom-s3: 0.75rem;
8
+ --bloom-s3_5: 0.875;
9
+ --bloom-s4: 1rem;
10
+ --bloom-s5: 1.25rem;
11
+ --bloom-s6: 1.5rem;
12
+ --bloom-s7: 1.75rem;
13
+ --bloom-s8: 2rem;
14
+ --bloom-s9: 2.25rem;
15
+ --bloom-s10: 2.5rem;
16
+ --bloom-s11: 2.75rem;
17
+ --bloom-s12: 3rem;
18
+ --bloom-s14: 3.5rem;
19
+ --bloom-s16: 4rem;
20
+ --bloom-s20: 5rem;
21
+ --bloom-s24: 6rem;
22
+ --bloom-s28: 7rem;
23
+ --bloom-s32: 8rem;
24
+ --bloom-s36: 9rem;
25
+ --bloom-s40: 10rem;
26
+ --bloom-s44: 11rem;
27
+ --bloom-s48: 12rem;
28
+ --bloom-s52: 13rem;
29
+ --bloom-s56: 14rem;
30
+ --bloom-s60: 15rem;
31
+ --bloom-s64: 16rem;
32
+ --bloom-s72: 18rem;
33
+ --bloom-s80: 20rem;
34
+ --bloom-s96: 24rem;
35
+
36
+ --bloom-width-xs: 20rem;
37
+ --bloom-width-sm: 24rem;
38
+ --bloom-width-md: 28rem;
39
+ --bloom-width-lg: 32rem;
40
+ --bloom-width-xl: 36rem;
41
+ --bloom-width-2xl: 42rem;
42
+ --bloom-width-3xl: 48rem;
43
+ --bloom-width-4xl: 56rem;
44
+ --bloom-width-5xl: 64rem;
45
+ --bloom-width-6xl: 72rem;
46
+ --bloom-width-7xl: 80rem;
47
+ --bloom-width-prose: 65ch;
48
+ }
@@ -15,6 +15,8 @@ const HeaderStyleMap = {
15
15
  tableHeader: "table-header",
16
16
  tableSubheader: "table-subheader",
17
17
  sidebarHeader: "text-caps-underline",
18
+ categoryHeader: "category-header",
19
+ sidebarSubHeader: "text-caps-tiny",
18
20
  }
19
21
 
20
22
  const Heading = (props: HeadingProps) => {
@@ -0,0 +1,45 @@
1
+ import { Canvas, Story, ArgsTable } from "@storybook/addon-docs"
2
+ import { PageHeader } from "./PageHeader"
3
+
4
+ # Page Header
5
+
6
+ The page header component displays a title, with an optional subtitle and/or arbitary children elements.
7
+
8
+ <Canvas>
9
+ <Story id="headers-page-header--with-content" />
10
+ </Canvas>
11
+
12
+ <br />
13
+ <br />
14
+
15
+ ## Variants
16
+
17
+ ### Inverse
18
+
19
+ Set the `inverse` property to `true`.
20
+
21
+ <Canvas>
22
+ <Story id="headers-page-header--inversed" />
23
+ </Canvas>
24
+
25
+ ## Component Properties
26
+
27
+ <ArgsTable of={PageHeader} />
28
+
29
+ ## Theming Variables
30
+
31
+ <Canvas>
32
+ <Story id="headers-page-header--style-overrides" />
33
+ </Canvas>
34
+
35
+ You can apply CSS variables to the `.page-header` selector to customize the appearance of the component.
36
+
37
+ | Name | Type | Description | Default |
38
+ | ---------------------------- | ----- | --------------------------------------------------------- | ------------------------------- |
39
+ | `--background-color` | Color | The background of the header | `--bloom-color-primary-lighter` |
40
+ | `--border-color` | Color | The color of the top border | `--bloom-color-gray-450` |
41
+ | `--text-color` | Color | The color of text inside the header | `inherit` |
42
+ | `--inverse-background-color` | Color | The `inverse` variant background | `--bloom-color-primary-darker` |
43
+ | `--inverse-border-color` | Color | The `inverse` variant color of the top border | `--bloom-color-primary` |
44
+ | `--inverse-text-color` | Color | The `inverse` variant color of text | `--bloom-color-white` |
45
+ | `--title-font-size` | Size | The font size of the title (only on medium+ size screens) | `--bloom-font-size-5xl` |
@@ -1,34 +1,47 @@
1
1
  .page-header {
2
- @apply py-8;
3
- @apply border-t;
4
- @apply border-gray-450;
2
+ /* Component Variables */
3
+ --background-color: var(--bloom-color-primary-lighter);
4
+ --border-color: var(--bloom-color-gray-450);
5
+ --text-color: inherit;
6
+ --inverse-background-color: var(--bloom-color-primary-darker);
7
+ --inverse-border-color: var(--bloom-color-primary);
8
+ --inverse-text-color: var(--bloom-color-white);
9
+ --title-font-size: var(--bloom-font-size-5xl);
5
10
 
6
- @screen md {
7
- @apply py-10;
11
+ /* Base Styles */
12
+ padding: var(--bloom-s8) 0;
13
+ background-color: var(--background-color);
14
+ border-top: var(--bloom-border-1) solid var(--border-color);
15
+ color: var(--text-color);
16
+
17
+ @media (min-width: $screen-sm) {
18
+ padding: var(--bloom-s10) 0;
8
19
  }
9
20
 
10
- &.bg-primary-dark {
11
- @apply text-white;
12
- @apply border-primary;
21
+ /* Variants */
22
+ &.is-inverse {
23
+ --background-color: var(--inverse-background-color);
24
+ --border-color: var(--inverse-border-color);
25
+ --text-color: var(--inverse-text-color);
13
26
  }
14
27
  }
15
28
 
16
29
  .page-header__group {
17
- @apply px-5;
18
- @apply m-auto;
19
- @apply max-w-5xl;
30
+ padding: 0 var(--bloom-s5);
31
+ margin: auto;
32
+ max-width: var(--bloom-width-5xl);
20
33
  }
21
34
 
22
35
  .page-header__title {
23
- @apply text-center;
36
+ text-align: center;
24
37
 
25
- @screen md {
26
- @apply text-5xl;
27
- @apply text-left;
38
+ @media (min-width: $screen-md) {
39
+ font-size: var(--title-font-size);
40
+ text-align: left;
28
41
  }
29
42
  }
30
43
 
31
44
  .page-header__lead {
32
- @apply m-auto;
33
- @apply max-w-5xl;
45
+ margin: auto;
46
+ max-width: var(--bloom-width-5xl);
34
47
  }
@@ -12,16 +12,8 @@ export interface PageHeaderProps {
12
12
 
13
13
  const PageHeader = (props: PageHeaderProps) => {
14
14
  const classNames = ["page-header"]
15
- if (props.className) {
16
- classNames.push(...props.className.split(" "))
17
- }
18
-
19
- if (props.inverse) {
20
- classNames.push("bg-primary-dark")
21
- classNames.push("text-white")
22
- } else {
23
- classNames.push("bg-primary-lighter")
24
- }
15
+ if (props.inverse) classNames.push("is-inverse")
16
+ if (props.className) classNames.push(...props.className.split(" "))
25
17
 
26
18
  return (
27
19
  <header className={classNames.join(" ")}>
@@ -24,6 +24,7 @@ export interface SiteHeaderProps {
24
24
  dropdownItemClassName?: string
25
25
  homeURL: string
26
26
  imageOnly?: boolean
27
+ languageNavLabel?: string
27
28
  languages?: LangItem[]
28
29
  logoClass?: string
29
30
  logoSrc: string
@@ -142,6 +143,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
142
143
  }
143
144
  dropdownOptionKeyDown(event, index)
144
145
  }}
146
+ data-test-id={`${option.title}-${index}`}
145
147
  >
146
148
  {dropdownOptionContent(option)}
147
149
  </button>
@@ -295,6 +297,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
295
297
  className={`navbar-link ${props.menuItemClassName && props.menuItemClassName}`}
296
298
  href={menuLink.href}
297
299
  key={`${menuLink.title}-${index}`}
300
+ data-test-id={`${menuLink.title}-${index}`}
298
301
  >
299
302
  {menuContent}
300
303
  </LinkComponent>
@@ -333,6 +336,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
333
336
  }}
334
337
  onMouseEnter={() => changeMenuShow(menuLink.title, activeMenus, setActiveMenus)}
335
338
  onMouseLeave={() => changeMenuShow(menuLink.title, activeMenus, setActiveMenus)}
339
+ data-test-id={`${menuLink.title}-${index}`}
336
340
  >
337
341
  {menuContent}
338
342
  </span>
@@ -423,7 +427,9 @@ const SiteHeader = (props: SiteHeaderProps) => {
423
427
 
424
428
  return (
425
429
  <header className={"site-header"}>
426
- {props.languages && <LanguageNav languages={props.languages} />}
430
+ {props.languages && (
431
+ <LanguageNav ariaLabel={props.languageNavLabel} languages={props.languages} />
432
+ )}
427
433
 
428
434
  <div className={`navbar-notice ${!props.noticeMobile && `navbar-notice-hide`}`}>
429
435
  <div className="navbar-notice__text">{props.notice ?? ""}</div>
@@ -0,0 +1,37 @@
1
+ import * as React from "react"
2
+
3
+ export interface Address {
4
+ city?: string
5
+ latitude?: number
6
+ longitude?: number
7
+ placeName?: string
8
+ state?: string
9
+ street2?: string
10
+ street?: string
11
+ zipCode?: string
12
+ }
13
+
14
+ export interface MultiLineAddressProps {
15
+ address: Address
16
+ }
17
+
18
+ const MultiLineAddress = ({ address }: MultiLineAddressProps) => {
19
+ if (!address) return null
20
+
21
+ return (
22
+ <>
23
+ {address.placeName && (
24
+ <>
25
+ {address.placeName}
26
+ <br />
27
+ </>
28
+ )}
29
+ {address.street} {address.street2}
30
+ {(address.street || address.street2) && <br />}
31
+ {address.city}
32
+ {address.city && (address.state || address.zipCode) && ","} {address.state} {address.zipCode}
33
+ </>
34
+ )
35
+ }
36
+
37
+ export { MultiLineAddress as default, MultiLineAddress }
@@ -0,0 +1,21 @@
1
+ import * as React from "react"
2
+ import { Address } from "./MultiLineAddress"
3
+
4
+ export interface OneLineAddressProps {
5
+ address: Address
6
+ }
7
+
8
+ const OneLineAddress = ({ address }: OneLineAddressProps) => {
9
+ if (!address) return null
10
+
11
+ return (
12
+ <>
13
+ {address.street} {address.street2}
14
+ {address.street && `, `}
15
+ {address.city}
16
+ {address.city && (address.state || address.zipCode) && ","} {address.state} {address.zipCode}
17
+ </>
18
+ )
19
+ }
20
+
21
+ export { OneLineAddress as default, OneLineAddress }
@@ -1,8 +1,9 @@
1
1
  import * as React from "react"
2
2
  import { t } from "./translator"
3
3
  import { UnitSummary } from "@bloom-housing/backend-core/types"
4
+ import { StandardTableData } from "../tables/StandardTable"
4
5
 
5
- export const unitSummariesTable = (summaries: UnitSummary[]) => {
6
+ export const unitSummariesTable = (summaries: UnitSummary[]): StandardTableData => {
6
7
  const unitSummaries = summaries?.map((unitSummary) => {
7
8
  const unitPluralization = unitSummary.totalAvailable == 1 ? t("t.unit") : t("t.units")
8
9
  const minIncome =
@@ -10,7 +11,8 @@ export const unitSummariesTable = (summaries: UnitSummary[]) => {
10
11
  <strong>{unitSummary.minIncomeRange.min}</strong>
11
12
  ) : (
12
13
  <>
13
- <strong>{unitSummary.minIncomeRange.min}</strong> {t("t.to")}{" "}
14
+ <strong>{unitSummary.minIncomeRange.min}</strong>
15
+ {` ${t("t.to")} `}
14
16
  <strong>{unitSummary.minIncomeRange.max}</strong>
15
17
  </>
16
18
  )
@@ -24,7 +26,9 @@ export const unitSummariesTable = (summaries: UnitSummary[]) => {
24
26
  </>
25
27
  ) : (
26
28
  <>
27
- <strong>{rentMin}</strong> {t("t.to")} <strong>{rentMax}</strong>
29
+ <strong>{rentMin}</strong>
30
+ {` ${t("t.to")} `}
31
+ <strong>{rentMax}</strong>
28
32
  {unit}
29
33
  </>
30
34
  )
@@ -40,32 +44,39 @@ export const unitSummariesTable = (summaries: UnitSummary[]) => {
40
44
  : getRent(unitSummary.rentRange.min, unitSummary.rentRange.max)
41
45
 
42
46
  return {
43
- unitType: <strong>{t(`listings.unitTypes.${unitSummary.unitType?.name}`)}</strong>,
44
- minimumIncome: (
45
- <>
46
- {minIncome} {t("t.perMonth")}
47
- </>
48
- ),
49
- rent: <>{rent}</>,
50
- availability: (
51
- <>
52
- {unitSummary.totalAvailable > 0 ? (
53
- <>
54
- <strong>{unitSummary.totalAvailable}</strong> {unitPluralization}
55
- </>
56
- ) : (
57
- <span className="uppercase">{t("listings.waitlist.label")}</span>
58
- )}
59
- </>
60
- ),
47
+ unitType: {
48
+ content: <strong>{t(`listings.unitTypes.${unitSummary.unitType?.name}`)}</strong>,
49
+ },
50
+ minimumIncome: {
51
+ content: (
52
+ <span>
53
+ {minIncome}
54
+ {` ${t("t.perMonth")}`}
55
+ </span>
56
+ ),
57
+ },
58
+ rent: { content: <span>{rent}</span> },
59
+ availability: {
60
+ content: (
61
+ <span>
62
+ {unitSummary.totalAvailable > 0 ? (
63
+ <>
64
+ <strong>{unitSummary.totalAvailable}</strong> {unitPluralization}
65
+ </>
66
+ ) : (
67
+ <span className="uppercase">{t("listings.waitlist.label")}</span>
68
+ )}
69
+ </span>
70
+ ),
71
+ },
61
72
  }
62
73
  })
63
74
 
64
75
  return unitSummaries
65
76
  }
66
77
 
67
- export const getSummariesTable = (summaries: UnitSummary[]) => {
68
- let unitSummaries = [] as Record<string, React.ReactNode>[]
78
+ export const getSummariesTable = (summaries: UnitSummary[]): StandardTableData => {
79
+ let unitSummaries: StandardTableData = []
69
80
 
70
81
  if (summaries?.length > 0) {
71
82
  unitSummaries = unitSummariesTable(summaries)