@bloom-housing/ui-components 4.2.2-alpha.2 → 4.2.2-alpha.22

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 (49) hide show
  1. package/CHANGELOG.md +192 -0
  2. package/README.md +10 -4
  3. package/index.ts +3 -0
  4. package/package.json +5 -3
  5. package/src/actions/Button.docs.mdx +76 -0
  6. package/src/actions/Button.scss +58 -61
  7. package/src/authentication/timeout.tsx +1 -0
  8. package/src/blocks/DashBlock.tsx +5 -3
  9. package/src/blocks/DashBlocks.scss +4 -1
  10. package/src/forms/FieldGroup.tsx +18 -17
  11. package/src/global/app-css.scss +7 -0
  12. package/src/global/markdown.scss +20 -0
  13. package/src/global/mixins.scss +66 -49
  14. package/src/global/tables.scss +236 -58
  15. package/src/global/text.scss +9 -1
  16. package/src/global/tokens/borders.scss +15 -0
  17. package/src/global/tokens/colors.scss +64 -0
  18. package/src/global/tokens/fonts.scss +45 -0
  19. package/src/global/tokens/screens.scss +6 -0
  20. package/src/global/tokens/sizes.scss +48 -0
  21. package/src/headers/Heading.tsx +1 -0
  22. package/src/headers/PageHeader.docs.mdx +45 -0
  23. package/src/headers/PageHeader.scss +30 -17
  24. package/src/headers/PageHeader.tsx +2 -10
  25. package/src/headers/SiteHeader.tsx +4 -1
  26. package/src/helpers/address.tsx +5 -4
  27. package/src/helpers/tableSummaries.tsx +34 -23
  28. package/src/locales/general.json +9 -2
  29. package/src/navigation/FooterNav.scss +2 -1
  30. package/src/overlays/Drawer.tsx +11 -3
  31. package/src/overlays/Modal.tsx +16 -7
  32. package/src/overlays/Overlay.tsx +4 -3
  33. package/src/page_components/ApplicationTimeline.scss +36 -0
  34. package/src/page_components/ApplicationTimeline.tsx +33 -0
  35. package/src/page_components/forgot-password/FormForgotPassword.tsx +5 -4
  36. package/src/page_components/listing/AdditionalFees.tsx +38 -31
  37. package/src/page_components/listing/ListingCard.scss +12 -0
  38. package/src/page_components/listing/ListingCard.tsx +5 -3
  39. package/src/page_components/listing/UnitTables.tsx +19 -18
  40. package/src/page_components/sign-in/FormSignIn.tsx +2 -1
  41. package/src/page_components/sign-in/ResendConfirmationModal.tsx +106 -0
  42. package/src/prototypes/Swatch.tsx +10 -0
  43. package/src/tables/CategoryTable.tsx +33 -0
  44. package/src/tables/GroupedTable.tsx +5 -5
  45. package/src/tables/MinimalTable.tsx +12 -2
  46. package/src/tables/StackedTable.tsx +38 -26
  47. package/src/tables/StandardTable.tsx +26 -10
  48. package/tailwind.config.js +76 -81
  49. package/tailwind.tosass.js +2 -1
