uikit-react-public 0.26.1 → 0.27.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 (30) hide show
  1. package/dist/components/BaseCheckbox/BaseCheckbox.d.ts +26 -0
  2. package/dist/components/BaseCheckbox/BaseCheckbox.stories.d.ts +29 -0
  3. package/dist/components/BaseCheckbox/__tests__/BaseCheckbox.test.d.ts +1 -0
  4. package/dist/components/BaseCheckbox/index.d.ts +2 -0
  5. package/dist/components/MenuNew/MenuAccordion/MenuAccordionItem.d.ts +2 -3
  6. package/dist/components/MenuNew/MenuBaseItem.d.ts +2 -1
  7. package/dist/components/MenuNew/index.d.ts +1 -1
  8. package/dist/components/index.d.ts +2 -0
  9. package/dist/index.js +4813 -4630
  10. package/lib/components/BaseCheckbox/BaseCheckbox.stories.tsx +82 -0
  11. package/lib/components/BaseCheckbox/BaseCheckbox.tsx +168 -0
  12. package/lib/components/BaseCheckbox/__tests__/BaseCheckbox.test.tsx +98 -0
  13. package/lib/components/BaseCheckbox/index.ts +2 -0
  14. package/lib/components/Checkbox/Checkbox.tsx +49 -53
  15. package/lib/components/Checkbox/__tests__/__snapshots__/Checkbox.test.tsx.snap +66 -43
  16. package/lib/components/DrawerMenu/__tests__/DrawerMenu.test.tsx +93 -1
  17. package/lib/components/Dropdown/DropdownContent.tsx +139 -7
  18. package/lib/components/Footer/Footer.tsx +12 -0
  19. package/lib/components/Footer/__tests__/__snapshots__/Footer.test.tsx.snap +36 -0
  20. package/lib/components/FooterNew/LegalAndCopyright.tsx +14 -0
  21. package/lib/components/FooterNew/__tests__/__snapshots__/Footer.test.tsx.snap +36 -0
  22. package/lib/components/MenuNew/MenuAccordion/MenuAccordion.tsx +11 -7
  23. package/lib/components/MenuNew/MenuAccordion/MenuAccordionItem.tsx +8 -5
  24. package/lib/components/MenuNew/MenuBaseItem.tsx +17 -0
  25. package/lib/components/MenuNew/__tests__/Menu.test.tsx +94 -0
  26. package/lib/components/MenuNew/index.ts +1 -0
  27. package/lib/components/Table/subcomponents/Cell/__tests__/__snapshots__/Cell.test.tsx.snap +7 -2
  28. package/lib/components/Table/subcomponents/HeadCell/__tests__/__snapshots__/HeadCell.test.tsx.snap +7 -2
  29. package/lib/components/index.ts +3 -0
  30. package/package.json +1 -1
@@ -14,6 +14,7 @@ import MenuAccordionChevron from './MenuAccordionChevron';
14
14
  import MenuAccordionItem, { MenuAccordionItemProps } from './MenuAccordionItem';
15
15
 
16
16
  export const NAME = 'ucl-uikit-menu__accordion';
17
+ const FOCUS_RING_GUTTER_PX = 6;
17
18
 
18
19
  export interface MenuAccordionProps extends Omit<
19
20
  MenuBaseItemProps,
