@linzjs/windows 4.1.3 → 5.0.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/dist/LuiModalAsync/LuiModalAsync.scss +1 -1
- package/dist/LuiModalAsync/LuiModalAsync.tsx +17 -13
- package/dist/LuiModalAsync/LuiModalAsyncButtonGroup.tsx +12 -12
- package/dist/LuiModalAsync/LuiModalAsyncContent.tsx +2 -2
- package/dist/LuiModalAsync/LuiModalAsyncContext.tsx +10 -7
- package/dist/LuiModalAsync/LuiModalAsyncContextProvider.tsx +25 -16
- package/dist/LuiModalAsync/LuiModalAsyncHeader.tsx +18 -18
- package/dist/LuiModalAsync/LuiModalAsyncInstanceContext.ts +3 -2
- package/dist/LuiModalAsync/LuiModalAsyncMain.tsx +2 -2
- package/dist/LuiModalAsync/index.ts +10 -10
- package/dist/LuiModalAsync/useLuiModalPrefab.tsx +50 -49
- package/dist/LuiModalAsync/useShowAsyncModal.ts +6 -4
- package/dist/common/index.ts +1 -1
- package/dist/common/useConstFunction.ts +1 -1
- package/dist/index.ts +4 -4
- package/dist/panel/OpenPanelButton.tsx +4 -3
- package/dist/panel/OpenPanelIcon.scss +3 -4
- package/dist/panel/OpenPanelIcon.tsx +12 -12
- package/dist/panel/Panel.scss +6 -6
- package/dist/panel/Panel.tsx +18 -17
- package/dist/panel/PanelBlue.scss +3 -3
- package/dist/panel/PanelContext.ts +4 -3
- package/dist/panel/PanelDock.tsx +6 -5
- package/dist/panel/PanelHeader.tsx +25 -25
- package/dist/panel/PanelHeaderButton.tsx +8 -8
- package/dist/panel/PanelInstanceContext.ts +5 -5
- package/dist/panel/PanelInstanceContextProvider.tsx +6 -5
- package/dist/panel/PanelsContext.tsx +5 -4
- package/dist/panel/PanelsContextProvider.tsx +12 -11
- package/dist/panel/PopinWIndow.tsx +23 -22
- package/dist/panel/PopoutWindow.tsx +18 -17
- package/dist/panel/generateId.ts +12 -12
- package/dist/panel/handleStyleSheetsChanges.ts +7 -7
- package/dist/panel/index.ts +12 -13
- package/dist/panel/types/PanelProps.ts +5 -4
- package/dist/panel/types/PanelRestoredState.ts +2 -2
- package/dist/panel/types/PanelState.ts +3 -3
- package/dist/panel/types/PanelStateOptions.ts +3 -3
- package/dist/panel/types/index.ts +6 -6
- package/dist/panel/usePanelStateHandler.tsx +12 -11
- package/package.json +51 -69
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
@use "
|
|
2
|
-
@use "node_modules/@linzjs/lui/dist/scss/Foundation/Variables/ColorVars.scss" as colours;
|
|
1
|
+
@use "@linzjs/lui/dist/scss/Core" as lui;
|
|
3
2
|
|
|
4
3
|
.lui-button.lui-button-toolbar {
|
|
5
4
|
border-color: transparent;
|
|
@@ -53,7 +52,7 @@
|
|
|
53
52
|
margin: 6px 0;
|
|
54
53
|
height: 2px;
|
|
55
54
|
width: 100%;
|
|
56
|
-
background-color:
|
|
55
|
+
background-color: lui.$grey-10;
|
|
57
56
|
}
|
|
58
57
|
}
|
|
59
58
|
|
|
@@ -68,6 +67,6 @@
|
|
|
68
67
|
margin-top: -3px;
|
|
69
68
|
padding-bottom: 8px;
|
|
70
69
|
width: 2px;
|
|
71
|
-
background-color:
|
|
70
|
+
background-color: lui.$grey-10;
|
|
72
71
|
}
|
|
73
72
|
}
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import './OpenPanelIcon.scss';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import { LuiIcon } from '@linzjs/lui';
|
|
4
|
+
import { IconName } from '@linzjs/lui/dist/components/LuiIcon/LuiIcon';
|
|
5
|
+
import clsx from 'clsx';
|
|
6
|
+
import { ReactNode, useContext } from 'react';
|
|
6
7
|
|
|
7
|
-
import {
|
|
8
|
-
import { IconName } from "@linzjs/lui/dist/components/LuiIcon/LuiIcon";
|
|
8
|
+
import { OpenPanelOptions, PanelsContext } from './PanelsContext';
|
|
9
9
|
|
|
10
10
|
export const ButtonIconHorizontalGroup = ({ children }: { children: ReactNode }) => (
|
|
11
11
|
<div>
|
|
12
|
-
<div className={
|
|
12
|
+
<div className={'OpenPanelIcon-horizontalGroup'}>{children}</div>
|
|
13
13
|
</div>
|
|
14
14
|
);
|
|
15
15
|
|
|
16
16
|
export const ButtonIconVerticalGroup = ({ children }: { children: ReactNode }) => (
|
|
17
17
|
<div>
|
|
18
|
-
<div className={
|
|
18
|
+
<div className={'OpenPanelIcon-verticalGroup'}>{children}</div>
|
|
19
19
|
</div>
|
|
20
20
|
);
|
|
21
21
|
|
|
@@ -45,16 +45,16 @@ export const OpenPanelIcon = ({
|
|
|
45
45
|
type="button"
|
|
46
46
|
className={clsx(
|
|
47
47
|
className,
|
|
48
|
-
|
|
49
|
-
openPanels.has(uniqueId) &&
|
|
50
|
-
disabled &&
|
|
48
|
+
'lui-button lui-button-secondary lui-button-toolbar panel-button',
|
|
49
|
+
openPanels.has(uniqueId) && 'OpenPanelIcon-selected',
|
|
50
|
+
disabled && 'OpenPanelIcon-disabled',
|
|
51
51
|
)}
|
|
52
52
|
title={iconTitle}
|
|
53
53
|
onClick={() => openPanel({ uniqueId, ...openPanelOptions })}
|
|
54
54
|
disabled={disabled}
|
|
55
55
|
data-testid={testId}
|
|
56
56
|
>
|
|
57
|
-
<LuiIcon name={icon} alt={iconTitle} size={
|
|
57
|
+
<LuiIcon name={icon} alt={iconTitle} size={'md'} />
|
|
58
58
|
</button>
|
|
59
59
|
);
|
|
60
60
|
};
|
package/dist/panel/Panel.scss
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@use "
|
|
1
|
+
@use "@linzjs/lui/dist/scss/Core" as lui;
|
|
2
2
|
|
|
3
3
|
.panelDock > .panelDock-content:not(:empty) + .panelDock-empty {
|
|
4
4
|
display: none;
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
.WindowPanel-header {
|
|
15
15
|
height: 48px;
|
|
16
16
|
line-height: 48px;
|
|
17
|
-
color:
|
|
17
|
+
color: lui.$charcoal;
|
|
18
18
|
padding: 0 16px;
|
|
19
19
|
display: flex;
|
|
20
20
|
overflow: hidden;
|
|
21
21
|
justify-content: space-between;
|
|
22
|
-
border-bottom: 2px
|
|
22
|
+
border-bottom: 2px lui.$lily solid;
|
|
23
23
|
font-size: 1em;
|
|
24
24
|
font-weight: 600;
|
|
25
25
|
flex-direction: row;
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
%WindowPanel-divider {
|
|
72
|
-
border-left: 2px solid
|
|
73
|
-
background-color:
|
|
72
|
+
border-left: 2px solid lui.$lily;
|
|
73
|
+
background-color: lui.$lily;
|
|
74
74
|
width: 0;
|
|
75
75
|
height: 19px;
|
|
76
76
|
}
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
.WindowPanel-header-title-icon {
|
|
113
|
-
fill:
|
|
113
|
+
fill: lui.$fuscous !important;
|
|
114
114
|
margin-right: 8px;
|
|
115
115
|
}
|
|
116
116
|
|
package/dist/panel/Panel.tsx
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
1
|
+
import './Panel.scss';
|
|
2
|
+
import './PanelBlue.scss';
|
|
3
|
+
import '@linzjs/lui/dist/scss/base.scss';
|
|
4
4
|
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
5
|
+
import clsx from 'clsx';
|
|
6
|
+
import { PropsWithChildren, ReactElement, useContext, useEffect, useMemo, useRef } from 'react';
|
|
7
|
+
import { createPortal } from 'react-dom';
|
|
8
|
+
|
|
9
|
+
import { useConstFunction } from '../common';
|
|
10
|
+
import { PanelInstanceContext } from './PanelInstanceContext';
|
|
11
|
+
import { PanelsContext } from './PanelsContext';
|
|
12
|
+
import { PopinWindow } from './PopinWIndow';
|
|
13
|
+
import { PopoutWindow } from './PopoutWindow';
|
|
14
|
+
import { PanelProps } from './types/PanelProps';
|
|
14
15
|
|
|
15
16
|
export const Panel = (props: PanelProps): ReactElement => {
|
|
16
17
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
@@ -49,7 +50,7 @@ export const Panel = (props: PanelProps): ReactElement => {
|
|
|
49
50
|
|
|
50
51
|
const memoizeNextStackPosition = useMemo(
|
|
51
52
|
() => {
|
|
52
|
-
if (props.position === undefined || props.position ===
|
|
53
|
+
if (props.position === undefined || props.position === 'tile') {
|
|
53
54
|
return nextStackPosition();
|
|
54
55
|
}
|
|
55
56
|
|
|
@@ -68,10 +69,10 @@ export const Panel = (props: PanelProps): ReactElement => {
|
|
|
68
69
|
<div
|
|
69
70
|
ref={panelRef}
|
|
70
71
|
style={{
|
|
71
|
-
display:
|
|
72
|
-
flexDirection:
|
|
73
|
-
width:
|
|
74
|
-
height:
|
|
72
|
+
display: 'flex',
|
|
73
|
+
flexDirection: 'column',
|
|
74
|
+
width: '100%',
|
|
75
|
+
height: '100%',
|
|
75
76
|
}}
|
|
76
77
|
className={className}
|
|
77
78
|
>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
@use "
|
|
1
|
+
@use "@linzjs/lui/dist/scss/Core" as lui;
|
|
2
2
|
|
|
3
3
|
.WindowPanel-blue.WindowPanel-header, .WindowPanel-blue .WindowPanel-header {
|
|
4
4
|
background: linear-gradient(270deg,#007198,#00425b 100%);
|
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.WindowPanel-blue .LuiTab {
|
|
13
|
-
color:
|
|
13
|
+
color: lui.$iceberg
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.WindowPanel-blue .LuiTab.LuiTab--active {
|
|
17
|
-
color:
|
|
17
|
+
color: lui.$downy
|
|
18
18
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { createContext } from
|
|
2
|
-
|
|
1
|
+
import { createContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import { PanelSize } from './types';
|
|
3
4
|
|
|
4
5
|
export interface PanelContextType {
|
|
5
6
|
resizePanel: (size: Partial<PanelSize>) => void;
|
|
@@ -7,7 +8,7 @@ export interface PanelContextType {
|
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
const NoContextError = () => {
|
|
10
|
-
console.error(
|
|
11
|
+
console.error('Missing PanelContext Provider');
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
/**
|
package/dist/panel/PanelDock.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { PropsWithChildren, ReactElement, useContext } from 'react';
|
|
2
|
+
|
|
3
|
+
import { PanelsContext } from './PanelsContext';
|
|
3
4
|
|
|
4
5
|
export interface PanelDockProps {
|
|
5
6
|
id: string;
|
|
@@ -11,9 +12,9 @@ export const PanelDock = ({ id, children }: PropsWithChildren<PanelDockProps>):
|
|
|
11
12
|
const setElement = (element: HTMLDivElement) => setDockElement(id, element);
|
|
12
13
|
|
|
13
14
|
return (
|
|
14
|
-
<div className={
|
|
15
|
-
<div ref={setElement} className={
|
|
16
|
-
<div className={
|
|
15
|
+
<div className={'panelDock'}>
|
|
16
|
+
<div ref={setElement} className={'panelDock-content'} />
|
|
17
|
+
<div className={'panelDock-empty'}>{children}</div>
|
|
17
18
|
</div>
|
|
18
19
|
);
|
|
19
20
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import { LuiIcon } from '@linzjs/lui';
|
|
2
|
+
import { LuiIconName } from '@linzjs/lui/dist/assets/svg-content';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { ReactNode, useContext, useState } from 'react';
|
|
4
5
|
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import clsx from "clsx";
|
|
6
|
+
import { PanelContext } from './PanelContext';
|
|
7
|
+
import { PanelHeaderButton } from './PanelHeaderButton';
|
|
8
|
+
import { PanelInstanceContext } from './PanelInstanceContext';
|
|
9
9
|
|
|
10
10
|
export interface PanelHeaderProps {
|
|
11
11
|
icon?: LuiIconName;
|
|
@@ -33,49 +33,49 @@ export const PanelHeader = ({
|
|
|
33
33
|
const { resizeable } = useContext(PanelContext);
|
|
34
34
|
const { panelClose, panelTogglePopout, panelPoppedOut, title, dock, undock, docked } =
|
|
35
35
|
useContext(PanelInstanceContext);
|
|
36
|
-
const [cursor, setCursor] = useState<
|
|
36
|
+
const [cursor, setCursor] = useState<'grab' | 'grabbing'>('grab');
|
|
37
37
|
|
|
38
38
|
const headerMouseDown = () => {
|
|
39
|
-
!panelPoppedOut && setCursor(
|
|
39
|
+
!panelPoppedOut && setCursor('grabbing');
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
return (
|
|
43
43
|
<div
|
|
44
|
-
className={clsx(
|
|
44
|
+
className={clsx('WindowPanel-header', resizeable && 'draggable-handle')}
|
|
45
45
|
onMouseDown={headerMouseDown}
|
|
46
|
-
onMouseUp={() => !panelPoppedOut && setCursor(
|
|
46
|
+
onMouseUp={() => !panelPoppedOut && setCursor('grab')}
|
|
47
47
|
style={resizeable ? { cursor } : {}}
|
|
48
48
|
>
|
|
49
|
-
<div className={
|
|
50
|
-
{icon && <LuiIcon name={icon} alt={
|
|
49
|
+
<div className={'WindowPanel-header-title'}>
|
|
50
|
+
{icon && <LuiIcon name={icon} alt={'icon'} size={'md'} className={'WindowPanel-header-title-icon'} />}
|
|
51
51
|
{title}
|
|
52
52
|
</div>
|
|
53
|
-
{extraLeft && <div className={
|
|
54
|
-
<div className={
|
|
55
|
-
<div className={
|
|
53
|
+
{extraLeft && <div className={'WindowPanel-divider-left'} />}
|
|
54
|
+
<div className={'WindowPanel-children'}>{extraLeft}</div>
|
|
55
|
+
<div className={'WindowPanel-buttons'}>
|
|
56
56
|
{extraRight}
|
|
57
57
|
{(helpUrl || onHelpClick) && (
|
|
58
|
-
<PanelHeaderButton aria-label={
|
|
58
|
+
<PanelHeaderButton aria-label={'Help'} href={helpUrl} onClick={onHelpClick} icon={'ic_help_outline'} />
|
|
59
59
|
)}
|
|
60
60
|
</div>
|
|
61
|
-
{(dockTo || !disablePopout || !disableClose) && <div className={
|
|
62
|
-
<div className={
|
|
63
|
-
{onDockClick && <PanelHeaderButton aria-label={
|
|
61
|
+
{(dockTo || !disablePopout || !disableClose) && <div className={'WindowPanel-divider-right'} />}
|
|
62
|
+
<div className={'WindowPanel-buttons'}>
|
|
63
|
+
{onDockClick && <PanelHeaderButton aria-label={'Dock'} onClick={() => onDockClick()} icon={'ic_left_col'} />}
|
|
64
64
|
{!onDockClick &&
|
|
65
65
|
dockTo &&
|
|
66
66
|
(docked ? (
|
|
67
|
-
<PanelHeaderButton aria-label={
|
|
67
|
+
<PanelHeaderButton aria-label={'Undock'} onClick={undock} icon={'ic_close_list'} />
|
|
68
68
|
) : (
|
|
69
|
-
<PanelHeaderButton aria-label={
|
|
69
|
+
<PanelHeaderButton aria-label={'Dock'} onClick={() => dock(dockTo)} icon={'ic_left_col'} />
|
|
70
70
|
))}
|
|
71
71
|
{!disablePopout && (
|
|
72
72
|
<PanelHeaderButton
|
|
73
|
-
aria-label={panelPoppedOut ?
|
|
73
|
+
aria-label={panelPoppedOut ? 'Pop-in' : 'Pop-out'}
|
|
74
74
|
onClick={panelTogglePopout}
|
|
75
|
-
icon={panelPoppedOut ?
|
|
75
|
+
icon={panelPoppedOut ? 'ic_pop_back' : 'ic_launch_new window_open'}
|
|
76
76
|
/>
|
|
77
77
|
)}
|
|
78
|
-
{!disableClose && <PanelHeaderButton aria-label={
|
|
78
|
+
{!disableClose && <PanelHeaderButton aria-label={'Close'} onClick={panelClose} icon={'ic_clear'} />}
|
|
79
79
|
</div>
|
|
80
80
|
</div>
|
|
81
81
|
);
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { LuiButton, LuiIcon } from
|
|
2
|
-
import { LuiIconName } from
|
|
1
|
+
import { LuiButton, LuiIcon } from '@linzjs/lui';
|
|
2
|
+
import { LuiIconName } from '@linzjs/lui/dist/assets/svg-content';
|
|
3
3
|
|
|
4
4
|
export interface PanelHeaderButtonProps {
|
|
5
|
-
|
|
5
|
+
'aria-label': string;
|
|
6
6
|
href?: string;
|
|
7
7
|
icon: LuiIconName;
|
|
8
8
|
onClick?: () => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export const PanelHeaderButton = ({
|
|
11
|
+
export const PanelHeaderButton = ({ 'aria-label': ariaLabel, href, icon, onClick }: PanelHeaderButtonProps) => (
|
|
12
12
|
<LuiButton
|
|
13
|
-
level={
|
|
14
|
-
className={
|
|
15
|
-
size={
|
|
13
|
+
level={'plain-text'}
|
|
14
|
+
className={'lui-button-icon-only'}
|
|
15
|
+
size={'sm'}
|
|
16
16
|
href={href}
|
|
17
17
|
onClick={onClick}
|
|
18
18
|
openInNewTab={!!href}
|
|
@@ -20,6 +20,6 @@ export const PanelHeaderButton = ({ "aria-label": ariaLabel, href, icon, onClick
|
|
|
20
20
|
onTouchStart: onClick,
|
|
21
21
|
}}
|
|
22
22
|
>
|
|
23
|
-
<LuiIcon name={icon} alt={ariaLabel} size={
|
|
23
|
+
<LuiIcon name={icon} alt={ariaLabel} size={'md'} />
|
|
24
24
|
</LuiButton>
|
|
25
25
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext } from
|
|
1
|
+
import { createContext } from 'react';
|
|
2
2
|
|
|
3
3
|
export interface PanelInstanceContextType {
|
|
4
4
|
title: string;
|
|
@@ -19,16 +19,16 @@ export interface PanelInstanceContextType {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
const NoContextError = () => {
|
|
22
|
-
console.error(
|
|
22
|
+
console.error('Missing PanelInstanceContext Provider');
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Provides access to closing/popping panels
|
|
27
27
|
*/
|
|
28
28
|
export const PanelInstanceContext = createContext<PanelInstanceContextType>({
|
|
29
|
-
title:
|
|
30
|
-
uniqueId:
|
|
31
|
-
panelName:
|
|
29
|
+
title: 'Missing PanelInstanceContext Provider: title',
|
|
30
|
+
uniqueId: 'Missing PanelInstanceContext Provider: uniqueId',
|
|
31
|
+
panelName: 'Missing PanelInstanceContext Provider: panelName',
|
|
32
32
|
bounds: document.body,
|
|
33
33
|
setTitle: NoContextError,
|
|
34
34
|
panelTogglePopout: NoContextError,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { ReactElement, ReactNode, useCallback, useContext, useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { PanelInstanceContext } from './PanelInstanceContext';
|
|
4
|
+
import { PanelInstance, PanelsContext } from './PanelsContext';
|
|
5
|
+
import { useRestoreStateFrom } from './usePanelStateHandler';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Provides access to closing/popping panels
|
|
@@ -16,7 +17,7 @@ export const PanelInstanceContextProvider = ({
|
|
|
16
17
|
children: ReactNode;
|
|
17
18
|
}): ReactElement => {
|
|
18
19
|
const { closePanel, bringPanelToFront, dockElements } = useContext(PanelsContext);
|
|
19
|
-
const [title, setTitle] = useState(
|
|
20
|
+
const [title, setTitle] = useState('');
|
|
20
21
|
const [dockId, setDockId] = useState<string>();
|
|
21
22
|
|
|
22
23
|
const savedState = useRestoreStateFrom({ uniqueId: panelInstance.uniqueId });
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { PanelPosition } from
|
|
1
|
+
import { createContext, ReactElement } from 'react';
|
|
2
|
+
|
|
3
|
+
import { PanelPosition } from './types';
|
|
4
|
+
import { PanelStateOptions } from './types/PanelStateOptions';
|
|
4
5
|
|
|
5
6
|
export interface PanelInstance {
|
|
6
7
|
uniqueId: string;
|
|
@@ -28,7 +29,7 @@ export interface PanelsContextType {
|
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
const NoContext = () => {
|
|
31
|
-
console.error(
|
|
32
|
+
console.error('Missing PanelContext Provider');
|
|
32
33
|
};
|
|
33
34
|
|
|
34
35
|
export const PanelsContext = createContext<PanelsContextType>({
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import { castArray, maxBy, sortBy } from 'lodash-es';
|
|
2
|
+
import React, { Fragment, PropsWithChildren, ReactElement, useCallback, useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { useInterval } from 'usehooks-ts';
|
|
4
|
+
import { v4 } from 'uuid';
|
|
5
|
+
|
|
6
|
+
import { PanelInstanceContextProvider } from './PanelInstanceContextProvider';
|
|
7
|
+
import { OpenPanelOptions, PanelInstance, PanelsContext } from './PanelsContext';
|
|
8
|
+
import { PanelPosition } from './types';
|
|
9
|
+
import { PanelStateOptions } from './types/PanelStateOptions';
|
|
9
10
|
|
|
10
11
|
export interface PanelsContextProviderProps {
|
|
11
12
|
baseZIndex?: number;
|
|
@@ -46,7 +47,7 @@ export const PanelsContextProvider = ({
|
|
|
46
47
|
if (panelInstance.window) {
|
|
47
48
|
panelInstance.window.focus();
|
|
48
49
|
} else {
|
|
49
|
-
const maxZIndexPanelInstance = maxBy(panelInstances,
|
|
50
|
+
const maxZIndexPanelInstance = maxBy(panelInstances, 'zIndex');
|
|
50
51
|
// Prevent unnecessary state updates
|
|
51
52
|
if (maxZIndexPanelInstance === panelInstance) return;
|
|
52
53
|
sortBy(panelInstances, (pi) => (panelInstance === pi ? 32768 : pi.zIndex)).forEach(
|
|
@@ -134,14 +135,14 @@ export const PanelsContextProvider = ({
|
|
|
134
135
|
panelStateOptions,
|
|
135
136
|
}}
|
|
136
137
|
>
|
|
137
|
-
<Fragment key={
|
|
138
|
+
<Fragment key={'panels'}>
|
|
138
139
|
{panelInstances.map((panelInstance) => (
|
|
139
140
|
<PanelInstanceContextProvider key={panelInstance.uniqueId} panelInstance={panelInstance} bounds={bounds}>
|
|
140
141
|
{panelInstance.componentInstance}
|
|
141
142
|
</PanelInstanceContextProvider>
|
|
142
143
|
))}
|
|
143
144
|
</Fragment>
|
|
144
|
-
<Fragment key={
|
|
145
|
+
<Fragment key={'children'}>{children}</Fragment>
|
|
145
146
|
</PanelsContext.Provider>
|
|
146
147
|
);
|
|
147
148
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { useCallback, useContext, useEffect, useRef, useState } from
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import clsx from 'clsx';
|
|
2
|
+
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Rnd } from 'react-rnd';
|
|
4
|
+
|
|
5
|
+
import { PanelContext } from './PanelContext';
|
|
6
|
+
import { PanelInstanceContext } from './PanelInstanceContext';
|
|
7
|
+
import { PanelPosition, PanelSize } from './types';
|
|
8
|
+
import { PanelProps } from './types/PanelProps';
|
|
9
|
+
import { useRestoreStateFrom, useSaveStateIn } from './usePanelStateHandler';
|
|
9
10
|
|
|
10
11
|
export function PopinWindow({
|
|
11
12
|
children,
|
|
@@ -16,7 +17,7 @@ export function PopinWindow({
|
|
|
16
17
|
minWidth,
|
|
17
18
|
modal,
|
|
18
19
|
nextStackPosition,
|
|
19
|
-
position = modal ?
|
|
20
|
+
position = modal ? 'center' : 'tile',
|
|
20
21
|
resizeable = modal !== true,
|
|
21
22
|
size = { height: 200, width: 320 },
|
|
22
23
|
}: PanelProps & { nextStackPosition: () => PanelPosition }): JSX.Element {
|
|
@@ -32,12 +33,12 @@ export function PopinWindow({
|
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
switch (position) {
|
|
35
|
-
case
|
|
36
|
+
case 'center':
|
|
36
37
|
return {
|
|
37
38
|
x: Math.max((window.innerWidth - size.width) / 2, 0),
|
|
38
39
|
y: Math.max((window.innerHeight - size.height) / 2, 0),
|
|
39
40
|
};
|
|
40
|
-
case
|
|
41
|
+
case 'tile':
|
|
41
42
|
return nextStackPosition();
|
|
42
43
|
default:
|
|
43
44
|
return position ?? nextStackPosition();
|
|
@@ -61,11 +62,11 @@ export function PopinWindow({
|
|
|
61
62
|
}, [size]);
|
|
62
63
|
|
|
63
64
|
useEffect(() => {
|
|
64
|
-
if (position ===
|
|
65
|
+
if (position === 'center' && !resizeable) {
|
|
65
66
|
centerWindow();
|
|
66
67
|
|
|
67
|
-
window.addEventListener(
|
|
68
|
-
return () => window.removeEventListener(
|
|
68
|
+
window.addEventListener('resize', centerWindow);
|
|
69
|
+
return () => window.removeEventListener('resize', centerWindow);
|
|
69
70
|
}
|
|
70
71
|
return;
|
|
71
72
|
}, [centerWindow, position, resizeable]);
|
|
@@ -91,20 +92,20 @@ export function PopinWindow({
|
|
|
91
92
|
{modal && (
|
|
92
93
|
<div
|
|
93
94
|
style={{
|
|
94
|
-
position:
|
|
95
|
+
position: 'absolute',
|
|
95
96
|
top: 0,
|
|
96
97
|
left: 0,
|
|
97
98
|
bottom: 0,
|
|
98
99
|
right: 0,
|
|
99
|
-
backgroundColor:
|
|
100
|
+
backgroundColor: 'rgb(0,0,0,0.1)',
|
|
100
101
|
zIndex,
|
|
101
102
|
}}
|
|
102
103
|
/>
|
|
103
104
|
)}
|
|
104
105
|
<Rnd
|
|
105
106
|
ref={panelRef}
|
|
106
|
-
className={clsx(
|
|
107
|
-
dragHandleClassName={
|
|
107
|
+
className={clsx('WindowPanel', className)}
|
|
108
|
+
dragHandleClassName={'draggable-handle'}
|
|
108
109
|
maxHeight={maxHeight}
|
|
109
110
|
maxWidth={maxWidth}
|
|
110
111
|
minWidth={minWidth}
|
|
@@ -129,10 +130,10 @@ export function PopinWindow({
|
|
|
129
130
|
>
|
|
130
131
|
<div
|
|
131
132
|
style={{
|
|
132
|
-
display:
|
|
133
|
-
flexDirection:
|
|
134
|
-
width:
|
|
135
|
-
height:
|
|
133
|
+
display: 'flex',
|
|
134
|
+
flexDirection: 'column',
|
|
135
|
+
width: '100%',
|
|
136
|
+
height: '100%',
|
|
136
137
|
}}
|
|
137
138
|
>
|
|
138
139
|
{children}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import { PanelPosition, PanelSize } from
|
|
1
|
+
import createCache from '@emotion/cache';
|
|
2
|
+
import { CacheProvider } from '@emotion/react';
|
|
3
|
+
import { Dispatch, ReactElement, ReactNode, SetStateAction, useContext, useEffect, useState } from 'react';
|
|
4
|
+
import ReactDOM from 'react-dom';
|
|
5
|
+
|
|
6
|
+
import { makePopoutId, popoutWindowDivId } from './generateId';
|
|
7
|
+
import { copyStyleSheets, observeStyleSheetChanges } from './handleStyleSheetsChanges';
|
|
8
|
+
import { PanelInstanceContext } from './PanelInstanceContext';
|
|
9
|
+
import { PanelPosition, PanelSize } from './types';
|
|
10
|
+
import { useRestoreStateFrom, useSaveStateIn } from './usePanelStateHandler';
|
|
10
11
|
|
|
11
12
|
interface PopoutWindowProps {
|
|
12
13
|
name: string;
|
|
@@ -62,14 +63,14 @@ const openExternalWindow = ({
|
|
|
62
63
|
const features =
|
|
63
64
|
`scrollbars=no,resizable=no,status=no,location=no,toolbar=no,menubar=no,` +
|
|
64
65
|
`width=${size.width},height=${size.height},left=${position.x},top=${position.y}`;
|
|
65
|
-
response.externalWindow = window.open(
|
|
66
|
+
response.externalWindow = window.open('', makePopoutId(title), features);
|
|
66
67
|
|
|
67
68
|
if (response.externalWindow) {
|
|
68
69
|
const { externalWindow } = response;
|
|
69
70
|
|
|
70
71
|
// Reset the default body style applied by the browser
|
|
71
|
-
externalWindow.document.body.style.margin =
|
|
72
|
-
externalWindow.document.body.style.padding =
|
|
72
|
+
externalWindow.document.body.style.margin = '0';
|
|
73
|
+
externalWindow.document.body.style.padding = '0';
|
|
73
74
|
|
|
74
75
|
// Remove any existing body HTML from this window
|
|
75
76
|
const existingBodyMountElement = externalWindow.document.body?.firstChild;
|
|
@@ -77,7 +78,7 @@ const openExternalWindow = ({
|
|
|
77
78
|
externalWindow.document.body.removeChild(existingBodyMountElement);
|
|
78
79
|
}
|
|
79
80
|
// Create a new HTML element to hang our rendering off
|
|
80
|
-
const newMountElement = externalWindow.document.createElement(
|
|
81
|
+
const newMountElement = externalWindow.document.createElement('div');
|
|
81
82
|
newMountElement.className = `PopoutWindowContainer ${className}`;
|
|
82
83
|
setContainerElement(newMountElement);
|
|
83
84
|
externalWindow.document.body.appendChild(newMountElement);
|
|
@@ -88,7 +89,7 @@ const openExternalWindow = ({
|
|
|
88
89
|
externalWindow.document.head.removeChild(existingHeadMountElement);
|
|
89
90
|
}
|
|
90
91
|
// and an HTML element to hang our copied styles off
|
|
91
|
-
const newHeadMountElement = externalWindow.document.createElement(
|
|
92
|
+
const newHeadMountElement = externalWindow.document.createElement('div');
|
|
92
93
|
externalWindow.document.head.appendChild(newHeadMountElement);
|
|
93
94
|
setHeadElement(newHeadMountElement);
|
|
94
95
|
|
|
@@ -175,11 +176,11 @@ export const PopoutWindow = ({
|
|
|
175
176
|
});
|
|
176
177
|
};
|
|
177
178
|
|
|
178
|
-
externalWindow.addEventListener(
|
|
179
|
-
externalWindow.addEventListener(
|
|
179
|
+
externalWindow.addEventListener('beforeunload', savePanelState);
|
|
180
|
+
externalWindow.addEventListener('resize', savePanelState);
|
|
180
181
|
|
|
181
182
|
// When the main window closes or reloads, close the popout
|
|
182
|
-
window.addEventListener(
|
|
183
|
+
window.addEventListener('beforeunload', closeExternalWindow, { once: true });
|
|
183
184
|
|
|
184
185
|
return () => {
|
|
185
186
|
onCloseExternalWindow?.();
|