@bloom-housing/ui-components 6.0.0 → 6.0.1-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +236 -7
  2. package/index.ts +1 -0
  3. package/package.json +3 -5
  4. package/src/actions/Button.tsx +1 -0
  5. package/src/actions/LinkButton.tsx +1 -0
  6. package/src/blocks/FormCard.scss +1 -0
  7. package/src/blocks/HousingCounselor.tsx +8 -3
  8. package/src/blocks/ImageCard.tsx +24 -13
  9. package/src/blocks/MediaCard.docs.mdx +37 -0
  10. package/src/blocks/MediaCard.scss +10 -11
  11. package/src/blocks/MediaCard.tsx +4 -4
  12. package/src/blocks/StandardCard.tsx +1 -1
  13. package/src/blocks/StatusItem.tsx +17 -6
  14. package/src/forms/DOBField.tsx +20 -8
  15. package/src/forms/DateField.tsx +16 -7
  16. package/src/forms/Dropzone.scss +7 -0
  17. package/src/forms/Dropzone.tsx +18 -5
  18. package/src/forms/Field.tsx +5 -0
  19. package/src/forms/FieldGroup.tsx +14 -3
  20. package/src/forms/HouseholdMemberForm.tsx +4 -1
  21. package/src/forms/HouseholdSizeField.tsx +16 -6
  22. package/src/forms/TimeField.tsx +15 -6
  23. package/src/global/custom_counter.scss +1 -1
  24. package/src/global/forms.scss +38 -5
  25. package/src/global/headers.scss +1 -1
  26. package/src/global/markdown.scss +2 -2
  27. package/src/global/vendor/ag_grid.scss +43 -9
  28. package/src/headers/Hero.tsx +8 -1
  29. package/src/headers/PageHeader.scss +3 -2
  30. package/src/headers/PageHeader.tsx +5 -1
  31. package/src/headers/SiteHeader.tsx +11 -4
  32. package/src/helpers/formOptions.tsx +4 -1
  33. package/src/helpers/formatYesNoLabel.ts +8 -6
  34. package/src/locales/es.json +1 -1
  35. package/src/locales/general.json +9 -4
  36. package/src/locales/tl.json +1 -1
  37. package/src/locales/vi.json +1 -1
  38. package/src/locales/zh.json +1 -1
  39. package/src/navigation/Breadcrumbs.scss +1 -0
  40. package/src/navigation/Breadcrumbs.tsx +1 -1
  41. package/src/navigation/FooterNav.tsx +5 -1
  42. package/src/navigation/LanguageNav.tsx +1 -1
  43. package/src/navigation/ProgressNav.docs.mdx +47 -0
  44. package/src/navigation/ProgressNav.scss +101 -56
  45. package/src/navigation/ProgressNav.tsx +45 -15
  46. package/src/navigation/SideNav.scss +56 -0
  47. package/src/navigation/SideNav.tsx +2 -2
  48. package/src/navigation/TabNav.scss +1 -1
  49. package/src/navigation/TabNav.tsx +1 -1
  50. package/src/navigation/Tabs.scss +25 -6
  51. package/src/notifications/AlertBox.docs.mdx +41 -0
  52. package/src/notifications/AlertBox.scss +78 -41
  53. package/src/notifications/AlertBox.tsx +20 -14
  54. package/src/notifications/SiteAlert.tsx +3 -0
  55. package/src/notifications/StatusMessage.tsx +8 -2
  56. package/src/notifications/alertTypes.ts +1 -0
  57. package/src/overlays/Modal.scss +3 -1
  58. package/src/page_components/ApplicationTimeline.scss +6 -6
  59. package/src/page_components/ApplicationTimeline.tsx +17 -7
  60. package/src/page_components/NavigationHeader.tsx +10 -10
  61. package/src/page_components/forgot-password/FormForgotPassword.tsx +1 -1
  62. package/src/page_components/listing/AdditionalFees.tsx +1 -1
  63. package/src/page_components/listing/ListingCard.scss +4 -0
  64. package/src/page_components/listing/ListingCard.tsx +18 -3
  65. package/src/page_components/listing/listing_sidebar/Contact.tsx +2 -2
  66. package/src/page_components/listing/listing_sidebar/GetApplication.tsx +31 -16
  67. package/src/page_components/listing/listing_sidebar/ListingUpdated.tsx +5 -1
  68. package/src/page_components/listing/listing_sidebar/OrDivider.tsx +4 -2
  69. package/src/page_components/listing/listing_sidebar/ReferralApplication.tsx +7 -4
  70. package/src/page_components/listing/listing_sidebar/events/DownloadLotteryResults.tsx +6 -1
  71. package/src/page_components/sign-in/FormSignIn.tsx +1 -1
  72. package/src/page_components/sign-in/FormSignInErrorBox.tsx +1 -1
  73. package/src/sections/InfoCardGrid.scss +1 -1
  74. package/src/sections/InfoCardGrid.tsx +4 -1
  75. package/src/sections/ListSection.tsx +1 -1
  76. package/src/tables/AgTable.tsx +56 -26
  77. package/src/tables/StandardTable.tsx +19 -7
  78. package/src/text/Tag.scss +7 -0
  79. package/src/text/Tag.tsx +2 -0
