@bloom-housing/ui-components 5.0.0 → 5.0.1-alpha.2

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,52 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [5.0.1-alpha.2](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@5.0.1-alpha.1...@bloom-housing/ui-components@5.0.1-alpha.2) (2022-06-23)
7
+
8
+ **Note:** Version bump only for package @bloom-housing/ui-components
9
+
10
+
11
+
12
+
13
+
14
+ ## [5.0.1-alpha.1](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@5.0.1-alpha.0...@bloom-housing/ui-components@5.0.1-alpha.1) (2022-06-21)
15
+
16
+
17
+ ### Features
18
+
19
+ * **listingcard:** add compatability for jsx elements in subheader ([#2821](https://github.com/bloom-housing/bloom/issues/2821)) ([77693dc](https://github.com/bloom-housing/bloom/commit/77693dcee60be8deba641595ed6ae5e141d14a51))
20
+
21
+
22
+ ### BREAKING CHANGES
23
+
24
+ * **listingcard:** prop name change for header from "text" to "content"
25
+
26
+
27
+
28
+
29
+
30
+ ## [5.0.1-alpha.0](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@4.4.1-alpha.27...@bloom-housing/ui-components@5.0.1-alpha.0) (2022-06-16)
31
+
32
+
33
+ * 2022-06 -16 sync master (#2825) ([17dabfe](https://github.com/bloom-housing/bloom/commit/17dabfeaf77afb55d629f97fe8e90001df94dc04)), closes [#2825](https://github.com/bloom-housing/bloom/issues/2825) [#2753](https://github.com/bloom-housing/bloom/issues/2753) [#2441](https://github.com/bloom-housing/bloom/issues/2441) [#2460](https://github.com/bloom-housing/bloom/issues/2460) [#2459](https://github.com/bloom-housing/bloom/issues/2459) [#2464](https://github.com/bloom-housing/bloom/issues/2464) [#2465](https://github.com/bloom-housing/bloom/issues/2465) [#2466](https://github.com/bloom-housing/bloom/issues/2466) [#2436](https://github.com/bloom-housing/bloom/issues/2436) [#2451](https://github.com/bloom-housing/bloom/issues/2451) [#2415](https://github.com/bloom-housing/bloom/issues/2415) [#2354](https://github.com/bloom-housing/bloom/issues/2354) [#2455](https://github.com/bloom-housing/bloom/issues/2455) [#2484](https://github.com/bloom-housing/bloom/issues/2484) [#2482](https://github.com/bloom-housing/bloom/issues/2482) [#2483](https://github.com/bloom-housing/bloom/issues/2483) [#2476](https://github.com/bloom-housing/bloom/issues/2476) [#2485](https://github.com/bloom-housing/bloom/issues/2485) [#2470](https://github.com/bloom-housing/bloom/issues/2470) [#2488](https://github.com/bloom-housing/bloom/issues/2488) [#2487](https://github.com/bloom-housing/bloom/issues/2487) [#2496](https://github.com/bloom-housing/bloom/issues/2496) [#2498](https://github.com/bloom-housing/bloom/issues/2498) [#2499](https://github.com/bloom-housing/bloom/issues/2499) [#2291](https://github.com/bloom-housing/bloom/issues/2291) [#2461](https://github.com/bloom-housing/bloom/issues/2461) [#2485](https://github.com/bloom-housing/bloom/issues/2485) [#2494](https://github.com/bloom-housing/bloom/issues/2494) [#2503](https://github.com/bloom-housing/bloom/issues/2503) [#2495](https://github.com/bloom-housing/bloom/issues/2495) [#2477](https://github.com/bloom-housing/bloom/issues/2477) [#2505](https://github.com/bloom-housing/bloom/issues/2505) [#2372](https://github.com/bloom-housing/bloom/issues/2372) [#2489](https://github.com/bloom-housing/bloom/issues/2489) [#2497](https://github.com/bloom-housing/bloom/issues/2497) [#2506](https://github.com/bloom-housing/bloom/issues/2506) [#2486](https://github.com/bloom-housing/bloom/issues/2486)
34
+
35
+
36
+ ### BREAKING CHANGES
37
+
38
+ * consolidated all event section components in one new component, uptake will require removing the deprecated components and uptaking EventSection
39
+
40
+ * chore(release): version
41
+
42
+ - @bloom-housing/backend-core@3.0.2-alpha.38
43
+ - @bloom-housing/shared-helpers@4.0.1-alpha.63
44
+ - @bloom-housing/partners@4.0.1-alpha.67
45
+ - @bloom-housing/public@4.0.1-alpha.66
46
+ - @bloom-housing/ui-components@4.0.1-alpha.62
47
+
48
+
49
+
50
+
51
+
6
52
  # [5.0.0](https://github.com/seanmalbert/bloom/compare/@bloom-housing/ui-components@4.4.0...@bloom-housing/ui-components@5.0.0) (2022-06-16)
7
53
 
8
54
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloom-housing/ui-components",
3
- "version": "5.0.0",
3
+ "version": "5.0.1-alpha.2",
4
4
  "author": "Sean Albert <sean.albert@exygy.com>",
5
5
  "description": "Shared user interface components for Bloom affordable housing system",
6
6
  "homepage": "https://github.com/bloom-housing/bloom/tree/master/shared/ui-components",
@@ -108,5 +108,5 @@
108
108
  "ts-jest": "^26.4.1",
109
109
  "typesafe-actions": "^5.1.0"
110
110
  },
111
- "gitHead": "6af474347ea32b98bf8a216704cc12efcd838ff6"
111
+ "gitHead": "f04434904aa50d2a8012266329dc53f08168defa"
112
112
  }
@@ -50,12 +50,12 @@ You can apply CSS variables to the `.button` selector to customize the appearanc
50
50
  | `--alert-appearance-hover-background-color` | <Swatch colorVar="--bloom-color-alert-dark" /> | Hover state alert background color |
51
51
  | `--alert-appearance-hover-border-color` | <Swatch colorVar="--bloom-color-alert" /> | Hover state alert border color |
52
52
  | `--alert-appearance-hover-label-color` | <Swatch colorVar="--bloom-color-white" /> | Hover state alert label color |
53
- | `--warn-appearance-background-color` | <Swatch colorVar="--bloom-color-warn" /> | Warning background color |
54
- | `--warn-appearance-border-color` | <Swatch colorVar="--bloom-color-warn" /> | Warning border color |
55
- | `--warn-appearance-label-color` | <Swatch colorVar="--bloom-color-white" /> | Warning label color |
56
- | `--warn-appearance-hover-background-color` | <Swatch colorVar="--bloom-color-warn-dark" /> | Hover state warning background color |
57
- | `--warn-appearance-hover-border-color` | <Swatch colorVar="--bloom-color-warn" /> | Hover state warning border color |
58
- | `--warn-appearance-hover-label-color` | <Swatch colorVar="--bloom-color-white" /> | Hover state warning label color |
53
+ | `--warning-appearance-background-color` | <Swatch colorVar="--bloom-color-warn" /> | Warning background color |
54
+ | `--warning-appearance-border-color` | <Swatch colorVar="--bloom-color-warn" /> | Warning border color |
55
+ | `--warning-appearance-label-color` | <Swatch colorVar="--bloom-color-white" /> | Warning label color |
56
+ | `--warning-appearance-hover-background-color` | <Swatch colorVar="--bloom-color-warn-dark" /> | Hover state warning background color |
57
+ | `--warning-appearance-hover-border-color` | <Swatch colorVar="--bloom-color-warn" /> | Hover state warning border color |
58
+ | `--warning-appearance-hover-label-color` | <Swatch colorVar="--bloom-color-white" /> | Hover state warning label color |
59
59
 
60
60
  ### Typographic & Spacing Variables
61
61
 
@@ -1,16 +1,32 @@
1
1
  @import "../global/mixins.scss";
2
2
 
3
3
  .button {
4
+ /* Component Variables */
5
+ --normal-rounded: var(--bloom-rounded);
6
+ --normal-padding: var(--bloom-s4) var(--bloom-s6);
7
+ --label-transform: uppercase;
8
+ --label-font: var(--bloom-font-alt-sans);
9
+ --label-letter-spacing: var(--bloom-letter-spacing-widest);
10
+ --normal-font-size: var(--bloom-font-size-sm);
11
+ --label-weight: bold;
12
+ --small-rounded: var(--bloom-rounded);
13
+ --small-padding: var(--bloom-s3) var(--bloom-s6);
14
+ --small-font-size: var(--bloom-font-size-xs);
15
+ --big-rounded: var(--bloom-rounded);
16
+ --big-padding: var(--bloom-s6);
17
+ --big-font-size: var(--bloom-font-size-sm);
18
+
19
+ /* Base Styles */
4
20
  position: relative;
5
- border-radius: var(--normal-rounded, var(--bloom-rounded));
6
- padding: var(--normal-padding, var(--bloom-s4) var(--bloom-s6));
21
+ border-radius: var(--normal-rounded);
22
+ padding: var(--normal-padding);
7
23
  text-align: center;
8
- text-transform: var(--label-transform, uppercase);
9
- font-family: var(--label-font, var(--bloom-font-alt-sans));
24
+ text-transform: var(--label-transform);
25
+ font-family: var(--label-font);
10
26
  display: inline-block;
11
- letter-spacing: var(--label-letter-spacing, var(--bloom-letter-spacing-widest));
12
- font-size: var(--normal-font-size, var(--bloom-font-size-sm));
13
- font-weight: var(--label-weight, bold);
27
+ letter-spacing: var(--label-letter-spacing);
28
+ font-size: var(--normal-font-size);
29
+ font-weight: var(--label-weight);
14
30
  line-height: var(--bloom-line-height-snug);
15
31
 
16
32
  &:focus {
@@ -40,15 +56,15 @@
40
56
  }
41
57
 
42
58
  &.is-small {
43
- border-radius: var(--small-rounded, var(--bloom-rounded));
44
- padding: var(--small-padding, var(--bloom-s3) var(--bloom-s6));
45
- font-size: var(--small-font-size, var(--bloom-font-size-xs));
59
+ border-radius: var(--small-rounded);
60
+ padding: var(--small-padding);
61
+ font-size: var(--small-font-size);
46
62
  }
47
63
 
48
64
  &.is-big {
49
- border-radius: var(--big-rounded, var(--bloom-rounded));
50
- padding: var(--big-padding, var(--bloom-s6));
51
- font-size: var(--big-font-size, var(--bloom-font-size-sm));
65
+ border-radius: var(--big-rounded);
66
+ padding: var(--big-padding);
67
+ font-size: var(--big-font-size);
52
68
  }
53
69
 
54
70
  &.is-normal-case {
@@ -19,6 +19,7 @@ export interface ButtonProps extends AppearanceProps {
19
19
  className?: string
20
20
  disabled?: boolean
21
21
  loading?: boolean
22
+ ariaHidden?: boolean
22
23
  ariaLabel?: string
23
24
  dataTestId?: string
24
25
  "data-test-id"?: string
@@ -75,6 +76,7 @@ const Button = (props: ButtonProps) => {
75
76
  className={buttonClasses.join(" ")}
76
77
  onClick={props.onClick}
77
78
  disabled={props.disabled || props.loading}
79
+ aria-hidden={props.ariaHidden}
78
80
  aria-label={props.ariaLabel}
79
81
  data-test-id={props.dataTestId || props["data-test-id"]}
80
82
  >
@@ -23,6 +23,7 @@ const LinkButton = (props: LinkButtonProps) => {
23
23
  return (
24
24
  <LinkComponent
25
25
  href={props.href}
26
+ aria-hidden={props.ariaHidden}
26
27
  className={buttonClasses.join(" ")}
27
28
  data-test-id={props.dataTestId}
28
29
  >
@@ -0,0 +1,30 @@
1
+ import { Canvas, Story, ArgsTable } from "@storybook/addon-docs"
2
+ import { Swatch } from "../prototypes/Swatch"
3
+ import { ImageCard } from "./ImageCard"
4
+
5
+ # Image Card
6
+
7
+ The image card component renders an image with optional tags at top and status bars below it.
8
+
9
+ <Canvas>
10
+ <Story id="blocks-image-card--with-one-status-and-tag" />
11
+ </Canvas>
12
+
13
+ <br />
14
+ <br />
15
+
16
+ ## Component Properties
17
+
18
+ <ArgsTable of={ImageCard} />
19
+
20
+ ## Theming Variables
21
+
22
+ You can apply CSS variables to the `.image-card` selector to customize the appearance of the component. Interior tags themselves are customizable separately, see the **Text/Tag** documentation for details.
23
+
24
+ | Name | Type | Description | Default |
25
+ | ---------------------------- | -------------------------------------------- | ------------------------------------------------------------------ | ------------------------ |
26
+ | `--default-background-color` | <Swatch colorVar="--bloom-color-gray-500" /> | Background color when an image URL isn't available | `--bloom-color-gray-500` |
27
+ | `--border-radius` | Size | The border radius of the card | `0px` |
28
+ | `--image-height` | Size | A height limit for the image area | `auto` |
29
+ | `--tags-justify-mobile` | Flex Jusification | The horizontal alignment of tags over the image on mobile screens | `center` |
30
+ | `--tags-justify-desktop` | Flex Jusification | The horizontal alignment of tags over the image on desktop screens | `flex-start` |
@@ -1,92 +1,67 @@
1
1
  @import "../global/mixins.scss";
2
2
 
3
- .image-card__wrapper {
4
- @apply relative;
3
+ .image-card {
4
+ /* Component Variables */
5
+ --default-background-color: var(--bloom-color-gray-500);
6
+ --border-radius: 0px;
7
+ --image-height: auto;
8
+ --tags-justify-mobile: center;
9
+ --tags-justify-desktop: flex-start;
10
+
11
+ position: relative;
5
12
  }
6
13
 
7
- .image-card {
8
- @apply relative;
9
- @apply bg-gray-500;
14
+ .image-card__inner {
15
+ position: relative;
16
+ background-color: var(--default-background-color);
17
+ border-radius: var(--border-radius);
18
+
10
19
  img {
11
- @apply w-full;
20
+ border-radius: var(--border-radius);
21
+ width: 100%;
22
+ height: var(--image-height);
23
+ object-fit: cover;
12
24
  }
13
25
  }
14
26
 
15
27
  .image-card-tag__wrapper {
16
- @apply flex;
17
- @apply items-center;
18
- @apply justify-center;
19
- @apply absolute;
20
- @apply z-10;
21
- @apply w-full;
22
- @apply mt-1;
23
- @apply px-4;
24
- @apply flex-wrap;
28
+ --tags-justify: var(--tags-justify-mobile);
25
29
 
26
- @screen md {
27
- @apply items-start;
28
- @apply justify-start;
29
- }
30
- }
31
-
32
- .image-card__figcaption {
33
- @apply absolute;
34
- @apply inset-x-0;
35
- @apply bottom-0;
36
- @apply py-1;
37
- }
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: var(--tags-justify);
33
+ position: absolute;
34
+ z-index: 10;
35
+ width: 100%;
36
+ margin-block-start: var(--bloom-s1);
37
+ padding-inline: var(--bloom-s4);
38
+ flex-wrap: wrap;
39
+ max-width: 100%;
38
40
 
39
- .image-card__placeholder {
40
- height: 300px;
41
- }
41
+ @media (min-width: $screen-sm) {
42
+ --tags-justify: var(--tags-justify-desktop);
43
+ }
42
44
 
43
- .image-card__tag {
44
- @apply absolute;
45
- @apply top-0;
46
- @apply p-3;
47
- @apply m-5;
48
- }
45
+ .tag {
46
+ margin-top: var(--bloom-s3);
47
+ margin-inline: var(--bloom-s2);
49
48
 
50
- .image-card__title {
51
- @apply text-white;
52
- @apply text-left;
53
- @apply text-lg;
54
- @apply uppercase;
55
- @apply font-alt-sans;
56
- @apply relative;
57
- @apply z-10;
58
- @apply tracking-wider;
59
- @apply px-5;
60
- @apply pb-1;
61
- @screen md {
62
- @apply text-3xl;
49
+ .ui-icon {
50
+ margin-inline-end: var(--bloom-s2);
51
+ }
63
52
  }
64
53
  }
65
54
 
66
- .image-card__subtitle {
67
- @apply text-white;
68
- @apply text-left;
69
- @apply uppercase;
70
- @apply font-alt-sans;
71
- @apply text-sm;
72
- @apply px-5;
73
- @apply pb-3;
74
- @apply relative;
75
- @apply z-10;
76
- @apply tracking-widest;
55
+ .image-card__placeholder {
56
+ height: 300px;
77
57
  }
78
58
 
79
59
  .image-card--leader {
80
- @apply w-full;
81
-
82
- @screen md {
83
- @apply w-2/3;
84
- @apply pr-8;
85
- @apply pt-8;
86
- }
60
+ width: 100%;
87
61
 
88
- .image-card__title {
89
- @apply text-4xl;
90
- @apply text-center;
62
+ @media (min-width: $screen-sm) {
63
+ width: var(--bloom-width-2-3rd);
64
+ margin-block-start: var(--bloom-s8);
65
+ margin-inline-end: var(--bloom-s8);
91
66
  }
92
67
  }
@@ -20,27 +20,26 @@ export interface ImageTag {
20
20
  text?: string
21
21
  iconType?: UniversalIconType
22
22
  iconColor?: string
23
+ styleType?: AppearanceStyleType
23
24
  }
24
25
 
25
26
  export interface ImageCardProps {
27
+ /** A description of the image, used as alt text */
26
28
  description?: string
29
+ /** A link, used to wrap the entire component */
27
30
  href?: string
31
+ /** An image URL, used as the background image */
28
32
  imageUrl?: string
33
+ /** A list of status indicators, an ApplicationStatus component is rendered for each item at the bottom of the card */
29
34
  statuses?: StatusBarType[]
35
+ /** A list of image tags, a Tag component is rendered for each over the image */
30
36
  tags?: ImageTag[]
31
37
  }
32
38
 
33
39
  /**
34
40
  * @component ImageCard
35
41
  *
36
- * A component that renders an image with optional status bars below it
37
- *
38
- * @prop description - A description of the image, used as alt text
39
- * @prop href - A link, used to wrap the entire component
40
- * @prop imageUrl - An image URL, used as a background image
41
- * @prop statuses - A list of status indicators, an ApplicationStatus component is rendered for each item at the bottom of the card
42
- * @prop tags - A list of image tags, a Tag component is rendered for each over the image
43
- *
42
+ * A component that renders an image with optional tags at top and status bars below it
44
43
  */
45
44
  const ImageCard = (props: ImageCardProps) => {
46
45
  const getStatuses = () => {
@@ -61,18 +60,17 @@ const ImageCard = (props: ImageCardProps) => {
61
60
  }
62
61
 
63
62
  const image = (
64
- <div className="image-card__wrapper">
63
+ <div className="image-card">
65
64
  <div className="image-card-tag__wrapper">
66
65
  {props.tags?.map((tag, index) => {
67
66
  return (
68
67
  <React.Fragment key={index}>
69
- <Tag styleType={AppearanceStyleType.warning} className={"mt-3 mr-2 ml-2"}>
68
+ <Tag styleType={tag.styleType || AppearanceStyleType.warning}>
70
69
  {tag.iconType && (
71
70
  <Icon
72
71
  size={"medium"}
73
72
  symbol={tag.iconType}
74
73
  fill={tag.iconColor ?? IconFillColors.primary}
75
- className={"mr-2"}
76
74
  />
77
75
  )}
78
76
  {tag.text}
@@ -81,7 +79,7 @@ const ImageCard = (props: ImageCardProps) => {
81
79
  )
82
80
  })}
83
81
  </div>
84
- <figure className="image-card">
82
+ <figure className="image-card__inner">
85
83
  {props.imageUrl ? (
86
84
  <img src={props.imageUrl} alt={props.description || t("listings.buildingImageAltText")} />
87
85
  ) : (
@@ -99,25 +99,32 @@
99
99
  }
100
100
 
101
101
  &.is-alert {
102
- background-color: var(--bloom-color-alert);
103
- border-color: var(--bloom-color-alert);
104
- color: var(--bloom-color-white);
102
+ background-color: var(--alert-appearance-background-color, var(--bloom-color-alert));
103
+ border-color: var(--alert-appearance-border-color, var(--bloom-color-alert));
104
+ color: var(--alert-appearance-label-color, var(--bloom-color-white));
105
105
 
106
106
  &:hover {
107
- background-color: var(--bloom-color-alert-dark);
108
- border-color: var(--bloom-color-alert-dark);
107
+ background-color: var(
108
+ --alert-appearance-hover-background-color,
109
+ var(--bloom-color-alert-dark)
110
+ );
111
+ border-color: var(--alert-appearance-hover-border-color, var(--bloom-color-alert-dark));
112
+ color: var(--alert-appearance-hover-label-color, var(--bloom-color-white));
109
113
  }
110
114
  }
111
115
 
112
116
  &.is-warning {
113
- background-color: var(--bloom-color-warn);
114
- border-color: var(--bloom-color-warn);
115
- color: var(--bloom-color-gray-800);
117
+ background-color: var(--warning-appearance-background-color, var(--bloom-color-warn));
118
+ border-color: var(--warning-appearance-border-color, var(--bloom-color-warn));
119
+ color: var(--warning-appearance-label-color, var(--bloom-color-gray-800));
116
120
 
117
121
  &:hover {
118
- color: var(--bloom-color-white);
119
- background-color: var(--bloom-color-warn-dark);
120
- border-color: var(--bloom-color-warn-dark);
122
+ background-color: var(
123
+ --warning-appearance-hover-background-color,
124
+ var(--bloom-color-warn-dark)
125
+ );
126
+ border-color: var(--warning-appearance-hover-border-color, var(--bloom-color-warn-dark));
127
+ color: var(--warning-appearance-hover-label-color, var(--bloom-color-white));
121
128
  }
122
129
  }
123
130
 
@@ -141,39 +141,41 @@ h1.title {
141
141
  }
142
142
 
143
143
  .card-header {
144
- @apply font-alt-sans;
145
- @apply font-semibold;
146
- @apply text-blue-700;
147
- @apply text-3xl;
148
- @apply mb-3;
149
- @apply leading-tight;
144
+ font-family: var(--card-header-font-family, var(--bloom-font-alt-sans));
145
+ font-weight: var(--card-header-font-weight, 600);
146
+ color: var(--card-header-color, var(--bloom-color-blue-700));
147
+ font-size: var(--card-header-font-size, var(--bloom-font-size-3xl));
148
+ margin-block: var(--card-header-margin-block, 0 var(--bloom-s3));
149
+ line-height: var(--card-header-line-height, var(--bloom-line-height-tight));
150
150
  }
151
151
 
152
152
  .card-subheader {
153
- @apply font-alt-sans;
154
- @apply text-black;
155
- @apply text-base;
156
- @apply mb-3;
153
+ font-family: var(--card-subheader-font-family, var(--bloom-font-alt-sans));
154
+ font-weight: var(--card-subheader-font-weight, normal);
155
+ color: var(--card-subheader-color, var(--bloom-color-black));
156
+ font-size: var(--card-subheader-font-size, var(--bloom-font-size-base));
157
+ margin-block: var(--card-subheader-margin-block, 0 var(--bloom-s3));
157
158
  }
158
159
 
159
160
  .table-header {
160
- @apply font-alt-sans;
161
- @apply font-semibold;
162
- @apply text-gray-800;
163
- @apply text-sm;
164
- @apply mb-1;
161
+ font-family: var(--table-header-font-family, var(--bloom-font-alt-sans));
162
+ font-weight: var(--table-header-font-weight, 600);
163
+ color: var(--table-header-color, var(--bloom-color-gray-800));
164
+ font-size: var(--table-header-font-size, var(--bloom-font-size-sm));
165
+ margin-block: var(--table-header-margin-block, 0 var(--bloom-s1));
165
166
  }
166
167
 
167
168
  .table-subheader {
168
- @apply font-alt-sans;
169
- @apply text-gray-750;
170
- @apply text-sm;
171
- @apply mb-3;
169
+ font-family: var(--table-subheader-font-family, var(--bloom-font-alt-sans));
170
+ font-weight: var(--table-subheader-font-weight, normal);
171
+ color: var(--table-subheader-color, var(--bloom-color-gray-750));
172
+ font-size: var(--table-subheader-font-size, var(--bloom-font-size-sm));
173
+ margin-block: var(--table-header-margin-block, 0 var(--bloom-s3));
172
174
  }
173
175
 
174
176
  .category-header {
175
- @apply font-alt-sans;
176
- @apply font-semibold;
177
- @apply text-gray-700;
178
- @apply text-sm;
177
+ font-family: var(--category-header-font-family, var(--bloom-font-alt-sans));
178
+ font-weight: var(--category-header-font-weight, 600);
179
+ color: var(--category-header-color, var(--bloom-color-gray-700));
180
+ font-size: var(--category-header-font-size, var(--bloom-font-size-sm));
179
181
  }
@@ -45,4 +45,6 @@
45
45
  --bloom-width-6xl: 72rem;
46
46
  --bloom-width-7xl: 80rem;
47
47
  --bloom-width-prose: 65ch;
48
+ --bloom-width-1-3rd: 33.333333%;
49
+ --bloom-width-2-3rd: 66.666667%;
48
50
  }
@@ -0,0 +1,43 @@
1
+ import { Canvas, Story, ArgsTable } from "@storybook/addon-docs"
2
+ import { ListingCard } from "./ListingCard"
3
+
4
+ # ListingCard
5
+
6
+ The listing card component renders an image with optional status bars below it, and a content section associated with the image which can include titles, a table, and custom content.
7
+
8
+ <Canvas>
9
+ <Story id="page-components-listing-card--with-tags-and-headers" />
10
+ </Canvas>
11
+
12
+ <br />
13
+ <br />
14
+
15
+ ## Variants
16
+
17
+ Many of the display variations of the card are enabled by the interior content props you pass, and you can survey the various stories available to see some common arrangements. In addition:
18
+
19
+ ### Stacked Tables
20
+
21
+ By setting `stackedTable` to true, the interior table component switches from `StandardTable` to `StackedTable` for a different UI presentation.
22
+
23
+ <Canvas>
24
+ <Story id="page-components-listing-card--with-stacked-table" />
25
+ </Canvas>
26
+
27
+ ## Component Properties
28
+
29
+ <ArgsTable of={ListingCard} />
30
+
31
+ **Note:** for accessbility reasons, if you have a link that should apply to the card as a whole, pass an `href` prop to the `contentHeader` key of `contentProps`. (If you previously passed `href` to `imageCardProps`, you should remove that.) You'll also want to pass `ariaHidden: true` as a prop for the footer button.
32
+
33
+ ## Theming Variables
34
+
35
+ You can apply CSS variables to the `.listings-row` selector to customize the appearance of the component.
36
+
37
+ | Name | Type | Description | Default |
38
+ | -------------------------- | ------- | -------------------------------------------------------------------------------------------------------------- | ------------------- |
39
+ | `--tags-flex-order` | Integer | Where content header tags are located relative to the heading text. Set to `2` to move tags below the headings | `0` |
40
+ | `--inter-row-gap` | Size | The margin between each card | `--bloom-s12` |
41
+ | `--max-width` | Size | The maximum width of the card on smaller screens | `--bloom-width-3xl` |
42
+ | `--max-width-large-screen` | Size | The maximum width of the card on larger screens | `--bloom-width-5xl` |
43
+ | `--cell-padding` | Size | The padding within both the image side and the content side | `--bloom-s3` |
@@ -1,64 +1,87 @@
1
1
  .listings-row {
2
- @apply flex;
3
- @apply flex-row;
4
- @apply flex-wrap;
5
- @apply max-w-5xl;
6
- @apply m-auto;
7
- @apply mb-12;
8
- max-width: 48rem;
2
+ --tags-flex-order: 0;
3
+ --inter-row-gap: var(--bloom-s12);
4
+ --max-width: var(--bloom-width-3xl);
5
+ --max-width-large-screen: var(--bloom-width-5xl);
6
+ --cell-padding: var(--bloom-s3);
9
7
 
10
- &:first-of-type {
11
- @apply mt-12;
12
- }
8
+ display: flex;
9
+ flex-direction: row;
10
+ flex-wrap: wrap;
11
+ max-width: var(--max-width);
12
+ margin: var(--inter-row-gap) auto;
13
+ position: relative;
13
14
 
14
- @screen lg {
15
- @apply max-w-5xl;
15
+ @media (min-width: $screen-lg) {
16
+ --max-width: var(--max-width-large-screen);
16
17
  }
17
18
  }
18
19
 
19
- .listings-row_figure {
20
- @apply w-full;
21
- @apply p-3;
22
- @apply pb-0;
20
+ .listings-row_figure,
21
+ .listings-row_content {
22
+ width: 100%;
23
+ padding: var(--cell-padding);
24
+ padding-bottom: 0px;
23
25
 
24
- @screen lg {
25
- @apply w-6/12;
26
+ @media (min-width: $screen-lg) {
27
+ width: 50%;
26
28
  }
27
29
  }
28
30
 
29
31
  .listings-row_content {
30
- @apply w-full;
31
- @apply p-3;
32
+ .listings-row_headers {
33
+ display: flex;
34
+ flex-direction: column;
35
+ align-items: center;
36
+ text-align: center;
32
37
 
33
- @screen lg {
34
- @apply w-6/12;
35
- }
38
+ @media (min-width: $screen-md) {
39
+ align-items: flex-start;
40
+ text-align: left;
41
+ }
36
42
 
37
- .listings-row_headers {
38
- @apply flex;
39
- @apply flex-col;
40
- @apply items-center;
41
- @apply text-center;
42
- @screen md {
43
- @apply items-start;
44
- @apply text-left;
43
+ .listings-row_tags {
44
+ order: var(--tags-flex-order);
45
+ display: inline-flex;
46
+ width: 100%;
47
+ flex-wrap: wrap;
48
+ justify-content: flex-start;
49
+
50
+ .tag {
51
+ margin-bottom: var(--bloom-s2);
52
+ margin-inline-end: var(--bloom-s2);
53
+
54
+ &:last-of-type {
55
+ margin-inline-end: 0;
56
+ }
57
+
58
+ .ui-icon {
59
+ margin-inline-end: var(--bloom-s2);
60
+ }
61
+ }
45
62
  }
46
63
  }
64
+
65
+ .is-card-link::after {
66
+ content: "";
67
+ position: absolute;
68
+ left: 0;
69
+ top: 0;
70
+ right: 0;
71
+ bottom: 0;
72
+ }
47
73
  }
48
74
 
49
75
  .listings-row_table {
50
- @apply mb-4;
76
+ margin-block-end: var(--bloom-s4);
51
77
  }
52
78
 
53
79
  .listings-row_footer {
54
- @apply flex;
55
- @apply justify-end;
56
- @apply w-full;
80
+ display: flex;
81
+ justify-content: flex-end;
82
+ width: 100%;
83
+
57
84
  a:not(:first-child) {
58
- @apply ml-1;
85
+ margin-inline-start: var(--bloom-s1);
59
86
  }
60
87
  }
61
-
62
- .listings-row_table {
63
- @apply mb-4;
64
- }
@@ -1,4 +1,4 @@
1
- import * as React from "react"
1
+ import React, { useContext } from "react"
2
2
  import { ImageCard, ImageCardProps, ImageTag } from "../../blocks/ImageCard"
3
3
  import { LinkButton } from "../../actions/LinkButton"
4
4
  import { StackedTable, StackedTableProps } from "../../tables/StackedTable"
@@ -8,17 +8,20 @@ import { Tag } from "../../text/Tag"
8
8
  import { AppearanceStyleType } from "../../global/AppearanceTypes"
9
9
  import { Icon, IconFillColors } from "../../icons/Icon"
10
10
  import "./ListingCard.scss"
11
+ import { NavigationContext } from "../../config/NavigationContext"
11
12
 
12
13
  interface ListingCardTableProps extends StandardTableProps, StackedTableProps {}
13
14
 
14
15
  export interface CardHeader {
16
+ content: string | React.ReactNode
17
+ href?: string
15
18
  customClass?: string
16
- text: string
17
19
  }
18
20
 
19
21
  export interface FooterButton {
20
22
  href: string
21
23
  text: string
24
+ ariaHidden?: boolean
22
25
  }
23
26
 
24
27
  export interface ListingCardContentProps {
@@ -28,14 +31,23 @@ export interface ListingCardContentProps {
28
31
  tableSubheader?: CardHeader
29
32
  }
30
33
  export interface ListingCardProps {
34
+ /** A list of tags to be rendered below the content header, a Tag component is rendered for each */
31
35
  cardTags?: ImageTag[]
36
+ /** Custom content rendered in the content section above the table */
32
37
  children?: React.ReactElement
38
+ /** An object containing fields that render optional headers above the content section's table */
33
39
  contentProps?: ListingCardContentProps
40
+ /** A list of buttons to render in the footer of the content section */
34
41
  footerButtons?: FooterButton[]
42
+ /** A class name applied to the footer container of the content section */
35
43
  footerContainerClass?: string
44
+ /** Custom content rendered below the content table */
36
45
  footerContent?: React.ReactNode
46
+ /** Prop interface for the ImageCard component */
37
47
  imageCardProps: ImageCardProps
48
+ /** Toggles on the StackedTable component in place of the default StandardTable component - they are functionally equivalent with differing UIs */
38
49
  stackedTable?: boolean
50
+ /** Prop interface for the StandardTable and StackedTable components */
39
51
  tableProps?: ListingCardTableProps
40
52
  }
41
53
 
@@ -44,17 +56,6 @@ export interface ListingCardProps {
44
56
  *
45
57
  * A component that renders an image with optional status bars below it,
46
58
  * and a content section associated with the image which can include titles, a table, and custom content
47
- *
48
- * @prop cardTags -A list of tags to be rendered below the content header, a Tag component is rendered for each
49
- * @prop children - Custom content rendered in the content section above the table
50
- * @prop footerButtons - A list of buttons to render in the footer of the content section
51
- * @prop footerContent - Custom content rendered below the content table
52
- * @prop footerContainerClass - A class name applied to the footer container of the content section
53
- * @prop imageCardProps - Prop interface for the ImageCard component
54
- * @prop stackedTable - Toggles on the StackedTable component in place of the default StandardTable component - they are functionally equivalent with differing UIs
55
- * @prop contentProps - An object containing fields that render optional headers above the content section's table
56
- * @prop tableProps - Prop interface for the StandardTable and StackedTable components
57
- *
58
59
  */
59
60
  const ListingCard = (props: ListingCardProps) => {
60
61
  const {
@@ -68,6 +69,7 @@ const ListingCard = (props: ListingCardProps) => {
68
69
  contentProps,
69
70
  tableProps,
70
71
  } = props
72
+ const { LinkComponent } = useContext(NavigationContext)
71
73
 
72
74
  const getHeader = (
73
75
  header: CardHeader | undefined,
@@ -75,10 +77,16 @@ const ListingCard = (props: ListingCardProps) => {
75
77
  style?: HeaderType,
76
78
  customClass?: string
77
79
  ) => {
78
- if (header && header.text) {
80
+ if (header && header.content) {
79
81
  return (
80
82
  <Heading priority={priority} style={style} className={customClass}>
81
- {header.text}
83
+ {header.href ? (
84
+ <LinkComponent className="is-card-link" href={header.href}>
85
+ {header.content}
86
+ </LinkComponent>
87
+ ) : (
88
+ header.content
89
+ )}
82
90
  </Heading>
83
91
  )
84
92
  } else {
@@ -88,20 +96,19 @@ const ListingCard = (props: ListingCardProps) => {
88
96
 
89
97
  const getContentHeader = () => {
90
98
  return (
91
- <>
99
+ <div className="listings-row_headers">
92
100
  {getHeader(contentProps?.contentHeader, 2, "cardHeader", "order-1")}
93
101
  {getHeader(contentProps?.contentSubheader, 3, "cardSubheader", "order-2")}
94
102
  {cardTags && cardTags?.length > 0 && (
95
- <div className={"inline-flex flex-wrap justify-start w-full"}>
103
+ <div className="listings-row_tags">
96
104
  {cardTags?.map((cardTag, index) => {
97
105
  return (
98
- <Tag styleType={AppearanceStyleType.warning} className={"mr-2 mb-2"} key={index}>
106
+ <Tag styleType={cardTag.styleType || AppearanceStyleType.warning} key={index}>
99
107
  {cardTag.iconType && (
100
108
  <Icon
101
109
  size={"medium"}
102
110
  symbol={cardTag.iconType}
103
111
  fill={cardTag.iconColor ?? IconFillColors.primary}
104
- className={"mr-2"}
105
112
  />
106
113
  )}
107
114
  {cardTag.text}
@@ -110,7 +117,7 @@ const ListingCard = (props: ListingCardProps) => {
110
117
  })}
111
118
  </div>
112
119
  )}
113
- </>
120
+ </div>
114
121
  )
115
122
  }
116
123
 
@@ -118,8 +125,8 @@ const ListingCard = (props: ListingCardProps) => {
118
125
  return (
119
126
  <>
120
127
  <div className="listings-row_table">
121
- {(contentProps?.tableHeader?.text || contentProps?.tableSubheader?.text) &&
122
- (contentProps.contentHeader?.text || contentProps?.contentSubheader?.text) && (
128
+ {(contentProps?.tableHeader?.content || contentProps?.tableSubheader?.content) &&
129
+ (contentProps.contentHeader?.content || contentProps?.contentSubheader?.content) && (
123
130
  <hr className={"mb-2"} />
124
131
  )}
125
132
  <div className={"listings-row_headers"}>
@@ -143,7 +150,11 @@ const ListingCard = (props: ListingCardProps) => {
143
150
  <div className={footerContainerClass ?? "listings-row_footer"}>
144
151
  {footerButtons?.map((footerButton, index) => {
145
152
  return (
146
- <LinkButton href={footerButton.href} key={index}>
153
+ <LinkButton
154
+ href={footerButton.href}
155
+ ariaHidden={footerButton.ariaHidden}
156
+ key={index}
157
+ >
147
158
  {footerButton.text}
148
159
  </LinkButton>
149
160
  )
@@ -161,7 +172,7 @@ const ListingCard = (props: ListingCardProps) => {
161
172
  <ImageCard {...imageCardProps} />
162
173
  </div>
163
174
  <div className="listings-row_content">
164
- <div className={"listings-row_headers"}>{getContentHeader()}</div>
175
+ {getContentHeader()}
165
176
  {getContent()}
166
177
  </div>
167
178
  </article>
@@ -0,0 +1,64 @@
1
+ import { Canvas, Story, ArgsTable } from "@storybook/addon-docs"
2
+ import { Tag } from "./Tag"
3
+
4
+ # Tag
5
+
6
+ The tag component offers a simple way to present a content label or status indicator.
7
+
8
+ <Canvas>
9
+ <Story id="text-tag--pill-colors" />
10
+ </Canvas>
11
+
12
+ <br />
13
+ <br />
14
+
15
+ ## Variants
16
+
17
+ There are several props which accept enums to adjust style type and size. For example, to choose the "primary" style and a "small" size, you would pass the `AppearanceStyleType.primary` enum to `styleType` prop and `AppearanceSizeType.small` enum to `size` prop.
18
+
19
+ ### Normal Shape
20
+
21
+ (Default, no prop required.)
22
+
23
+ <Canvas>
24
+ <Story id="text-tag--standard" />
25
+ </Canvas>
26
+
27
+ ### Pill
28
+
29
+ Set the `pillStyle` property to `true`.
30
+
31
+ <Canvas>
32
+ <Story id="text-tag--pill" />
33
+ </Canvas>
34
+
35
+ ### Fill Container
36
+
37
+ Set the `fillContainer` property to `true` for a block tag which spans the entire width of its container.
38
+
39
+ <Canvas>
40
+ <Story id="text-tag--pill-listings" />
41
+ </Canvas>
42
+
43
+ ## Component Properties
44
+
45
+ <ArgsTable of={Tag} />
46
+
47
+ ## Theming Variables
48
+
49
+ You can apply CSS variables to the `.tag` selector to customize the appearance of the component.
50
+
51
+ | Name | Type | Description | Default |
52
+ | ------------------------ | ----------- | ----------------------------------------------- | --------------------------------------------------- |
53
+ | `--normal-padding` | Size | Padding of the normal (no variant) tag | `--bloom-s3` (top/bottom) `--bloom-s5` (left/right) |
54
+ | `--normal-rounded` | Size | The border radius of the normal tag | `--bloom-rounded-md` |
55
+ | `--normal-font-size` | Size | The font size of the normal tag | `--bloom-font-size-tiny` |
56
+ | `--normal-font-weight` | Font Weight | The font weight of the normal tag | `normal` |
57
+ | `--pill-padding` | Size | Padding of the pill variant tag | `--bloom-s2` (top/bottom) `--bloom-s4` (left/right) |
58
+ | `--pill-rounded` | Size | The border radius of the pill tag | `--bloom-rounded-full` |
59
+ | `--pill-font-size` | Size | The font size of the pill tag | `--bloom-font-size-tiny` |
60
+ | `--pill-font-weight` | Font Weight | The font weight of the pill tag | `600` |
61
+ | `--pill-text-transform` | Case | Text case of of the pill tag | `uppercase` |
62
+ | `--pill-letter-spacing` | Size | The average gap between letters of the pill tag | `--bloom-letter-spacing-ultrawide` |
63
+ | `--small-pill-padding` | Size | Padding of the small-size pill tag | `--bloom-s1` (top/bottom) `--bloom-s3` (left/right) | |
64
+ | `--small-pill-font-size` | Size | The font size of the small-size pill tag | `--bloom-font-size-2xs` |
package/src/text/Tag.scss CHANGED
@@ -1,94 +1,132 @@
1
1
  .tag {
2
- @apply py-3;
3
- @apply px-5;
4
- @apply text-white;
5
- @apply text-tiny;
6
- @apply bg-primary;
7
- @apply rounded-md;
8
- @apply text-center;
2
+ /* Component Variables */
3
+ --normal-padding: var(--bloom-s3) var(--bloom-s5);
4
+ --normal-rounded: var(--bloom-rounded-md);
5
+ --normal-font-size: var(--bloom-font-size-tiny);
6
+ --normal-font-weight: normal;
7
+
8
+ --pill-padding: var(--bloom-s2) var(--bloom-s4);
9
+ --pill-rounded: var(--bloom-rounded-full);
10
+ --pill-font-size: var(--bloom-font-size-tiny);
11
+ --pill-font-weight: 600;
12
+ --pill-text-transform: uppercase;
13
+ --pill-letter-spacing: var(--bloom-letter-spacing-ultrawide);
14
+
15
+ --small-pill-padding: var(--bloom-s1) var(--bloom-s3);
16
+ --small-pill-font-size: var(--bloom-font-size-2xs);
17
+
18
+ /* Default Styles */
19
+ padding: var(--normal-padding);
20
+ border-radius: var(--normal-rounded);
21
+ font-size: var(--normal-font-size);
22
+ font-weight: var(--normal-font-weight);
23
+ color: var(--primary-appearance-label-color, var(--bloom-color-white));
24
+ font-family: var(--bloom-font-sans);
25
+ background-color: var(--primary-appearance-border-color, var(--bloom-color-primary));
26
+ text-align: center;
9
27
 
10
28
  &.is-pill {
11
- @apply px-4;
12
- @apply py-2;
13
- @apply bg-primary-light;
14
- @apply text-primary-dark;
15
- @apply rounded-full;
16
- @apply font-semibold;
17
- @apply font-alt-sans;
18
- @apply uppercase;
19
- @apply tracking-ultrawide;
20
- @apply inline;
21
- @apply text-tiny;
22
- @apply leading-4;
29
+ padding: var(--pill-padding);
30
+ background-color: var(--bloom-color-primary-light);
31
+ color: var(--bloom-color-primary-dark);
32
+ border-radius: var(--pill-rounded);
33
+ font-weight: var(--pill-font-weight);
34
+ font-family: var(--bloom-font-alt-sans);
35
+ text-transform: var(--pill-text-transform);
36
+ letter-spacing: var(--pill-letter-spacing);
37
+ display: inline;
38
+ font-size: var(--pill-font-size);
39
+ line-height: var(--bloom-line-height-4);
23
40
 
24
41
  &.is-small {
25
- @apply text-2xs;
26
- @apply py-1;
27
- @apply px-3;
28
- @apply leading-3;
42
+ font-size: var(--small-pill-font-size);
43
+ padding: var(--small-pill-padding);
44
+ line-height: var(--bloom-line-height-3);
29
45
  }
30
46
  }
31
47
 
32
48
  &.fill-container {
33
- @apply w-full;
34
- @apply inline-block;
49
+ width: 100%;
50
+ display: inline-block;
35
51
  }
36
52
 
37
53
  &.is-warning {
38
- @apply bg-accent-warm-dark;
54
+ color: var(--warning-appearance-label-color, var(--bloom-color-white));
55
+ background-color: var(
56
+ --warning-appearance-background-color,
57
+ var(--bloom-color-accent-warm-dark)
58
+ );
39
59
  }
40
60
 
41
61
  &.is-secondary {
42
- @apply text-white;
43
- @apply bg-secondary;
62
+ color: var(--secondary-appearance-label-color, var(--bloom-color-white));
63
+ background-color: var(--secondary-appearance-background-color, var(--bloom-color-secondary));
44
64
  }
45
65
 
46
66
  &.is-success {
47
67
  &:not(.is-light-mode) {
48
- @apply text-white;
49
- @apply bg-success;
68
+ color: var(--success-appearance-label-color, var(--bloom-color-white));
69
+ background-color: var(--success-appearance-background-color, var(--bloom-color-success));
50
70
  }
71
+
51
72
  &.is-light-mode {
52
- @apply text-gray-900;
53
- @apply bg-success-light;
73
+ color: var(--success-light-appearance-label-color, var(--bloom-color-gray-900));
74
+ background-color: var(
75
+ --success-light-appearance-background-color,
76
+ var(--bloom-color-success-light)
77
+ );
54
78
  }
55
79
  }
56
80
 
57
81
  &.is-accent-cool {
58
82
  &:not(.is-light-mode) {
59
- @apply text-white;
60
- @apply bg-accent-cool-dark;
83
+ color: var(--accent-cool-appearance-label-color, var(--bloom-color-white));
84
+ background-color: var(
85
+ --accent-cool-appearance-background-color,
86
+ var(--bloom-color-accent-cool-dark)
87
+ );
61
88
  }
89
+
62
90
  &.is-light-mode {
63
- @apply text-gray-900;
64
- @apply bg-accent-cool;
91
+ color: var(--accent-cool-light-appearance-label-color, var(--bloom-color-gray-900));
92
+ background-color: var(
93
+ --accent-cool-light-appearance-background-color,
94
+ var(--bloom-color-accent-cool)
95
+ );
65
96
  }
66
97
  }
67
98
 
68
99
  &.is-accent-warm {
69
100
  &:not(.is-light-mode) {
70
- @apply text-white;
71
- @apply bg-accent-warm-dark;
101
+ color: var(--accent-warm-appearance-label-color, var(--bloom-color-white));
102
+ background-color: var(
103
+ --accent-warm-appearance-background-color,
104
+ var(--bloom-color-accent-warm-dark)
105
+ );
72
106
  }
107
+
73
108
  &.is-light-mode {
74
- @apply text-gray-900;
75
- @apply bg-accent-warm;
109
+ color: var(--accent-warm-light-appearance-label-color, var(--bloom-color-gray-900));
110
+ background-color: var(
111
+ --accent-warm-light-appearance-background-color,
112
+ var(--bloom-color-accent-warm)
113
+ );
76
114
  }
77
115
  }
78
116
 
79
117
  &.is-closed {
80
- @apply text-white;
81
- @apply bg-gray-750;
118
+ color: var(--closed-appearance-label-color, var(--bloom-color-white));
119
+ background-color: var(--closed-appearance-background-color, var(--bloom-color-gray-750));
82
120
  }
83
121
 
84
122
  &.is-info {
85
- @apply text-gray-800;
86
- @apply bg-warn-light;
123
+ color: var(--info-appearance-label-color, var(--bloom-color-gray-800));
124
+ background-color: var(--info-appearance-background-color, var(--bloom-color-warn-light));
87
125
  }
88
126
 
89
127
  &.is-small {
90
- @apply text-sm;
91
- @apply py-2;
92
- @apply px-4;
128
+ font-size: var(--bloom-font-size-sm);
129
+ padding-block: var(--bloom-s2);
130
+ padding-inline: var(--bloom-s4);
93
131
  }
94
132
  }