@centreon/ui 24.4.45-develop.0 → 24.4.46
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 +5 -1
- package/src/Graph/BarStack/BarStack.cypress.spec.tsx +154 -0
- package/src/Graph/BarStack/BarStack.stories.tsx +123 -0
- package/src/Graph/BarStack/BarStack.styles.ts +36 -0
- package/src/Graph/BarStack/BarStack.tsx +14 -0
- package/src/Graph/BarStack/ResponsiveBarStack.tsx +208 -0
- package/src/Graph/BarStack/index.ts +1 -0
- package/src/Graph/BarStack/models.ts +19 -0
- package/src/Graph/BarStack/useResponsiveBarStack.ts +139 -0
- package/src/Graph/Gauge/Gauge.cypress.spec.tsx +102 -0
- package/src/Graph/Gauge/Gauge.tsx +1 -1
- package/src/Graph/HeatMap/HeatMap.cypress.spec.tsx +145 -0
- package/src/Graph/HeatMap/HeatMap.stories.tsx +0 -25
- package/src/Graph/HeatMap/ResponsiveHeatMap.tsx +8 -2
- package/src/Graph/Legend/Legend.tsx +21 -0
- package/src/Graph/Legend/index.ts +1 -0
- package/src/Graph/Legend/models.ts +11 -0
- package/src/Graph/LineChart/Legend/Legend.styles.ts +1 -1
- package/src/Graph/LineChart/Legend/LegendHeader.tsx +1 -1
- package/src/Graph/LineChart/Legend/useInteractiveValues.ts +2 -2
- package/src/Graph/LineChart/index.tsx +1 -1
- package/src/Graph/PieChart/PieChart.cypress.spec.tsx +169 -0
- package/src/Graph/PieChart/PieChart.stories.tsx +194 -0
- package/src/Graph/PieChart/PieChart.styles.ts +39 -0
- package/src/Graph/PieChart/PieChart.tsx +14 -0
- package/src/Graph/PieChart/ResponsivePie.tsx +251 -0
- package/src/Graph/PieChart/index.ts +1 -0
- package/src/Graph/PieChart/models.ts +19 -0
- package/src/Graph/PieChart/useResponsivePie.ts +86 -0
- package/src/Graph/SingleBar/SingleBar.cypress.spec.tsx +121 -0
- package/src/Graph/Text/Text.cypress.spec.tsx +101 -0
- package/src/Graph/Text/Text.tsx +1 -1
- package/src/Graph/common/testUtils.ts +71 -0
- package/src/Graph/common/timeSeries/index.ts +19 -11
- package/src/Graph/common/utils.ts +19 -0
- package/src/Graph/index.ts +3 -0
- package/src/Graph/translatedLabels.ts +1 -0
- package/src/Listing/ActionBar/index.tsx +9 -8
- package/src/Listing/Cell/DataCell.styles.ts +3 -0
- package/src/Listing/Cell/DataCell.tsx +8 -4
- package/src/Listing/Listing.cypress.spec.tsx +80 -4
- package/src/Listing/Listing.styles.ts +3 -5
- package/src/Listing/index.stories.tsx +25 -2
- package/src/Listing/index.test.tsx +1 -1
- package/src/Listing/index.tsx +3 -1
- package/src/Listing/models.ts +1 -0
- package/src/api/useMutationQuery/index.test.ts +4 -4
- package/src/api/useMutationQuery/index.ts +24 -13
- package/src/components/Form/AccessRights/ShareInput/ContactSwitch.tsx +3 -3
- package/src/components/Form/AccessRights/ShareInput/ShareInput.tsx +1 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/useFullscreen/Fullscreen.cypress.spec.tsx +109 -0
- package/src/utils/useFullscreen/atoms.ts +3 -0
- package/src/utils/useFullscreen/index.ts +2 -0
- package/src/utils/useFullscreen/translatedLabels.ts +1 -0
- package/src/utils/useFullscreen/useFullscreen.ts +73 -0
- package/src/utils/useFullscreen/useFullscreenListener.ts +54 -0
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { makeStyles } from 'tss-react/mui';
|
|
2
2
|
|
|
3
|
-
import { ListingVariant } from '@centreon/ui-context';
|
|
4
|
-
|
|
5
3
|
import { TableStyleAtom as TableStyle } from './models';
|
|
6
4
|
|
|
7
5
|
const loadingIndicatorHeight = 3;
|
|
@@ -9,12 +7,12 @@ const loadingIndicatorHeight = 3;
|
|
|
9
7
|
interface StylesProps {
|
|
10
8
|
dataStyle: TableStyle;
|
|
11
9
|
getGridTemplateColumn: string;
|
|
12
|
-
|
|
10
|
+
isResponsive: string;
|
|
13
11
|
rows: Array<unknown>;
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
const useListingStyles = makeStyles<StylesProps>()(
|
|
17
|
-
(theme, { dataStyle, getGridTemplateColumn, rows }) => ({
|
|
15
|
+
(theme, { dataStyle, getGridTemplateColumn, rows, isResponsive }) => ({
|
|
18
16
|
actionBar: {
|
|
19
17
|
alignItems: 'center',
|
|
20
18
|
display: 'flex'
|
|
@@ -56,7 +54,7 @@ const useListingStyles = makeStyles<StylesProps>()(
|
|
|
56
54
|
gridTemplateColumns: getGridTemplateColumn,
|
|
57
55
|
gridTemplateRows: `${theme.spacing(dataStyle.header.height / 8)} repeat(${
|
|
58
56
|
rows?.length || 1
|
|
59
|
-
}, ${dataStyle.body.height}px)`,
|
|
57
|
+
}, ${isResponsive ? 'auto' : `${dataStyle.body.height}px`})`,
|
|
60
58
|
position: 'relative'
|
|
61
59
|
},
|
|
62
60
|
tableBody: {
|
|
@@ -40,7 +40,7 @@ const useStyles = makeStyles()((theme) => ({
|
|
|
40
40
|
}));
|
|
41
41
|
|
|
42
42
|
const ComponentColumn = ({ row, isSelected }): JSX.Element => (
|
|
43
|
-
|
|
43
|
+
<div style={{ display: 'flex', flexDirection: 'row', flexWrap: 'wrap' }}>
|
|
44
44
|
<span>
|
|
45
45
|
{'I am '}
|
|
46
46
|
<b>{`${isSelected ? 'selected' : 'not selected'}`}</b>
|
|
@@ -50,7 +50,7 @@ const ComponentColumn = ({ row, isSelected }): JSX.Element => (
|
|
|
50
50
|
{'I am '}
|
|
51
51
|
<b>{`${row.active ? 'active' : 'not active'}`}</b>
|
|
52
52
|
</span>
|
|
53
|
-
|
|
53
|
+
</div>
|
|
54
54
|
);
|
|
55
55
|
|
|
56
56
|
const ButtonColumn = ({ row }): JSX.Element => (
|
|
@@ -395,3 +395,26 @@ export const ListingWithSubItems = {
|
|
|
395
395
|
},
|
|
396
396
|
render: TemplateSubItems
|
|
397
397
|
};
|
|
398
|
+
|
|
399
|
+
export const ListingWithResponsive = {
|
|
400
|
+
args: {
|
|
401
|
+
checkable: true,
|
|
402
|
+
columns: [
|
|
403
|
+
...defaultColumns,
|
|
404
|
+
{
|
|
405
|
+
Component: ComponentColumn,
|
|
406
|
+
id: '##',
|
|
407
|
+
label: 'Responsive',
|
|
408
|
+
type: ColumnType.component,
|
|
409
|
+
width: '140px'
|
|
410
|
+
}
|
|
411
|
+
],
|
|
412
|
+
currentPage: 1,
|
|
413
|
+
isResponsive: true,
|
|
414
|
+
limit: 10,
|
|
415
|
+
loading: false,
|
|
416
|
+
rows: listingWithSubItems,
|
|
417
|
+
totalRows: 10
|
|
418
|
+
},
|
|
419
|
+
render: TemplateSubItems
|
|
420
|
+
};
|
package/src/Listing/index.tsx
CHANGED
|
@@ -102,6 +102,7 @@ export interface Props<TRow> {
|
|
|
102
102
|
getId?: (row: TRow) => RowId;
|
|
103
103
|
headerMemoProps?: Array<unknown>;
|
|
104
104
|
innerScrollDisabled?: boolean;
|
|
105
|
+
isResponsive?: boolean;
|
|
105
106
|
limit?: number;
|
|
106
107
|
listingVariant?: ListingVariant;
|
|
107
108
|
loading?: boolean;
|
|
@@ -147,6 +148,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
147
148
|
columns,
|
|
148
149
|
columnConfiguration = defaultColumnConfiguration,
|
|
149
150
|
customPaginationClassName,
|
|
151
|
+
isResponsive = false,
|
|
150
152
|
onResetColumns,
|
|
151
153
|
onSelectColumns,
|
|
152
154
|
rows = [],
|
|
@@ -233,7 +235,7 @@ const Listing = <TRow extends { id: RowId }>({
|
|
|
233
235
|
const { classes } = useListingStyles({
|
|
234
236
|
dataStyle,
|
|
235
237
|
getGridTemplateColumn,
|
|
236
|
-
|
|
238
|
+
isResponsive,
|
|
237
239
|
rows: rowsToDisplay
|
|
238
240
|
});
|
|
239
241
|
|
package/src/Listing/models.ts
CHANGED
|
@@ -48,7 +48,7 @@ describe('useFetchQuery', () => {
|
|
|
48
48
|
method: Method.POST
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
result.current.mutate(user);
|
|
51
|
+
result.current.mutate({ payload: user });
|
|
52
52
|
|
|
53
53
|
await waitFor(() => {
|
|
54
54
|
expect(result.current?.isError).toEqual(false);
|
|
@@ -64,7 +64,7 @@ describe('useFetchQuery', () => {
|
|
|
64
64
|
method: Method.POST
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
result.current.mutate(user);
|
|
67
|
+
result.current.mutate({ payload: user });
|
|
68
68
|
|
|
69
69
|
await waitFor(() => {
|
|
70
70
|
expect(result.current?.isError).toEqual(true);
|
|
@@ -85,7 +85,7 @@ describe('useFetchQuery', () => {
|
|
|
85
85
|
method: Method.POST
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
result.current.mutate(user);
|
|
88
|
+
result.current.mutate({ payload: user });
|
|
89
89
|
|
|
90
90
|
await waitFor(() => {
|
|
91
91
|
expect(result.current?.isError).toEqual(true);
|
|
@@ -109,7 +109,7 @@ describe('useFetchQuery', () => {
|
|
|
109
109
|
method: Method.POST
|
|
110
110
|
});
|
|
111
111
|
|
|
112
|
-
result.current.mutate(user);
|
|
112
|
+
result.current.mutate({ payload: user });
|
|
113
113
|
|
|
114
114
|
await waitFor(() => {
|
|
115
115
|
expect(mockedShowErrorMessage).not.toHaveBeenCalled();
|
|
@@ -22,6 +22,11 @@ export enum Method {
|
|
|
22
22
|
PUT = 'PUT'
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
interface Variables<TMeta, T> {
|
|
26
|
+
_meta?: TMeta;
|
|
27
|
+
payload?: T;
|
|
28
|
+
}
|
|
29
|
+
|
|
25
30
|
export type UseMutationQueryProps<T, TMeta> = {
|
|
26
31
|
baseEndpoint?: string;
|
|
27
32
|
catchError?: (props: CatchErrorProps) => void;
|
|
@@ -33,30 +38,36 @@ export type UseMutationQueryProps<T, TMeta> = {
|
|
|
33
38
|
method: Method;
|
|
34
39
|
onError?: (
|
|
35
40
|
error: ResponseError,
|
|
36
|
-
variables:
|
|
41
|
+
variables: Variables<TMeta, T>,
|
|
37
42
|
context: unknown
|
|
38
43
|
) => unknown;
|
|
39
|
-
onMutate?: (variables:
|
|
44
|
+
onMutate?: (variables: Variables<TMeta, T>) => Promise<unknown> | unknown;
|
|
40
45
|
onSuccess?: (
|
|
41
46
|
data: ResponseError | T,
|
|
42
|
-
variables: T
|
|
43
|
-
_meta: TMeta;
|
|
44
|
-
},
|
|
47
|
+
variables: Variables<TMeta, T>,
|
|
45
48
|
context: unknown
|
|
46
49
|
) => unknown;
|
|
47
50
|
} & Omit<
|
|
48
|
-
UseMutationOptions<
|
|
49
|
-
'mutationFn' | 'onError' | 'onMutate' | 'onSuccess'
|
|
51
|
+
UseMutationOptions<{ _meta?: TMeta; payload: T }>,
|
|
52
|
+
'mutationFn' | 'onError' | 'onMutate' | 'onSuccess' | 'mutateAsync' | 'mutate'
|
|
50
53
|
>;
|
|
51
54
|
|
|
52
55
|
const log = anylogger('API Request');
|
|
53
56
|
|
|
54
|
-
export type UseMutationQueryState<T> = Omit<
|
|
57
|
+
export type UseMutationQueryState<T, TMeta> = Omit<
|
|
55
58
|
UseMutationResult<T | ResponseError>,
|
|
56
|
-
'isError'
|
|
59
|
+
'isError' | 'mutate' | 'mutateAsync'
|
|
57
60
|
> & {
|
|
58
61
|
isError: boolean;
|
|
59
62
|
isMutating: boolean;
|
|
63
|
+
mutate: (variables: Variables<TMeta, T>) => ResponseError | T;
|
|
64
|
+
mutateAsync: (
|
|
65
|
+
variables: Variables<TMeta, T>,
|
|
66
|
+
rest?: Pick<
|
|
67
|
+
UseMutationQueryProps<T, TMeta>,
|
|
68
|
+
'onError' | 'onMutate' | 'onSettled' | 'onSuccess'
|
|
69
|
+
>
|
|
70
|
+
) => Promise<ResponseError | T>;
|
|
60
71
|
};
|
|
61
72
|
|
|
62
73
|
const useMutationQuery = <T extends object, TMeta>({
|
|
@@ -72,18 +83,18 @@ const useMutationQuery = <T extends object, TMeta>({
|
|
|
72
83
|
onSuccess,
|
|
73
84
|
onSettled,
|
|
74
85
|
baseEndpoint
|
|
75
|
-
}: UseMutationQueryProps<T, TMeta>): UseMutationQueryState<T> => {
|
|
86
|
+
}: UseMutationQueryProps<T, TMeta>): UseMutationQueryState<T, TMeta> => {
|
|
76
87
|
const { showErrorMessage } = useSnackbar();
|
|
77
88
|
|
|
78
89
|
const queryData = useMutation<
|
|
79
90
|
T | ResponseError,
|
|
80
91
|
ResponseError,
|
|
81
|
-
|
|
92
|
+
Variables<TMeta, T>
|
|
82
93
|
>({
|
|
83
94
|
mutationFn: (
|
|
84
|
-
|
|
95
|
+
variables: Variables<TMeta, T>
|
|
85
96
|
): Promise<T | ResponseError> => {
|
|
86
|
-
const { _meta,
|
|
97
|
+
const { _meta, payload } = variables || {};
|
|
87
98
|
|
|
88
99
|
return customFetch<T>({
|
|
89
100
|
baseEndpoint,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useAtom } from 'jotai';
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
|
|
4
4
|
import { FormControlLabel, Radio, RadioGroup } from '@mui/material';
|
|
@@ -17,7 +17,7 @@ const ContactSwitch = ({ labels }: Props): JSX.Element => {
|
|
|
17
17
|
const { classes } = useContactSwitchStyles();
|
|
18
18
|
const { t } = useTranslation();
|
|
19
19
|
|
|
20
|
-
const setContactType =
|
|
20
|
+
const [contactType, setContactType] = useAtom(contactTypeAtom);
|
|
21
21
|
|
|
22
22
|
const change = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
|
23
23
|
setContactType(event.target.value as ContactType);
|
|
@@ -29,7 +29,7 @@ const ContactSwitch = ({ labels }: Props): JSX.Element => {
|
|
|
29
29
|
<RadioGroup
|
|
30
30
|
row
|
|
31
31
|
className={classes.inputs}
|
|
32
|
-
|
|
32
|
+
value={contactType}
|
|
33
33
|
onChange={change}
|
|
34
34
|
>
|
|
35
35
|
<FormControlLabel
|
|
@@ -52,6 +52,7 @@ const ShareInput = ({ labels, endpoints, roles }: Props): JSX.Element => {
|
|
|
52
52
|
? t(labels.autocompleteContactGroup)
|
|
53
53
|
: t(labels.autocompleteContact)
|
|
54
54
|
)}
|
|
55
|
+
queryKey={isContactGroup ? labels.contactGroup : labels.contact}
|
|
55
56
|
renderOption={renderOption}
|
|
56
57
|
value={selectedContact}
|
|
57
58
|
onChange={selectContact}
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { Provider, createStore } from 'jotai';
|
|
2
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
3
|
+
|
|
4
|
+
import { Button } from '@mui/material';
|
|
5
|
+
|
|
6
|
+
import { useFullscreen } from './useFullscreen';
|
|
7
|
+
import { router, useFullscreenListener } from './useFullscreenListener';
|
|
8
|
+
|
|
9
|
+
const labelEnterFullscreen = 'Enter fullscreen';
|
|
10
|
+
const labelExitFullscreen = 'Exit fullscreen';
|
|
11
|
+
|
|
12
|
+
const ChildComponent = (): JSX.Element => {
|
|
13
|
+
const { toggleFullscreen, fullscreenEnabled, isFullscreenActivated } =
|
|
14
|
+
useFullscreen();
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<div
|
|
18
|
+
data-fullscreenActivated={isFullscreenActivated}
|
|
19
|
+
data-fullscreenEnabled={fullscreenEnabled}
|
|
20
|
+
id="test"
|
|
21
|
+
>
|
|
22
|
+
<Button onClick={() => toggleFullscreen(document.body)}>
|
|
23
|
+
{isFullscreenActivated ? labelExitFullscreen : labelEnterFullscreen}
|
|
24
|
+
</Button>
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const TestComponent = (): JSX.Element => {
|
|
30
|
+
useFullscreenListener();
|
|
31
|
+
|
|
32
|
+
return <ChildComponent />;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const initialize = (): void => {
|
|
36
|
+
const store = createStore();
|
|
37
|
+
|
|
38
|
+
const queryParameters = new Map();
|
|
39
|
+
|
|
40
|
+
cy.stub(router, 'useSearchParams', () => queryParameters);
|
|
41
|
+
|
|
42
|
+
cy.mount({
|
|
43
|
+
Component: (
|
|
44
|
+
<BrowserRouter>
|
|
45
|
+
<Provider store={store}>
|
|
46
|
+
<TestComponent />
|
|
47
|
+
</Provider>
|
|
48
|
+
</BrowserRouter>
|
|
49
|
+
)
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
describe('Fullscreen', () => {
|
|
54
|
+
it('enters fullscreen mode when the button is clicked', () => {
|
|
55
|
+
initialize();
|
|
56
|
+
|
|
57
|
+
cy.get('#test')
|
|
58
|
+
.should('have.attr', 'data-fullscreenActivated', 'false')
|
|
59
|
+
.should('have.attr', 'data-fullscreenEnabled', 'true');
|
|
60
|
+
|
|
61
|
+
cy.contains(labelEnterFullscreen).realClick();
|
|
62
|
+
|
|
63
|
+
cy.get('#test')
|
|
64
|
+
.should('have.attr', 'data-fullscreenActivated', 'true')
|
|
65
|
+
.should('have.attr', 'data-fullscreenEnabled', 'true');
|
|
66
|
+
|
|
67
|
+
cy.contains(labelExitFullscreen).realClick();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('exits fullscreen mode when the button is clicked', () => {
|
|
71
|
+
initialize();
|
|
72
|
+
|
|
73
|
+
cy.get('#test')
|
|
74
|
+
.should('have.attr', 'data-fullscreenActivated', 'false')
|
|
75
|
+
.should('have.attr', 'data-fullscreenEnabled', 'true');
|
|
76
|
+
|
|
77
|
+
cy.contains(labelEnterFullscreen).realClick();
|
|
78
|
+
|
|
79
|
+
cy.get('#test')
|
|
80
|
+
.should('have.attr', 'data-fullscreenActivated', 'true')
|
|
81
|
+
.should('have.attr', 'data-fullscreenEnabled', 'true');
|
|
82
|
+
|
|
83
|
+
cy.contains(labelExitFullscreen).realClick();
|
|
84
|
+
|
|
85
|
+
cy.get('#test')
|
|
86
|
+
.should('have.attr', 'data-fullscreenActivated', 'false')
|
|
87
|
+
.should('have.attr', 'data-fullscreenEnabled', 'true');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('toggles fullscreen mode when the corresponding shortcut is clicked', () => {
|
|
91
|
+
initialize();
|
|
92
|
+
|
|
93
|
+
cy.get('#test')
|
|
94
|
+
.should('have.attr', 'data-fullscreenActivated', 'false')
|
|
95
|
+
.should('have.attr', 'data-fullscreenEnabled', 'true');
|
|
96
|
+
|
|
97
|
+
cy.get('#test').realPress(['Alt', 'F']);
|
|
98
|
+
|
|
99
|
+
cy.get('#test')
|
|
100
|
+
.should('have.attr', 'data-fullscreenActivated', 'true')
|
|
101
|
+
.should('have.attr', 'data-fullscreenEnabled', 'true');
|
|
102
|
+
|
|
103
|
+
cy.get('#test').realPress(['Alt', 'F']);
|
|
104
|
+
|
|
105
|
+
cy.get('#test')
|
|
106
|
+
.should('have.attr', 'data-fullscreenActivated', 'false')
|
|
107
|
+
.should('have.attr', 'data-fullscreenEnabled', 'true');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const labelCannotEnterInFullscreen = 'Cannot enter fullscreen mode';
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { useTranslation } from 'react-i18next';
|
|
2
|
+
import { useAtom } from 'jotai';
|
|
3
|
+
|
|
4
|
+
import { useSnackbar } from '../..';
|
|
5
|
+
|
|
6
|
+
import { labelCannotEnterInFullscreen } from './translatedLabels';
|
|
7
|
+
import { isFullscreenActivatedAtom } from './atoms';
|
|
8
|
+
|
|
9
|
+
interface UseFullscreenState {
|
|
10
|
+
enterInFullscreen: (element: HTMLElement | null) => void;
|
|
11
|
+
exitFullscreen: () => void;
|
|
12
|
+
fullscreenEnabled: boolean;
|
|
13
|
+
isFullscreenActivated: boolean;
|
|
14
|
+
resetVariables: () => void;
|
|
15
|
+
toggleFullscreen: (element: HTMLElement | null) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const useFullscreen = (): UseFullscreenState => {
|
|
19
|
+
const { t } = useTranslation();
|
|
20
|
+
|
|
21
|
+
const { showErrorMessage } = useSnackbar();
|
|
22
|
+
|
|
23
|
+
const [isFullscreenActivated, setIsFullscreenActivated] = useAtom(
|
|
24
|
+
isFullscreenActivatedAtom
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const resetVariables = (): void => {
|
|
28
|
+
setIsFullscreenActivated(false);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const enterInFullscreen = (element: HTMLElement | null): void => {
|
|
32
|
+
if (!document.fullscreenEnabled) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (!element) {
|
|
37
|
+
showErrorMessage(t(labelCannotEnterInFullscreen));
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
element
|
|
41
|
+
?.requestFullscreen({ navigationUI: 'show' })
|
|
42
|
+
.then(() => {
|
|
43
|
+
setIsFullscreenActivated(true);
|
|
44
|
+
})
|
|
45
|
+
.catch(() => {
|
|
46
|
+
showErrorMessage(t(labelCannotEnterInFullscreen));
|
|
47
|
+
setIsFullscreenActivated(false);
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const exitFullscreen = (): void => {
|
|
52
|
+
document.exitFullscreen().then(resetVariables);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const toggleFullscreen = (element: HTMLElement | null): void => {
|
|
56
|
+
if (isFullscreenActivated) {
|
|
57
|
+
exitFullscreen();
|
|
58
|
+
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
enterInFullscreen(element);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
enterInFullscreen,
|
|
67
|
+
exitFullscreen,
|
|
68
|
+
fullscreenEnabled: document.fullscreenEnabled,
|
|
69
|
+
isFullscreenActivated,
|
|
70
|
+
resetVariables,
|
|
71
|
+
toggleFullscreen
|
|
72
|
+
};
|
|
73
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
|
+
|
|
3
|
+
import { equals } from 'ramda';
|
|
4
|
+
import { useSearchParams } from 'react-router-dom';
|
|
5
|
+
|
|
6
|
+
import { useDeepCompare } from '../useMemoComponent';
|
|
7
|
+
|
|
8
|
+
import { useFullscreen } from './useFullscreen';
|
|
9
|
+
|
|
10
|
+
export const router = {
|
|
11
|
+
useSearchParams
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const useFullscreenListener = (): boolean => {
|
|
15
|
+
const { toggleFullscreen, resetVariables, isFullscreenActivated } =
|
|
16
|
+
useFullscreen();
|
|
17
|
+
|
|
18
|
+
const toggle = (event: KeyboardEvent): void => {
|
|
19
|
+
if (!event.altKey || !equals(event.code, 'KeyF')) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
toggleFullscreen(document.querySelector('body'));
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const changeFullscreen = (): void => {
|
|
27
|
+
if (document.fullscreenElement) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
resetVariables();
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
useEffect(
|
|
35
|
+
() => {
|
|
36
|
+
document.addEventListener('fullscreenchange', changeFullscreen);
|
|
37
|
+
|
|
38
|
+
return () => {
|
|
39
|
+
document.removeEventListener('fullscreenchange', changeFullscreen);
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
useDeepCompare([document.fullscreenElement])
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
window.addEventListener('keypress', toggle);
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
window.removeEventListener('keypress', toggle);
|
|
50
|
+
};
|
|
51
|
+
}, [isFullscreenActivated]);
|
|
52
|
+
|
|
53
|
+
return isFullscreenActivated;
|
|
54
|
+
};
|