@@ -0,0 +1,64 @@
1
+ :root {
2
+ --bloom-color-white: #ffffff;
3
+ --bloom-color-black: #000000;
4
+
5
+ --bloom-color-red-800: #b21d38;
6
+ --bloom-color-red-700: #e41d3d;
7
+ --bloom-color-red-300: #f9d2d8;
8
+
9
+ --bloom-color-green-800: #216e1f;
10
+ --bloom-color-green-700: #2e8540;
11
+ --bloom-color-green-300: #b4e5be;
12
+
13
+ --bloom-color-blue-800: #205493;
14
+ --bloom-color-blue-700: #0067be;
15
+ --bloom-color-blue-600: #0077da;
16
+ --bloom-color-blue-300: #daeeff;
17
+ --bloom-color-blue-200: #f5f8f9;
18
+
19
+ --bloom-color-yellow-800: #e5a000;
20
+ --bloom-color-yellow-700: #fdb81e;
21
+ --bloom-color-yellow-300: #fee8b6;
22
+
23
+ --bloom-color-gray-950: #242c2e;
24
+ --bloom-color-gray-900: #222222;
25
+ --bloom-color-gray-850: #333333;
26
+ --bloom-color-gray-800: #30383a;
27
+ --bloom-color-gray-750: #555555;
28
+ --bloom-color-gray-700: #767676;
29
+ --bloom-color-gray-600: #999999;
30
+ --bloom-color-gray-550: #aaaaaa;
31
+ --bloom-color-gray-500: #cccccc;
32
+ --bloom-color-gray-450: #dedee0;
33
+ --bloom-color-gray-400: #efefef;
34
+ --bloom-color-gray-300: #f6f6f6;
35
+ --bloom-color-gray-200: #f7f7f7;
36
+ --bloom-color-gray-100: #f9f9f9;
37
+
38
+ --bloom-color-primary: var(--bloom-color-blue-600);
39
+ --bloom-color-primary-dark: var(--bloom-color-blue-700);
40
+ --bloom-color-primary-darker: var(--bloom-color-blue-800);
41
+ --bloom-color-primary-light: var(--bloom-color-blue-300);
42
+ --bloom-color-primary-lighter: var(--bloom-color-blue-200);
43
+
44
+ --bloom-color-secondary: var(--bloom-color-blue-700);
45
+ --bloom-color-alert: var(--bloom-color-red-700);
46
+ --bloom-color-alert-light: var(--bloom-color-red-300);
47
+ --bloom-color-alert-dark: var(--bloom-color-red-800);
48
+ --bloom-color-success: var(--bloom-color-green-700);
49
+ --bloom-color-success-light: var(--bloom-color-green-300);
50
+ --bloom-color-success-dark: var(--bloom-color-green-800);
51
+ --bloom-color-warn: var(--bloom-color-yellow-700);
52
+ --bloom-color-warn-light: var(--bloom-color-yellow-300);
53
+ --bloom-color-warn-dark: var(--bloom-color-yellow-800);
54
+
55
+ --bloom-color-accent-cool: #00bed5;
56
+ --bloom-color-accent-cool-light: #c8f1ff;
57
+ --bloom-color-accent-cool-dark: #009db0;
58
+ --bloom-color-accent-warm: #ff6627;
59
+ --bloom-color-accent-warm-dark: #d54309;
60
+ --bloom-color-accent-warm-light: #ffd2c0;
61
+ --bloom-color-accent-warm-lighter: #fff7f3;
62
+
63
+ --bloom-color-lush: #99cd00;
64
+ }
@@ -0,0 +1,45 @@
1
+ :root {
2
+ --bloom-font-sans: "Open Sans", Helvetica, Arial, Verdana, sans-serif;
3
+ --bloom-font-serif: "Droid Serif", Georgia, Times, serif;
4
+ --bloom-font-alt-sans: Lato, Helvetica, Arial, Verdana, sans-serif;
5
+ --bloom-font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
6
+ "Courier New", monospace;
7
+
8
+ --bloom-font-size-2xs: 0.6875rem;
9
+ --bloom-font-size-xs: 0.75rem;
10
+ --bloom-font-size-sm: 0.8125rem;
11
+ --bloom-font-size-tiny: 0.875rem;
12
+ --bloom-font-size-base: 1rem;
13
+ --bloom-font-size-lg: 1.25rem;
14
+ --bloom-font-size-xl: 1.375rem;
15
+ --bloom-font-size-2xl: 1.5rem;
16
+ --bloom-font-size-3xl: 1.625rem;
17
+ --bloom-font-size-4xl: 2rem;
18
+ --bloom-font-size-5xl: 2.5rem;
19
+ --bloom-font-size-6xl: 3rem;
20
+ --bloom-font-size-6_5xl: 4rem;
21
+ --bloom-font-size-7xl: 4.5rem;
22
+
23
+ --bloom-letter-spacing-tightest: -0.075em;
24
+ --bloom-letter-spacing-tighter: -0.05em;
25
+ --bloom-letter-spacing-tight: -0.025em;
26
+ --bloom-letter-spacing-wide: 0.025em;
27
+ --bloom-letter-spacing-wider: 0.05em;
28
+ --bloom-letter-spacing-widest: 0.12em;
29
+ --bloom-letter-spacing-ultrawide: 0.25em;
30
+
31
+ --bloom-line-height-3: 0.75rem;
32
+ --bloom-line-height-4: 1rem;
33
+ --bloom-line-height-5: 1.25rem;
34
+ --bloom-line-height-6: 1.5rem;
35
+ --bloom-line-height-7: 1.75rem;
36
+ --bloom-line-height-8: 2rem;
37
+ --bloom-line-height-9: 2.25rem;
38
+ --bloom-line-height-10: 2.5rem;
39
+ --bloom-line-height-none: 1;
40
+ --bloom-line-height-tight: 1.25;
41
+ --bloom-line-height-snug: 1.375;
42
+ --bloom-line-height-normal: 1.5;
43
+ --bloom-line-height-relaxed: 1.625;
44
+ --bloom-line-height-loose: 2;
45
+ }
@@ -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,7 @@ const HeaderStyleMap = {
15
15
  tableHeader: "table-header",
16
16
  tableSubheader: "table-subheader",
17
17
  sidebarHeader: "text-caps-underline",
18
+ categoryHeader: "category-header",
18
19
  }
