@bloom-housing/ui-components 6.0.0 → 6.0.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 (72) hide show
  1. package/CHANGELOG.md +214 -9
  2. package/package.json +3 -5
  3. package/src/actions/Button.tsx +1 -0
  4. package/src/actions/LinkButton.tsx +1 -0
  5. package/src/blocks/FormCard.scss +1 -0
  6. package/src/blocks/HousingCounselor.tsx +8 -3
  7. package/src/blocks/ImageCard.tsx +24 -13
  8. package/src/blocks/MediaCard.docs.mdx +37 -0
  9. package/src/blocks/MediaCard.scss +10 -11
  10. package/src/blocks/MediaCard.tsx +4 -4
  11. package/src/blocks/StandardCard.tsx +1 -1
  12. package/src/blocks/StatusItem.tsx +17 -6
  13. package/src/forms/DOBField.tsx +20 -8
  14. package/src/forms/DateField.tsx +16 -7
  15. package/src/forms/Dropzone.scss +7 -0
  16. package/src/forms/Dropzone.tsx +18 -5
  17. package/src/forms/Field.tsx +5 -0
  18. package/src/forms/FieldGroup.tsx +14 -3
  19. package/src/forms/HouseholdMemberForm.tsx +4 -1
  20. package/src/forms/HouseholdSizeField.tsx +16 -6
  21. package/src/forms/TimeField.tsx +15 -6
  22. package/src/global/custom_counter.scss +1 -1
  23. package/src/global/forms.scss +38 -5
  24. package/src/global/headers.scss +1 -1
  25. package/src/global/markdown.scss +2 -2
  26. package/src/headers/Hero.tsx +8 -1
  27. package/src/headers/PageHeader.scss +1 -1
  28. package/src/headers/PageHeader.tsx +5 -1
  29. package/src/headers/SiteHeader.tsx +11 -4
  30. package/src/helpers/formOptions.tsx +4 -1
  31. package/src/helpers/formatYesNoLabel.ts +8 -6
  32. package/src/locales/es.json +1 -1
  33. package/src/locales/general.json +9 -4
  34. package/src/locales/tl.json +1 -1
  35. package/src/locales/vi.json +1 -1
  36. package/src/locales/zh.json +1 -1
  37. package/src/navigation/Breadcrumbs.tsx +1 -1
  38. package/src/navigation/FooterNav.tsx +5 -1
  39. package/src/navigation/LanguageNav.tsx +1 -1
  40. package/src/navigation/ProgressNav.docs.mdx +47 -0
  41. package/src/navigation/ProgressNav.scss +101 -56
  42. package/src/navigation/ProgressNav.tsx +45 -15
  43. package/src/navigation/TabNav.scss +1 -1
  44. package/src/navigation/TabNav.tsx +1 -1
  45. package/src/notifications/AlertBox.docs.mdx +41 -0
  46. package/src/notifications/AlertBox.scss +78 -41
  47. package/src/notifications/AlertBox.tsx +20 -14
  48. package/src/notifications/SiteAlert.tsx +3 -0
  49. package/src/notifications/StatusMessage.tsx +8 -2
  50. package/src/notifications/alertTypes.ts +1 -0
  51. package/src/overlays/Modal.scss +3 -1
  52. package/src/page_components/ApplicationTimeline.scss +6 -6
  53. package/src/page_components/ApplicationTimeline.tsx +17 -7
  54. package/src/page_components/forgot-password/FormForgotPassword.tsx +1 -1
  55. package/src/page_components/listing/AdditionalFees.tsx +1 -1
  56. package/src/page_components/listing/ListingCard.scss +4 -0
  57. package/src/page_components/listing/ListingCard.tsx +18 -3
  58. package/src/page_components/listing/listing_sidebar/Contact.tsx +2 -2
  59. package/src/page_components/listing/listing_sidebar/GetApplication.tsx +31 -16
  60. package/src/page_components/listing/listing_sidebar/ListingUpdated.tsx +5 -1
  61. package/src/page_components/listing/listing_sidebar/OrDivider.tsx +4 -2
  62. package/src/page_components/listing/listing_sidebar/ReferralApplication.tsx +7 -4
  63. package/src/page_components/listing/listing_sidebar/events/DownloadLotteryResults.tsx +6 -1
  64. package/src/page_components/sign-in/FormSignIn.tsx +1 -1
  65. package/src/page_components/sign-in/FormSignInErrorBox.tsx +1 -1
  66. package/src/sections/InfoCardGrid.scss +1 -1
  67. package/src/sections/InfoCardGrid.tsx +4 -1
  68. package/src/sections/ListSection.tsx +1 -1
  69. package/src/tables/AgTable.tsx +10 -4
  70. package/src/tables/StandardTable.tsx +19 -7
  71. package/src/text/Tag.scss +7 -0
  72. package/src/text/Tag.tsx +2 -0
