uikit-react-public 0.26.0 → 0.26.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.
@@ -23,7 +23,13 @@ const HeaderItem = ({
23
23
  min-height: 40px;
24
24
 
25
25
  &:not(:first-of-type) {
26
- margin-left: ${theme.margin.m8};
26
+ margin-left: ${theme.margin.m16};
27
+ }
28
+
29
+ @media (min-width: ${theme.breakpoints.desktop}px) {
30
+ &:not(:first-of-type) {
31
+ margin-left: 0;
32
+ }
27
33
  }
28
34
  `;
29
35
 
@@ -39,4 +39,34 @@ describe('Header', () => {
39
39
  expect(link).toBeInTheDocument();
40
40
  expect(link.getAttribute('href')).toBe('/');
41
41
  });
42
+
43
+ test('spaces subsequent header items on smaller screens and resets spacing on desktop', () => {
44
+ render(
45
+ <ThemeContextProvider>
46
+ <Header title='LIDS'>
47
+ <Header.MenuContainer>
48
+ <Header.Item testId='first-header-item'>First</Header.Item>
49
+ <Header.Item testId='second-header-item'>Second</Header.Item>
50
+ </Header.MenuContainer>
51
+ </Header>
52
+ </ThemeContextProvider>
53
+ );
54
+
55
+ const firstItem = screen.getByTestId('first-header-item');
56
+ const secondItem = screen.getByTestId('second-header-item');
57
+ const generatedClass = [...secondItem.classList].find((className) =>
58
+ className.startsWith('css-')
59
+ );
60
+ const styles = document.head.textContent;
61
+
62
+ expect(firstItem).toHaveClass('ucl-uikit-header__item');
63
+ expect(secondItem).toHaveClass('ucl-uikit-header__item');
64
+ expect(generatedClass).toBeDefined();
65
+ expect(styles).toContain(
66
+ `.${generatedClass}:not(:first-of-type){margin-left:16px;}`
67
+ );
68
+ expect(styles).toContain(
69
+ `@media (min-width: 1056px){.${generatedClass}:not(:first-of-type){margin-left:0;}}`
70
+ );
71
+ });
42
72
  });
@@ -60,8 +60,33 @@ const MenuAccordion = ({
60
60
  `;
61
61
 
62
62
  const bodyStyle = css`
63
+ display: grid;
64
+ grid-template-rows: 0fr;
63
65
  width: 100%;
66
+ margin-top: 0;
67
+ overflow: hidden;
68
+ opacity: 0;
69
+ pointer-events: none;
70
+ transition:
71
+ grid-template-rows 300ms ease-in,
72
+ margin-top 300ms ease-in,
73
+ opacity 300ms ease-in;
74
+ `;
75
+
76
+ const bodyExpandedStyle = css`
77
+ grid-template-rows: 1fr;
64
78
  margin-top: ${theme.margin.m8};
79
+ opacity: 1;
80
+ pointer-events: auto;
81
+ transition:
82
+ grid-template-rows 300ms ease-out,
83
+ margin-top 300ms ease-out,
84
+ opacity 300ms ease-out;
85
+ `;
86
+
87
+ const bodyInnerStyle = css`
88
+ min-height: 0;
89
+ overflow: hidden;
65
90
  `;
66
91
 
67
92
  const handleClick = (event: MouseEvent<HTMLDivElement>) => {
@@ -74,7 +99,7 @@ const MenuAccordion = ({
74
99
  <MenuBaseItem
75
100
  className={style}
76
101
  iconPosition='left'
77
- underlineOnHover={false}
102
+ hoverMode='background'
78
103
  onClick={handleClick}
79
104
  endAdornment={<MenuAccordionChevron expanded={expanded} />}
80
105
  aria-expanded={expanded}
@@ -84,7 +109,13 @@ const MenuAccordion = ({
84
109
  <MenuItemText className={textStyle}>{label}</MenuItemText>
85
110
  </span>
86
111
  </MenuBaseItem>
87
- {expanded && <div className={bodyStyle}>{children}</div>}
112
+ <div
113
+ className={cx(bodyStyle, expanded && bodyExpandedStyle)}
114
+ aria-hidden={!expanded}
115
+ inert={!expanded}
116
+ >
117
+ <div className={bodyInnerStyle}>{children}</div>
118
+ </div>
88
119
  </>
89
120
  );
90
121
  };
@@ -1,3 +1,4 @@
1
+ import { css, cx } from '@emotion/css';
1
2
  import Icon from '../../Icon';
2
3
 
3
4
  export interface MenuAccordionChevronProps {
@@ -8,23 +9,24 @@ export interface MenuAccordionChevronProps {
8
9
  const MenuAccordionChevron = ({
9
10
  expanded,
10
11
  className,
11
- }: MenuAccordionChevronProps) =>
12
- expanded ? (
13
- <Icon.ChevronUp
14
- className={className}
15
- size={24}
16
- aria-hidden='true'
17
- focusable='false'
18
- testId='ucl-uikit-menu__accordion__icon--chevron-up'
19
- />
20
- ) : (
12
+ }: MenuAccordionChevronProps) => {
13
+ const baseStyle = css`
14
+ transition: transform 150ms ease-in-out;
15
+ `;
16
+
17
+ const expandedStyle = css`
18
+ transform: rotate(180deg);
19
+ `;
20
+
21
+ return (
21
22
  <Icon.ChevronDown
22
- className={className}
23
+ className={cx(baseStyle, expanded && expandedStyle, className)}
23
24
  size={24}
24
25
  aria-hidden='true'
25
26
  focusable='false'
26
27
  testId='ucl-uikit-menu__accordion__icon--chevron-down'
27
28
  />
28
29
  );
30
+ };
29
31
 
30
32
  export default MenuAccordionChevron;
@@ -6,7 +6,7 @@ export interface MenuBaseItemProps extends HTMLAttributes<HTMLDivElement> {
6
6
  icon?: ReactNode;
7
7
  iconPosition?: 'left' | 'right';
8
8
  endAdornment?: ReactNode;
9
- underlineOnHover?: boolean;
9
+ hoverMode?: 'background' | 'underline';
10
10
  asChild?: boolean;
11
11
  }
12
12
 
@@ -20,7 +20,7 @@ const MenuBaseItem = ({
20
20
  onKeyDown,
21
21
  role,
22
22
  tabIndex,
23
- underlineOnHover = true,
23
+ hoverMode = 'background',
24
24
  asChild = false,
25
25
  ...props
26
26
  }: MenuBaseItemProps) => {
@@ -63,15 +63,26 @@ const MenuBaseItem = ({
63
63
  &:focus-within {
64
64
  box-shadow: ${theme.boxShadow.focus};
65
65
  }
66
+ `;
66
67
 
67
- ${underlineOnHover &&
68
- `
69
- &:hover .ucl-uikit-menu__item-text {
70
- text-decoration: underline;
71
- }
72
- `}
68
+ const backgroundOnHoverStyle = css`
69
+ &:hover {
70
+ background-color: ${theme.colour.fill.brandSubtleHover};
71
+ }
73
72
  `;
74
- const style = cx(baseStyle, className);
73
+
74
+ const underlineStyleOnHoverStyle = css`
75
+ &:hover .ucl-uikit-menu__item-text {
76
+ text-decoration: underline;
77
+ }
78
+ `;
79
+
80
+ const style = cx(
81
+ baseStyle,
82
+ hoverMode === 'underline' && underlineStyleOnHoverStyle,
83
+ hoverMode === 'background' && backgroundOnHoverStyle,
84
+ className
85
+ );
75
86
 
76
87
  const endAdornmentStyle = css`
77
88
  margin-left: auto;
@@ -49,6 +49,7 @@ const SecondaryMenuItem = ({
49
49
  <MenuBaseItem
50
50
  className={style}
51
51
  asChild={asChild}
52
+ hoverMode='underline'
52
53
  {...props}
53
54
  >
54
55
  <span className={contentStyle}>
@@ -86,7 +86,7 @@ describe('Menu', () => {
86
86
  ).toBeInTheDocument();
87
87
  });
88
88
 
89
- test('accordion toggles to expanded state with up chevron', () => {
89
+ test('accordion toggles to expanded state with rotated down chevron', () => {
90
90
  wrap(
91
91
  <Menu>
92
92
  <Menu.Accordion
@@ -98,11 +98,18 @@ describe('Menu', () => {
98
98
  </Menu>
99
99
  );
100
100
 
101
- expect(screen.queryByText('Library')).not.toBeInTheDocument();
101
+ const accordionContent = screen
102
+ .getByText('Library')
103
+ .closest('[aria-hidden]');
104
+ expect(accordionContent).toHaveAttribute('aria-hidden', 'true');
102
105
  fireEvent.click(screen.getByText('Services'));
106
+ expect(accordionContent).toHaveAttribute('aria-hidden', 'false');
103
107
  expect(
104
- screen.getByTestId('ucl-uikit-menu__accordion__icon--chevron-up')
108
+ screen.getByTestId('ucl-uikit-menu__accordion__icon--chevron-down')
105
109
  ).toBeInTheDocument();
110
+ expect(
111
+ screen.queryByTestId('ucl-uikit-menu__accordion__icon--chevron-up')
112
+ ).not.toBeInTheDocument();
106
113
  expect(screen.getByText('Library')).toBeInTheDocument();
107
114
  });
108
115
 
@@ -220,10 +227,10 @@ describe('Menu', () => {
220
227
  expect(item?.firstChild).toHaveAttribute('data-testid', 'left-icon');
221
228
  });
222
229
 
223
- test('can disable hover underline', () => {
230
+ test('primary items use background hover instead of underline hover', () => {
224
231
  wrap(
225
232
  <Menu>
226
- <Menu.PrimaryItem underlineOnHover={false}>Home</Menu.PrimaryItem>
233
+ <Menu.PrimaryItem>Home</Menu.PrimaryItem>
227
234
  </Menu>
228
235
  );
229
236
 
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "uikit-react-public",
3
3
  "private": false,
4
4
  "license": "UNLICENSED",
5
- "version": "0.26.0",
5
+ "version": "0.26.1",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",