19
20
 
20
21
  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
@@ -423,7 +424,9 @@ const SiteHeader = (props: SiteHeaderProps) => {
423
424
 
424
425
  return (
425
426
  <header className={"site-header"}>
426
- {props.languages && <LanguageNav languages={props.languages} />}
427
+ {props.languages && (
428
+ <LanguageNav ariaLabel={props.languageNavLabel} languages={props.languages} />
429
+ )}
427
430
 
428
431
  <div className={`navbar-notice ${!props.noticeMobile && `navbar-notice-hide`}`}>
429
432
  <div className="navbar-notice__text">{props.notice ?? ""}</div>
@@ -1,5 +1,4 @@
1
1
  import * as React from "react"
2
- import Markdown from "markdown-to-jsx"
3
2
 
4
3
  export interface Address {
5
4
  city?: string
@@ -38,9 +37,11 @@ export const MultiLineAddress = (props: AddressProps) => {
38
37
  <br />
39
38
  </>
40
39
  )}
41
- <Markdown children={props.address.street || ""} />
42
- <br />
43
- {props.address.city}, {props.address.state} {props.address.zipCode}
40
+ {props.address.street} {props.address.street2}
41
+ {(props.address.street || props.address.street2) && <br />}
42
+ {props.address.city}
43
+ {props.address.city && (props.address.state || props.address.zipCode) && ","}{" "}
44
+ {props.address.state} {props.address.zipCode}
44
45
  </>
45
46
  )
46
47
  }
@@ -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)
@@ -98,6 +98,7 @@
98
98
  "application.contact.yourPhoneNumber": "Your Phone Number",
99
99
  "application.contact.zip": "Zip",
100
100
  "application.contact.zipCode": "Zipcode",
101
+ "application.details.adaPriorities": "ADA Priorities Selected",
101
102
  "application.edited": "Edited",
102
103
  "application.financial.income.instruction1": "Add up your total gross (pre-tax) household income from wages, benefits and other sources from all household members.",
103
104
  "application.financial.income.instruction2": "You only need to provide an estimated total right now. The actual total will be calculated if you are selected.",
@@ -353,22 +354,28 @@
353
354
  "application.referralApplication.furtherInformation": "For further information",
354
355
  "application.referralApplication.instructions": "The permanent supportive housing units are referred directly through <JURISDICTION> Coordinated Entry System. Households experiencing homelessness can call <PHONE_NUMBER> in order to get connected to an Access Point to learn more about the coordinated entry system and access housing-related resources and information.",
355
356
  "application.referralApplication.phoneNumber": "211",
357
+ "application.review.confirmation.applicationReceived": "Application \nreceived",
358
+ "application.review.confirmation.applicationsClosed": "Application \nclosed",
359
+ "application.review.confirmation.applicationsRanked": "Application \nranked",
356
360
  "application.review.confirmation.browseMore": "Browse more listings",
357
361
  "application.review.confirmation.createAccountParagraph": "Creating an account will save your information for future applications, and you can check the status of this application anytime.",
362
+ "application.review.confirmation.createAccount": "### Would you like to create an account?\n\nCreating an account will save your information for future applications, and you can check the status of this application anytime.",
358
363
  "application.review.confirmation.createAccountTitle": "Would you like to create an account?",
359
364
  "application.review.confirmation.doNotSubmitTitle": "Do not submit another application for this listing.",
360
365
  "application.review.confirmation.imdone": "No thanks, I'm done.",
361
- "application.review.confirmation.lotteryNumber": "Here's your application confirmation number",
366
+ "application.review.confirmation.lotteryNumber": "Your confirmation number",
362
367
  "application.review.confirmation.needToUpdate": "If you need to update information on your application, do not apply again. Contact the agent if you did not receive an email confirmation.",