@@ -25,6 +25,15 @@ export interface DOBFieldProps {
25
25
  required?: boolean
26
26
  disabled?: boolean
27
27
  readerOnly?: boolean
28
+ strings?: {
29
+ dateError?: string
30
+ day?: string
31
+ dayPlaceholder?: string
32
+ month?: string
33
+ monthPlaceholder?: string
34
+ year?: string
35
+ yearPlaceholder?: string
36
+ }
28
37
  }
29
38
 
30
39
  const DOBField = (props: DOBFieldProps) => {
@@ -35,6 +44,8 @@ const DOBField = (props: DOBFieldProps) => {
35
44
  return [name, baseName].filter((item) => item).join(".")
36
45
  }
37
46
 
47
+ const hasError = error?.birthMonth || error?.birthDay || error?.birthYear
48
+
38
49
  const birthDay = watch(getFieldName("birthDay")) ?? defaultDOB?.birthDay
39
50
  const birthMonth = watch(getFieldName("birthMonth")) ?? defaultDOB?.birthMonth
40
51
 
@@ -47,6 +58,7 @@ const DOBField = (props: DOBFieldProps) => {
47
58
 
48
59
  const labelClasses = ["field-label--caps"]
49
60
  if (props.readerOnly) labelClasses.push("sr-only")
61
+ if (hasError) labelClasses.push("text-alert")
50
62
 
51
63
  return (
52
64
  <fieldset id={id}>
@@ -55,10 +67,10 @@ const DOBField = (props: DOBFieldProps) => {
55
67
  <div className="field-group--date">
56
68
  <Field
57
69
  name={getFieldName("birthMonth")}
58
- label={t("t.month")}
70
+ label={props.strings?.month ?? t("t.month")}
59
71
  disabled={props.disabled}
60
72
  readerOnly={true}
61
- placeholder={t("account.settings.placeholders.month")}
73
+ placeholder={props.strings?.monthPlaceholder ?? t("account.settings.placeholders.month")}
62
74
  defaultValue={defaultDOB?.birthMonth ? defaultDOB.birthMonth : ""}
63
75
  error={error?.birthMonth !== undefined}
64
76
  validation={{
@@ -77,10 +89,10 @@ const DOBField = (props: DOBFieldProps) => {
77
89
  />
78
90
  <Field
79
91
  name={getFieldName("birthDay")}
80
- label={t("t.day")}
92
+ label={props.strings?.day ?? t("t.day")}
81
93
  disabled={props.disabled}
82
94
  readerOnly={true}
83
- placeholder={t("account.settings.placeholders.day")}
95
+ placeholder={props.strings?.dayPlaceholder ?? t("account.settings.placeholders.day")}
84
96
  defaultValue={defaultDOB?.birthDay ? defaultDOB.birthDay : ""}
85
97
  error={error?.birthDay !== undefined}
86
98
  validation={{
@@ -99,10 +111,10 @@ const DOBField = (props: DOBFieldProps) => {
99
111
  />
100
112
  <Field
101
113
  name={getFieldName("birthYear")}
102
- label={t("t.year")}
114
+ label={props.strings?.year ?? t("t.year")}
103
115
  disabled={props.disabled}
104
116
  readerOnly={true}
105
- placeholder={t("account.settings.placeholders.year")}
117
+ placeholder={props.strings?.yearPlaceholder ?? t("account.settings.placeholders.year")}
106
118
  defaultValue={defaultDOB?.birthYear ? defaultDOB.birthYear : ""}
107
119
  error={error?.birthYear !== undefined}
108
120
  validation={{
@@ -123,10 +135,10 @@ const DOBField = (props: DOBFieldProps) => {
123
135
  />
124
136
  </div>
125
137
 
126
- {(error?.birthMonth || error?.birthDay || error?.birthYear) && (
138
+ {hasError && (
127
139
  <div className="field error">
128
140
  <span id={`${id}-error`} className="error-message">
129
- {errorMessage ? errorMessage : t("errors.dateOfBirthError")}
141
+ {errorMessage ? errorMessage : props.strings?.dateError ?? t("errors.dateOfBirthError")}
130
142
  </span>
131
143
  </div>
132
144
  )}
@@ -25,6 +25,15 @@ export interface DateFieldProps {
25
25
  required?: boolean
26
26
  watch: UseFormMethods["watch"]
27
27
  dataTestId?: string
28
+ strings?: {
29
+ dateError?: string
30
+ day?: string
31
+ dayPlaceholder?: string
32
+ month?: string
33
+ monthPlaceholder?: string
34
+ year?: string
35
+ yearPlaceholder?: string
36
+ }
28
37
  }
29
38
 
30
39
  const DateField = (props: DateFieldProps) => {
@@ -44,10 +53,10 @@ const DateField = (props: DateFieldProps) => {
44
53
  <div className="field-group--date">
45
54
  <Field
46
55
  name={getFieldName("month")}
47
- label={t("t.month")}
56
+ label={props.strings?.month ?? t("t.month")}
48
57
  disabled={props.disabled}
49
58
  readerOnly={true}
50
- placeholder={t("account.settings.placeholders.month")}
59
+ placeholder={props.strings?.monthPlaceholder ?? t("account.settings.placeholders.month")}
51
60
  defaultValue={defaultDate?.month ?? ""}
52
61
  error={error?.month !== undefined}
53
62
  validation={{
@@ -65,10 +74,10 @@ const DateField = (props: DateFieldProps) => {
65
74
  />
66
75
  <Field
67
76
  name={getFieldName("day")}
68
- label={t("t.day")}
77
+ label={props.strings?.day ?? t("t.day")}
69
78
  disabled={props.disabled}
70
79
  readerOnly={true}
71
- placeholder={t("account.settings.placeholders.day")}
80
+ placeholder={props.strings?.dayPlaceholder ?? t("account.settings.placeholders.day")}
72
81
  defaultValue={defaultDate?.day ?? ""}
73
82
  error={error?.day !== undefined}
74
83
  validation={{
@@ -86,10 +95,10 @@ const DateField = (props: DateFieldProps) => {
86
95
  />
87
96
  <Field
88
97
  name={getFieldName("year")}
89
- label={t("t.year")}
98
+ label={props.strings?.year ?? t("t.year")}
90
99
  disabled={props.disabled}
91
100
  readerOnly={true}
92
- placeholder={t("account.settings.placeholders.year")}
101
+ placeholder={props.strings?.yearPlaceholder ?? t("account.settings.placeholders.year")}
93
102
  defaultValue={defaultDate?.year ?? ""}
94
103
  error={error?.year !== undefined}
95
104
  validation={{
@@ -113,7 +122,7 @@ const DateField = (props: DateFieldProps) => {
113
122
  {(error?.month || error?.day || error?.year) && (
114
123
  <div className="field error">
115
124
  <span id={`${id}-error`} className="error-message">
116
- {errorMessage ? errorMessage : t("errors.dateError")}
125
+ {errorMessage ? errorMessage : props.strings?.dateError ?? t("errors.dateError")}
117
126
  </span>
118
127
  </div>
119
128
  )}
@@ -15,3 +15,10 @@
15
15
  .dropzone__progress {
16
16
  max-width: 250px;
17
17
  }
18
+
19
+ .dropzone__helptext {
20
+ margin-block: var(--bloom-s2) var(--bloom-s4);
21
+ color: var(--bloom-color-gray-700);
22
+ font-family: var(--bloom-font-alt-sans);
23
+ font-size: var(--bloom-font-size-sm);
24
+ }
@@ -11,6 +11,13 @@ interface DropzoneProps {
11
11
  accept?: string | string[]
12
12
  progress?: number
13
13
  className?: string
14
+ maxFiles?: number
15
+ strings?: {
16
+ chooseFromFolder?: string
17
+ dragHere?: string
18
+ dropHere?: string
19
+ orString?: string
20
+ }
14
21
  }
15
22
 
16
23
  const Dropzone = (props: DropzoneProps) => {
@@ -18,6 +25,8 @@ const Dropzone = (props: DropzoneProps) => {
18
25
  const classNames = ["field"]
19
26
  if (props.className) classNames.push(props.className)
20
27
 
28
+ const maxFiles = props.maxFiles || 1
29
+
21
30
  const onDrop = useCallback(
22
31
  (acceptedFiles) => {
23
32
  acceptedFiles.forEach((file: File) => uploader(file))
@@ -27,7 +36,8 @@ const Dropzone = (props: DropzoneProps) => {
27
36
  const { getRootProps, getInputProps, isDragActive } = useDropzone({
28
37
  onDrop,
29
38
  accept: props.accept,
30
- maxFiles: 1,
39
+ maxFiles: maxFiles > 1 ? maxFiles : undefined,
40
+ multiple: maxFiles > 1,
31
41
  })
32
42
 
33
43
  const dropzoneClasses = ["dropzone", "control"]
@@ -42,7 +52,7 @@ const Dropzone = (props: DropzoneProps) => {
42
52
  <label htmlFor={props.id} className="label">
43
53
  {props.label}
44
54
  </label>
45
- {props.helptext && <p className="view-item__label mt-2 mb-4">{props.helptext}</p>}
55
+ {props.helptext && <p className="dropzone__helptext">{props.helptext}</p>}
46
56
  {props.progress && props.progress === 100 ? (
47
57
  <></>
48
58
  ) : props.progress && props.progress > 0 ? (
@@ -51,11 +61,14 @@ const Dropzone = (props: DropzoneProps) => {
51
61
  <div className={dropzoneClasses.join(" ")} {...getRootProps()}>
52
62
  <input id={props.id} {...getInputProps()} data-test-id={"dropzone-input"} />
53
63
  {isDragActive ? (
54
- <p>{t("t.dropFilesHere")}</p>
64
+ <p>{props.strings?.dropHere ?? t("t.dropFilesHere")}</p>
55
65
  ) : (
56
66
  <p>
57
- {t("t.dragFilesHere")} {t("t.or")}{" "}
58
- <u className="text-primary">{t("t.chooseFromFolder").toLowerCase()}</u>
67
+ {props.strings?.dragHere ?? t("t.dragFilesHere")}{" "}
68
+ {props.strings?.orString ?? t("t.or")}{" "}
69
+ <u className="text-primary">
70
+ {props.strings?.chooseFromFolder ?? t("t.chooseFromFolder").toLowerCase()}
71
+ </u>
59
72
  </p>
60
73
  )}
61
74
  </div>
@@ -31,6 +31,7 @@ export interface FieldProps {
31
31
  setValue?: UseFormMethods["setValue"]
32
32
  dataTestId?: string
33
33
  hidden?: boolean
34
+ bordered?: boolean
34
35
  }
35
36
 
36
37
  const Field = (props: FieldProps) => {
@@ -53,6 +54,9 @@ const Field = (props: FieldProps) => {
53
54
  controlClasses.push(props.controlClassName)
54
55
  }
55
56
 
57
+ if (props.bordered && (props.type === "radio" || props.type === "checkbox"))
58
+ controlClasses.push("field-border")
59
+
56
60
  const formatValue = () => {
57
61
  if (props.getValues && props.setValue) {
58
62
  const currencyValue = props.getValues(props.name)
@@ -77,6 +81,7 @@ const Field = (props: FieldProps) => {
77
81
  if (props.type === "radio") {
78
82
  labelClasses.push("font-semibold")
79
83
  }
84
+ if (props.error) labelClasses.push("text-alert")
80
85
 
81
86
  return (
82
87
  <label className={labelClasses.join(" ")} htmlFor={props.id || props.name}>
@@ -37,6 +37,11 @@ interface FieldGroupProps {
37
37
  register: UseFormMethods["register"]
38
38
  type?: string
39
39
  validation?: RegisterOptions
40
+ strings?: {
41
+ description?: string
42
+ readLess?: string
43
+ readMore?: string
44
+ }
40
45
  }
41
46
 
42
47
  const FieldGroup = ({
@@ -54,8 +59,9 @@ const FieldGroup = ({
54
59
  fieldLabelClassName,
55
60
  groupSubNote,
56
61
  dataTestId,
62
+ strings,
57
63
  }: FieldGroupProps) => {
58
- // Always align two-option radio groups side by side
64
+ // Always default align two-option radio groups side by side
59
65
  if (fields?.length === 2) {
60
66
  fieldGroupClassName = `${fieldGroupClassName} flex`
61
67
  fieldClassName = `${fieldClassName} flex-initial mr-4`
@@ -103,7 +109,12 @@ const FieldGroup = ({
103
109
 
104
110
  {item.description && (
105
111
  <div className="ml-8 -mt-1 mb-5">
106
- <ExpandableContent strings={{ readMore: t("t.readMore"), readLess: t("t.readLess") }}>
112
+ <ExpandableContent
113
+ strings={{
114
+ readMore: strings?.readMore ?? t("t.readMore"),
115
+ readLess: strings?.readLess ?? t("t.readLess"),
116
+ }}
117
+ >
107
118
  <p className="field-note mb-2 -mt-2">{item.description}</p>
108
119
  </ExpandableContent>
109
120
  </div>
@@ -143,7 +154,7 @@ const FieldGroup = ({
143
154
  name={`${name}-${item.value}`}
144
155
  register={register}
145
156
  defaultValue={item.defaultText}
146
- placeholder={t("t.description")}
157
+ placeholder={strings?.description ?? t("t.description")}
147
158
  className={"mb-4"}
148
159
  disabled={item.disabled}
149
160
  dataTestId={item.dataTestId}
@@ -10,6 +10,9 @@ export interface HouseholdMemberFormProps {
10
10
  memberId?: number
11
11
  memberLastName: string
12
12
  subtitle: string
13
+ strings?: {
14
+ edit?: string
15
+ }
13
16
  }
14
17
 
15
18
  const HouseholdMemberForm = (props: HouseholdMemberFormProps) => {
@@ -26,7 +29,7 @@ const HouseholdMemberForm = (props: HouseholdMemberFormProps) => {
26
29
  type={"button"}
27
30
  data-test-id={"app-household-member-edit-button"}
28
31
  >
29
- {t("t.edit")}
32
+ {props.strings?.edit ?? t("t.edit")}
30
33
  </button>
31
34
  ) : (
32
35
  <Icon
@@ -14,6 +14,13 @@ export interface HouseholdSizeFieldProps {
14
14
  householdSizeMin: number
15
15
  register: UseFormMethods["register"]
16
16
  validate: boolean
17
+ strings?: {
18
+ dontQualifyDescription?: string
19
+ dontQualifyHeader?: string
20
+ getAssistance?: string
21
+ householdTooBigError?: string
22
+ householdTooSmallError?: string
23
+ }
17
24
  }
18
25
 
19
26
  const HouseholdSizeField = (props: HouseholdSizeFieldProps) => {
@@ -26,6 +33,7 @@ const HouseholdSizeField = (props: HouseholdSizeFieldProps) => {
26
33
  clearErrors,
27
34
  error,
28
35
  assistanceUrl,
36
+ strings,
29
37
  } = props
30
38
  if (!householdSizeMax || !validate) {
31
39
  return <></>
@@ -44,11 +52,11 @@ const HouseholdSizeField = (props: HouseholdSizeFieldProps) => {
44
52
  ? register({
45
53
  min: {
46
54
  value: householdSizeMin || 0,
47
- message: t("errors.householdTooSmall"),
55
+ message: strings?.householdTooSmallError ?? t("errors.householdTooSmall"),
48
56
  },
49
57
  max: {
50
58
  value: householdSizeMax,
51
- message: t("errors.householdTooBig"),
59
+ message: strings?.householdTooBigError ?? t("errors.householdTooBig"),
52
60
  },
53
61
  })
54
62
  : register
@@ -58,15 +66,17 @@ const HouseholdSizeField = (props: HouseholdSizeFieldProps) => {
58
66
  <ErrorMessage
59
67
  id={"householdsize-error"}
60
68
  error={!!error}
61
- className="block mt-0 line-normal text-red-700"
69
+ className="block mt-0 line-normal text-alert"
62
70
  >
63
71
  <AlertBox type="alert" inverted onClose={() => clearErrors()}>
64
- {t("application.household.dontQualifyHeader")}
72
+ {strings?.dontQualifyHeader ?? t("application.household.dontQualifyHeader")}
65
73
  </AlertBox>
66
74
  <AlertNotice title={error?.message} type="alert" inverted>
67
- <p className="mb-2">{t("application.household.dontQualifyInfo")}</p>
75
+ <p className="mb-2">
76
+ {strings?.dontQualifyDescription ?? t("application.household.dontQualifyInfo")}
77
+ </p>
68
78
  <p>
69
- <a href={assistanceUrl}>{t("pageTitle.getAssistance")}</a>
79
+ <a href={assistanceUrl}>{strings?.getAssistance ?? t("pageTitle.getAssistance")}</a>
70
80
  </p>
71
81
  </AlertNotice>
72
82
  </ErrorMessage>
@@ -29,6 +29,14 @@ export type TimeFieldProps = {
29
29
  watch: UseFormMethods["watch"]
30
30
  seconds?: boolean
31
31
  dataTestId?: string
32
+ strings?: {
33
+ hour?: string
34
+ minutes?: string
35
+ minutesPlaceholder?: string
36
+ seconds?: string
37
+ time?: string
38
+ timeError?: string
39
+ }
32
40
  }
33
41
 
34
42
  export const formatDateToTimeField = (date: Date) => {
@@ -56,6 +64,7 @@ const TimeField = ({
56
64
  defaultValues,
57
65
  disabled,
58
66
  dataTestId,
67
+ strings,
59
68
  }: TimeFieldProps) => {
60
69
  const fieldName = (baseName: string) => {
61
70
  return [name, baseName].filter((item) => item).join(".")
@@ -82,7 +91,7 @@ const TimeField = ({
82
91
  <div className="field-group--date">
83
92
  <Field
84
93
  name={fieldName("hours")}
85
- label={t("t.hour")}
94
+ label={strings?.hour ?? t("t.hour")}
86
95
  defaultValue={defaultValues?.hours ?? ""}
87
96
  readerOnly={true}
88
97
  placeholder="HH"
@@ -106,10 +115,10 @@ const TimeField = ({
106
115
 
107
116
  <Field
108
117
  name={fieldName("minutes")}
109
- label={t("t.minutes")}
118
+ label={strings?.minutes ?? t("t.minutes")}
110
119
  defaultValue={defaultValues?.minutes ?? ""}
111
120
  readerOnly={true}
112
- placeholder={t("account.settings.placeholders.month")}
121
+ placeholder={strings?.minutesPlaceholder ?? t("account.settings.placeholders.month")}
113
122
  error={error}
114
123
  validation={{
115
124
  required: required || innerRequiredRule,
@@ -130,7 +139,7 @@ const TimeField = ({
130
139
 
131
140
  {seconds && (
132
141
  <Field
133
- label={t("t.seconds")}
142
+ label={strings?.seconds ?? t("t.seconds")}
134
143
  defaultValue={defaultValues?.seconds ?? ""}
135
144
  name={fieldName("seconds")}
136
145
  readerOnly={true}
@@ -158,7 +167,7 @@ const TimeField = ({
158
167
  name={fieldName("period")}
159
168
  id={fieldName("period")}
160
169
  labelClassName="sr-only"
161
- label={t("t.time")}
170
+ label={strings?.time ?? t("t.time")}
162
171
  register={register}
163
172
  options={["am", "pm"]}
164
173
  keyPrefix="t"
@@ -172,7 +181,7 @@ const TimeField = ({
172
181
 
173
182
  <div id={`${id}-error`} className="field error">
174
183
  <ErrorMessage id={"time-field-error"} error={error}>
175
- {t("errors.timeError")}
184
+ {strings?.timeError ?? t("errors.timeError")}
176
185
  </ErrorMessage>
177
186
  </div>
178
187
  </fieldset>
@@ -45,6 +45,6 @@
45
45
  }
46
46
 
47
47
  .custom-counter__subtitle {
48
- @apply text-gray-700;
48
+ @apply text-gray-750;
49
49
  @apply text-tiny;
50
50
  }
@@ -1,4 +1,10 @@
1
1
  .field {
2
+ --bordered-border-width: 1px;
3
+ --bordered-border-radius: var(--bloom-s1_5);
4
+ --bordered-vertical-padding: var(--bloom-s4);
5
+ --bordered-leftward-padding: 2.875rem;
6
+ --bordered-checked-bg-color: var(--bloom-color-gray-100);
7
+
2
8
  margin-bottom: 1.25rem;
3
9
 
4
10
  * > &:last-child {
@@ -29,6 +35,34 @@
29
35
  @apply mt-0;
30
36
  }
31
37
 
38
+ .field-border {
39
+ label {
40
+ background-color: var(--bloom-color-white);
41
+ padding-top: var(--bordered-vertical-padding);
42
+ padding-bottom: var(--bordered-vertical-padding);
43
+ padding-left: var(--bordered-leftward-padding);
44
+ border-width: var(--bordered-border-width);
45
+ border-radius: var(--bordered-border-radius);
46
+ border-color: var(--bloom-color-gray-450);
47
+ }
48
+ input[type="checkbox"] + label::before,
49
+ input[type="radio"] + label::before,
50
+ input[type="checkbox"]:focus + label::before,
51
+ input[type="radio"]:focus + label::before {
52
+ background-color: none;
53
+ box-shadow: 0 0 0 1px white, 0 0 0 2px var(--bloom-color-gray-450);
54
+ }
55
+ input[type="checkbox"]:focus + label,
56
+ input[type="radio"]:focus + label {
57
+ box-shadow: 0 0 0 1px white, 0 0 0 2px var(--bloom-color-accent-cool),
58
+ 0 0 3px 4px var(--bloom-color-accent-cool);
59
+ }
60
+ input[type="checkbox"]:checked + label,
61
+ input[type="radio"]:checked + label {
62
+ background-color: var(--bordered-checked-bg-color);
63
+ }
64
+ }
65
+
32
66
  .control {
33
67
  position: relative;
34
68
 
@@ -196,7 +230,7 @@
196
230
 
197
231
  &.error {
198
232
  label {
199
- @apply text-red-700;
233
+ @apply text-alert;
200
234
  }
201
235
 
202
236
  .control {
@@ -208,7 +242,7 @@
208
242
  }
209
243
 
210
244
  .prepend {
211
- @apply text-red-700;
245
+ @apply text-alert;
212
246
  }
213
247
  }
214
248
 
@@ -321,17 +355,16 @@ input[type="number"] {
321
355
  .field-note {
322
356
  @apply text-tiny;
323
357
  @apply text-gray-700;
324
- @apply font-semibold;
325
358
  white-space: pre-line;
326
359
  }
327
360
 
328
361
  .error-message {
329
362
  display: inline-block;
330
363
  @apply text-sm;
331
- @apply text-red-700;
364
+ @apply text-alert;
332
365
  @apply tracking-wide;
333
366
  @apply leading-5;
334
- @apply mt-2;
367
+ @apply mt-1;
335
368
  }
336
369
 
337
370
  .field-sub-note {
@@ -74,7 +74,7 @@
74
74
  @apply text-tiny;
75
75
 
76
76
  @screen md {
77
- @apply text-gray-700;
77
+ @apply text-gray-750;
78
78
  }
79
79
  }
80
80
 
@@ -1,5 +1,5 @@
1
1
  .markdown {
2
- h3 {
2
+ h2 {
3
3
  @apply mt-8;
4
4
  @apply mb-5;
5
5
  @apply text-3xl;
@@ -9,7 +9,7 @@
9
9
  }
10
10
  }
11
11
 
12
- h3:first-child {
12
+ h2:first-child {
13
13
  @apply mt-0;
14
14
  }
15
15
 
@@ -14,6 +14,9 @@ export interface HeroProps {
14
14
  secondaryButtonLink?: string
15
15
  secondaryButtonTitle?: string
16
16
  title: React.ReactNode
17
+ strings?: {
18
+ allApplicationsClosed?: string
19
+ }
17
20
  }
18
21
 
19
22
  const HeroButton = (props: { title: string; href: string; className?: string }) => (
@@ -26,7 +29,11 @@ const Hero = (props: HeroProps) => {
26
29
  let subHeader, styles
27
30
  let classNames = ""
28
31
  if (props.allApplicationsClosed) {
29
- subHeader = <h2 className="hero__subtitle">{t("welcome.allApplicationClosed")}</h2>
32
+ subHeader = (
33
+ <h2 className="hero__subtitle">
34
+ {props.strings?.allApplicationsClosed ?? t("welcome.allApplicationClosed")}
35
+ </h2>
36
+ )
30
37
  } else if (props.children) {
31
38
  subHeader = <h2 className="hero__subtitle">{props.children}</h2>
32
39
  }
@@ -1,6 +1,6 @@
1
1
  .page-header {
2
2
  /* Component Variables */
3
- --background-color: var(--bloom-color-primary-lighter);
3
+ --background-color: var(--bloom-color-gray-300);
4
4
  --border-color: var(--bloom-color-gray-450);
5
5
  --text-color: inherit;
6
6
  --text-font-family: var(--bloom-font-serif);
@@ -19,7 +19,11 @@ const PageHeader = (props: PageHeaderProps) => {
19
19
  return (
20
20
  <header className={classNames.join(" ")}>
21
21
  <hgroup className="page-header__group">
22
- {props?.breadcrumbs && <nav className="page-header__breadcrumbs">{props?.breadcrumbs}</nav>}
22
+ {props?.breadcrumbs && (
23
+ <nav className="page-header__breadcrumbs" aria-label={"Page Header"}>
24
+ {props?.breadcrumbs}
25
+ </nav>
26
+ )}
23
27
 
24
28
  {props.title && (
25
29
  <h1 data-test-id="page-header" className="page-header__title">
@@ -38,6 +38,11 @@ export interface SiteHeaderProps {
38
38
  noticeMobile?: boolean
39
39
  siteHeaderWidth?: SiteHeaderWidth
40
40
  title?: string
41
+ strings?: {
42
+ close?: string
43
+ logoAriaLable?: string
44
+ menu?: string
45
+ }
41
46
  }
42
47
 
43
48
  const SiteHeader = (props: SiteHeaderProps) => {
@@ -240,7 +245,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
240
245
  setMobileDrawer(false)
241
246
  }
242
247
  }}
243
- aria-label={t("t.close")}
248
+ aria-label={props.strings?.close ?? t("t.close")}
244
249
  >
245
250
  <Icon size="small" symbol="arrowForward" fill={"#ffffff"} className={"pl-2"} />
246
251
  </button>
@@ -377,7 +382,9 @@ const SiteHeader = (props: SiteHeaderProps) => {
377
382
  }
378
383
  }}
379
384
  >
380
- <div className={"pr-2 text-tiny text-primary uppercase"}>{t("t.menu")}</div>
385
+ <div className={"pr-2 text-tiny text-primary uppercase"}>
386
+ {props.strings?.menu ?? t("t.menu")}
387
+ </div>
381
388
  <Icon
382
389
  symbol={mobileMenu ? "closeSmall" : "hamburger"}
383
390
  size={"base"}
@@ -400,7 +407,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
400
407
  className={"navbar-mobile-menu-button"}
401
408
  unstyled
402
409
  >
403
- {mobileMenu ? t("t.close") : t("t.menu")}
410
+ {mobileMenu ? props.strings?.close ?? t("t.close") : props.strings?.menu ?? t("t.menu")}
404
411
  </Button>
405
412
  )}
406
413
  </>
@@ -415,7 +422,7 @@ const SiteHeader = (props: SiteHeaderProps) => {
415
422
  props.logoWidth && "navbar-custom-width"
416
423
  }`}
417
424
  href={props.homeURL}
418
- aria-label={t("t.homePage")}
425
+ aria-label={props.strings?.logoAriaLable ?? t("t.homePage")}
419
426
  >
420
427
  <div className={`logo-content ${props.imageOnly && "navbar-image-only-container"}`}>
421
428
  <img
@@ -5,6 +5,9 @@ import { SelectOption } from "../forms/Select"
5
5
  export interface FormOptionsProps {
6
6
  options: (string | SelectOption)[]
7
7
  keyPrefix?: string
8
+ strings?: {
9
+ selectOne?: string
10
+ }
8
11
  }
9
12
 
10
13
  export const numberOptions = (end: number, start = 1): SelectOption[] => {
@@ -21,7 +24,7 @@ export const FormOptions = (props: FormOptionsProps) => {
21
24
  if (option == "" || option["value"] == "") {
22
25
  return (
23
26
  <option value="" key="select-one">
24
- {t("t.selectOne")}
27
+ {props.strings?.selectOne ?? t("t.selectOne")}
25
28
  </option>
26
29
  )
27
30
  } else {