@stack-spot/portal-layout 1.0.2 → 1.1.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/CHANGELOG.md +18 -0
- package/dist/Layout.d.ts +2 -2
- package/dist/Layout.js +1 -1
- package/dist/LayoutOverlayManager.js +6 -6
- package/dist/components/Dialog.d.ts +1 -1
- package/dist/components/Dialog.js +1 -1
- package/dist/components/Header.d.ts +1 -1
- package/dist/components/Header.js +1 -1
- package/dist/components/OverlayContent.d.ts +1 -1
- package/dist/components/OverlayContent.js +20 -20
- package/dist/components/PortalSwitcher.d.ts +1 -1
- package/dist/components/PortalSwitcher.js +54 -54
- package/dist/components/Toaster.d.ts +2 -2
- package/dist/components/Toaster.js +1 -1
- package/dist/components/UserMenu.d.ts +1 -1
- package/dist/components/UserMenu.d.ts.map +1 -1
- package/dist/components/UserMenu.js +44 -42
- package/dist/components/UserMenu.js.map +1 -1
- package/dist/components/error/ErrorBoundary.d.ts +1 -1
- package/dist/components/error/ErrorBoundary.js +1 -1
- package/dist/components/error/SilentErrorBoundary.d.ts +1 -1
- package/dist/components/error/SilentErrorBoundary.js +1 -1
- package/dist/components/menu/MenuContent.d.ts +5 -5
- package/dist/components/menu/MenuContent.d.ts.map +1 -1
- package/dist/components/menu/MenuContent.js +126 -124
- package/dist/components/menu/MenuContent.js.map +1 -1
- package/dist/components/menu/MenuSections.d.ts +8 -1
- package/dist/components/menu/MenuSections.d.ts.map +1 -1
- package/dist/components/menu/MenuSections.js +14 -2
- package/dist/components/menu/MenuSections.js.map +1 -1
- package/dist/components/menu/PageSelector.d.ts +1 -1
- package/dist/components/menu/PageSelector.js +69 -69
- package/dist/components/tour/PortalSwitcherStep.js +1 -1
- package/dist/components/user-menu-manager.d.ts +13 -0
- package/dist/components/user-menu-manager.d.ts.map +1 -0
- package/dist/components/user-menu-manager.js +36 -0
- package/dist/components/user-menu-manager.js.map +1 -0
- package/dist/layout.css +477 -477
- package/dist/toaster.js +1 -1
- package/package.json +9 -6
- package/readme.md +146 -146
- package/src/Layout.tsx +171 -171
- package/src/LayoutOverlayManager.tsx +464 -464
- package/src/components/Dialog.tsx +140 -140
- package/src/components/Header.tsx +62 -62
- package/src/components/OverlayContent.tsx +80 -80
- package/src/components/PortalSwitcher.tsx +161 -161
- package/src/components/Toaster.tsx +95 -95
- package/src/components/UserMenu.tsx +127 -124
- package/src/components/error/ErrorBoundary.tsx +47 -47
- package/src/components/error/ErrorManager.ts +47 -47
- package/src/components/error/SilentErrorBoundary.tsx +64 -64
- package/src/components/menu/MenuContent.tsx +272 -270
- package/src/components/menu/MenuSections.tsx +334 -320
- package/src/components/menu/PageSelector.tsx +164 -164
- package/src/components/menu/constants.ts +2 -2
- package/src/components/menu/types.ts +205 -205
- package/src/components/tour/PortalSwitcherStep.tsx +39 -39
- package/src/components/types.ts +1 -1
- package/src/components/user-menu-manager.ts +31 -0
- package/src/dictionary.ts +28 -28
- package/src/elements.ts +30 -30
- package/src/errors.ts +11 -11
- package/src/index.ts +14 -14
- package/src/layout.css +477 -477
- package/src/toaster.tsx +153 -153
- package/src/utils.ts +29 -29
- package/tsconfig.json +8 -8
|
@@ -1,140 +1,140 @@
|
|
|
1
|
-
import { Button, Flex, Input, Label } from '@citric/core'
|
|
2
|
-
import { ColorSchemeName } from '@stack-spot/portal-theme'
|
|
3
|
-
import { interpolate } from '@stack-spot/portal-translate'
|
|
4
|
-
import { ReactNode, useState } from 'react'
|
|
5
|
-
import { useDictionary } from '../dictionary'
|
|
6
|
-
import { OverlayContent } from './OverlayContent'
|
|
7
|
-
|
|
8
|
-
interface Validation {
|
|
9
|
-
/**
|
|
10
|
-
* The expected value of the field.
|
|
11
|
-
*/
|
|
12
|
-
value: string,
|
|
13
|
-
/**
|
|
14
|
-
* A custom label for the input field.
|
|
15
|
-
*/
|
|
16
|
-
label?: string | ReactNode,
|
|
17
|
-
/**
|
|
18
|
-
* A placeholder for the input field.
|
|
19
|
-
*/
|
|
20
|
-
placeholder?: string,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface DialogOptions {
|
|
24
|
-
/**
|
|
25
|
-
* The dialog's title.
|
|
26
|
-
*/
|
|
27
|
-
title: string,
|
|
28
|
-
/**
|
|
29
|
-
* The dialog's subtitle.
|
|
30
|
-
*/
|
|
31
|
-
subtitle?: string,
|
|
32
|
-
/**
|
|
33
|
-
* The dialog's content.
|
|
34
|
-
*/
|
|
35
|
-
children: ReactNode,
|
|
36
|
-
/**
|
|
37
|
-
* A text for the confirm button. If left blank, the confirm button won't render.
|
|
38
|
-
*/
|
|
39
|
-
confirm?: string,
|
|
40
|
-
/**
|
|
41
|
-
* A text for the cancel button. If left blank, the cancel button won't render.
|
|
42
|
-
*/
|
|
43
|
-
cancel?: string,
|
|
44
|
-
/**
|
|
45
|
-
* A validation input field. If the validation is incorrect, the confirm button is disabled.
|
|
46
|
-
* If this is a string, the validation input's value must be equal to this string in order to enable the confirm button.
|
|
47
|
-
* If this is an object, a value, label and placeholder may be specified.
|
|
48
|
-
* Use false or undefined to not include a validation field.
|
|
49
|
-
*/
|
|
50
|
-
validation?: false | string | Validation,
|
|
51
|
-
/**
|
|
52
|
-
* If this is a modal or a rightPanel.
|
|
53
|
-
* @default modal
|
|
54
|
-
*/
|
|
55
|
-
type?: 'modal' | 'panel',
|
|
56
|
-
/**
|
|
57
|
-
* The placement for the confirm/cancel buttons.
|
|
58
|
-
* @default "left" if type is "panel", "right" otherwise.
|
|
59
|
-
*/
|
|
60
|
-
buttonPlacement?: 'left' | 'center' | 'right',
|
|
61
|
-
/**
|
|
62
|
-
* The color of the primary button.
|
|
63
|
-
* @default "primary"
|
|
64
|
-
*/
|
|
65
|
-
buttonColor?: ColorSchemeName,
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
interface Props extends Omit<DialogOptions, 'message'> {
|
|
69
|
-
/**
|
|
70
|
-
* Function to run when the confirm button is clicked.
|
|
71
|
-
*/
|
|
72
|
-
onConfirm: () => void,
|
|
73
|
-
/**
|
|
74
|
-
* Function to run when the cancel button is clicked.
|
|
75
|
-
*/
|
|
76
|
-
onCancel: () => void,
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const justifyButtons: Record<Required<DialogOptions>['buttonPlacement'], React.CSSProperties['justifyContent']> = {
|
|
80
|
-
center: 'center',
|
|
81
|
-
left: 'start',
|
|
82
|
-
right: 'end',
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* A dialog, i.e. A UI with title, subtitle, close button, content and a set of buttons: cancel and confirm. May be placed under a Modal or
|
|
87
|
-
* RightPanel.
|
|
88
|
-
* @param props the React props of the component {@link Props}.
|
|
89
|
-
*/
|
|
90
|
-
export const Dialog = ({
|
|
91
|
-
children,
|
|
92
|
-
title,
|
|
93
|
-
subtitle,
|
|
94
|
-
cancel,
|
|
95
|
-
confirm,
|
|
96
|
-
validation,
|
|
97
|
-
onConfirm,
|
|
98
|
-
onCancel,
|
|
99
|
-
type = 'modal',
|
|
100
|
-
buttonPlacement = type === 'panel' ? 'left' : 'right',
|
|
101
|
-
buttonColor = 'primary',
|
|
102
|
-
}: Props,
|
|
103
|
-
) => {
|
|
104
|
-
const t = useDictionary()
|
|
105
|
-
const [enabled, setEnabled] = useState(!validation)
|
|
106
|
-
|
|
107
|
-
function renderValidation() {
|
|
108
|
-
if (!validation) return null
|
|
109
|
-
const value = typeof validation === 'string' ? validation : validation.value
|
|
110
|
-
const label = typeof validation === 'object' && validation.label
|
|
111
|
-
? validation.label
|
|
112
|
-
: interpolate(t.validationLabel, value)
|
|
113
|
-
const placeholder = typeof validation === 'object' ? validation.placeholder : undefined
|
|
114
|
-
return (
|
|
115
|
-
<div style={{ margin: '24px 0 16px' }}>
|
|
116
|
-
<Label htmlFor="input-validation">{label}</Label>
|
|
117
|
-
<Input
|
|
118
|
-
id="input-validation"
|
|
119
|
-
placeholder={placeholder}
|
|
120
|
-
onChange={e => setEnabled(e.target.value === value)}
|
|
121
|
-
style={{ marginTop: '10px' }} />
|
|
122
|
-
</div>
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return (
|
|
127
|
-
<OverlayContent title={title} subtitle={subtitle} onClose={onCancel} type={type}>
|
|
128
|
-
<Flex flexDirection="column" flex={1}>
|
|
129
|
-
{children}
|
|
130
|
-
{renderValidation()}
|
|
131
|
-
</Flex>
|
|
132
|
-
{(cancel || confirm) && <Flex gap justifyContent={justifyButtons[buttonPlacement]} alignItems="center" sx={{ mt: 6 }}>
|
|
133
|
-
{cancel && <Button appearance="outlined" colorScheme="inverse" onClick={onCancel}>{cancel}</Button>}
|
|
134
|
-
{confirm && <Button colorScheme={buttonColor} onClick={onConfirm} disabled={!enabled}>
|
|
135
|
-
{confirm}
|
|
136
|
-
</Button>}
|
|
137
|
-
</Flex>}
|
|
138
|
-
</OverlayContent>
|
|
139
|
-
)
|
|
140
|
-
}
|
|
1
|
+
import { Button, Flex, Input, Label } from '@citric/core'
|
|
2
|
+
import { ColorSchemeName } from '@stack-spot/portal-theme'
|
|
3
|
+
import { interpolate } from '@stack-spot/portal-translate'
|
|
4
|
+
import { ReactNode, useState } from 'react'
|
|
5
|
+
import { useDictionary } from '../dictionary'
|
|
6
|
+
import { OverlayContent } from './OverlayContent'
|
|
7
|
+
|
|
8
|
+
interface Validation {
|
|
9
|
+
/**
|
|
10
|
+
* The expected value of the field.
|
|
11
|
+
*/
|
|
12
|
+
value: string,
|
|
13
|
+
/**
|
|
14
|
+
* A custom label for the input field.
|
|
15
|
+
*/
|
|
16
|
+
label?: string | ReactNode,
|
|
17
|
+
/**
|
|
18
|
+
* A placeholder for the input field.
|
|
19
|
+
*/
|
|
20
|
+
placeholder?: string,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DialogOptions {
|
|
24
|
+
/**
|
|
25
|
+
* The dialog's title.
|
|
26
|
+
*/
|
|
27
|
+
title: string,
|
|
28
|
+
/**
|
|
29
|
+
* The dialog's subtitle.
|
|
30
|
+
*/
|
|
31
|
+
subtitle?: string,
|
|
32
|
+
/**
|
|
33
|
+
* The dialog's content.
|
|
34
|
+
*/
|
|
35
|
+
children: ReactNode,
|
|
36
|
+
/**
|
|
37
|
+
* A text for the confirm button. If left blank, the confirm button won't render.
|
|
38
|
+
*/
|
|
39
|
+
confirm?: string,
|
|
40
|
+
/**
|
|
41
|
+
* A text for the cancel button. If left blank, the cancel button won't render.
|
|
42
|
+
*/
|
|
43
|
+
cancel?: string,
|
|
44
|
+
/**
|
|
45
|
+
* A validation input field. If the validation is incorrect, the confirm button is disabled.
|
|
46
|
+
* If this is a string, the validation input's value must be equal to this string in order to enable the confirm button.
|
|
47
|
+
* If this is an object, a value, label and placeholder may be specified.
|
|
48
|
+
* Use false or undefined to not include a validation field.
|
|
49
|
+
*/
|
|
50
|
+
validation?: false | string | Validation,
|
|
51
|
+
/**
|
|
52
|
+
* If this is a modal or a rightPanel.
|
|
53
|
+
* @default modal
|
|
54
|
+
*/
|
|
55
|
+
type?: 'modal' | 'panel',
|
|
56
|
+
/**
|
|
57
|
+
* The placement for the confirm/cancel buttons.
|
|
58
|
+
* @default "left" if type is "panel", "right" otherwise.
|
|
59
|
+
*/
|
|
60
|
+
buttonPlacement?: 'left' | 'center' | 'right',
|
|
61
|
+
/**
|
|
62
|
+
* The color of the primary button.
|
|
63
|
+
* @default "primary"
|
|
64
|
+
*/
|
|
65
|
+
buttonColor?: ColorSchemeName,
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface Props extends Omit<DialogOptions, 'message'> {
|
|
69
|
+
/**
|
|
70
|
+
* Function to run when the confirm button is clicked.
|
|
71
|
+
*/
|
|
72
|
+
onConfirm: () => void,
|
|
73
|
+
/**
|
|
74
|
+
* Function to run when the cancel button is clicked.
|
|
75
|
+
*/
|
|
76
|
+
onCancel: () => void,
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const justifyButtons: Record<Required<DialogOptions>['buttonPlacement'], React.CSSProperties['justifyContent']> = {
|
|
80
|
+
center: 'center',
|
|
81
|
+
left: 'start',
|
|
82
|
+
right: 'end',
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* A dialog, i.e. A UI with title, subtitle, close button, content and a set of buttons: cancel and confirm. May be placed under a Modal or
|
|
87
|
+
* RightPanel.
|
|
88
|
+
* @param props the React props of the component {@link Props}.
|
|
89
|
+
*/
|
|
90
|
+
export const Dialog = ({
|
|
91
|
+
children,
|
|
92
|
+
title,
|
|
93
|
+
subtitle,
|
|
94
|
+
cancel,
|
|
95
|
+
confirm,
|
|
96
|
+
validation,
|
|
97
|
+
onConfirm,
|
|
98
|
+
onCancel,
|
|
99
|
+
type = 'modal',
|
|
100
|
+
buttonPlacement = type === 'panel' ? 'left' : 'right',
|
|
101
|
+
buttonColor = 'primary',
|
|
102
|
+
}: Props,
|
|
103
|
+
) => {
|
|
104
|
+
const t = useDictionary()
|
|
105
|
+
const [enabled, setEnabled] = useState(!validation)
|
|
106
|
+
|
|
107
|
+
function renderValidation() {
|
|
108
|
+
if (!validation) return null
|
|
109
|
+
const value = typeof validation === 'string' ? validation : validation.value
|
|
110
|
+
const label = typeof validation === 'object' && validation.label
|
|
111
|
+
? validation.label
|
|
112
|
+
: interpolate(t.validationLabel, value)
|
|
113
|
+
const placeholder = typeof validation === 'object' ? validation.placeholder : undefined
|
|
114
|
+
return (
|
|
115
|
+
<div style={{ margin: '24px 0 16px' }}>
|
|
116
|
+
<Label htmlFor="input-validation">{label}</Label>
|
|
117
|
+
<Input
|
|
118
|
+
id="input-validation"
|
|
119
|
+
placeholder={placeholder}
|
|
120
|
+
onChange={e => setEnabled(e.target.value === value)}
|
|
121
|
+
style={{ marginTop: '10px' }} />
|
|
122
|
+
</div>
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<OverlayContent title={title} subtitle={subtitle} onClose={onCancel} type={type}>
|
|
128
|
+
<Flex flexDirection="column" flex={1}>
|
|
129
|
+
{children}
|
|
130
|
+
{renderValidation()}
|
|
131
|
+
</Flex>
|
|
132
|
+
{(cancel || confirm) && <Flex gap justifyContent={justifyButtons[buttonPlacement]} alignItems="center" sx={{ mt: 6 }}>
|
|
133
|
+
{cancel && <Button appearance="outlined" colorScheme="inverse" onClick={onCancel}>{cancel}</Button>}
|
|
134
|
+
{confirm && <Button colorScheme={buttonColor} onClick={onConfirm} disabled={!enabled}>
|
|
135
|
+
{confirm}
|
|
136
|
+
</Button>}
|
|
137
|
+
</Flex>}
|
|
138
|
+
</OverlayContent>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
import { Flex } from '@citric/core'
|
|
2
|
-
import { SelectionListProps } from '@stack-spot/portal-components/SelectionList'
|
|
3
|
-
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
4
|
-
import { Logo } from '@stack-spot/portal-components/svg'
|
|
5
|
-
import { ReactNode } from 'react'
|
|
6
|
-
import { PortalSwitcher, PortalSwitcherProps } from './PortalSwitcher'
|
|
7
|
-
import { UserMenu } from './UserMenu'
|
|
8
|
-
|
|
9
|
-
export interface HeaderProps {
|
|
10
|
-
/**
|
|
11
|
-
* The logo to show in the header, if the portal switch feature is disabled.
|
|
12
|
-
*/
|
|
13
|
-
logo?: ReactNode,
|
|
14
|
-
/**
|
|
15
|
-
* The url the logo links to, if the portal switch feature is disabled.
|
|
16
|
-
*/
|
|
17
|
-
logoHref?: string,
|
|
18
|
-
/**
|
|
19
|
-
* The username to show in the user menu.
|
|
20
|
-
*/
|
|
21
|
-
userName?: string,
|
|
22
|
-
/**
|
|
23
|
-
* The email to show in the user menu.
|
|
24
|
-
*/
|
|
25
|
-
email?: string,
|
|
26
|
-
/**
|
|
27
|
-
* A portal switch config. If not specified, disables the portal switch feature.
|
|
28
|
-
*/
|
|
29
|
-
portalSwitch?: PortalSwitcherProps['portals'],
|
|
30
|
-
/**
|
|
31
|
-
* The options to show in the user menu.
|
|
32
|
-
*/
|
|
33
|
-
options?: SelectionListProps['items'],
|
|
34
|
-
/**
|
|
35
|
-
* A custom React Node to show at the center of the header. This is a good place for a search field, for instance.
|
|
36
|
-
*/
|
|
37
|
-
center?: ReactNode,
|
|
38
|
-
/**
|
|
39
|
-
* A custom React Node to show at the right (end) of the header.
|
|
40
|
-
*/
|
|
41
|
-
right?: ReactNode,
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* The page header.
|
|
46
|
-
* @param props the React props for the header {@link HeaderProps}.
|
|
47
|
-
*/
|
|
48
|
-
export const Header = ({ logo, logoHref, center, right, userName, email, options, portalSwitch }: HeaderProps) => {
|
|
49
|
-
const Link = useAnchorTag()
|
|
50
|
-
|
|
51
|
-
return (
|
|
52
|
-
<>
|
|
53
|
-
{portalSwitch ?
|
|
54
|
-
<PortalSwitcher portals={portalSwitch} /> :
|
|
55
|
-
<Link href={logoHref} title="Home">{logo ?? <Logo style={{ width: 130 }} />}</Link>
|
|
56
|
-
}
|
|
57
|
-
<Flex flex={1}>{center}</Flex>
|
|
58
|
-
{right}
|
|
59
|
-
{userName && <UserMenu userName={userName} email={email} options={options} />}
|
|
60
|
-
</>
|
|
61
|
-
)
|
|
62
|
-
}
|
|
1
|
+
import { Flex } from '@citric/core'
|
|
2
|
+
import { SelectionListProps } from '@stack-spot/portal-components/SelectionList'
|
|
3
|
+
import { useAnchorTag } from '@stack-spot/portal-components/anchor'
|
|
4
|
+
import { Logo } from '@stack-spot/portal-components/svg'
|
|
5
|
+
import { ReactNode } from 'react'
|
|
6
|
+
import { PortalSwitcher, PortalSwitcherProps } from './PortalSwitcher'
|
|
7
|
+
import { UserMenu } from './UserMenu'
|
|
8
|
+
|
|
9
|
+
export interface HeaderProps {
|
|
10
|
+
/**
|
|
11
|
+
* The logo to show in the header, if the portal switch feature is disabled.
|
|
12
|
+
*/
|
|
13
|
+
logo?: ReactNode,
|
|
14
|
+
/**
|
|
15
|
+
* The url the logo links to, if the portal switch feature is disabled.
|
|
16
|
+
*/
|
|
17
|
+
logoHref?: string,
|
|
18
|
+
/**
|
|
19
|
+
* The username to show in the user menu.
|
|
20
|
+
*/
|
|
21
|
+
userName?: string,
|
|
22
|
+
/**
|
|
23
|
+
* The email to show in the user menu.
|
|
24
|
+
*/
|
|
25
|
+
email?: string,
|
|
26
|
+
/**
|
|
27
|
+
* A portal switch config. If not specified, disables the portal switch feature.
|
|
28
|
+
*/
|
|
29
|
+
portalSwitch?: PortalSwitcherProps['portals'],
|
|
30
|
+
/**
|
|
31
|
+
* The options to show in the user menu.
|
|
32
|
+
*/
|
|
33
|
+
options?: SelectionListProps['items'],
|
|
34
|
+
/**
|
|
35
|
+
* A custom React Node to show at the center of the header. This is a good place for a search field, for instance.
|
|
36
|
+
*/
|
|
37
|
+
center?: ReactNode,
|
|
38
|
+
/**
|
|
39
|
+
* A custom React Node to show at the right (end) of the header.
|
|
40
|
+
*/
|
|
41
|
+
right?: ReactNode,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* The page header.
|
|
46
|
+
* @param props the React props for the header {@link HeaderProps}.
|
|
47
|
+
*/
|
|
48
|
+
export const Header = ({ logo, logoHref, center, right, userName, email, options, portalSwitch }: HeaderProps) => {
|
|
49
|
+
const Link = useAnchorTag()
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<>
|
|
53
|
+
{portalSwitch ?
|
|
54
|
+
<PortalSwitcher portals={portalSwitch} /> :
|
|
55
|
+
<Link href={logoHref} title="Home">{logo ?? <Logo style={{ width: 130 }} />}</Link>
|
|
56
|
+
}
|
|
57
|
+
<Flex flex={1}>{center}</Flex>
|
|
58
|
+
{right}
|
|
59
|
+
{userName && <UserMenu userName={userName} email={email} options={options} />}
|
|
60
|
+
</>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import { Flex, Text } from '@citric/core'
|
|
2
|
-
import { TimesMini } from '@citric/icons'
|
|
3
|
-
import { IconButton } from '@citric/ui'
|
|
4
|
-
import { WithStyle, listToClass, theme } from '@stack-spot/portal-theme'
|
|
5
|
-
import { ReactNode } from 'react'
|
|
6
|
-
import { styled } from 'styled-components'
|
|
7
|
-
import { useDictionary } from '../dictionary'
|
|
8
|
-
|
|
9
|
-
export const CLOSE_OVERLAY_ID = 'close-overlay'
|
|
10
|
-
|
|
11
|
-
export interface OverlayContentProps extends WithStyle {
|
|
12
|
-
/**
|
|
13
|
-
* The title for the modal or right panel.
|
|
14
|
-
*/
|
|
15
|
-
title: string,
|
|
16
|
-
/**
|
|
17
|
-
* The subtitle for the modal or right panel.
|
|
18
|
-
*/
|
|
19
|
-
subtitle?: string,
|
|
20
|
-
/**
|
|
21
|
-
* The content for the modal or right panel.
|
|
22
|
-
*/
|
|
23
|
-
children: ReactNode,
|
|
24
|
-
/**
|
|
25
|
-
* A function to run when the close button is pressed.
|
|
26
|
-
*/
|
|
27
|
-
onClose?: () => void,
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
interface Props extends OverlayContentProps {
|
|
31
|
-
/**
|
|
32
|
-
* A function to run when the close button is pressed.
|
|
33
|
-
*/
|
|
34
|
-
onClose: () => void,
|
|
35
|
-
/**
|
|
36
|
-
* Whether this is a modal or a right panel.
|
|
37
|
-
*/
|
|
38
|
-
type: 'modal' | 'panel',
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const ContentBox = styled.section`
|
|
42
|
-
display: flex;
|
|
43
|
-
flex-direction: column;
|
|
44
|
-
border-radius: 1rem;
|
|
45
|
-
background-color: ${theme.color.light['400']};
|
|
46
|
-
&.modal {
|
|
47
|
-
padding: 32px;
|
|
48
|
-
}
|
|
49
|
-
&.panel {
|
|
50
|
-
padding: 20px;
|
|
51
|
-
display: flex;
|
|
52
|
-
flex-direction: column;
|
|
53
|
-
flex: 1;
|
|
54
|
-
}
|
|
55
|
-
header {
|
|
56
|
-
display: flex;
|
|
57
|
-
flex-direction: row;
|
|
58
|
-
margin-bottom: 1.25rem;
|
|
59
|
-
}
|
|
60
|
-
`
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Renders a modal or right panel with title, subtitle, close button and content.
|
|
64
|
-
* @param props the React props for the component {@link Props}.
|
|
65
|
-
*/
|
|
66
|
-
export const OverlayContent = ({ children, title, subtitle, className, style, onClose, type }: Props) => {
|
|
67
|
-
const t = useDictionary()
|
|
68
|
-
return (
|
|
69
|
-
<ContentBox style={style} className={listToClass([className, type])}>
|
|
70
|
-
<header>
|
|
71
|
-
<Flex flexDirection="column" flex={1}>
|
|
72
|
-
<Text as="h2" appearance={type === 'modal' ? 'h3' : 'h4'}>{title}</Text>
|
|
73
|
-
{subtitle && <Text appearance="body2" colorScheme="light.700">{subtitle}</Text>}
|
|
74
|
-
</Flex>
|
|
75
|
-
<IconButton onClick={onClose} title={t.close} aria-label={t.close} id={CLOSE_OVERLAY_ID}><TimesMini /></IconButton>
|
|
76
|
-
</header>
|
|
77
|
-
{children}
|
|
78
|
-
</ContentBox>
|
|
79
|
-
)
|
|
80
|
-
}
|
|
1
|
+
import { Flex, Text } from '@citric/core'
|
|
2
|
+
import { TimesMini } from '@citric/icons'
|
|
3
|
+
import { IconButton } from '@citric/ui'
|
|
4
|
+
import { WithStyle, listToClass, theme } from '@stack-spot/portal-theme'
|
|
5
|
+
import { ReactNode } from 'react'
|
|
6
|
+
import { styled } from 'styled-components'
|
|
7
|
+
import { useDictionary } from '../dictionary'
|
|
8
|
+
|
|
9
|
+
export const CLOSE_OVERLAY_ID = 'close-overlay'
|
|
10
|
+
|
|
11
|
+
export interface OverlayContentProps extends WithStyle {
|
|
12
|
+
/**
|
|
13
|
+
* The title for the modal or right panel.
|
|
14
|
+
*/
|
|
15
|
+
title: string,
|
|
16
|
+
/**
|
|
17
|
+
* The subtitle for the modal or right panel.
|
|
18
|
+
*/
|
|
19
|
+
subtitle?: string,
|
|
20
|
+
/**
|
|
21
|
+
* The content for the modal or right panel.
|
|
22
|
+
*/
|
|
23
|
+
children: ReactNode,
|
|
24
|
+
/**
|
|
25
|
+
* A function to run when the close button is pressed.
|
|
26
|
+
*/
|
|
27
|
+
onClose?: () => void,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface Props extends OverlayContentProps {
|
|
31
|
+
/**
|
|
32
|
+
* A function to run when the close button is pressed.
|
|
33
|
+
*/
|
|
34
|
+
onClose: () => void,
|
|
35
|
+
/**
|
|
36
|
+
* Whether this is a modal or a right panel.
|
|
37
|
+
*/
|
|
38
|
+
type: 'modal' | 'panel',
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const ContentBox = styled.section`
|
|
42
|
+
display: flex;
|
|
43
|
+
flex-direction: column;
|
|
44
|
+
border-radius: 1rem;
|
|
45
|
+
background-color: ${theme.color.light['400']};
|
|
46
|
+
&.modal {
|
|
47
|
+
padding: 32px;
|
|
48
|
+
}
|
|
49
|
+
&.panel {
|
|
50
|
+
padding: 20px;
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
flex: 1;
|
|
54
|
+
}
|
|
55
|
+
header {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: row;
|
|
58
|
+
margin-bottom: 1.25rem;
|
|
59
|
+
}
|
|
60
|
+
`
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Renders a modal or right panel with title, subtitle, close button and content.
|
|
64
|
+
* @param props the React props for the component {@link Props}.
|
|
65
|
+
*/
|
|
66
|
+
export const OverlayContent = ({ children, title, subtitle, className, style, onClose, type }: Props) => {
|
|
67
|
+
const t = useDictionary()
|
|
68
|
+
return (
|
|
69
|
+
<ContentBox style={style} className={listToClass([className, type])}>
|
|
70
|
+
<header>
|
|
71
|
+
<Flex flexDirection="column" flex={1}>
|
|
72
|
+
<Text as="h2" appearance={type === 'modal' ? 'h3' : 'h4'}>{title}</Text>
|
|
73
|
+
{subtitle && <Text appearance="body2" colorScheme="light.700">{subtitle}</Text>}
|
|
74
|
+
</Flex>
|
|
75
|
+
<IconButton onClick={onClose} title={t.close} aria-label={t.close} id={CLOSE_OVERLAY_ID}><TimesMini /></IconButton>
|
|
76
|
+
</header>
|
|
77
|
+
{children}
|
|
78
|
+
</ContentBox>
|
|
79
|
+
)
|
|
80
|
+
}
|