363
- "application.review.confirmation.pleaseWriteNumber": "Please write down your application number and keep it in a safe place. We have also emailed this number to you if you provided an email address.",
368
+ "application.review.confirmation.pleaseWriteNumber": "Please write down your application number and keep it in a safe place. We have also emailed this number to you if you have provided an email address.",
364
369
  "application.review.confirmation.print": "View submitted application and print a copy.",
365
370
  "application.review.confirmation.title": "Thanks. We have received your application for ",
371
+ "application.review.confirmation.needToMakeUpdates": "### Need to make updates?\n\nIf you need to update information on your application, do not apply again. Instead, contact the agent for this listing.\n\n**%{agentName}** \n%{agentPhone} \n%{agentEmail}\n\n**Office Hours** \n%{agentOfficeHours}\n\nContact the agent if you did not receive an email confirmation.",
366
372
  "application.review.confirmation.whatExpectFirstParagraph.attend": " You do not need to attend the housing lottery. Results will be posted ",
367
373
  "application.review.confirmation.whatExpectFirstParagraph.held": "The lottery will be held on ",
368
374
  "application.review.confirmation.whatExpectFirstParagraph.listing": "on the listing. ",
369
375
  "application.review.confirmation.whatExpectFirstParagraph.refer": "Please refer to the listing for the lottery results date.",
370
376
  "application.review.confirmation.whatExpectSecondparagraph": "Applicants will be contacted in order until vacancies are filled. Should your application be chosen, be prepared to fill out a more detailed application and provide required supporting documents.",
371
377
  "application.review.confirmation.whatExpectTitle": "What to expect next",
378
+ "application.review.confirmation.whatHappensNext": "### What happens next?\n\n* After all applications are submitted, the property manager will begin processing applications.\n\n* Eligibile applicants will be contacted by on a **first come first serve** basis until vacancies are filled\n\n* If you are contacted for an interview, you will need to fill out a more detailed application and provide supporting documents.",
372
379
  "application.review.demographics.ethnicityLabel": "Which best describes your ethnicity?",
373
380
  "application.review.demographics.ethnicityOptions.hispanicLatino": "Hispanic / Latino",
374
381
  "application.review.demographics.ethnicityOptions.notHispanicLatino": "Not Hispanic / Latino",
@@ -30,7 +30,8 @@
30
30
 
31
31
  .footer-copyright {
32
32
  @screen lg {
33
- @apply w-full;
33
+ @apply w-6/12;
34
+ @apply text-left;
34
35
  }
35
36
  }
36
37
 
@@ -1,4 +1,4 @@
1
- import * as React from "react"
1
+ import React, { useRef } from "react"
2
2
  import "./Drawer.scss"
3
3
  import { Icon } from "../icons/Icon"
4
4
  import { Overlay, OverlayProps } from "./Overlay"
@@ -6,6 +6,7 @@ import { Tag } from "../text/Tag"
6
6
  import { AppearanceStyleType, AppearanceSizeType } from "../global/AppearanceTypes"
7
7
  import { AlertTypes } from "../notifications/alertTypes"
8
8
  import { AlertBox } from "../notifications"
9
+ import { nanoid } from "nanoid"
9
10
 
