@bloom-housing/ui-components 5.0.1-alpha.16 → 5.0.1-alpha.19

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,36 @@
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.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)
7
+
8
+ **Note:** Version bump only for package @bloom-housing/ui-components
9
+
10
+
11
+
12
+
13
+
14
+ ## [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)
15
+
16
+
17
+ ### Features
18
+
19
+ * visuals for add preference, preference option drawers ([#2877](https://github.com/bloom-housing/bloom/issues/2877)) ([8611034](https://github.com/bloom-housing/bloom/commit/8611034845b45ce4d4e4eb44e790ac2adec0ba94))
20
+
21
+
22
+
23
+
24
+
25
+ ## [5.0.1-alpha.17](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@5.0.1-alpha.16...@bloom-housing/ui-components@5.0.1-alpha.17) (2022-07-15)
26
+
27
+
28
+ ### Features
29
+
30
+ * creating users as admin ([#2856](https://github.com/bloom-housing/bloom/issues/2856)) ([dd946d1](https://github.com/bloom-housing/bloom/commit/dd946d1777b4678e89832da527768180f474d129))
31
+
32
+
33
+
34
+
35
+
6
36
  ## [5.0.1-alpha.16](https://github.com/bloom-housing/bloom/compare/@bloom-housing/ui-components@5.0.1-alpha.15...@bloom-housing/ui-components@5.0.1-alpha.16) (2022-07-13)
7
37
 
8
38
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bloom-housing/ui-components",
3
- "version": "5.0.1-alpha.16",
3
+ "version": "5.0.1-alpha.19",
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": "ec0d2acb5338c69e6e43b998d04176aab5731cf1"
111
+ "gitHead": "416b300b573c622ffa776199bf9bd05ea7341d5f"
112
112
  }
@@ -74,7 +74,7 @@ const Field = (props: FieldProps) => {
74
74
  if (props.caps) labelClasses.push("field-label--caps")
75
75
  if (props.primary) labelClasses.push("text-primary")
76
76
  if (props.readerOnly) labelClasses.push("sr-only")
77
- if (props.type === "checkbox" || props.type === "radio") {
77
+ if (props.type === "radio") {
78
78
  labelClasses.push("font-semibold")
79
79
  }
80
80
 
@@ -23,6 +23,7 @@ export interface TextareaProps {
23
23
  wrap?: WrapOptions
24
24
  readerOnly?: boolean
25
25
  inputProps?: Record<string, unknown>
26
+ dataTestId?: string
26
27
  }
27
28
 
28
29
  export const Textarea = (props: TextareaProps) => {
@@ -56,6 +57,7 @@ export const Textarea = (props: TextareaProps) => {
56
57
  wrap={props.wrap ?? "soft"}
57
58
  title={props.label}
58
59
  {...inputProps}
60
+ data-test-id={props.dataTestId}
59
61
  />
60
62
  {props.note && <p className="field-note font-normal mb-2">{props.note}</p>}
61
63
  {props.errorMessage && <span className="textarea-error-message">{props.errorMessage}</span>}
@@ -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
  }
@@ -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
  })}
@@ -7,6 +7,10 @@ type SiteAlertProps = {
7
7
  dismissable?: boolean
8
8
  type?: AlertTypes
9
9
  className?: string
10
+ alertMessage?: {
11
+ type: AlertTypes
12
+ message: string
13
+ }
10
14
  }
11
15
 
12
16
  export const setSiteAlertMessage = (message: string, type: AlertTypes) => {
@@ -25,9 +29,17 @@ export const SiteAlert = ({
25
29
  dismissable = true,
26
30
  type = "alert",
27
31
  className,
32
+ alertMessage,
28
33
  }: SiteAlertProps) => {
29
34
  const [open, setOpen] = useState(false)
30
35
  const [message, setMessage] = useState("")
36
+ /**
37
+ * We use 2 useEffects here 1 for if we are consuming what is stored in sessionStorage
38
+ * and another for if the message is passed in as a prop
39
+
40
+ * this gives the ability for the SiteAlert to "survive" a re-render, or if no re-render will occur
41
+ * for the SiteAlert to simply render itself
42
+ **/
31
43
 
32
44
  useEffect(() => {
33
45
  let timeoutRef: number
@@ -46,11 +58,23 @@ export const SiteAlert = ({
46
58
  return () => clearTimeout(timeoutRef)
47
59
  }, [timeout, type])
48
60
 
61
+ useEffect(() => {
62
+ let timeoutRef: number
63
+ if (alertMessage?.message) {
64
+ setMessage(alertMessage?.message)
65
+ setOpen(true)
66
+ if (timeout) {
67
+ timeoutRef = (setTimeout(() => setOpen(false), timeout) as unknown) as number
68
+ }
69
+ }
70
+ return () => clearTimeout(timeoutRef)
71
+ }, [alertMessage, timeout])
72
+
49
73
  return open ? (
50
74
  <AlertBox
51
75
  onClose={dismissable ? () => setOpen(false) : undefined}
52
76
  className={className}
53
- type={type}
77
+ type={alertMessage?.type ?? type}
54
78
  >
55
79
  {message}
56
80
  </AlertBox>
@@ -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: {