@bloom-housing/ui-components 5.0.1-alpha.18 → 5.0.1-alpha.20

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,25 @@
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.20](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@5.0.1-alpha.19...@bloom-housing/ui-components@5.0.1-alpha.20) (2022-07-20)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * render html address properly ([#2897](https://github.com/bloom-housing/bloom/issues/2897)) ([87a759a](https://github.com/bloom-housing/bloom/commit/87a759a68c35d1c47ec4fbbec6c947a63993d27c))
12
+
13
+
14
+
15
+
16
+
17
+ ## [5.0.1-alpha.19](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@5.0.1-alpha.18...@bloom-housing/ui-components@5.0.1-alpha.19) (2022-07-19)
18
+
19
+ **Note:** Version bump only for package @bloom-housing/ui-components
20
+
21
+
22
+
23
+
24
+
6
25
  ## [5.0.1-alpha.18](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@5.0.1-alpha.17...@bloom-housing/ui-components@5.0.1-alpha.18) (2022-07-19)
7
26
 
8
27
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloom-housing/ui-components",
3
- "version": "5.0.1-alpha.18",
3
+ "version": "5.0.1-alpha.20",
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",
@@ -40,6 +40,7 @@
40
40
  "@storybook/theming": "^6.3.8",
41
41
  "@testing-library/jest-dom": "^5.11.9",
42
42
  "@testing-library/react": "^11.2.5",
43
+ "@types/dompurify": "^2.3.3",
43
44
  "@types/jest": "^26.0.14",
44
45
  "@types/jwt-decode": "^2.2.1",
45
46
  "@types/react-map-gl": "^5.2.10",
@@ -89,6 +90,7 @@
89
90
  "axios": "0.21.2",
90
91
  "body-scroll-lock": "^3.1.5",
91
92
  "dayjs": "^1.10.7",
93
+ "dompurify": "^2.3.10",
92
94
  "jwt-decode": "^2.2.0",
93
95
  "markdown-to-jsx": "^6.11.4",
94
96
  "nanoid": "^3.1.12",
@@ -108,5 +110,5 @@
108
110
  "ts-jest": "^26.4.1",
109
111
  "typesafe-actions": "^5.1.0"
110
112
  },
111
- "gitHead": "4e40ad752bff76d99704102756ec9074ac763089"
113
+ "gitHead": "e9eb58b6a83245200b200af3d17fe6987096c256"
112
114
  }
@@ -133,3 +133,25 @@ $shadow-left-slight: -3px 0px 3px -1px rgba(0, 0, 0, 0.1);
133
133
  @apply block;
134
134
  }
135
135
  }
136
+
137
+ .sidebar-detail-layout {
138
+ display: flex;
139
+ flex-direction: column;
140
+ gap: var(--bloom-s6);
141
+ margin-inline: auto;
142
+ max-width: var(--bloom-screen-2xl);
143
+
144
+ @media (min-width: 1000px) {
145
+ flex-direction: row;
146
+ }
147
+
148
+ & > div {
149
+ flex-grow: 1;
150
+ }
151
+
152
+ & > aside {
153
+ @media (min-width: 1000px) {
154
+ width: var(--bloom-s72);
155
+ }
156
+ }
157
+ }
@@ -3,4 +3,5 @@
3
3
  --bloom-screen-md: #{$screen-md};
4
4
  --bloom-screen-lg: #{$screen-lg};
5
5
  --bloom-screen-xl: #{$screen-xl};
6
+ --bloom-screen-2xl: #{$screen-2xl};
6
7
  }
@@ -1,4 +1,5 @@
1
1
  import * as React from "react"
2
+ import DOMPurify from "dompurify"
2
3
 
