@os-design/core 1.0.198 → 1.0.200
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/cjs/InputSearch/index.js +2 -2
- package/dist/cjs/InputSearch/index.js.map +1 -1
- package/dist/esm/InputSearch/index.js +2 -2
- package/dist/esm/InputSearch/index.js.map +1 -1
- package/dist/types/InputSearch/index.d.ts.map +1 -1
- package/package.json +21 -13
- package/src/@types/emotion.d.ts +7 -0
- package/src/Alert/index.tsx +112 -0
- package/src/Avatar/index.tsx +173 -0
- package/src/Avatar/utils/nameToInitials.ts +12 -0
- package/src/Avatar/utils/strToHue.ts +13 -0
- package/src/AvatarSkeleton/index.tsx +29 -0
- package/src/Breadcrumb/index.tsx +93 -0
- package/src/BreadcrumbItem/index.tsx +83 -0
- package/src/Button/ButtonContent.tsx +91 -0
- package/src/Button/index.tsx +225 -0
- package/src/Button/utils/useButtonColors.ts +84 -0
- package/src/Checkbox/index.tsx +225 -0
- package/src/CheckboxSkeleton/index.tsx +50 -0
- package/src/DatePicker/DatePickerCalendar.tsx +220 -0
- package/src/DatePicker/index.tsx +568 -0
- package/src/Drawer/index.tsx +212 -0
- package/src/Form/FormConfigContext.ts +16 -0
- package/src/Form/index.tsx +49 -0
- package/src/FormDivider/index.tsx +74 -0
- package/src/FormItem/index.tsx +118 -0
- package/src/Gallery/Status.tsx +62 -0
- package/src/Gallery/index.tsx +290 -0
- package/src/GlobalStyles/index.tsx +17 -0
- package/src/GlobalStyles/resetStyles.ts +17 -0
- package/src/GlobalStyles/typographyStyles.ts +78 -0
- package/src/HeaderSkeleton/index.tsx +64 -0
- package/src/Image/index.tsx +104 -0
- package/src/ImageSkeleton/index.tsx +22 -0
- package/src/Input/index.tsx +330 -0
- package/src/Input/utils/getFocusableElements.ts +8 -0
- package/src/InputNumber/index.tsx +208 -0
- package/src/InputNumber/utils/defaultLocale.ts +9 -0
- package/src/InputPassword/index.tsx +201 -0
- package/src/InputPassword/utils/defaultLocale.ts +11 -0
- package/src/InputSearch/index.tsx +111 -0
- package/src/InputSearch/utils/defaultLocale.ts +9 -0
- package/src/InputSkeleton/index.tsx +28 -0
- package/src/Layout/LayoutContext.ts +21 -0
- package/src/Layout/index.tsx +44 -0
- package/src/Link/index.tsx +129 -0
- package/src/LinkButton/index.tsx +100 -0
- package/src/List/WindowScroller.tsx +53 -0
- package/src/List/index.tsx +255 -0
- package/src/List/utils/bodyPointerEvents.ts +24 -0
- package/src/List/utils/frameTimeout.ts +36 -0
- package/src/List/utils/useRWLoadNext.ts +38 -0
- package/src/ListItem/index.tsx +92 -0
- package/src/ListItemActions/index.tsx +207 -0
- package/src/ListItemLink/index.tsx +63 -0
- package/src/ListSkeleton/index.tsx +115 -0
- package/src/LogoLink/index.tsx +93 -0
- package/src/LogoLink/logo.example.svg +18 -0
- package/src/Menu/index.tsx +128 -0
- package/src/Menu/utils/useFocusWithArrows.ts +50 -0
- package/src/MenuDivider/index.tsx +22 -0
- package/src/MenuGroup/index.tsx +190 -0
- package/src/MenuItem/index.tsx +108 -0
- package/src/Modal/index.tsx +411 -0
- package/src/Modal/utils/defaultLocale.ts +9 -0
- package/src/Navigation/index.tsx +214 -0
- package/src/Navigation/utils/useScrollFlags.ts +39 -0
- package/src/NavigationItem/index.tsx +136 -0
- package/src/PageContent/index.tsx +99 -0
- package/src/PageHeader/index.tsx +246 -0
- package/src/PageHeader/utils/defaultLocale.ts +9 -0
- package/src/PageHeaderInputSearch/index.tsx +145 -0
- package/src/PageHeaderInputSearch/utils/defaultLocale.ts +16 -0
- package/src/PageHeaderSkeleton/index.tsx +33 -0
- package/src/ParagraphSkeleton/index.tsx +65 -0
- package/src/Popover/index.tsx +243 -0
- package/src/Popover/utils/usePopoverPosition.ts +216 -0
- package/src/Progress/index.tsx +100 -0
- package/src/RadioGroup/index.tsx +165 -0
- package/src/RadioGroupSkeleton/index.tsx +36 -0
- package/src/Result/index.tsx +109 -0
- package/src/ScrollButton/index.tsx +159 -0
- package/src/ScrollButton/utils/useContainerPosition.ts +41 -0
- package/src/ScrollButton/utils/useVisibility.ts +56 -0
- package/src/Select/index.tsx +970 -0
- package/src/Select/utils/defaultLocale.ts +11 -0
- package/src/Skeleton/index.tsx +52 -0
- package/src/Switch/index.tsx +217 -0
- package/src/SwitchSkeleton/index.tsx +30 -0
- package/src/Tag/index.tsx +75 -0
- package/src/TagLink/index.tsx +53 -0
- package/src/TagList/index.tsx +95 -0
- package/src/TagListSkeleton/index.tsx +38 -0
- package/src/TagSkeleton/index.tsx +40 -0
- package/src/TextArea/index.tsx +231 -0
- package/src/TextAreaSkeleton/index.tsx +20 -0
- package/src/ThemeSwitcher/index.tsx +39 -0
- package/src/TimePicker/index.tsx +142 -0
- package/src/Video/index.tsx +41 -0
- package/src/index.ts +125 -0
- package/src/message/AlertIcon.tsx +50 -0
- package/src/message/Message.tsx +108 -0
- package/src/message/index.tsx +64 -0
- package/src/message/styles.ts +25 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { css } from '@emotion/react';
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
import { Left } from '@os-design/icons';
|
|
4
|
+
import { m } from '@os-design/media';
|
|
5
|
+
|
|
6
|
+
import { ellipsisStyles } from '@os-design/styles';
|
|
7
|
+
import { ThemeOverrider, clr } from '@os-design/theming';
|
|
8
|
+
|
|
9
|
+
import { omitEmotionProps } from '@os-design/utils';
|
|
10
|
+
import React, { forwardRef, useContext } from 'react';
|
|
11
|
+
|
|
12
|
+
import Button from '../Button';
|
|
13
|
+
import LayoutContext from '../Layout/LayoutContext';
|
|
14
|
+
import defaultLocale, { PageHeaderLocale } from './utils/defaultLocale';
|
|
15
|
+
|
|
16
|
+
type JsxDivProps = Omit<JSX.IntrinsicElements['div'], 'ref'>;
|
|
17
|
+
export interface PageHeaderProps extends JsxDivProps {
|
|
18
|
+
/**
|
|
19
|
+
* The title of the page.
|
|
20
|
+
* @default undefined
|
|
21
|
+
*/
|
|
22
|
+
title: string;
|
|
23
|
+
/**
|
|
24
|
+
* The subtitle of the page.
|
|
25
|
+
* @default undefined
|
|
26
|
+
*/
|
|
27
|
+
subtitle?: string;
|
|
28
|
+
/**
|
|
29
|
+
* The component located on the left side.
|
|
30
|
+
* @default undefined
|
|
31
|
+
*/
|
|
32
|
+
left?: React.ReactNode;
|
|
33
|
+
/**
|
|
34
|
+
* Reduces the left padding of the page header.
|
|
35
|
+
* @default false
|
|
36
|
+
*/
|
|
37
|
+
leftIsGhostButton?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* The component located on the right side.
|
|
40
|
+
* @default undefined
|
|
41
|
+
*/
|
|
42
|
+
right?: React.ReactNode;
|
|
43
|
+
/**
|
|
44
|
+
* Reduces the right padding of the page header.
|
|
45
|
+
* @default false
|
|
46
|
+
*/
|
|
47
|
+
rightIsGhostButton?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* The back event handler. If passed, the page header has the back button.
|
|
50
|
+
* @default undefined
|
|
51
|
+
*/
|
|
52
|
+
onBack?: () => void;
|
|
53
|
+
/**
|
|
54
|
+
* The locale.
|
|
55
|
+
* @default undefined
|
|
56
|
+
*/
|
|
57
|
+
locale?: PageHeaderLocale;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const getReducedPadding = (p, isMinSm: boolean) => {
|
|
61
|
+
const i = isMinSm ? 1 : 0;
|
|
62
|
+
let padding = p.theme.horizontalPadding[i] - p.theme.buttonPaddingHorizontal;
|
|
63
|
+
if (padding < 0) padding = 0;
|
|
64
|
+
return padding;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const horizontalPaddingStyles = (p) => {
|
|
68
|
+
const reducedPadding = getReducedPadding(p, false);
|
|
69
|
+
const reducedPaddingSm = getReducedPadding(p, true);
|
|
70
|
+
return css`
|
|
71
|
+
padding-left: ${p.leftIsGhostButton
|
|
72
|
+
? reducedPadding
|
|
73
|
+
: p.theme.horizontalPadding[0]}em;
|
|
74
|
+
padding-right: ${p.rightIsGhostButton
|
|
75
|
+
? reducedPadding
|
|
76
|
+
: p.theme.horizontalPadding[0]}em;
|
|
77
|
+
|
|
78
|
+
${m.min.sm} {
|
|
79
|
+
padding-left: ${p.leftIsGhostButton
|
|
80
|
+
? reducedPaddingSm
|
|
81
|
+
: p.theme.horizontalPadding[1]}em;
|
|
82
|
+
padding-right: ${p.rightIsGhostButton
|
|
83
|
+
? reducedPaddingSm
|
|
84
|
+
: p.theme.horizontalPadding[1]}em;
|
|
85
|
+
}
|
|
86
|
+
`;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const hasNavigationIndentStyles = (p) =>
|
|
90
|
+
p.hasNavigationIndent &&
|
|
91
|
+
css`
|
|
92
|
+
${m.min.md} {
|
|
93
|
+
left: ${p.theme.navigationSideWidth}em;
|
|
94
|
+
}
|
|
95
|
+
`;
|
|
96
|
+
|
|
97
|
+
interface ContainerProps {
|
|
98
|
+
leftIsGhostButton?: boolean;
|
|
99
|
+
rightIsGhostButton?: boolean;
|
|
100
|
+
hasNavigationIndent?: boolean;
|
|
101
|
+
}
|
|
102
|
+
export const PageHeaderContainer = styled(
|
|
103
|
+
'div',
|
|
104
|
+
omitEmotionProps(
|
|
105
|
+
'leftIsGhostButton',
|
|
106
|
+
'rightIsGhostButton',
|
|
107
|
+
'hasNavigationIndent'
|
|
108
|
+
)
|
|
109
|
+
)<ContainerProps>`
|
|
110
|
+
position: fixed;
|
|
111
|
+
top: 0;
|
|
112
|
+
left: 0;
|
|
113
|
+
right: 0;
|
|
114
|
+
|
|
115
|
+
height: ${(p) => p.theme.pageHeaderHeight[0]}em;
|
|
116
|
+
${m.min.md} {
|
|
117
|
+
height: ${(p) => p.theme.pageHeaderHeight[1]}em;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
display: flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
box-sizing: border-box;
|
|
123
|
+
z-index: 101;
|
|
124
|
+
|
|
125
|
+
background-color: ${(p) => clr(p.theme.pageHeaderColorBg)};
|
|
126
|
+
color: ${(p) => clr(p.theme.pageHeaderColorText)};
|
|
127
|
+
border-bottom: 1px solid ${(p) => clr(p.theme.pageHeaderColorBorder)};
|
|
128
|
+
|
|
129
|
+
${horizontalPaddingStyles};
|
|
130
|
+
${hasNavigationIndentStyles};
|
|
131
|
+
`;
|
|
132
|
+
|
|
133
|
+
const BackButton = styled(Button)`
|
|
134
|
+
margin-right: 0.2em;
|
|
135
|
+
flex-shrink: 0;
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
const Content = styled.div`
|
|
139
|
+
overflow: hidden; // For ellipsis
|
|
140
|
+
`;
|
|
141
|
+
|
|
142
|
+
const notHasSubtitleStyles = (p) =>
|
|
143
|
+
!p.hasSubtitle &&
|
|
144
|
+
css`
|
|
145
|
+
font-size: ${p.theme.sizes.large}em;
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
interface TitleProps {
|
|
149
|
+
hasSubtitle: boolean;
|
|
150
|
+
}
|
|
151
|
+
const Title = styled('h1', omitEmotionProps('hasSubtitle'))<TitleProps>`
|
|
152
|
+
margin: 0;
|
|
153
|
+
font-size: 1em;
|
|
154
|
+
font-weight: 500;
|
|
155
|
+
line-height: 1.2;
|
|
156
|
+
${notHasSubtitleStyles};
|
|
157
|
+
${ellipsisStyles};
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
const Subtitle = styled.div`
|
|
161
|
+
font-size: ${(p) => p.theme.sizes.small}em;
|
|
162
|
+
color: ${(p) => clr(p.theme.pageHeaderSubtitleColorText)};
|
|
163
|
+
line-height: 1;
|
|
164
|
+
margin-top: 0.2em;
|
|
165
|
+
${ellipsisStyles};
|
|
166
|
+
`;
|
|
167
|
+
|
|
168
|
+
const Addon = styled.div`
|
|
169
|
+
display: flex;
|
|
170
|
+
align-items: center;
|
|
171
|
+
`;
|
|
172
|
+
|
|
173
|
+
const LeftAddon = styled(Addon)`
|
|
174
|
+
padding-right: ${(p) => p.theme.pageHeaderAddonPaddingHorizontal}em;
|
|
175
|
+
`;
|
|
176
|
+
|
|
177
|
+
const RightAddon = styled(Addon)`
|
|
178
|
+
padding-left: ${(p) => p.theme.pageHeaderAddonPaddingHorizontal}em;
|
|
179
|
+
margin-left: auto;
|
|
180
|
+
|
|
181
|
+
display: grid;
|
|
182
|
+
grid-auto-flow: column;
|
|
183
|
+
grid-column-gap: 0.4em;
|
|
184
|
+
`;
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* The header of the page.
|
|
188
|
+
*/
|
|
189
|
+
const PageHeader = forwardRef<HTMLDivElement, PageHeaderProps>(
|
|
190
|
+
(
|
|
191
|
+
{
|
|
192
|
+
title,
|
|
193
|
+
subtitle,
|
|
194
|
+
left,
|
|
195
|
+
leftIsGhostButton = false,
|
|
196
|
+
right,
|
|
197
|
+
rightIsGhostButton = false,
|
|
198
|
+
onBack,
|
|
199
|
+
locale = defaultLocale,
|
|
200
|
+
...rest
|
|
201
|
+
},
|
|
202
|
+
ref
|
|
203
|
+
) => {
|
|
204
|
+
const { hasNavigation } = useContext(LayoutContext);
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<ThemeOverrider
|
|
208
|
+
overrides={(t) => ({
|
|
209
|
+
buttonPaddingHorizontal: t.pageHeaderButtonPaddingHorizontal,
|
|
210
|
+
})}
|
|
211
|
+
>
|
|
212
|
+
<PageHeaderContainer
|
|
213
|
+
leftIsGhostButton={leftIsGhostButton || !!onBack}
|
|
214
|
+
rightIsGhostButton={rightIsGhostButton}
|
|
215
|
+
hasNavigationIndent={hasNavigation}
|
|
216
|
+
{...rest}
|
|
217
|
+
ref={ref}
|
|
218
|
+
>
|
|
219
|
+
{onBack && (
|
|
220
|
+
<BackButton
|
|
221
|
+
type='ghost'
|
|
222
|
+
wide='never'
|
|
223
|
+
onClick={onBack}
|
|
224
|
+
aria-label={locale.backLabel}
|
|
225
|
+
>
|
|
226
|
+
<Left />
|
|
227
|
+
</BackButton>
|
|
228
|
+
)}
|
|
229
|
+
|
|
230
|
+
{left && <LeftAddon>{left}</LeftAddon>}
|
|
231
|
+
|
|
232
|
+
<Content>
|
|
233
|
+
<Title hasSubtitle={!!subtitle}>{title}</Title>
|
|
234
|
+
{subtitle && <Subtitle>{subtitle}</Subtitle>}
|
|
235
|
+
</Content>
|
|
236
|
+
|
|
237
|
+
{right && <RightAddon>{right}</RightAddon>}
|
|
238
|
+
</PageHeaderContainer>
|
|
239
|
+
</ThemeOverrider>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
PageHeader.displayName = 'PageHeader';
|
|
245
|
+
|
|
246
|
+
export default PageHeader;
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { css, keyframes } from '@emotion/react';
|
|
2
|
+
import styled from '@emotion/styled';
|
|
3
|
+
import { Close, Search } from '@os-design/icons';
|
|
4
|
+
import { ThemeOverrider, useTheme } from '@os-design/theming';
|
|
5
|
+
import { omitEmotionProps, useClosable } from '@os-design/utils';
|
|
6
|
+
import React, { forwardRef, useContext, useState } from 'react';
|
|
7
|
+
import Button from '../Button';
|
|
8
|
+
import InputSearch, { InputSearchProps } from '../InputSearch';
|
|
9
|
+
import LayoutContext from '../Layout/LayoutContext';
|
|
10
|
+
import { PageHeaderContainer } from '../PageHeader';
|
|
11
|
+
import defaultLocale, {
|
|
12
|
+
PageHeaderInputSearchLocale,
|
|
13
|
+
} from './utils/defaultLocale';
|
|
14
|
+
|
|
15
|
+
export interface PageHeaderInputSearchProps
|
|
16
|
+
extends Omit<InputSearchProps, 'size' | 'locale'> {
|
|
17
|
+
/**
|
|
18
|
+
* The locale.
|
|
19
|
+
* @default undefined
|
|
20
|
+
*/
|
|
21
|
+
locale?: PageHeaderInputSearchLocale;
|
|
22
|
+
/**
|
|
23
|
+
* Whether the search input opens on mount.
|
|
24
|
+
* @default false
|
|
25
|
+
*/
|
|
26
|
+
autoOpen?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* The close event handler.
|
|
29
|
+
* @default undefined
|
|
30
|
+
*/
|
|
31
|
+
onClose?: () => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const fadeIn = keyframes`
|
|
35
|
+
from { transform: translateY(-100%); }
|
|
36
|
+
to { transform: translateY(0); }
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
const fadeOut = keyframes`
|
|
40
|
+
from { transform: translateY(0); }
|
|
41
|
+
to { transform: translateY(-100%); }
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const visibleStyles = (p) =>
|
|
45
|
+
p.visible &&
|
|
46
|
+
css`
|
|
47
|
+
animation: ${fadeIn} ${p.theme.transitionDelay}ms forwards;
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
const invisibleStyles = (p) =>
|
|
51
|
+
!p.visible &&
|
|
52
|
+
css`
|
|
53
|
+
animation: ${fadeOut} ${p.theme.transitionDelay}ms forwards;
|
|
54
|
+
`;
|
|
55
|
+
|
|
56
|
+
interface ContainerProps {
|
|
57
|
+
visible: boolean;
|
|
58
|
+
}
|
|
59
|
+
const Container = styled(
|
|
60
|
+
PageHeaderContainer,
|
|
61
|
+
omitEmotionProps('visible')
|
|
62
|
+
)<ContainerProps>`
|
|
63
|
+
z-index: 102; // After PageHeaderContainer
|
|
64
|
+
${visibleStyles};
|
|
65
|
+
${invisibleStyles};
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
const CloseButton = styled(Button)`
|
|
69
|
+
margin-left: ${(p) => p.theme.pageHeaderAddonPaddingHorizontal}em;
|
|
70
|
+
`;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The search input for the page header.
|
|
74
|
+
*/
|
|
75
|
+
const PageHeaderInputSearch = forwardRef<
|
|
76
|
+
HTMLInputElement,
|
|
77
|
+
PageHeaderInputSearchProps
|
|
78
|
+
>(
|
|
79
|
+
(
|
|
80
|
+
{
|
|
81
|
+
locale = defaultLocale,
|
|
82
|
+
autoOpen = false,
|
|
83
|
+
onClose = () => {},
|
|
84
|
+
loading = false,
|
|
85
|
+
...rest
|
|
86
|
+
},
|
|
87
|
+
ref
|
|
88
|
+
) => {
|
|
89
|
+
const [visible, setVisible] = useState(autoOpen);
|
|
90
|
+
const { theme } = useTheme();
|
|
91
|
+
const mounted = useClosable(visible, theme.transitionDelay);
|
|
92
|
+
const { hasNavigation } = useContext(LayoutContext);
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<>
|
|
96
|
+
<Button
|
|
97
|
+
type='ghost'
|
|
98
|
+
wide='never'
|
|
99
|
+
loading={loading}
|
|
100
|
+
onClick={() => setVisible(true)}
|
|
101
|
+
aria-label={locale.searchLabel}
|
|
102
|
+
>
|
|
103
|
+
<Search />
|
|
104
|
+
</Button>
|
|
105
|
+
|
|
106
|
+
{mounted && (
|
|
107
|
+
<ThemeOverrider
|
|
108
|
+
overrides={(t) => ({
|
|
109
|
+
buttonPaddingHorizontal: t.pageHeaderButtonPaddingHorizontal,
|
|
110
|
+
})}
|
|
111
|
+
>
|
|
112
|
+
<Container
|
|
113
|
+
visible={visible}
|
|
114
|
+
rightIsGhostButton
|
|
115
|
+
hasNavigationIndent={hasNavigation}
|
|
116
|
+
>
|
|
117
|
+
<InputSearch
|
|
118
|
+
autoFocus
|
|
119
|
+
locale={locale}
|
|
120
|
+
loading={loading}
|
|
121
|
+
{...rest}
|
|
122
|
+
ref={ref}
|
|
123
|
+
/>
|
|
124
|
+
<CloseButton
|
|
125
|
+
type='ghost'
|
|
126
|
+
wide='never'
|
|
127
|
+
onClick={() => {
|
|
128
|
+
setVisible(false);
|
|
129
|
+
onClose();
|
|
130
|
+
}}
|
|
131
|
+
aria-label={locale.closeLabel}
|
|
132
|
+
>
|
|
133
|
+
<Close />
|
|
134
|
+
</CloseButton>
|
|
135
|
+
</Container>
|
|
136
|
+
</ThemeOverrider>
|
|
137
|
+
)}
|
|
138
|
+
</>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
PageHeaderInputSearch.displayName = 'PageHeaderInputSearch';
|
|
144
|
+
|
|
145
|
+
export default PageHeaderInputSearch;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import inputSearchDefaultLocale, {
|
|
2
|
+
InputSearchLocale,
|
|
3
|
+
} from '../../InputSearch/utils/defaultLocale';
|
|
4
|
+
|
|
5
|
+
export interface PageHeaderInputSearchLocale extends InputSearchLocale {
|
|
6
|
+
searchLabel: string;
|
|
7
|
+
closeLabel: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const defaultLocale: PageHeaderInputSearchLocale = {
|
|
11
|
+
...inputSearchDefaultLocale,
|
|
12
|
+
searchLabel: 'Search',
|
|
13
|
+
closeLabel: 'Close search',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default defaultLocale;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { WithSize } from '@os-design/styles';
|
|
2
|
+
|
|
3
|
+
import React, { forwardRef, useContext } from 'react';
|
|
4
|
+
import LayoutContext from '../Layout/LayoutContext';
|
|
5
|
+
import { PageHeaderContainer } from '../PageHeader';
|
|
6
|
+
|
|
7
|
+
import Skeleton, { SkeletonProps } from '../Skeleton';
|
|
8
|
+
|
|
9
|
+
export type PageHeaderSkeletonProps = SkeletonProps & WithSize;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Provides a page header placeholder while a user waits for
|
|
13
|
+
* the content to load.
|
|
14
|
+
*/
|
|
15
|
+
const PageHeaderSkeleton = forwardRef<HTMLDivElement, PageHeaderSkeletonProps>(
|
|
16
|
+
({ width = '30%', ...rest }, ref) => {
|
|
17
|
+
const { hasNavigation } = useContext(LayoutContext);
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<PageHeaderContainer
|
|
21
|
+
hasNavigationIndent={hasNavigation}
|
|
22
|
+
{...rest}
|
|
23
|
+
ref={ref}
|
|
24
|
+
>
|
|
25
|
+
<Skeleton width={width} />
|
|
26
|
+
</PageHeaderContainer>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
PageHeaderSkeleton.displayName = 'PageHeaderSkeleton';
|
|
32
|
+
|
|
33
|
+
export default PageHeaderSkeleton;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { css } from '@emotion/react';
|
|
2
|
+
|
|
3
|
+
import styled from '@emotion/styled';
|
|
4
|
+
|
|
5
|
+
import { omitEmotionProps } from '@os-design/utils';
|
|
6
|
+
import React, { forwardRef } from 'react';
|
|
7
|
+
|
|
8
|
+
import Skeleton, { SkeletonProps } from '../Skeleton';
|
|
9
|
+
|
|
10
|
+
export interface ParagraphSkeletonProps extends SkeletonProps {
|
|
11
|
+
/**
|
|
12
|
+
* The number of rows.
|
|
13
|
+
* @default 4
|
|
14
|
+
*/
|
|
15
|
+
rows?: number;
|
|
16
|
+
/**
|
|
17
|
+
* The width of the last row.
|
|
18
|
+
* @default 70%
|
|
19
|
+
*/
|
|
20
|
+
width?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Whether the paragraph has a bottom margin.
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
hasMargin?: boolean;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const hasMarginStyles = (p) =>
|
|
29
|
+
p.hasMargin &&
|
|
30
|
+
css`
|
|
31
|
+
margin-bottom: ${p.theme.paragraphMarginBottom +
|
|
32
|
+
(p.theme.lineHeight - 1)}em;
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
type ContainerProps = Pick<ParagraphSkeletonProps, 'hasMargin'>;
|
|
36
|
+
const Container = styled('div', omitEmotionProps('hasMargin'))<ContainerProps>`
|
|
37
|
+
& > *:not(:last-of-type) {
|
|
38
|
+
margin-bottom: ${(p) => p.theme.lineHeight - 1}em;
|
|
39
|
+
}
|
|
40
|
+
${hasMarginStyles};
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
let key = 0;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Provides a paragraph placeholder while a user waits for the content to load.
|
|
47
|
+
*/
|
|
48
|
+
const ParagraphSkeleton = forwardRef<HTMLDivElement, ParagraphSkeletonProps>(
|
|
49
|
+
({ rows = 4, width = '70%', hasMargin = false, ...rest }, ref) => (
|
|
50
|
+
<Container hasMargin={hasMargin} {...rest} ref={ref}>
|
|
51
|
+
{Array(rows)
|
|
52
|
+
.fill({})
|
|
53
|
+
.map((_, index) => {
|
|
54
|
+
key += 1;
|
|
55
|
+
return (
|
|
56
|
+
<Skeleton key={key} width={index < rows - 1 ? '100%' : width} />
|
|
57
|
+
);
|
|
58
|
+
})}
|
|
59
|
+
</Container>
|
|
60
|
+
)
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
ParagraphSkeleton.displayName = 'ParagraphSkeleton';
|
|
64
|
+
|
|
65
|
+
export default ParagraphSkeleton;
|