@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 CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "sideEffects": false,
3
3
  "name": "@aarhus-university/au-lib-react-components",
4
- "version": "11.4.2",
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.35.1",
75
+ "@aarhus-university/au-designsystem-delphinus": "0.39.3",
76
76
  "@aarhus-university/au-designsystem-delphinus-dev": "0.2.0",
77
- "@aarhus-university/types": "^0.17.13",
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, { FC } from 'react';
4
- import ReactDOM from 'react-dom';
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
- children,
9
- alert,
10
- buttons,
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 renderButtons = (buttons || []).map((button) => (
13
- <button
14
- key={button.text}
15
- type="button"
16
- className={button.className}
17
- data-icon={button.dataIcon}
18
- onClick={() => {
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
- if (alert) {
27
- return (
28
- <>
29
- {
30
- ReactDOM.createPortal(
31
- <div key="0" className="theme--normal toast-notification toast-notification--attention toast-notification--persistent">
32
- <div className="toast-notification__content">
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
- if (!children) {
46
- return null;
47
- }
48
-
49
- return children;
50
- };
51
-
52
- AUAlertComponent.defaultProps = {
53
- buttons: [{
54
- className: 'button',
55
- text: 'OK',
56
- dataIcon: null,
57
- // eslint-disable-next-line no-console
58
- onClick: () => console.log('clicked on OK'),
59
- }, {
60
- className: 'button',
61
- text: 'Annuller',
62
- dataIcon: null,
63
- // eslint-disable-next-line no-console
64
- onClick: () => console.log('clicked on cancel'),
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 !== 'processing' ? 'visually-disabled' : '',
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 })}>
@@ -323,4 +323,5 @@ Filter.args = {
323
323
  </div>
324
324
  </AUContentToggleComponent>
325
325
  ],
326
+ onCloseContentToggles: () => console.log('luuuuuk?'),
326
327
  };