10
11
  export enum DrawerSide {
11
12
  left = "left",
@@ -28,18 +29,25 @@ const Drawer = (props: DrawerProps) => {
28
29
  const drawerClasses = ["drawer"]
29
30
  if (props.className) drawerClasses.push(props.className)
30
31
 
32
+ const uniqueIdRef = useRef(nanoid())
33
+
31
34
  return (
32
35
  <Overlay
33
- ariaLabel={props.ariaLabel || props.title}
36
+ ariaLabelledBy={uniqueIdRef.current}
34
37
  ariaDescription={props.ariaDescription}
35
38
  open={props.open}
36
39
  onClose={props.onClose}
37
40
  backdrop={props.backdrop}
38
41
  className={"has-drawer" + (props.direction == DrawerSide.left ? " is-direction-left" : "")}
42
+ role="dialog"
39
43
  >
40
44
  <div className={drawerClasses.join(" ")}>
41
45
  <header className="drawer__header">
42
- {props.title && <h1 className="drawer__title">{props.title}</h1>}
46
+ {props.title && (
47
+ <h1 className="drawer__title" id={uniqueIdRef.current}>
48
+ {props.title}
49
+ </h1>
50
+ )}
43
51
  {props.headerTag && (
44
52
  <Tag
45
53
  pillStyle={true}
@@ -1,7 +1,8 @@
1
- import React from "react"
1
+ import React, { useRef } from "react"
2
2
  import "./Modal.scss"
3
3
  import { Icon } from "../icons/Icon"
4
4
  import { Overlay, OverlayProps } from "./Overlay"
5
+ import { nanoid } from "nanoid"
5
6
 
6
7
  export interface ModalProps extends Omit<OverlayProps, "children"> {
7
8
  title: string
@@ -9,12 +10,17 @@ export interface ModalProps extends Omit<OverlayProps, "children"> {
9
10
  hideCloseIcon?: boolean
10
11
  children?: React.ReactNode
11
12
  slim?: boolean
13
+ role?: string
12
14
  }
13
15
 
14
- const ModalHeader = (props: { title: string }) => (
15
- <header className="modal__inner">
16
- <h1 className="modal__title">{props.title}</h1>
17
- </header>
16
+ const ModalHeader = (props: { title: string; uniqueId?: string }) => (
17
+ <>
18
+ <header className="modal__inner">
19
+ <h1 className="modal__title" id={props.uniqueId}>
20
+ {props.title}
21
+ </h1>
22
+ </header>
23
+ </>
18
24
  )
19
25
 
20
26
  const ModalFooter = (props: { actions: React.ReactNode[] }) => (
@@ -28,17 +34,20 @@ const ModalFooter = (props: { actions: React.ReactNode[] }) => (
28
34
  )
29
35
 
30
36
  export const Modal = (props: ModalProps) => {
37
+ const uniqueIdRef = useRef(nanoid())
38
+
31
39
  return (
32
40
  <Overlay
33
- ariaLabel={props.ariaLabel || props.title}
41
+ ariaLabelledBy={uniqueIdRef.current}
34
42
  ariaDescription={props.ariaDescription}
35
43
  open={props.open}
36
44
  onClose={props.onClose}
37
45
  backdrop={props.backdrop}
38
46
  slim={props.slim}
47
+ role={props.role ? props.role : "dialog"}
39
48
  >
40
49
  <div className="modal">
41
- <ModalHeader title={props.title} />
50
+ <ModalHeader title={props.title} uniqueId={uniqueIdRef.current} />
42
51
 
43
52
  <section className="modal__inner">
44
53
  {typeof props.children === "string" ? (
@@ -8,13 +8,14 @@ import { CSSTransition } from "react-transition-group"
8
8
 
9
9
  export type OverlayProps = {
10
10
  open?: boolean
11
- ariaLabel?: string
11
+ ariaLabelledBy?: string
12
12
  ariaDescription?: string
13
13
  className?: string
14
14
  backdrop?: boolean
15
15
  onClose?: () => void
16
16
  children: React.ReactNode
17
17
  slim?: boolean
18
+ role?: string
18
19
  }
19
20
 
20
21
  const OverlayInner = (props: OverlayProps) => {
@@ -31,8 +32,8 @@ const OverlayInner = (props: OverlayProps) => {
31
32
  return (
32
33
  <div
33
34
  className={classNames.join(" ")}
34
- role="dialog"
35
- aria-labelledby={props.ariaLabel}
35
+ role={props.role}
36
+ aria-labelledby={props.ariaLabelledBy}
36
37
  aria-describedby={props.ariaDescription}
37
38
  onClick={(e) => {
38
39
  if (e.target === e.currentTarget) closeHandler()
@@ -0,0 +1,36 @@
1
+ .markdown ul.application-timeline {
2
+ @apply mb-8;
3
+ @apply ml-0;
4
+ }
5
+
6
+ .application-timeline {
7
+ .progress-nav__item {
8
+ @apply pt-0;
9
+
10
+ text-transform: unset;
11
+
12
+ .absolute {
13
+ margin-top: 0.45rem;
14
+ z-index: 2;
15
+ margin-left: -0.4rem;
16
+ }
17
+
18
+ p {
19
+ padding-top: 3.8em;
20
+ }
21
+ }
22
+
23
+ .progress-nav__item.is-active::before,
24
+ .progress-nav__item.is-disabled::before {
25
+ height: 2rem;
26
+ width: 2rem;
27
+ }
28
+
29
+ .progress-nav__item.is-active::before {
30
+ @apply bg-green-700;
31
+ }
32
+
33
+ .progress-nav__item::after {
34
+ top: 1rem;
35
+ }
36
+ }