@@ -86,3 +86,7 @@
86
86
  margin-inline-start: var(--bloom-s1);
87
87
  }
88
88
  }
89
+ .listings-pill_header {
90
+ margin-bottom: var(--bloom-s3);
91
+ margin-top: var(--bloom-s1);
92
+ }
@@ -5,7 +5,7 @@ import { StackedTable, StackedTableProps } from "../../tables/StackedTable"
5
5
  import { StandardTable, StandardTableProps } from "../../tables/StandardTable"
6
6
  import { Heading, HeaderType } from "../../headers/Heading"
7
7
  import { Tag } from "../../text/Tag"
8
- import { AppearanceStyleType } from "../../global/AppearanceTypes"
8
+ import { AppearanceShadeType, AppearanceStyleType } from "../../global/AppearanceTypes"
9
9
  import { Icon, IconFillColors } from "../../icons/Icon"
10
10
  import "./ListingCard.scss"
11
11
  import { NavigationContext } from "../../config/NavigationContext"
@@ -16,6 +16,8 @@ export interface CardHeader {
16
16
  content: string | React.ReactNode
17
17
  href?: string
18
18
  customClass?: string
19
+ styleType?: AppearanceStyleType
20
+ isPillType?: boolean
19
21
  }
20
22
 
21
23
  export interface FooterButton {
@@ -74,12 +76,25 @@ const ListingCard = (props: ListingCardProps) => {
74
76
  const getHeader = (
75
77
  header: CardHeader | undefined,
76
78
  priority: number,
77
- style?: HeaderType,
79
+ styleType?: HeaderType,
78
80
  customClass?: string
79
81
  ) => {
80
82
  if (header && header.content) {
83
+ if (header.isPillType) {
84
+ return (
85
+ <Tag
86
+ className="listings-pill_header"
87
+ pillStyle
88
+ capitalized
89
+ styleType={header.styleType}
90
+ shade={AppearanceShadeType.light}
91
+ >
92
+ {header.content}
93
+ </Tag>
94
+ )
95
+ }
81
96
  return (
82
- <Heading priority={priority} style={style} className={customClass}>
97
+ <Heading priority={priority} style={styleType} className={customClass}>
83
98
  {header.href ? (
84
99
  <LinkComponent className="is-card-link" href={header.href}>
85
100
  {header.content}
@@ -95,12 +95,12 @@ const Contact = ({
95
95
 
96
96
  {additionalInformation?.map((info) => {
97
97
  return (
98
- <React.Fragment key={info.title}>
98
+ <div key={info.title} className={"my-3"}>
99
99
  <Heading priority={3} style={"sidebarSubHeader"}>
100
100
  {info.title}
101
101
  </Heading>
102
102
  <div className="text-gray-800 text-tiny markdown">{info.content}</div>
103
- </React.Fragment>
103
+ </div>
104
104
  )
105
105
  })}
106
106
  </section>
@@ -1,13 +1,13 @@
1
1
  import React, { useState } from "react"
2
- import { t } from "../../../helpers/translator"
2
+ import Markdown from "markdown-to-jsx"
3
3
  import { Button } from "../../../actions/Button"
4
4
  import { LinkButton } from "../../../actions/LinkButton"
5
5
  import { AppearanceStyleType } from "../../../global/AppearanceTypes"
6
6
  import { Address } from "../../../helpers/MultiLineAddress"
7
- import { ContactAddress } from "./ContactAddress"
8
- import { OrDivider } from "./OrDivider"
9
7
  import { Heading } from "../../../headers/Heading"
10
- import Markdown from "markdown-to-jsx"
8
+ import { t } from "../../../helpers/translator"
9
+ import { OrDivider } from "./OrDivider"
10
+ import { ContactAddress } from "./ContactAddress"
11
11
 
12
12
  export interface PaperApplication {
13
13
  fileURL: string
@@ -33,6 +33,16 @@ export interface ApplicationsProps {
33
33
  postmarkedApplicationsReceivedByDate?: string
34
34
  /** Whether or not to hide actionable application buttons */
35
35
  preview?: boolean
36
+ strings?: {
37
+ applicationsOpenInFuture?: string
38
+ applyOnline?: string
39
+ downloadApplication?: string
40
+ getAPaperApplication?: string
41
+ getDirections?: string
42
+ howToApply?: string
43
+ officeHoursHeading?: string
44
+ pickUpApplication?: string
45
+ }
36
46
  }
37
47
  /** Displays information regarding how to apply, including an online application link button, paper application downloads, and a paper application pickup address */
38
48
  const GetApplication = (props: ApplicationsProps) => {
@@ -46,19 +56,22 @@ const GetApplication = (props: ApplicationsProps) => {
46
56
 
47
57
  return (
48
58
  <section className="aside-block" data-test-id="get-application-section">
49
- <h2 className="text-caps-underline">{t("listings.apply.howToApply")}</h2>
59
+ <h2 className="text-caps-underline">
60
+ {props.strings?.howToApply ?? t("listings.apply.howToApply")}
61
+ </h2>
50
62
  {!props.applicationsOpen && (
51
63
  <p className="mb-5 text-gray-700">
52
- {t("listings.apply.applicationWillBeAvailableOn", {
53
- openDate: props.applicationsOpenDate,
54
- })}
64
+ {props.strings?.applicationsOpenInFuture ??
65
+ t("listings.apply.applicationWillBeAvailableOn", {
66
+ openDate: props.applicationsOpenDate,
67
+ })}
55
68
  </p>
56
69
  )}
57
70
  {props.applicationsOpen && props.onlineApplicationURL && (
58
71
  <>
59
72
  {props.preview ? (
60
73
  <Button disabled className="w-full mb-2" data-test-id={"listing-view-apply-button"}>
61
- {t("listings.apply.applyOnline")}
74
+ {props.strings?.applyOnline ?? t("listings.apply.applyOnline")}
62
75
  </Button>
63
76
  ) : (
64
77
  <LinkButton
@@ -67,7 +80,7 @@ const GetApplication = (props: ApplicationsProps) => {
67
80
  href={props.onlineApplicationURL}
68
81
  dataTestId={"listing-view-apply-button"}
69
82
  >
70
- {t("listings.apply.applyOnline")}
83
+ {props.strings?.applyOnline ?? t("listings.apply.applyOnline")}
71
84
  </LinkButton>
72
85
  )}
73
86
  </>
@@ -76,7 +89,9 @@ const GetApplication = (props: ApplicationsProps) => {
76
89
  {props.applicationsOpen && props.paperMethod && !!props.paperApplications?.length && (
77
90
  <>
78
91
  {props.onlineApplicationURL && <OrDivider bgColor="white" />}
79
- <div className="text-serif-lg">{t("listings.apply.getAPaperApplication")}</div>
92
+ <div className="text-serif-lg">
93
+ {props.strings?.getAPaperApplication ?? t("listings.apply.getAPaperApplication")}
94
+ </div>
80
95
  <Button
81
96
  styleType={
82
97
  !props.preview && props.onlineApplicationURL ? AppearanceStyleType.primary : undefined
@@ -85,7 +100,7 @@ const GetApplication = (props: ApplicationsProps) => {
85
100
  onClick={toggleDownload}
86
101
  disabled={props.preview}
87
102
  >
88
- {t("listings.apply.downloadApplication")}
103
+ {props.strings?.downloadApplication ?? t("listings.apply.downloadApplication")}
89
104
  </Button>
90
105
  </>
91
106
  )}
@@ -94,7 +109,7 @@ const GetApplication = (props: ApplicationsProps) => {
94
109
  <p key={index} className="text-center mt-2 mb-4 text-sm">
95
110
  <a
96
111
  href={paperApplication.fileURL}
97
- title={t("listings.apply.downloadApplication")}
112
+ title={props.strings?.downloadApplication ?? t("listings.apply.downloadApplication")}
98
113
  target="_blank"
99
114
  >
100
115
  {paperApplication.languageString}
@@ -107,16 +122,16 @@ const GetApplication = (props: ApplicationsProps) => {
107
122
  <OrDivider bgColor="white" />
108
123
  )}
109
124
  <Heading priority={3} style={"sidebarSubHeader"}>
110
- {t("listings.apply.pickUpAnApplication")}
125
+ {props.strings?.pickUpApplication ?? t("listings.apply.pickUpAnApplication")}
111
126
  </Heading>
112
127
  <ContactAddress
113
128
  address={props.applicationPickUpAddress}
114
- mapString={t("t.getDirections")}
129
+ mapString={props.strings?.getDirections ?? t("t.getDirections")}
115
130
  />
116
131
  {props.applicationPickUpAddressOfficeHours && (
117
132
  <>
118
133
  <Heading priority={3} style={"sidebarSubHeader"}>
119
- {t("leasingAgent.officeHours")}
134
+ {props.strings?.officeHoursHeading ?? t("leasingAgent.officeHours")}
120
135
  </Heading>
121
136
  <p className="text-gray-800 text-tiny markdown">
122
137
  <Markdown
@@ -4,6 +4,9 @@ import dayjs from "dayjs"
4
4
 
5
5
  interface ListingUpdatedProps {
6
6
  listingUpdated: Date
7
+ strings?: {
8
+ listingUpdated?: string
9
+ }
7
10
  }
8
11
 
9
12
  const ListingUpdated = (props: ListingUpdatedProps) => {
@@ -11,7 +14,8 @@ const ListingUpdated = (props: ListingUpdatedProps) => {
11
14
  return (
12
15
  <section className="aside-block">
13
16
  <p className="text-tiny text-gray-800">
14
- {`${t("listings.listingUpdated")}: ${dayjs(listingUpdated).format("MMMM DD, YYYY")}`}
17
+ {props?.strings?.listingUpdated ??
18
+ `${t("listings.listingUpdated")}: ${dayjs(listingUpdated).format("MMMM DD, YYYY")}`}
15
19
  </p>
16
20
  </section>
17
21
  )
@@ -1,9 +1,11 @@
1
1
  import * as React from "react"
2
2
  import { t } from "../../../helpers/translator"
3
3
 
4
- const OrDivider = (props: { bgColor: string }) => (
4
+ const OrDivider = (props: { bgColor: string; strings?: { orString?: string } }) => (
5
5
  <div className="aside-block__divider">
6
- <span className={`bg-${props.bgColor} aside-block__conjunction`}>{t("t.or")}</span>
6
+ <span className={`bg-${props.bgColor} aside-block__conjunction`}>
7
+ {props.strings?.orString ?? t("t.or")}
8
+ </span>
7
9
  </div>
8
10
  )
9
11
 
@@ -5,7 +5,10 @@ import { Icon, IconFillColors } from "../../../icons/Icon"
5
5
  interface ReferralApplicationProps {
6
6
  description: string
7
7
  phoneNumber: string
8
- title: string
8
+ strings: {
9
+ call?: string
10
+ title: string
11
+ }
9
12
  }
10
13
 
11
14
  const ReferralApplication = (props: ReferralApplicationProps) => {
@@ -13,11 +16,11 @@ const ReferralApplication = (props: ReferralApplicationProps) => {
13
16
 
14
17
  return (
15
18
  <section className="aside-block">
16
- <h2 className="text-caps-underline">{props.title}</h2>
19
+ <h2 className="text-caps-underline">{props.strings.title}</h2>
17
20
  <p>
18
21
  <a href={linkedPhoneNumber}>
19
- <Icon symbol="phone" size="medium" fill={IconFillColors.primary} /> {t("t.call")}{" "}
20
- {props.phoneNumber}
22
+ <Icon symbol="phone" size="medium" fill={IconFillColors.primary} />{" "}
23
+ {props.strings.call ?? t("t.call")} {props.phoneNumber}
21
24
  </a>
22
25
  </p>
23
26
  <p className="text-tiny mt-4 text-gray-800">{props.description}</p>
@@ -5,13 +5,18 @@ type DownloadLotteryResultsProps = {
5
5
  resultsDate?: string
6
6
  buttonText?: string
7
7
  pdfURL?: string
8
+ strings?: {
9
+ sectionHeader?: string
10
+ }
8
11
  }
9
12
 
10
13
  const DownloadLotteryResults = (props: DownloadLotteryResultsProps) => {
11
14
  if (!props.pdfURL) return null
12
15
  return (
13
16
  <section className="aside-block text-center">
14
- <h2 className="text-caps pb-4">{t("listings.lotteryResults.header")}</h2>
17
+ <h2 className="text-caps pb-4">
18
+ {props.strings?.sectionHeader ?? t("listings.lotteryResults.header")}
19
+ </h2>
15
20
  {props.resultsDate && (
16
21
  <p className="uppercase text-gray-800 text-tiny font-semibold pb-4">{props.resultsDate}</p>
17
22
  )}
@@ -66,7 +66,7 @@ const FormSignIn = ({
66
66
  <FormCard>
67
67
  <div className="form-card__lead text-center">
68
68
  <Icon size="2xl" symbol="profile" />
69
- <h2 className="form-card__title">{t(`nav.signIn`)}</h2>
69
+ <h1 className="form-card__title">{t(`nav.signIn`)}</h1>
70
70
  </div>
71
71
  <FormSignInErrorBox
72
72
  errors={errors}
@@ -27,7 +27,7 @@ const FormSignInErrorBox = ({ networkStatus, errors, errorMessageId }: FormSignI
27
27
  <ErrorMessage
28
28
  id={`form-sign-in-${errorMessageId}-error`}
29
29
  error={!!networkStatus.content}
30
- className="block mt-0 leading-normal text-red-700"
30
+ className="block mt-0 leading-normal text-alert"
31
31
  >
32
32
  <AlertBox type={"alert"} inverted onClose={() => networkStatus.reset()}>
33
33
  {networkStatus.content.title}
@@ -1,5 +1,5 @@
1
1
  .info-cards__header {
2
- @apply mb-3;
2
+ @apply my-3;
3
3
 
4
4
  @screen md {
5
5
  margin-right: 1rem;
@@ -1,4 +1,5 @@
1
1
  import * as React from "react"
2
+ import { Heading } from "../headers/Heading"
2
3
  import "./InfoCardGrid.scss"
3
4
 
4
5
  export interface InfoCardGridProps {
@@ -10,7 +11,9 @@ export interface InfoCardGridProps {
10
11
  const InfoCardGrid = (props: InfoCardGridProps) => (
11
12
  <section className="info-cards">
12
13
  <header className="info-cards__header">
13
- <h2 className="info-cards__title">{props.title}</h2>
14
+ <Heading style={"sidebarHeader"} priority={2} className={"text-tiny"}>
15
+ {props.title}
16
+ </Heading>
14
17
  {props.subtitle && <p className="info-cards__subtitle">{props.subtitle}</p>}
15
18
  </header>
16
19
  <div className="info-cards__grid">{props.children}</div>
@@ -11,7 +11,7 @@ const ListSection = (props: ListSectionProps) => (
11
11
  <li className="list-section custom-counter__item">
12
12
  <header className="list-section__header custom-counter__header">
13
13
  <hgroup>
14
- <h4 className="custom-counter__title">{props.title}</h4>
14
+ <h3 className="custom-counter__title">{props.title}</h3>
15
15
  <span className="custom-counter__subtitle">{props.subtitle}</span>
16
16
  </hgroup>
17
17
  </header>
@@ -1,7 +1,14 @@
1
1
  import React, { useState, useCallback, useEffect, useRef } from "react"
2
2
  import { useForm } from "react-hook-form"
3
3
  import { AgGridReact } from "ag-grid-react"
4
- import { GridOptions, ColumnState, ColumnApi, ColDef, ColGroupDef } from "ag-grid-community"
4
+ import {
5
+ GridOptions,
6
+ ColumnState,
7
+ ColumnApi,
8
+ ColDef,
9
+ ColGroupDef,
10
+ GridApi,
11
+ } from "ag-grid-community"
5
12
  import { AgPagination, AG_PER_PAGE_OPTIONS } from "./AgPagination"
6
13
  import { LoadingOverlay } from "../overlays/LoadingOverlay"
7
14
  import { Field } from "../forms/Field"
@@ -15,14 +22,19 @@ export interface ColumnOrder {
15
22
  }
16
23
 
17
24
  export interface AgTableProps {
18
- id: string
19
25
  config: AgTableConfig
20
26
  data: AgTableData
21
- pagination: AgTablePagination
27
+ id: string
28
+ pagination?: AgTablePagination
22
29
  search: AgTableSearch
30
+ selectConfig?: AgTableSelectConfig
23
31
  sort?: AgTableSort
24
32
  headerContent?: React.ReactNode
25
33
  className?: string
34
+ strings?: {
35
+ filter?: string
36
+ searchError?: string
37
+ }
26
38
  }
27
39
 
28
40
  export interface AgTablePagination {
@@ -32,11 +44,17 @@ export interface AgTablePagination {
32
44
  setCurrentPage: React.Dispatch<React.SetStateAction<number>>
33
45
  }
34
46
 
47
+ export interface AgTableSelectConfig {
48
+ setGridApi: React.Dispatch<React.SetStateAction<GridApi | null>>
49
+ updateSelectedValues: () => void
50
+ }
51
+
35
52
  export interface AgTableConfig {
36
53
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
37
54
  gridComponents?: { [p: string]: any }
38
55
  columns: (ColDef | ColGroupDef)[]
39
56
  totalItemsLabel: string
57
+ rowSelection?: boolean
40
58
  }
41
59
 
42
60
  export interface AgTableData {
@@ -49,6 +67,7 @@ export interface AgTableData {
49
67
 
50
68
  export interface AgTableSearch {
51
69
  setSearch: React.Dispatch<React.SetStateAction<string>>
70
+ showSearch?: boolean
52
71
  }
53
72
 
54
73
  export interface AgTableSort {
@@ -81,20 +100,21 @@ export const useAgTable = () => {
81
100
  }
82
101
 
83
102
  const AgTable = ({
84
- id,
85
103
  className,
104
+ config: { gridComponents, columns, totalItemsLabel, rowSelection },
105
+ data,
106
+ headerContent,
107
+ id,
108
+ selectConfig,
86
109
  pagination,
87
- search: { setSearch },
110
+ search: { setSearch, showSearch = true },
88
111
  sort: { setSort } = {},
89
- headerContent,
90
- data,
91
- config: { gridComponents, columns, totalItemsLabel },
112
+ strings,
92
113
  }: AgTableProps) => {
93
114
  // local storage key with column state
94
115
  const columnStateLsKey = `column-state_${id}`
95
116
  const defaultColDef = {
96
117
  resizable: true,
97
- maxWidth: 300,
98
118
  }
99
119
 
100
120
  const [gridColumnApi, setGridColumnApi] = useState<ColumnApi | null>(null)
@@ -144,7 +164,7 @@ const AgTable = ({
144
164
  const debounceFilter = useRef(
145
165
  debounce((value: string) => {
146
166
  setSearch(value)
147
- pagination.setCurrentPage(1)
167
+ pagination?.setCurrentPage(1)
148
168
  }, 500)
149
169
  )
150
170
  useEffect(() => {
@@ -180,33 +200,37 @@ const AgTable = ({
180
200
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
181
201
  const onGridReady = (params: any) => {
182
202
  setGridColumnApi(params.columnApi)
203
+ if (selectConfig?.setGridApi) {
204
+ selectConfig.setGridApi(params.api)
205
+ }
183
206
  }
184
207
 
185
208
  return (
186
209
  <div className={`ag-theme-alpine ag-theme-bloom ${className || ""}`}>
187
210
  <div className="flex justify-between flex-col md:flex-row">
188
- <div className="flex flex-wrap">
211
+ <div className={`flex flex-wrap ${showSearch ? "mb-5" : "hidden"}`}>
189
212
  <div className="md:mr-5 w-full md:w-56">
190
213
  <Field
191
214
  dataTestId="ag-search-input"
192
215
  name="filter-input"
193
- label={t("t.filter")}
216
+ label={strings?.filter ?? t("t.filter")}
194
217
  readerOnly={true}
195
218
  register={register}
196
- placeholder={t("t.filter")}
219
+ placeholder={strings?.filter ?? t("t.filter")}
197
220
  />
198
221
  </div>
199
- <div className="w-full md:w-auto mt-2 mb-2 md:mb-0">
222
+ <div className="w-full md:w-auto mt-2 md:mt-0 mb-2 md:mb-0">
200
223
  {!validSearch && (
201
- <AlertBox type="notice">{t("applications.table.searchError")}</AlertBox>
224
+ <AlertBox type="notice">
225
+ {strings?.searchError ?? t("applications.table.searchError")}
226
+ </AlertBox>
202
227
  )}
203
228
  </div>
204
229
  </div>
205
230
 
206
231
  {headerContent}
207
232
  </div>
208
-
209
- <div className="applications-table mt-5">
233
+ <div className="applications-table">
210
234
  <LoadingOverlay isLoading={data.loading}>
211
235
  <div>
212
236
  <AgGridReact
@@ -221,19 +245,25 @@ const AgTable = ({
221
245
  suppressPaginationPanel={true}
222
246
  paginationPageSize={AG_PER_PAGE_OPTIONS[0]}
223
247
  suppressScrollOnNewData={true}
248
+ rowSelection={rowSelection ? "multiple" : undefined}
249
+ rowMultiSelectWithClick={rowSelection}
250
+ onRowDataChanged={selectConfig?.updateSelectedValues ?? undefined}
251
+ onFirstDataRendered={selectConfig?.updateSelectedValues ?? undefined}
224
252
  ></AgGridReact>
225
253
  </div>
226
254
  </LoadingOverlay>
227
255
 
228
- <AgPagination
229
- totalItems={data.totalItems}
230
- totalPages={data.totalPages}
231
- currentPage={pagination.currentPage}
232
- itemsPerPage={pagination.perPage}
233
- quantityLabel={totalItemsLabel}
234
- setCurrentPage={pagination.setCurrentPage}
235
- setItemsPerPage={pagination.setPerPage}
236
- />
256
+ {pagination && (
257
+ <AgPagination
258
+ totalItems={data.totalItems}
259
+ totalPages={data.totalPages}
260
+ currentPage={pagination.currentPage}
261
+ itemsPerPage={pagination.perPage}
262
+ quantityLabel={totalItemsLabel}
263
+ setCurrentPage={pagination.setCurrentPage}
264
+ setItemsPerPage={pagination.setPerPage}
265
+ />
266
+ )}
237
267
  </div>
238
268
  </div>
239
269
  )
@@ -1,10 +1,10 @@
1
1
  import React, { useState, useEffect } from "react"
2
2
  import { DragDropContext, Droppable, Draggable, DropResult } from "react-beautiful-dnd"
3
3
  import { nanoid } from "nanoid"
4
+ import { faGripLines } from "@fortawesome/free-solid-svg-icons"
4
5
  import { getTranslationWithArguments } from "../helpers/getTranslationWithArguments"
5
6
  import { Icon, IconFillColors } from "../icons/Icon"
6
7
  import { t } from "../helpers/translator"
7
- import { faGripLines } from "@fortawesome/free-solid-svg-icons"
8
8
 
9
9
  export interface TableHeadersOptions {
10
10
  name: string
@@ -51,6 +51,8 @@ export type StandardTableCell = {
51
51
  content: React.ReactNode
52
52
  /** Text content that will replace this cell's header on mobile views */
53
53
  mobileReplacement?: string
54
+ /** Classname to apply to this row */
55
+ rowClass?: string
54
56
  }
55
57
 
56
58
  export type StandardTableData = Record<string, StandardTableCell>[]
@@ -74,6 +76,10 @@ export interface StandardTableProps {
74
76
  translateData?: boolean
75
77
  /** An id applied to the table */
76
78
  id?: string
79
+ strings?: {
80
+ orderString?: string
81
+ sortString?: string
82
+ }
77
83
  }
78
84
 
79
85
  const headerName = (header: string | TableHeadersOptions) => {
@@ -110,12 +116,16 @@ export const StandardTable = (props: StandardTableProps) => {
110
116
  }, [props.data])
111
117
 
112
118
  if (props.draggable) {
113
- headerLabels.splice(0, 0, <th key={"header-draggable"}>{t("t.order")}</th>)
114
119
  headerLabels.splice(
115
120
  0,
116
121
  0,
117
- <th key={"header-draggable"} className={"table__draggable-cell pl-5"}>
118
- {t("t.sort")}
122
+ <th key={"header-draggable-order"}>{props.strings?.orderString ?? t("t.order")}</th>
123
+ )
124
+ headerLabels.splice(
125
+ 0,
126
+ 0,
127
+ <th key={"header-draggable-sort"} className={"table__draggable-cell pl-5"}>
128
+ {props.strings?.sortString ?? t("t.sort")}
119
129
  </th>
120
130
  )
121
131
  }
@@ -127,9 +137,11 @@ export const StandardTable = (props: StandardTableProps) => {
127
137
  ? `standardrow-${dataIndex}`
128
138
  : nanoid()
129
139
 
140
+ let rowClass: string | undefined = ""
130
141
  const cols = Object.keys(headers)?.map((colKey, colIndex) => {
131
142
  const uniqKey = process.env.NODE_ENV === "test" ? `standardcol-${colIndex}` : nanoid()
132
143
  const cell = row[colKey]?.content
144
+ rowClass = row[colKey]?.rowClass ? row[colKey].rowClass : ""
133
145
 
134
146
  const cellClass = [headerClassName(headers[colKey]), cellClassName].join(" ")
135
147
 
@@ -156,7 +168,7 @@ export const StandardTable = (props: StandardTableProps) => {
156
168
  0,
157
169
  <Cell
158
170
  key={`${dataIndex}-order-draggable`}
159
- headerLabel={t("t.sort")}
171
+ headerLabel={props.strings?.sortString ?? t("t.sort")}
160
172
  className={`pl-5 ${cellClassName ?? undefined}`}
161
173
  >
162
174
  {dataIndex + 1}
@@ -167,7 +179,7 @@ export const StandardTable = (props: StandardTableProps) => {
167
179
  0,
168
180
  <Cell
169
181
  key={`${dataIndex}-sort-draggable`}
170
- headerLabel={t("t.sort")}
182
+ headerLabel={props.strings?.sortString ?? t("t.sort")}
171
183
  className={`table__draggable-cell pl-7`}
172
184
  >
173
185
  <Icon symbol={faGripLines} size={"medium"} fill={IconFillColors.primary} />
@@ -193,7 +205,7 @@ export const StandardTable = (props: StandardTableProps) => {
193
205
  )}
194
206
  </Draggable>
195
207
  ) : (
196
- <tr id={rowKey} key={rowKey}>
208
+ <tr id={rowKey} key={rowKey} className={rowClass ? rowClass : ""}>
197
209
  {cols}
198
210
  </tr>
199
211
  )}
package/src/text/Tag.scss CHANGED
@@ -11,6 +11,8 @@
11
11
  --pill-font-weight: 600;
12
12
  --pill-text-transform: uppercase;
13
13
  --pill-letter-spacing: var(--bloom-letter-spacing-ultrawide);
14
+ --pill-capitalized-text-transform: capitalized;
15
+ --pill-capitalized-letter-spacing: var(--bloom-letter-spacing-wide);
14
16
 
15
17
  --small-pill-padding: var(--bloom-s1) var(--bloom-s3);
16
18
  --small-pill-font-size: var(--bloom-font-size-2xs);
@@ -129,4 +131,9 @@
129
131
  padding-block: var(--bloom-s2);
130
132
  padding-inline: var(--bloom-s4);
131
133
  }
134
+
135
+ &.is-capitalized {
136
+ text-transform: var(--pill-capitalized-text-transform);
137
+ letter-spacing: var(--pill-capitalized-letter-spacing);
138
+ }
132
139
  }
package/src/text/Tag.tsx CHANGED
@@ -5,6 +5,7 @@ import "./Tag.scss"
5
5
  export interface TagProps extends AppearanceProps {
6
6
  className?: string
7
7
  pillStyle?: boolean
8
+ capitalized?: boolean
8
9
  children: React.ReactNode
9
10
  fillContainer?: boolean
10
11
  }
@@ -14,6 +15,7 @@ export const Tag = (props: TagProps) => {
14
15
 
15
16
  if (props.pillStyle) tagClasses.push("is-pill")
16
17
  if (props.fillContainer) tagClasses.push("fill-container")
18
+ if (props.capitalized) tagClasses.push("is-capitalized")
17
19
  if (props.className) tagClasses.push(props.className)
18
20
 
19
21
  return <span className={tagClasses.join(" ")}>{props.children}</span>