@@ -62,15 +63,16 @@ const MenuAccordion = ({
62
63
  const bodyStyle = css`
63
64
  display: grid;
64
65
  grid-template-rows: 0fr;
65
- width: 100%;
66
+ width: calc(100% + ${FOCUS_RING_GUTTER_PX * 2}px);
67
+ margin-left: -${FOCUS_RING_GUTTER_PX}px;
66
68
  margin-top: 0;
67
69
  overflow: hidden;
68
70
  opacity: 0;
69
71
  pointer-events: none;
70
72
  transition:
71
- grid-template-rows 300ms ease-in,
72
- margin-top 300ms ease-in,
73
- opacity 300ms ease-in;
73
+ grid-template-rows 200ms ease-in-out,
74
+ margin-top 200ms ease-in-out,
75
+ opacity 200ms ease-in-out;
74
76
  `;
75
77
 
76
78
  const bodyExpandedStyle = css`
@@ -79,13 +81,15 @@ const MenuAccordion = ({
79
81
  opacity: 1;
80
82
  pointer-events: auto;
81
83
  transition:
82
- grid-template-rows 300ms ease-out,
83
- margin-top 300ms ease-out,
84
- opacity 300ms ease-out;
84
+ grid-template-rows 200ms ease-in-out,
85
+ margin-top 200ms ease-in-out,
86
+ opacity 200ms ease-in-out;
85
87
  `;
86
88
 
87
89
  const bodyInnerStyle = css`
88
90
  min-height: 0;
91
+ padding-top: ${FOCUS_RING_GUTTER_PX}px;
92
+ padding-bottom: ${FOCUS_RING_GUTTER_PX}px;
89
93
  overflow: hidden;
90
94
  `;
91
95
 
@@ -1,13 +1,15 @@
1
- import { HTMLAttributes } from 'react';
2
1
  import { css, cx } from '@emotion/css';
3
- import MenuBaseItem from '../MenuBaseItem';
2
+ import MenuBaseItem, { MenuBaseItemProps } from '../MenuBaseItem';
4
3
  import MenuItemText from '../MenuItemText';
5
4
  import { useTheme } from '../../../theme';
6
5
 
7
6
  export const NAME = 'ucl-uikit-menu__accordion-item';
7
+ const FOCUS_RING_GUTTER_PX = 6;
8
8
 
9
- export interface MenuAccordionItemProps extends HTMLAttributes<HTMLDivElement> {
10
- asChild?: boolean;
9
+ export interface MenuAccordionItemProps extends Omit<
10
+ MenuBaseItemProps,
11
+ 'iconPosition'
12
+ > {
11
13
  testId?: string;
12
14
  }
13
15
 
@@ -21,7 +23,8 @@ const MenuAccordionItem = ({
21
23
  const [theme] = useTheme();
22
24
 
23
25
  const baseStyle = css`
24
- margin: 0;
26
+ width: calc(100% - ${FOCUS_RING_GUTTER_PX * 2}px);
27
+ margin: 0 ${FOCUS_RING_GUTTER_PX}px;
25
28
  padding-left: ${theme.padding.p40};
26
29
 
27
30
  @media screen and (min-width: ${theme.breakpoints.tablet}px) {
@@ -8,6 +8,7 @@ export interface MenuBaseItemProps extends HTMLAttributes<HTMLDivElement> {
8
8
  endAdornment?: ReactNode;
9
9
  hoverMode?: 'background' | 'underline';
10
10
  asChild?: boolean;
11
+ active?: boolean;
11
12
  }
12
13
 
13
14
  const MenuBaseItem = ({
@@ -22,6 +23,7 @@ const MenuBaseItem = ({
22
23
  tabIndex,
23
24
  hoverMode = 'background',
24
25
  asChild = false,
26
+ active = false,
25
27
  ...props
26
28
  }: MenuBaseItemProps) => {
27
29
  const [theme] = useTheme();
@@ -53,6 +55,7 @@ const MenuBaseItem = ({
53
55
  display: flex;
54
56
  align-items: center;
55
57
  gap: ${theme.margin.m16};
58
+ position: relative;
56
59
  cursor: pointer;
57
60
  outline: none;
58
61
 
@@ -65,6 +68,19 @@ const MenuBaseItem = ({
65
68
  }
66
69
  `;
67
70
 
71
+ const activeStyle = css`
72
+ &::before {
73
+ content: '';
74
+ position: absolute;
75
+ left: 0;
76
+ top: calc(50% - 12px);
77
+ width: 6px;
78
+ height: 24px;
79
+ background-color: ${theme.colour.fill.brand};
80
+ pointer-events: none;
81
+ }
82
+ `;
83
+
68
84
  const backgroundOnHoverStyle = css`
69
85
  &:hover {
70
86
  background-color: ${theme.colour.fill.brandSubtleHover};
@@ -79,6 +95,7 @@ const MenuBaseItem = ({
79
95
 
80
96
  const style = cx(
81
97
  baseStyle,
98
+ active && activeStyle,
82
99
  hoverMode === 'underline' && underlineStyleOnHoverStyle,
83
100
  hoverMode === 'background' && backgroundOnHoverStyle,
84
101
  className
@@ -113,6 +113,41 @@ describe('Menu', () => {
113
113
  expect(screen.getByText('Library')).toBeInTheDocument();
114
114
  });
115
115
 
116
+ test('accordion items allow space for focus borders', () => {
117
+ wrap(
118
+ <Menu>
119
+ <Menu.Accordion
120
+ label='Services'
121
+ defaultExpanded
122
+ >
123
+ <Menu.Accordion.Item>Library</Menu.Accordion.Item>
124
+ </Menu.Accordion>
125
+ </Menu>
126
+ );
127
+
128
+ const accordionItem = screen
129
+ .getByText('Library')
130
+ .closest('.ucl-uikit-menu__accordion-item');
131
+ const accordionContentInner = accordionItem?.parentElement;
132
+ const accordionContent = accordionContentInner?.parentElement;
133
+
134
+ expect(accordionItem).toHaveStyle({
135
+ marginTop: '0px',
136
+ marginLeft: '6px',
137
+ marginRight: '6px',
138
+ marginBottom: '0px',
139
+ width: 'calc(100% - 12px)',
140
+ });
141
+ expect(accordionContent).toHaveStyle({
142
+ marginLeft: '-6px',
143
+ width: 'calc(100% + 12px)',
144
+ });
145
+ expect(accordionContentInner).toHaveStyle({
146
+ paddingTop: '6px',
147
+ paddingBottom: '6px',
148
+ });
149
+ });
150
+
116
151
  test('accordion item supports asChild link content', () => {
117
152
  wrap(
118
153
  <Menu>
@@ -227,6 +262,65 @@ describe('Menu', () => {
227
262
  expect(item?.firstChild).toHaveAttribute('data-testid', 'left-icon');
228
263
  });
229
264
 
265
+ test('active items render a non-disruptive marker', () => {
266
+ wrap(
267
+ <Menu>
268
+ <Menu.PrimaryItem active>Home</Menu.PrimaryItem>
269
+ </Menu>
270
+ );
271
+
272
+ const item = screen
273
+ .getByText('Home')
274
+ .closest('.ucl-uikit-menu__primary-item');
275
+ const generatedClass = Array.from(item?.classList ?? []).find((className) =>
276
+ className.startsWith('css-')
277
+ );
278
+ const cssRules = Array.from(document.styleSheets)
279
+ .flatMap((styleSheet) => Array.from(styleSheet.cssRules))
280
+ .map((rule) => rule.cssText)
281
+ .join(' ');
282
+
283
+ expect(item).not.toHaveAttribute('active');
284
+ expect(item).toHaveStyle({ position: 'relative' });
285
+ expect(cssRules).toContain(`.${generatedClass}::before`);
286
+ expect(cssRules).toContain('width: 6px');
287
+ expect(cssRules).toContain('height: 24px');
288
+ });
289
+
290
+ test.each([
291
+ {
292
+ name: 'accordion',
293
+ menu: (
294
+ <Menu.Accordion
295
+ active
296
+ label='Systems'
297
+ />
298
+ ),
299
+ text: 'Systems',
300
+ selector: '.ucl-uikit-menu__accordion',
301
+ },
302
+ {
303
+ name: 'accordion item',
304
+ menu: <Menu.Accordion.Item active>Library</Menu.Accordion.Item>,
305
+ text: 'Library',
306
+ selector: '.ucl-uikit-menu__accordion-item',
307
+ },
308
+ ])('$name supports active state', ({ menu, text, selector }) => {
309
+ wrap(<Menu>{menu}</Menu>);
310
+
311
+ const item = screen.getByText(text).closest(selector);
312
+ const generatedClass = Array.from(item?.classList ?? []).find((className) =>
313
+ className.startsWith('css-')
314
+ );
315
+ const cssRules = Array.from(document.styleSheets)
316
+ .flatMap((styleSheet) => Array.from(styleSheet.cssRules))
317
+ .map((rule) => rule.cssText)
318
+ .join(' ');
319
+
320
+ expect(item).not.toHaveAttribute('active');
321
+ expect(cssRules).toContain(`.${generatedClass}::before`);
322
+ });
323
+
230
324
  test('primary items use background hover instead of underline hover', () => {
231
325
  wrap(
232
326
  <Menu>
@@ -6,6 +6,7 @@ export type {
6
6
  MenuHeadingProps,
7
7
  MenuSectionProps,
8
8
  MenuAccordionProps,
9
+ MenuAccordionItemProps,
9
10
  MenuBaseItemProps,
10
11
  PrimaryMenuItemProps,
11
12
  SecondaryMenuItemProps,
@@ -44,13 +44,18 @@ exports[`Cell > Snapshot: variants 1`] = `
44
44
  data-testid="ucl-uikit-table__cell-content"
45
45
  >
46
46
  <span
47
- class="ucl-uikit-checkbox css-tumlz"
47
+ class="ucl-uikit-base-checkbox ucl-uikit-checkbox css-tfrbiv"
48
+ data-testid="ucl-uikit-checkbox__root"
48
49
  >
49
50
  <input
50
- class="css-nzy7im"
51
+ class="css-1bjd9qx"
51
52
  data-testid="ucl-uikit-checkbox"
52
53
  type="checkbox"
53
54
  />
55
+ <span
56
+ aria-hidden="true"
57
+ class="css-1quq9cp"
58
+ />
54
59
  </span>
55
60
  </div>
56
61
  </td>
@@ -14,14 +14,19 @@ exports[`HeadCell > Snapshot: checkbox variant 1`] = `
14
14
  data-testid="ucl-uikit-table__head-cell-content"
15
15
  >
16
16
  <span
17
- class="ucl-uikit-checkbox css-tumlz"
17
+ class="ucl-uikit-base-checkbox ucl-uikit-checkbox css-tfrbiv"
18
+ data-testid="ucl-uikit-checkbox__root"
18
19
  >
19
20
  <input
20
21
  aria-label="Select all rows"
21
- class="css-nzy7im"
22
+ class="css-1bjd9qx"
22
23
  data-testid="ucl-uikit-checkbox"
23
24
  type="checkbox"
24
25
  />
26
+ <span
27
+ aria-hidden="true"
28
+ class="css-1quq9cp"
29
+ />
25
30
  </span>
26
31
  </div>
27
32
  </th>
@@ -34,6 +34,9 @@ export type { AvatarProps } from './Avatar';
34
34
  export { default as Badge } from './Badge';
35
35
  export type { BadgeProps } from './Badge';
36
36
 
37
+ export { default as BaseCheckbox } from './BaseCheckbox';
38
+ export type { BaseCheckboxProps, BaseCheckboxState } from './BaseCheckbox';
39
+
37
40
  export { default as Spinner } from './Spinner';
38
41
  export type { SpinnerProps } from './Spinner';
39
42
 
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.1",
5
+ "version": "0.27.1",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",