@aarhus-university/au-lib-react-components 11.4.2 → 11.5.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.
- package/package.json +4 -4
- package/src/components/AUAlertComponent.tsx +100 -57
- package/src/components/AUButtonComponent.tsx +6 -3
- package/src/components/AUEditFilterComponent.tsx +67 -0
- package/src/components/AUToolbarComponent.tsx +5 -0
- package/stories/AUAlertComponent.stories.tsx +120 -0
- package/stories/AUEditFilterComponent.stories.tsx +29 -0
- package/stories/AUModalComponent.stories.tsx +1 -0
- package/stories/AUToolbarComponent.stories.tsx +1 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sideEffects": false,
|
|
3
3
|
"name": "@aarhus-university/au-lib-react-components",
|
|
4
|
-
"version": "11.
|
|
4
|
+
"version": "11.5.1",
|
|
5
5
|
"description": "Library for shared React components for various applications on au.dk",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "jest",
|
|
8
8
|
"build": "jest && webpack --config ./webpack.config.js",
|
|
9
|
-
"storybook": "start-storybook -p 6006",
|
|
9
|
+
"storybook": "start-storybook -p 6006 -h 127.0.0.1",
|
|
10
10
|
"build-storybook": "build-storybook",
|
|
11
11
|
"chromatic": "npx chromatic --project-token=6e78be9148c0"
|
|
12
12
|
},
|
|
@@ -72,9 +72,9 @@
|
|
|
72
72
|
"webpack-cli": "^4.9.2"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@aarhus-university/au-designsystem-delphinus": "0.
|
|
75
|
+
"@aarhus-university/au-designsystem-delphinus": "0.39.3",
|
|
76
76
|
"@aarhus-university/au-designsystem-delphinus-dev": "0.2.0",
|
|
77
|
-
"@aarhus-university/types": "
|
|
77
|
+
"@aarhus-university/types": "0.20.0",
|
|
78
78
|
"@reduxjs/toolkit": "^1.8.3",
|
|
79
79
|
"@types/google.analytics": "^0.0.42",
|
|
80
80
|
"@types/history": "^5.0.0",
|
|
@@ -1,69 +1,112 @@
|
|
|
1
|
+
/* eslint-disable max-len */
|
|
1
2
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
3
|
/* eslint-env browser */
|
|
3
|
-
import React, {
|
|
4
|
-
|
|
4
|
+
import React, {
|
|
5
|
+
FC, useState, useRef, useEffect,
|
|
6
|
+
} from 'react';
|
|
7
|
+
import { hideModal } from '@aarhus-university/au-designsystem-delphinus/source/js/components/modal-view';
|
|
8
|
+
import AUButtonComponent from './AUButtonComponent';
|
|
9
|
+
import AUModalComponent from './AUModalComponent';
|
|
5
10
|
|
|
6
11
|
const AUAlertComponent: FC<AUAlertComponentProps> = ({
|
|
12
|
+
modalId,
|
|
13
|
+
confirm,
|
|
14
|
+
processing,
|
|
15
|
+
done,
|
|
16
|
+
header,
|
|
7
17
|
message,
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
18
|
+
okButtonText,
|
|
19
|
+
cancelButtonText,
|
|
20
|
+
label,
|
|
21
|
+
size,
|
|
22
|
+
type,
|
|
23
|
+
icon,
|
|
24
|
+
iconPosition,
|
|
25
|
+
hideLabel,
|
|
26
|
+
mode,
|
|
27
|
+
classNames,
|
|
28
|
+
dataGtm,
|
|
29
|
+
asSubmit,
|
|
30
|
+
onClick,
|
|
11
31
|
}: AUAlertComponentProps) => {
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
button.onClick();
|
|
20
|
-
}}
|
|
21
|
-
>
|
|
22
|
-
{button.text}
|
|
23
|
-
</button>
|
|
24
|
-
));
|
|
32
|
+
const [alert, setAlert] = useState<boolean>(false);
|
|
33
|
+
const btnRef = useRef<HTMLButtonElement>(null);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (done) {
|
|
36
|
+
hideModal(modalId, btnRef.current as HTMLButtonElement, () => setAlert(false));
|
|
37
|
+
}
|
|
38
|
+
}, [done]);
|
|
25
39
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
<p dangerouslySetInnerHTML={{ __html: message }} />
|
|
34
|
-
</div>
|
|
35
|
-
{renderButtons}
|
|
36
|
-
</div>,
|
|
37
|
-
document.querySelector('body')!,
|
|
38
|
-
)
|
|
39
|
-
}
|
|
40
|
-
{children}
|
|
41
|
-
</>
|
|
42
|
-
);
|
|
40
|
+
let okBtnMode = mode;
|
|
41
|
+
if (processing) {
|
|
42
|
+
if (mode === 'confirmable-action') {
|
|
43
|
+
okBtnMode = 'confirmable-action processing';
|
|
44
|
+
} else if (mode === 'ireversable-action') {
|
|
45
|
+
okBtnMode = 'ireversable-action processing';
|
|
46
|
+
}
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
49
|
+
return (
|
|
50
|
+
<>
|
|
51
|
+
<AUModalComponent
|
|
52
|
+
domId={modalId}
|
|
53
|
+
show={alert}
|
|
54
|
+
sender={btnRef.current}
|
|
55
|
+
onClose={() => setAlert(false)}
|
|
56
|
+
closeButtonDisabled={processing}
|
|
57
|
+
>
|
|
58
|
+
<>
|
|
59
|
+
<h2 className="modal-view__header">{header}</h2>
|
|
60
|
+
<div className="modal-view__content">
|
|
61
|
+
<div className="content-container" dangerouslySetInnerHTML={{ __html: message }} />
|
|
62
|
+
<div className="button-container vertical-spacing-top">
|
|
63
|
+
<AUButtonComponent
|
|
64
|
+
label={okButtonText}
|
|
65
|
+
disabled={processing}
|
|
66
|
+
mode={okBtnMode}
|
|
67
|
+
onClick={(event) => {
|
|
68
|
+
if (typeof onClick === 'function') {
|
|
69
|
+
onClick(event, btnRef);
|
|
70
|
+
}
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
{
|
|
74
|
+
confirm && (
|
|
75
|
+
<AUButtonComponent
|
|
76
|
+
label={cancelButtonText}
|
|
77
|
+
disabled={processing}
|
|
78
|
+
type="text"
|
|
79
|
+
onClick={() => {
|
|
80
|
+
hideModal(modalId, btnRef.current as HTMLButtonElement, () => setAlert(false));
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</>
|
|
88
|
+
</AUModalComponent>
|
|
89
|
+
<AUButtonComponent
|
|
90
|
+
label={label}
|
|
91
|
+
disabled={alert}
|
|
92
|
+
size={size}
|
|
93
|
+
type={type}
|
|
94
|
+
icon={icon}
|
|
95
|
+
iconPosition={iconPosition}
|
|
96
|
+
hideLabel={hideLabel}
|
|
97
|
+
mode={mode}
|
|
98
|
+
btnRef={btnRef}
|
|
99
|
+
classNames={classNames}
|
|
100
|
+
ariaExpanded={alert}
|
|
101
|
+
ariaHasPopup
|
|
102
|
+
dataGtm={dataGtm}
|
|
103
|
+
asSubmit={asSubmit}
|
|
104
|
+
onClick={() => {
|
|
105
|
+
setAlert(true);
|
|
106
|
+
}}
|
|
107
|
+
/>
|
|
108
|
+
</>
|
|
109
|
+
);
|
|
67
110
|
};
|
|
68
111
|
|
|
69
112
|
AUAlertComponent.displayName = 'AUAlertComponent';
|
|
@@ -14,6 +14,7 @@ const AUButtonComponent: FC<AUButtonComponentProps> = ({
|
|
|
14
14
|
btnRef,
|
|
15
15
|
classNames,
|
|
16
16
|
ariaExpanded,
|
|
17
|
+
ariaHasPopup,
|
|
17
18
|
asSubmit,
|
|
18
19
|
onClick,
|
|
19
20
|
}: AUButtonComponentProps) => {
|
|
@@ -31,8 +32,8 @@ const AUButtonComponent: FC<AUButtonComponentProps> = ({
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
let modeClass = '';
|
|
34
|
-
if (mode !== 'none') {
|
|
35
|
-
modeClass = `button--${mode}`;
|
|
35
|
+
if (mode && mode !== 'none') {
|
|
36
|
+
modeClass = mode.includes(' ') ? mode.split(' ').map((m) => `button--${m}`).join(' ') : `button--${mode}`;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
return (
|
|
@@ -46,10 +47,11 @@ const AUButtonComponent: FC<AUButtonComponentProps> = ({
|
|
|
46
47
|
typeClass,
|
|
47
48
|
iconClass,
|
|
48
49
|
modeClass,
|
|
49
|
-
disabled && mode
|
|
50
|
+
disabled && !mode?.includes('processing') ? 'visually-disabled' : '',
|
|
50
51
|
].concat(classNames || []).join(' ').replace(/\s+/g, ' ').trim()}
|
|
51
52
|
title={icon && hideLabel ? label : undefined}
|
|
52
53
|
aria-expanded={ariaExpanded}
|
|
54
|
+
aria-haspopup={ariaHasPopup}
|
|
53
55
|
onClick={(event: MouseEvent<HTMLButtonElement>) => {
|
|
54
56
|
if (typeof onClick !== 'undefined') {
|
|
55
57
|
onClick(event, btnRef);
|
|
@@ -71,6 +73,7 @@ AUButtonComponent.defaultProps = {
|
|
|
71
73
|
mode: 'none',
|
|
72
74
|
classNames: [],
|
|
73
75
|
ariaExpanded: false,
|
|
76
|
+
ariaHasPopup: undefined,
|
|
74
77
|
asSubmit: false,
|
|
75
78
|
// eslint-disable-next-line no-console
|
|
76
79
|
onClick: (
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/* eslint-disable jsx-a11y/label-has-associated-control */
|
|
2
|
+
import React, { FC } from 'react';
|
|
3
|
+
|
|
4
|
+
const AUEditFilterComponent: FC = () => (
|
|
5
|
+
<form className="form">
|
|
6
|
+
<h2>Rediger filter</h2>
|
|
7
|
+
<div className="form__field">
|
|
8
|
+
<label htmlFor="title">Titel</label>
|
|
9
|
+
<input type="text" id="title" />
|
|
10
|
+
</div>
|
|
11
|
+
<h3>Kriterier</h3>
|
|
12
|
+
<div>
|
|
13
|
+
<div className="form__field">
|
|
14
|
+
<label htmlFor="orgunit">
|
|
15
|
+
Organisatorisk enhed
|
|
16
|
+
</label>
|
|
17
|
+
<input type="text" id="orgunit" />
|
|
18
|
+
</div>
|
|
19
|
+
<div className="search-filter">
|
|
20
|
+
<h3 className="search-filter__label">Valgte enheder:</h3>
|
|
21
|
+
<div className="search-filter__items">
|
|
22
|
+
<button type="button" className="search-filter__item">
|
|
23
|
+
<span className="search-filter__item__value">
|
|
24
|
+
Arts
|
|
25
|
+
</span>
|
|
26
|
+
</button>
|
|
27
|
+
<button type="button" className="search-filter__item">
|
|
28
|
+
<span className="search-filter__item__value">
|
|
29
|
+
Health
|
|
30
|
+
</span>
|
|
31
|
+
</button>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
<div>
|
|
36
|
+
<div className="form__field">
|
|
37
|
+
<label htmlFor="orgunit">
|
|
38
|
+
Uddannelser
|
|
39
|
+
</label>
|
|
40
|
+
<input type="text" id="orgunit" />
|
|
41
|
+
</div>
|
|
42
|
+
<div className="search-filter">
|
|
43
|
+
<h3 className="search-filter__label">Valgte uddannelser:</h3>
|
|
44
|
+
<div className="search-filter__items">
|
|
45
|
+
<button type="button" className="search-filter__item">
|
|
46
|
+
<span className="search-filter__item__value">
|
|
47
|
+
Bacheloruddannelsen i Medicin
|
|
48
|
+
</span>
|
|
49
|
+
</button>
|
|
50
|
+
<button type="button" className="search-filter__item">
|
|
51
|
+
<span className="search-filter__item__value">
|
|
52
|
+
Kandidatuddannelsen i Medicin
|
|
53
|
+
</span>
|
|
54
|
+
</button>
|
|
55
|
+
<button type="button" className="search-filter__item">
|
|
56
|
+
<span className="search-filter__item__value">
|
|
57
|
+
Den sundhedsfaglige kandidatuddannelse
|
|
58
|
+
</span>
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</form>
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
AUEditFilterComponent.displayName = 'AUEditFilterComponent';
|
|
67
|
+
export default AUEditFilterComponent;
|
|
@@ -13,6 +13,7 @@ const AUToolbarComponent: FC<AUToolbarComponentProps> = ({
|
|
|
13
13
|
title,
|
|
14
14
|
buttonClass,
|
|
15
15
|
buttonElements,
|
|
16
|
+
onCloseContentToggles,
|
|
16
17
|
}: AUToolbarComponentProps) => {
|
|
17
18
|
const toolbarRef = useRef<HTMLDivElement>(null);
|
|
18
19
|
useEffect(() => {
|
|
@@ -28,6 +29,9 @@ const AUToolbarComponent: FC<AUToolbarComponentProps> = ({
|
|
|
28
29
|
// eslint-disable-next-line max-len
|
|
29
30
|
toolbarCleanUp = setToolbar(toolbarRef.current, (toolbar: HTMLElement) => {
|
|
30
31
|
closeAllContentTogglesInToolbar(toolbar);
|
|
32
|
+
if (typeof onCloseContentToggles === 'function') {
|
|
33
|
+
onCloseContentToggles();
|
|
34
|
+
}
|
|
31
35
|
}, false);
|
|
32
36
|
}
|
|
33
37
|
|
|
@@ -95,6 +99,7 @@ AUToolbarComponent.defaultProps = {
|
|
|
95
99
|
title: undefined,
|
|
96
100
|
buttonClass: 'toolbar__toggle',
|
|
97
101
|
buttonElements: [],
|
|
102
|
+
onCloseContentToggles: undefined,
|
|
98
103
|
};
|
|
99
104
|
|
|
100
105
|
AUToolbarComponent.displayName = 'AUToolbarComponent';
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React, { FC, useState } from 'react';
|
|
2
|
+
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
|
3
|
+
import AUAlertComponent from '../src/components/AUAlertComponent';
|
|
4
|
+
import { ThemeWrapper } from './lib/helpers';
|
|
5
|
+
|
|
6
|
+
const AlertWrapper: FC<AUAlertComponentProps> = ({
|
|
7
|
+
confirm,
|
|
8
|
+
label,
|
|
9
|
+
mode,
|
|
10
|
+
header,
|
|
11
|
+
message,
|
|
12
|
+
okButtonText,
|
|
13
|
+
cancelButtonText,
|
|
14
|
+
}) => {
|
|
15
|
+
const [processing, setProcessing] = useState<boolean>(false);
|
|
16
|
+
const [done, setDone] = useState<boolean>(false);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<AUAlertComponent
|
|
20
|
+
modalId="alertModal"
|
|
21
|
+
confirm={confirm}
|
|
22
|
+
label={label}
|
|
23
|
+
mode={mode}
|
|
24
|
+
header={header}
|
|
25
|
+
message={message}
|
|
26
|
+
okButtonText={okButtonText}
|
|
27
|
+
cancelButtonText={cancelButtonText}
|
|
28
|
+
processing={processing}
|
|
29
|
+
done={done}
|
|
30
|
+
onClick={() => {
|
|
31
|
+
setDone(false);
|
|
32
|
+
setProcessing(true);
|
|
33
|
+
setTimeout(() => {
|
|
34
|
+
setDone(true);
|
|
35
|
+
setProcessing(false);
|
|
36
|
+
}, 2500);
|
|
37
|
+
}}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default {
|
|
43
|
+
title: 'Delphinus/Alert and Confirm',
|
|
44
|
+
component: AUAlertComponent,
|
|
45
|
+
argTypes: {
|
|
46
|
+
label: {
|
|
47
|
+
table: {
|
|
48
|
+
disable: true,
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
mode: {
|
|
52
|
+
table: {
|
|
53
|
+
disable: true,
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
onClick: {
|
|
57
|
+
table: {
|
|
58
|
+
disable: true,
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
modalId: {
|
|
62
|
+
table: {
|
|
63
|
+
disable: true,
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
confirm: {
|
|
67
|
+
table: {
|
|
68
|
+
disable: true,
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
processing: {
|
|
72
|
+
table: {
|
|
73
|
+
disable: true,
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
done: {
|
|
77
|
+
table: {
|
|
78
|
+
disable: true,
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
cancelButtonText: {
|
|
82
|
+
table: {
|
|
83
|
+
disable: true,
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
decorators: [
|
|
88
|
+
(Story, context) => (
|
|
89
|
+
<ThemeWrapper theme={context.globals.theme}>
|
|
90
|
+
{Story()}
|
|
91
|
+
</ThemeWrapper>
|
|
92
|
+
)
|
|
93
|
+
],
|
|
94
|
+
} as ComponentMeta<typeof AUAlertComponent>;
|
|
95
|
+
|
|
96
|
+
const Template: ComponentStory<typeof AUAlertComponent> = (args) => <AlertWrapper {...args} />;
|
|
97
|
+
|
|
98
|
+
export const Alert = Template.bind({});
|
|
99
|
+
|
|
100
|
+
Alert.args = {
|
|
101
|
+
label: 'Slet',
|
|
102
|
+
mode: 'ireversable-action',
|
|
103
|
+
header: 'Advarsel',
|
|
104
|
+
message: '<p>Den valgte fil vil blive slettet.</p>',
|
|
105
|
+
okButtonText: 'Ok, forstået',
|
|
106
|
+
onClick: () => console.log('Clicked'),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
export const Confirm = Template.bind({});
|
|
110
|
+
|
|
111
|
+
Confirm.args = {
|
|
112
|
+
confirm: true,
|
|
113
|
+
label: 'Slet',
|
|
114
|
+
mode: 'ireversable-action',
|
|
115
|
+
header: 'Bekræft',
|
|
116
|
+
message: '<p>Er du sikker på, at du vil slette den valgte fil?</p>',
|
|
117
|
+
okButtonText: 'Ja',
|
|
118
|
+
cancelButtonText: 'Annuller',
|
|
119
|
+
onClick: () => console.log('Clicked'),
|
|
120
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
|
3
|
+
import AUEditFilterComponent from '../src/components/AUEditFilterComponent';
|
|
4
|
+
import { ThemeWrapper } from './lib/helpers';
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
title: 'Delphinus/Filters',
|
|
8
|
+
component: AUEditFilterComponent,
|
|
9
|
+
argTypes: {
|
|
10
|
+
},
|
|
11
|
+
decorators: [
|
|
12
|
+
(Story, context) => (
|
|
13
|
+
<ThemeWrapper theme={context.globals.theme}>
|
|
14
|
+
{Story()}
|
|
15
|
+
</ThemeWrapper>
|
|
16
|
+
)
|
|
17
|
+
],
|
|
18
|
+
} as ComponentMeta<typeof AUEditFilterComponent>;
|
|
19
|
+
|
|
20
|
+
const Template: ComponentStory<typeof AUEditFilterComponent> = (args) => (
|
|
21
|
+
<>
|
|
22
|
+
<AUEditFilterComponent {...args} />
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
export const Edit = Template.bind({});
|
|
27
|
+
Edit.args = {
|
|
28
|
+
};
|
|
29
|
+
|
|
@@ -33,6 +33,7 @@ const Template: ComponentStory<typeof AUModalComponent> = (args) => {
|
|
|
33
33
|
<div className="page__content__block">
|
|
34
34
|
<AUButtonComponent
|
|
35
35
|
label="Open modal"
|
|
36
|
+
ariaHasPopup
|
|
36
37
|
onClick={() => updateArgs({ ...args, show: true })}
|
|
37
38
|
/>
|
|
38
39
|
<AUModalComponent {...args} onClose={() => updateArgs({ ...args, show: false })}>
|