3
4
  export interface Address {
4
5
  city?: string
@@ -19,18 +20,21 @@ const MultiLineAddress = ({ address }: MultiLineAddressProps) => {
19
20
  if (!address) return null
20
21
 
21
22
  return (
22
- <>
23
- {address.placeName && (
24
- <>
25
- {address.placeName}
26
- <br />
27
- </>
28
- )}
29
- {address.street} {address.street2}
30
- {(address.street || address.street2) && <br />}
31
- {address.city}
32
- {address.city && (address.state || address.zipCode) && ","} {address.state} {address.zipCode}
33
- </>
23
+ <span
24
+ dangerouslySetInnerHTML={{
25
+ __html: DOMPurify.sanitize(
26
+ `
27
+ ${address.placeName ? `${address.placeName} <br />` : ""}
28
+ ${address.street || ""} ${address.street2 || ""}
29
+ ${address.street || address.street2 ? `<br />` : ""}
30
+ ${address.city}
31
+ ${address.city && (address.state || address.zipCode) ? "," : ""} ${address.state} ${` `}
32
+ ${address.zipCode}
33
+ `,
34
+ { USE_PROFILES: { html: true } }
35
+ ),
36
+ }}
37
+ />
34
38
  )
35
39
  }
36
40
 
@@ -0,0 +1,34 @@
1
+ import { Canvas, Story, ArgsTable } from "@storybook/addon-docs"
2
+ import { Swatch } from "../prototypes/Swatch"
3
+ import { SideNav } from "./SideNav"
4
+
5
+ # Side Navigation
6
+
7
+ The side nav component renders a list of navigation links, any of which can optionally have children links for a hierarchical list.
8
+
9
+ <Canvas>
10
+ <Story id="navigation-side-nav--current" />
11
+ </Canvas>
12
+
13
+ <br />
14
+ <br />
15
+
16
+ ## Component Properties
17
+
18
+ <ArgsTable of={SideNav} />
19
+
20
+ ## Theming Variables
21
+
22
+ You can apply CSS variables to the `.side-nav` selector to customize the appearance of the component.
23
+
24
+ | Name | Type | Description | Default |
25
+ | --------------------------- | --------------------------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------- |
26
+ | `--border` | Border | Border of the nav | `solid var(--bloom-border-1) var(--bloom-color-gray-450)` |
27
+ | `--border-radius` | Size | The border radius of the nav | `--bloom-rounded-lg` |
28
+ | `--current-padding-inline` | Size | The space on either side of a link | `--bloom-s6` |
29
+ | `--current-padding-block` | Size | The space above and below a link | `--bloom-s4` |
30
+ | `--link-color` | <Swatch colorVar="--bloom-color-gray-700" /> | Default color of links | `--bloom-color-gray-700` |
31
+ | `--current-selection-color` | <Swatch colorVar="--bloom-color-gray-900" /> | Color of the current link and parent of the current link if applicable | `--bloom-color-gray-900` |
32
+ | `--selection-parent-accent` | <Swatch colorVar="--bloom-color-gray-450" /> | Color of the current link's parent's border accent | `--bloom-color-gray-900` |
33
+ | `--hover-link-color` | <Swatch colorVar="--bloom-color-primary" /> | Link text color when you hover over it or tab to it | `--bloom-color-primary` |
34
+ | `--hover-background-color` | <Swatch colorVar="--bloom-color-primary-lighter" /> | Link background color when you hover over it or tab to it | `--bloom-color-primary-lighter` |
@@ -1,38 +1,72 @@
1
1
  .side-nav {
2
- @apply border;
3
- @apply rounded-lg;
2
+ --border: solid var(--bloom-border-1) var(--bloom-color-gray-450);
3
+ --border-radius: var(--bloom-rounded-lg);
4
+ --current-padding-inline: var(--bloom-s6);
5
+ --current-padding-block: var(--bloom-s4);
6
+ --link-color: var(--bloom-color-gray-700);
7
+ --current-selection-color: var(--bloom-color-gray-900);
8
+ --selection-parent-accent: var(--bloom-color-gray-450);
9
+ --hover-link-color: var(--bloom-color-primary);
10
+ --hover-background-color: var(--bloom-color-primary-lighter);
4
11
 
5
- li {
6
- &:first-of-type {
7
- @apply rounded-t-lg;
8
- }
12
+ border: var(--border);
13
+ border-radius: var(--border-radius);
9
14
 
10
- &:last-of-type {
11
- @apply rounded-b-lg;
15
+ & > ul {
16
+ & > li:first-child > a {
17
+ border-top-right-radius: var(--border-radius);
18
+ border-top-left-radius: var(--border-radius);
12
19
  }
13
20
 
14
- &.is-current {
15
- cursor: pointer;
16
- @apply text-gray-900;
17
- box-shadow: inset 3px 0px 0px 0px $tailwind-primary;
18
- @apply block;
19
- @apply px-4;
20
- @apply py-2;
21
+ & > li:last-child > a {
22
+ border-bottom-right-radius: var(--border-radius);
23
+ border-bottom-left-radius: var(--border-radius);
21
24
  }
22
25
 
23
- &:not(:last-child) {
24
- @apply border-b;
26
+ & > li > ul > li:first-child {
27
+ border-top: var(--border);
25
28
  }
26
29
  }
27
30
 
31
+ li:not(:last-child) {
32
+ border-bottom: var(--border);
33
+ }
34
+
28
35
  a {
29
- @apply text-gray-700;
30
- @apply block;
31
- @apply px-4;
32
- @apply py-2;
33
- &:hover {
34
- @apply bg-primary-lighter;
35
- @apply text-primary;
36
+ display: flex;
37
+ justify-content: space-between;
38
+ color: var(--link-color);
39
+ padding-inline: var(--current-padding-inline);
40
+ padding-block: var(--current-padding-block);
41
+
42
+ &[aria-current] {
43
+ color: var(--current-selection-color);
44
+ }
45
+
46
+ &[aria-current]:not(:focus) {
47
+ box-shadow: inset 3px 0px 0px 0px var(--hover-link-color);
48
+ }
49
+
50
+ &.has-current-child {
51
+ color: var(--current-selection-color);
36
52
  }
53
+
54
+ &.has-current-child:not(:focus) {
55
+ box-shadow: inset 3px 0px 0px 0px var(--selection-parent-accent);
56
+ }
57
+
58
+ &:hover,
59
+ &:focus {
60
+ background-color: var(--hover-background-color);
61
+ color: var(--hover-link-color);
62
+ }
63
+
64
+ span:last-of-type {
65
+ color: var(--link-color);
66
+ }
67
+ }
68
+
69
+ ul ul a {
70
+ padding-inline-start: calc(var(--current-padding-inline) + var(--current-padding-block));
37
71
  }
38
72
  }
@@ -6,29 +6,64 @@ export interface SideNavItemProps {
6
6
  current?: boolean
7
7
  url: string
8
8
  label: string
9
+ count?: number
10
+ childrenItems?: SideNavItemProps[]
9
11
  }
10
12
 
11
13
  export interface SideNavProps {
12
14
  navItems?: SideNavItemProps[]
15
+ className?: string
16
+ }
17
+
18
+ const ItemLabel = ({ item }: { item: SideNavItemProps }) => {
19
+ if (typeof item.count !== "undefined") {
20
+ return (
21
+ <>
22
+ <span>{item.label}</span>
23
+ <span>{item.count}</span>
24
+ </>
25
+ )
26
+ } else {
27
+ return <>{item.label}</>
28
+ }
13
29
  }
14
30
 
15
31
  const SideNav = (props: SideNavProps) => {
16
32
  const { LinkComponent } = React.useContext(NavigationContext)
17
33
 
34
+ const classNames = ["side-nav"]
35
+ if (props.className) classNames.push(props.className)
36
+
18
37
  return (
19
- <nav className="side-nav" aria-label="Secondary navigation">
38
+ <nav className={classNames.join(" ")} aria-label="Secondary navigation">
20
39
  <ul>
21
40
  {props.navItems?.map((navItem: SideNavItemProps, index: number) => {
22
- if (navItem.current) {
23
- return (
24
- <li className="is-current" key={index} aria-current="page">
25
- {navItem.label}
26
- </li>
27
- )
28
- }
41
+ const hasCurrentChild = navItem.childrenItems?.some((item) => item.current)
29
42
  return (
30
43
  <li key={index}>
31
- <LinkComponent href={navItem.url}>{navItem.label}</LinkComponent>
44
+ <LinkComponent
45
+ href={navItem.url}
46
+ className={hasCurrentChild ? "has-current-child" : ""}
47
+ aria-current={navItem.current ? "page" : undefined}
48
+ >
49
+ <ItemLabel item={navItem} />
50
+ </LinkComponent>
51
+ {navItem.childrenItems && (
52
+ <ul>
53
+ {navItem.childrenItems.map((childItem, childIndex) => {
54
+ return (
55
+ <li key={childIndex}>
56
+ <LinkComponent
57
+ href={childItem.url}
58
+ aria-current={childItem.current ? "page" : undefined}
59
+ >
60
+ <ItemLabel item={childItem} />
61
+ </LinkComponent>
62
+ </li>
63
+ )
64
+ })}
65
+ </ul>
66
+ )}
32
67
  </li>
33
68
  )
34
69
  })}
@@ -9,6 +9,7 @@ module.exports = {
9
9
  md: "768px",
10
10
  lg: "1200px",
11
11
  xl: "1280px",
12
+ "2xl": "1440px",
12
13
  print: { raw: "print" },
13
14
  },
14
15
  fontSize: {