uikit-react-public 0.30.0 → 0.32.3
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/dist/components/Dialog/BaseDialog.d.ts +1 -1
- package/dist/components/Dialog/Dialog.d.ts +1 -1
- package/dist/components/Dialog/Dialog.stories.d.ts +1 -1
- package/dist/components/Heading/Heading.stories.d.ts +5 -7
- package/dist/components/MenuNew/Menu.context.d.ts +9 -0
- package/dist/components/MenuNew/Menu.d.ts +2 -1
- package/dist/components/MenuNew/MenuHeading.d.ts +1 -1
- package/dist/components/MenuNew/MenuItemText.d.ts +2 -1
- package/dist/components/MenuNew/PrimaryMenuItem.d.ts +1 -1
- package/dist/components/Select/Select.types.d.ts +1 -1
- package/dist/components/Sidebar/Sidebar.d.ts +12 -0
- package/dist/components/Sidebar/Sidebar.stories.d.ts +38 -0
- package/dist/components/Sidebar/__tests__/Sidebar.test.d.ts +1 -0
- package/dist/components/Sidebar/index.d.ts +2 -0
- package/dist/components/Snackbar/Snackbar.d.ts +9 -5
- package/dist/components/Snackbar/Snackbar.stories.d.ts +2 -1
- package/dist/components/Snackbar/Snackbars.d.ts +19 -0
- package/dist/components/Snackbar/Snackbars.stories.d.ts +52 -0
- package/dist/components/Snackbar/__tests__/Snackbars.test.d.ts +1 -0
- package/dist/components/Snackbar/index.d.ts +2 -0
- package/dist/components/index.d.ts +4 -1
- package/dist/index.js +5897 -5358
- package/dist/utils/announce.d.ts +2 -1
- package/lib/components/Dialog/BaseDialog.tsx +180 -161
- package/lib/components/Dialog/Dialog.tsx +15 -11
- package/lib/components/Dropdown/Dropdown.stories.tsx +69 -74
- package/lib/components/Heading/Documentation.mdx +4 -14
- package/lib/components/Heading/Heading.stories.tsx +16 -30
- package/lib/components/MenuNew/Menu.context.tsx +18 -0
- package/lib/components/MenuNew/Menu.tsx +14 -9
- package/lib/components/MenuNew/MenuDivider.tsx +12 -1
- package/lib/components/MenuNew/MenuHeading.tsx +6 -0
- package/lib/components/MenuNew/MenuItemText.tsx +27 -3
- package/lib/components/MenuNew/MenuSection.tsx +11 -0
- package/lib/components/MenuNew/PrimaryMenuItem.tsx +71 -2
- package/lib/components/Select/Select.types.ts +1 -7
- package/lib/components/Select/__tests__/Select.test.tsx +112 -0
- package/lib/components/Select/__tests__/__snapshots__/Select.test.tsx.snap +5 -0
- package/lib/components/Select/subcomponents/CustomSelect.tsx +75 -3
- package/lib/components/Select/subcomponents/FilterInput.tsx +1 -1
- package/lib/components/Sidebar/Sidebar.stories.tsx +94 -0
- package/lib/components/Sidebar/Sidebar.tsx +208 -0
- package/lib/components/Sidebar/__tests__/Sidebar.test.tsx +96 -0
- package/lib/components/Sidebar/__tests__/__snapshots__/Sidebar.test.tsx.snap +272 -0
- package/lib/components/Sidebar/index.ts +2 -0
- package/lib/components/Snackbar/Snackbar.stories.tsx +11 -0
- package/lib/components/Snackbar/Snackbar.tsx +162 -118
- package/lib/components/Snackbar/Snackbars.stories.tsx +130 -0
- package/lib/components/Snackbar/Snackbars.tsx +377 -0
- package/lib/components/Snackbar/__tests__/Snackbar.test.tsx +104 -0
- package/lib/components/Snackbar/__tests__/Snackbars.test.tsx +377 -0
- package/lib/components/Snackbar/__tests__/__snapshots__/Snackbar.test.tsx.snap +36 -19
- package/lib/components/Snackbar/index.ts +6 -0
- package/lib/components/index.ts +10 -1
- package/lib/utils/__tests__/announce.test.ts +53 -0
- package/lib/utils/announce.ts +33 -10
- package/package.json +1 -1
package/dist/utils/announce.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Announces a message to screen readers.
|
|
3
|
+
*
|
|
3
4
|
*/
|
|
4
|
-
declare const announce: (message: string, force?: boolean) => void;
|
|
5
|
+
declare const announce: (message: string, force?: boolean, container?: HTMLElement | null) => void;
|
|
5
6
|
export declare const __resetForTesting: () => void;
|
|
6
7
|
export default announce;
|
|
@@ -5,6 +5,7 @@ import React, {
|
|
|
5
5
|
useEffect,
|
|
6
6
|
useRef,
|
|
7
7
|
useContext,
|
|
8
|
+
forwardRef,
|
|
8
9
|
} from 'react';
|
|
9
10
|
import { css, cx } from '@emotion/css';
|
|
10
11
|
import useTheme from '../../theme/useTheme';
|
|
@@ -33,182 +34,200 @@ export interface BaseDialogProps extends HTMLAttributes<HTMLDialogElement> {
|
|
|
33
34
|
testId?: string;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
const BaseDialog = (
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
`;
|
|
82
|
-
|
|
83
|
-
useEffect(() => {
|
|
84
|
-
if (open && modal) {
|
|
85
|
-
document.body.classList.add(hideBodyScroll);
|
|
86
|
-
} else {
|
|
87
|
-
document.body.classList.remove(hideBodyScroll);
|
|
88
|
-
}
|
|
89
|
-
return () => {
|
|
90
|
-
document.body.classList.remove(hideBodyScroll);
|
|
91
|
-
};
|
|
92
|
-
}, [open, modal, hideBodyScroll]);
|
|
93
|
-
|
|
94
|
-
useEffect(() => {
|
|
95
|
-
const dialogElement = dialogRef.current;
|
|
96
|
-
|
|
97
|
-
if (!dialogElement) return;
|
|
37
|
+
const BaseDialog = forwardRef<HTMLDialogElement, BaseDialogProps>(
|
|
38
|
+
function BaseDialog(
|
|
39
|
+
{
|
|
40
|
+
open = false,
|
|
41
|
+
size = 'medium',
|
|
42
|
+
modal = true,
|
|
43
|
+
closeOnClickOutside = true,
|
|
44
|
+
closeOnClickOutsideStopPropagation = true,
|
|
45
|
+
nonModalCloseOnEscape = false,
|
|
46
|
+
onClose,
|
|
47
|
+
className,
|
|
48
|
+
children,
|
|
49
|
+
initialFocusRef,
|
|
50
|
+
finalFocusRef,
|
|
51
|
+
disableFocusTrap = false,
|
|
52
|
+
restoreFocus = true,
|
|
53
|
+
skipCloseOnInitialFocus = false,
|
|
54
|
+
testId = NAME,
|
|
55
|
+
...props
|
|
56
|
+
}: BaseDialogProps,
|
|
57
|
+
ref
|
|
58
|
+
) {
|
|
59
|
+
const width = {
|
|
60
|
+
small: SMALL_WIDTH,
|
|
61
|
+
medium: MEDIUM_WIDTH,
|
|
62
|
+
large: LARGE_WIDTH,
|
|
63
|
+
}[size];
|
|
64
|
+
|
|
65
|
+
const [theme] = useTheme();
|
|
66
|
+
|
|
67
|
+
const dialogRef = useRef<HTMLDialogElement>(null);
|
|
68
|
+
const previousActiveElement = useRef<HTMLElement | null>(null);
|
|
69
|
+
|
|
70
|
+
const setDialogRef = useCallback(
|
|
71
|
+
(node: HTMLDialogElement | null) => {
|
|
72
|
+
dialogRef.current = node;
|
|
73
|
+
|
|
74
|
+
if (typeof ref === 'function') {
|
|
75
|
+
ref(node);
|
|
76
|
+
} else if (ref) {
|
|
77
|
+
ref.current = node;
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
[ref]
|
|
81
|
+
);
|
|
98
82
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
83
|
+
const context = useContext(DialogContext);
|
|
84
|
+
const dialogHeaderId = context?.dialogHeaderId;
|
|
85
|
+
const dialogBodyId = context?.dialogBodyId;
|
|
86
|
+
|
|
87
|
+
// Use the focus trap hook
|
|
88
|
+
useFocusTrap({
|
|
89
|
+
isActive: open && modal && !disableFocusTrap,
|
|
90
|
+
containerRef: dialogRef,
|
|
91
|
+
initialFocusRef,
|
|
92
|
+
finalFocusRef,
|
|
93
|
+
restoreFocus,
|
|
94
|
+
skipFirstFocusable: skipCloseOnInitialFocus,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const hideBodyScroll = css`
|
|
98
|
+
overflow: hidden;
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
if (open && modal) {
|
|
103
|
+
document.body.classList.add(hideBodyScroll);
|
|
103
104
|
} else {
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
} else if (!open && dialogElement.hasAttribute('open')) {
|
|
107
|
-
dialogElement.close();
|
|
108
|
-
// Focus restoration is handled by the focus trap hook for modal dialogs,
|
|
109
|
-
// but we keep the fallback for non-modal dialogs or when focus trap is disabled
|
|
110
|
-
if ((!modal || disableFocusTrap) && restoreFocus) {
|
|
111
|
-
previousActiveElement.current?.focus();
|
|
105
|
+
document.body.classList.remove(hideBodyScroll);
|
|
112
106
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (
|
|
122
|
-
|
|
107
|
+
return () => {
|
|
108
|
+
document.body.classList.remove(hideBodyScroll);
|
|
109
|
+
};
|
|
110
|
+
}, [open, modal, hideBodyScroll]);
|
|
111
|
+
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
const dialogElement = dialogRef.current;
|
|
114
|
+
|
|
115
|
+
if (!dialogElement) return;
|
|
116
|
+
|
|
117
|
+
if (open && !dialogElement.hasAttribute('open')) {
|
|
118
|
+
previousActiveElement.current = document.activeElement as HTMLElement;
|
|
119
|
+
if (modal) {
|
|
120
|
+
dialogElement.showModal();
|
|
121
|
+
} else {
|
|
122
|
+
dialogElement.show();
|
|
123
|
+
}
|
|
124
|
+
} else if (!open && dialogElement.hasAttribute('open')) {
|
|
125
|
+
dialogElement.close();
|
|
126
|
+
// Focus restoration is handled by the focus trap hook for modal dialogs,
|
|
127
|
+
// but we keep the fallback for non-modal dialogs or when focus trap is disabled
|
|
128
|
+
if ((!modal || disableFocusTrap) && restoreFocus) {
|
|
129
|
+
previousActiveElement.current?.focus();
|
|
130
|
+
}
|
|
123
131
|
}
|
|
124
|
-
};
|
|
132
|
+
}, [open, modal, disableFocusTrap, restoreFocus]);
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
// Handle Escape key to close dialog
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (!open || modal || !nonModalCloseOnEscape) return;
|
|
129
137
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
138
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
139
|
+
if (event.key === 'Escape' && onClose) {
|
|
140
|
+
onClose(event);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
145
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
146
|
+
}, [open, modal, nonModalCloseOnEscape, onClose]);
|
|
147
|
+
|
|
148
|
+
const handleClick = useCallback(
|
|
149
|
+
(ev: React.MouseEvent<HTMLDialogElement>) => {
|
|
150
|
+
if (closeOnClickOutside && onClose && dialogRef.current) {
|
|
151
|
+
if (closeOnClickOutsideStopPropagation) {
|
|
152
|
+
ev.stopPropagation();
|
|
153
|
+
}
|
|
154
|
+
const rect = dialogRef.current.getBoundingClientRect();
|
|
155
|
+
const isInDialog =
|
|
156
|
+
rect.top <= ev.clientY &&
|
|
157
|
+
ev.clientY <= rect.top + rect.height &&
|
|
158
|
+
rect.left <= ev.clientX &&
|
|
159
|
+
ev.clientX <= rect.left + rect.width;
|
|
160
|
+
if (!isInDialog) {
|
|
161
|
+
onClose(ev);
|
|
162
|
+
}
|
|
135
163
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (
|
|
164
|
+
},
|
|
165
|
+
[closeOnClickOutside, closeOnClickOutsideStopPropagation, onClose]
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
const handleDialogClose = useCallback(
|
|
169
|
+
(ev: React.MouseEvent<HTMLDialogElement>) => {
|
|
170
|
+
if (onClose) {
|
|
143
171
|
onClose(ev);
|
|
144
172
|
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
);
|
|
149
|
-
|
|
150
|
-
const handleDialogClose = useCallback(
|
|
151
|
-
(ev: React.MouseEvent<HTMLDialogElement>) => {
|
|
152
|
-
if (onClose) {
|
|
153
|
-
onClose(ev);
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
[onClose]
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
const baseStyle = css`
|
|
160
|
-
padding: 0;
|
|
161
|
-
border: none;
|
|
162
|
-
background: ${theme.color.neutral.white};
|
|
163
|
-
color: ${theme.color.text.primary};
|
|
164
|
-
font-family: ${theme.font.family.primary};
|
|
165
|
-
font-size: ${theme.font.size.f16};
|
|
166
|
-
width: 100vw;
|
|
167
|
-
height: 100vh;
|
|
168
|
-
margin: auto;
|
|
169
|
-
|
|
170
|
-
&:modal {
|
|
171
|
-
max-width: none;
|
|
172
|
-
max-height: none;
|
|
173
|
-
}
|
|
173
|
+
},
|
|
174
|
+
[onClose]
|
|
175
|
+
);
|
|
174
176
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
const baseStyle = css`
|
|
178
|
+
padding: 0;
|
|
179
|
+
border: none;
|
|
180
|
+
background: ${theme.color.neutral.white};
|
|
181
|
+
color: ${theme.color.text.primary};
|
|
182
|
+
font-family: ${theme.font.family.primary};
|
|
183
|
+
font-size: ${theme.font.size.f16};
|
|
184
|
+
width: 100vw;
|
|
185
|
+
height: 100vh;
|
|
186
|
+
margin: auto;
|
|
179
187
|
|
|
180
188
|
&:modal {
|
|
181
|
-
max-width:
|
|
182
|
-
max-height:
|
|
189
|
+
max-width: none;
|
|
190
|
+
max-height: none;
|
|
183
191
|
}
|
|
184
|
-
}
|
|
185
192
|
|
|
186
|
-
|
|
187
|
-
|
|
193
|
+
@media (min-width: ${theme.breakpoints.tablet}px) {
|
|
194
|
+
width: ${width}px;
|
|
195
|
+
max-width: calc(100vw - ${theme.margin.m16});
|
|
196
|
+
height: fit-content;
|
|
197
|
+
|
|
198
|
+
&:modal {
|
|
199
|
+
max-width: min(${width}px, calc(100vw - ${theme.margin.m16}));
|
|
200
|
+
max-height: calc(100vh - 32px);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
&::backdrop {
|
|
205
|
+
background-color: ${theme.color.overlay.blanket};
|
|
206
|
+
}
|
|
207
|
+
`;
|
|
208
|
+
|
|
209
|
+
const style = cx(NAME, baseStyle, className);
|
|
210
|
+
|
|
211
|
+
if (open) {
|
|
212
|
+
return (
|
|
213
|
+
<dialog
|
|
214
|
+
ref={setDialogRef}
|
|
215
|
+
className={style}
|
|
216
|
+
data-testid={testId}
|
|
217
|
+
onClick={handleClick}
|
|
218
|
+
onClose={handleDialogClose}
|
|
219
|
+
aria-modal={modal ? 'true' : 'false'}
|
|
220
|
+
aria-labelledby={dialogHeaderId}
|
|
221
|
+
aria-describedby={dialogBodyId}
|
|
222
|
+
{...props}
|
|
223
|
+
>
|
|
224
|
+
{children}
|
|
225
|
+
</dialog>
|
|
226
|
+
);
|
|
227
|
+
} else {
|
|
228
|
+
return null;
|
|
188
229
|
}
|
|
189
|
-
`;
|
|
190
|
-
|
|
191
|
-
const style = cx(NAME, baseStyle, className);
|
|
192
|
-
|
|
193
|
-
if (open) {
|
|
194
|
-
return (
|
|
195
|
-
<dialog
|
|
196
|
-
ref={dialogRef}
|
|
197
|
-
className={style}
|
|
198
|
-
data-testid={testId}
|
|
199
|
-
onClick={handleClick}
|
|
200
|
-
onClose={handleDialogClose}
|
|
201
|
-
aria-modal={modal ? 'true' : 'false'}
|
|
202
|
-
aria-labelledby={dialogHeaderId}
|
|
203
|
-
aria-describedby={dialogBodyId}
|
|
204
|
-
{...props}
|
|
205
|
-
>
|
|
206
|
-
{children}
|
|
207
|
-
</dialog>
|
|
208
|
-
);
|
|
209
|
-
} else {
|
|
210
|
-
return null;
|
|
211
230
|
}
|
|
212
|
-
|
|
231
|
+
);
|
|
213
232
|
|
|
214
233
|
export default memo(BaseDialog);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useId } from 'react';
|
|
1
|
+
import { createContext, forwardRef, useId } from 'react';
|
|
2
2
|
import { css, cx } from '@emotion/css';
|
|
3
3
|
import useTheme from '../../theme/useTheme';
|
|
4
4
|
import BaseDialog, { BaseDialogProps } from './BaseDialog';
|
|
@@ -23,15 +23,18 @@ export interface DialogProps extends BaseDialogProps {
|
|
|
23
23
|
onSecondaryAction?: () => void;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const Dialog = (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
26
|
+
const Dialog = forwardRef<HTMLDialogElement, DialogProps>(function Dialog(
|
|
27
|
+
{
|
|
28
|
+
onClose,
|
|
29
|
+
onAction,
|
|
30
|
+
onSecondaryAction,
|
|
31
|
+
testId = NAME,
|
|
32
|
+
className,
|
|
33
|
+
children,
|
|
34
|
+
...props
|
|
35
|
+
}: DialogProps,
|
|
36
|
+
ref
|
|
37
|
+
) {
|
|
35
38
|
const [theme] = useTheme();
|
|
36
39
|
const dialogHeaderId = useId();
|
|
37
40
|
const dialogBodyId = useId();
|
|
@@ -53,6 +56,7 @@ const Dialog = ({
|
|
|
53
56
|
return (
|
|
54
57
|
<DialogContext value={contextValue}>
|
|
55
58
|
<BaseDialog
|
|
59
|
+
ref={ref}
|
|
56
60
|
onClose={onClose}
|
|
57
61
|
testId={testId}
|
|
58
62
|
className={style}
|
|
@@ -63,7 +67,7 @@ const Dialog = ({
|
|
|
63
67
|
</BaseDialog>
|
|
64
68
|
</DialogContext>
|
|
65
69
|
);
|
|
66
|
-
};
|
|
70
|
+
});
|
|
67
71
|
|
|
68
72
|
export interface DialogSubComponents {
|
|
69
73
|
Header: typeof DialogHeader;
|
|
@@ -8,7 +8,6 @@ import IconButton from '../IconButton';
|
|
|
8
8
|
import LabelledCheckbox from '../Checkbox/LabelledCheckbox';
|
|
9
9
|
import useTheme from '../../theme/useTheme';
|
|
10
10
|
import useMediaQuery from '../../hooks/useMediaQuery';
|
|
11
|
-
import { ThemeContextProvider, lightTheme } from '../../theme';
|
|
12
11
|
|
|
13
12
|
const meta = {
|
|
14
13
|
title: 'Components/Dropdown',
|
|
@@ -74,55 +73,53 @@ export const HeaderResponsiveTrigger: Story = {
|
|
|
74
73
|
`;
|
|
75
74
|
|
|
76
75
|
return (
|
|
77
|
-
<
|
|
78
|
-
<
|
|
79
|
-
<HeaderNew
|
|
80
|
-
<
|
|
81
|
-
<Dropdown
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
aria-label='Menu'
|
|
89
|
-
>
|
|
90
|
-
Menu
|
|
91
|
-
</Button>
|
|
92
|
-
) : (
|
|
93
|
-
<IconButton
|
|
94
|
-
className={iconButtonStyle}
|
|
95
|
-
aria-label='Menu'
|
|
96
|
-
>
|
|
97
|
-
<Icon.Menu size={20} />
|
|
98
|
-
</IconButton>
|
|
99
|
-
)}
|
|
100
|
-
</Dropdown.Trigger>
|
|
101
|
-
<Dropdown.Content className={menuStyle}>
|
|
102
|
-
<button
|
|
103
|
-
type='button'
|
|
104
|
-
className={menuItemStyle}
|
|
76
|
+
<div className={containerStyle}>
|
|
77
|
+
<HeaderNew title='Name of the application'>
|
|
78
|
+
<HeaderNew.MenuContainer>
|
|
79
|
+
<Dropdown {...args}>
|
|
80
|
+
<Dropdown.Trigger>
|
|
81
|
+
{isDesktop ? (
|
|
82
|
+
<Button
|
|
83
|
+
variant='primary-subtle'
|
|
84
|
+
size='small'
|
|
85
|
+
icon={<Icon.Menu size={20} />}
|
|
86
|
+
aria-label='Menu'
|
|
105
87
|
>
|
|
106
|
-
|
|
107
|
-
</
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
className={
|
|
88
|
+
Menu
|
|
89
|
+
</Button>
|
|
90
|
+
) : (
|
|
91
|
+
<IconButton
|
|
92
|
+
className={iconButtonStyle}
|
|
93
|
+
aria-label='Menu'
|
|
111
94
|
>
|
|
112
|
-
|
|
113
|
-
</
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
95
|
+
<Icon.Menu size={20} />
|
|
96
|
+
</IconButton>
|
|
97
|
+
)}
|
|
98
|
+
</Dropdown.Trigger>
|
|
99
|
+
<Dropdown.Content className={menuStyle}>
|
|
100
|
+
<button
|
|
101
|
+
type='button'
|
|
102
|
+
className={menuItemStyle}
|
|
103
|
+
>
|
|
104
|
+
View profile
|
|
105
|
+
</button>
|
|
106
|
+
<button
|
|
107
|
+
type='button'
|
|
108
|
+
className={menuItemStyle}
|
|
109
|
+
>
|
|
110
|
+
Team settings
|
|
111
|
+
</button>
|
|
112
|
+
<button
|
|
113
|
+
type='button'
|
|
114
|
+
className={menuItemStyle}
|
|
115
|
+
>
|
|
116
|
+
Sign out
|
|
117
|
+
</button>
|
|
118
|
+
</Dropdown.Content>
|
|
119
|
+
</Dropdown>
|
|
120
|
+
</HeaderNew.MenuContainer>
|
|
121
|
+
</HeaderNew>
|
|
122
|
+
</div>
|
|
126
123
|
);
|
|
127
124
|
},
|
|
128
125
|
};
|
|
@@ -152,33 +149,31 @@ export const StandaloneInfoPanel: Story = {
|
|
|
152
149
|
`;
|
|
153
150
|
|
|
154
151
|
return (
|
|
155
|
-
<
|
|
156
|
-
<
|
|
157
|
-
<Dropdown
|
|
158
|
-
<
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
icon={<Icon.Info size={20} />}
|
|
163
|
-
>
|
|
164
|
-
Notification preferences
|
|
165
|
-
</Button>
|
|
166
|
-
</Dropdown.Trigger>
|
|
167
|
-
<Dropdown.Content
|
|
168
|
-
className={infoContentStyle}
|
|
169
|
-
align='left'
|
|
152
|
+
<div className={containerStyle}>
|
|
153
|
+
<Dropdown {...args}>
|
|
154
|
+
<Dropdown.Trigger>
|
|
155
|
+
<Button
|
|
156
|
+
variant='secondary'
|
|
157
|
+
size='small'
|
|
158
|
+
icon={<Icon.Info size={20} />}
|
|
170
159
|
>
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
</
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
160
|
+
Notification preferences
|
|
161
|
+
</Button>
|
|
162
|
+
</Dropdown.Trigger>
|
|
163
|
+
<Dropdown.Content
|
|
164
|
+
className={infoContentStyle}
|
|
165
|
+
align='left'
|
|
166
|
+
>
|
|
167
|
+
<p className={infoTitleStyle}>Weekly update</p>
|
|
168
|
+
<p className={infoBodyStyle}>
|
|
169
|
+
Get a summary of new activity in your workspace every Friday.
|
|
170
|
+
</p>
|
|
171
|
+
<LabelledCheckbox id='storybook-weekly-update-checkbox'>
|
|
172
|
+
Email me the weekly summary
|
|
173
|
+
</LabelledCheckbox>
|
|
174
|
+
</Dropdown.Content>
|
|
175
|
+
</Dropdown>
|
|
176
|
+
</div>
|
|
182
177
|
);
|
|
183
178
|
},
|
|
184
179
|
};
|
|
@@ -15,8 +15,7 @@ export const usage = {
|
|
|
15
15
|
level2: `<Heading level={2}>Level 2 Heading</Heading>`,
|
|
16
16
|
level3: `<Heading level={3}>Level 3 Heading</Heading>`,
|
|
17
17
|
level4: `<Heading level={4}>Level 4 Heading</Heading>`,
|
|
18
|
-
withMargins: `<Heading
|
|
19
|
-
noMargins: `<Heading margins={false} >Heading with no margins</Heading>`,
|
|
18
|
+
withMargins: `<Heading mb="24">Heading with bottom margin</Heading>`,
|
|
20
19
|
};
|
|
21
20
|
|
|
22
21
|
<Meta of={HeadingStories} />
|
|
@@ -52,7 +51,8 @@ All screens in UCL Experience apps should have a sensible semantic hierarchy. Th
|
|
|
52
51
|
### Props
|
|
53
52
|
|
|
54
53
|
- `level`: A **number** from 1 to 4, corresponding to the level of the HTML heading element to be rendered. Default is 1, if otherwise unspecified.
|
|
55
|
-
- `
|
|
54
|
+
- `m`, `mv`, `mh`, `mt`, `mb`, `ml`, `mr`: common margin props for applying theme spacing.
|
|
55
|
+
- `margins`: Deprecated. If `false`, the heading will have no margins.
|
|
56
56
|
- `testid`: A **string** value. If provided, the heading element will have a `data-testid` attribute with this value. The <a href="https://www.educative.io/answers/what-is-the-data-testid-attribute-in-testing" target="_blank">`data-testid` attribute</a> is used for identifying this element for testing. If unspecified, `ucl-uikit-heading` is used.
|
|
57
57
|
|
|
58
58
|
Pass the text you want in the heading as children: `<Heading>My heading text</Heading>`.
|
|
@@ -99,20 +99,10 @@ Custom CSS styling can be added as with all UIKit-React components by passing an
|
|
|
99
99
|
|
|
100
100
|
Red lines are added to the examples below to show the margins of the heading element.
|
|
101
101
|
|
|
102
|
-
Note that `margins={true}` in the below example merely specifies explicitly the default behaviour.
|
|
103
|
-
|
|
104
102
|
<Canvas
|
|
105
|
-
of={HeadingStories.
|
|
103
|
+
of={HeadingStories.withMargins}
|
|
106
104
|
sourceState='shown'
|
|
107
105
|
source={{
|
|
108
106
|
code: usage.withMargins,
|
|
109
107
|
}}
|
|
110
108
|
/>
|
|
111
|
-
|
|
112
|
-
<Canvas
|
|
113
|
-
of={HeadingStories.NoMargins}
|
|
114
|
-
sourceState='shown'
|
|
115
|
-
source={{
|
|
116
|
-
code: usage.noMargins,
|
|
117
|
-
}}
|
|
118
|
-
/>
|