@os-design/core 1.0.199 → 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.
Files changed (99) hide show
  1. package/package.json +21 -13
  2. package/src/@types/emotion.d.ts +7 -0
  3. package/src/Alert/index.tsx +112 -0
  4. package/src/Avatar/index.tsx +173 -0
  5. package/src/Avatar/utils/nameToInitials.ts +12 -0
  6. package/src/Avatar/utils/strToHue.ts +13 -0
  7. package/src/AvatarSkeleton/index.tsx +29 -0
  8. package/src/Breadcrumb/index.tsx +93 -0
  9. package/src/BreadcrumbItem/index.tsx +83 -0
  10. package/src/Button/ButtonContent.tsx +91 -0
  11. package/src/Button/index.tsx +225 -0
  12. package/src/Button/utils/useButtonColors.ts +84 -0
  13. package/src/Checkbox/index.tsx +225 -0
  14. package/src/CheckboxSkeleton/index.tsx +50 -0
  15. package/src/DatePicker/DatePickerCalendar.tsx +220 -0
  16. package/src/DatePicker/index.tsx +568 -0
  17. package/src/Drawer/index.tsx +212 -0
  18. package/src/Form/FormConfigContext.ts +16 -0
  19. package/src/Form/index.tsx +49 -0
  20. package/src/FormDivider/index.tsx +74 -0
  21. package/src/FormItem/index.tsx +118 -0
  22. package/src/Gallery/Status.tsx +62 -0
  23. package/src/Gallery/index.tsx +290 -0
  24. package/src/GlobalStyles/index.tsx +17 -0
  25. package/src/GlobalStyles/resetStyles.ts +17 -0
  26. package/src/GlobalStyles/typographyStyles.ts +78 -0
  27. package/src/HeaderSkeleton/index.tsx +64 -0
  28. package/src/Image/index.tsx +104 -0
  29. package/src/ImageSkeleton/index.tsx +22 -0
  30. package/src/Input/index.tsx +330 -0
  31. package/src/Input/utils/getFocusableElements.ts +8 -0
  32. package/src/InputNumber/index.tsx +208 -0
  33. package/src/InputNumber/utils/defaultLocale.ts +9 -0
  34. package/src/InputPassword/index.tsx +201 -0
  35. package/src/InputPassword/utils/defaultLocale.ts +11 -0
  36. package/src/InputSearch/index.tsx +111 -0
  37. package/src/InputSearch/utils/defaultLocale.ts +9 -0
  38. package/src/InputSkeleton/index.tsx +28 -0
  39. package/src/Layout/LayoutContext.ts +21 -0
  40. package/src/Layout/index.tsx +44 -0
  41. package/src/Link/index.tsx +129 -0
  42. package/src/LinkButton/index.tsx +100 -0
  43. package/src/List/WindowScroller.tsx +53 -0
  44. package/src/List/index.tsx +255 -0
  45. package/src/List/utils/bodyPointerEvents.ts +24 -0
  46. package/src/List/utils/frameTimeout.ts +36 -0
  47. package/src/List/utils/useRWLoadNext.ts +38 -0
  48. package/src/ListItem/index.tsx +92 -0
  49. package/src/ListItemActions/index.tsx +207 -0
  50. package/src/ListItemLink/index.tsx +63 -0
  51. package/src/ListSkeleton/index.tsx +115 -0
  52. package/src/LogoLink/index.tsx +93 -0
  53. package/src/LogoLink/logo.example.svg +18 -0
  54. package/src/Menu/index.tsx +128 -0
  55. package/src/Menu/utils/useFocusWithArrows.ts +50 -0
  56. package/src/MenuDivider/index.tsx +22 -0
  57. package/src/MenuGroup/index.tsx +190 -0
  58. package/src/MenuItem/index.tsx +108 -0
  59. package/src/Modal/index.tsx +411 -0
  60. package/src/Modal/utils/defaultLocale.ts +9 -0
  61. package/src/Navigation/index.tsx +214 -0
  62. package/src/Navigation/utils/useScrollFlags.ts +39 -0
  63. package/src/NavigationItem/index.tsx +136 -0
  64. package/src/PageContent/index.tsx +99 -0
  65. package/src/PageHeader/index.tsx +246 -0
  66. package/src/PageHeader/utils/defaultLocale.ts +9 -0
  67. package/src/PageHeaderInputSearch/index.tsx +145 -0
  68. package/src/PageHeaderInputSearch/utils/defaultLocale.ts +16 -0
  69. package/src/PageHeaderSkeleton/index.tsx +33 -0
  70. package/src/ParagraphSkeleton/index.tsx +65 -0
  71. package/src/Popover/index.tsx +243 -0
  72. package/src/Popover/utils/usePopoverPosition.ts +216 -0
  73. package/src/Progress/index.tsx +100 -0
  74. package/src/RadioGroup/index.tsx +165 -0
  75. package/src/RadioGroupSkeleton/index.tsx +36 -0
  76. package/src/Result/index.tsx +109 -0
  77. package/src/ScrollButton/index.tsx +159 -0
  78. package/src/ScrollButton/utils/useContainerPosition.ts +41 -0
  79. package/src/ScrollButton/utils/useVisibility.ts +56 -0
  80. package/src/Select/index.tsx +970 -0
  81. package/src/Select/utils/defaultLocale.ts +11 -0
  82. package/src/Skeleton/index.tsx +52 -0
  83. package/src/Switch/index.tsx +217 -0
  84. package/src/SwitchSkeleton/index.tsx +30 -0
  85. package/src/Tag/index.tsx +75 -0
  86. package/src/TagLink/index.tsx +53 -0
  87. package/src/TagList/index.tsx +95 -0
  88. package/src/TagListSkeleton/index.tsx +38 -0
  89. package/src/TagSkeleton/index.tsx +40 -0
  90. package/src/TextArea/index.tsx +231 -0
  91. package/src/TextAreaSkeleton/index.tsx +20 -0
  92. package/src/ThemeSwitcher/index.tsx +39 -0
  93. package/src/TimePicker/index.tsx +142 -0
  94. package/src/Video/index.tsx +41 -0
  95. package/src/index.ts +125 -0
  96. package/src/message/AlertIcon.tsx +50 -0
  97. package/src/message/Message.tsx +108 -0
  98. package/src/message/index.tsx +64 -0
  99. package/src/message/styles.ts +25 -0
@@ -0,0 +1,231 @@
1
+ import { css } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+ import { Loading } from '@os-design/icons';
4
+ import { WithSize } from '@os-design/styles';
5
+ import { clr, ThemeOverrider } from '@os-design/theming';
6
+ import { omitEmotionProps, useForwardedRef } from '@os-design/utils';
7
+ import React, {
8
+ ChangeEvent,
9
+ FocusEventHandler,
10
+ ForwardedRef,
11
+ forwardRef,
12
+ KeyboardEventHandler,
13
+ useCallback,
14
+ useMemo,
15
+ } from 'react';
16
+ import { InputContainer, StyledInput } from '../Input';
17
+ import getFocusableElements from '../Input/utils/getFocusableElements';
18
+
19
+ type JsxTextAreaProps = Omit<
20
+ JSX.IntrinsicElements['textarea'],
21
+ 'value' | 'onChange' | 'ref'
22
+ >;
23
+ export interface TextAreaProps extends JsxTextAreaProps, WithSize {
24
+ /**
25
+ * The component located on the left side.
26
+ * @default undefined
27
+ */
28
+ left?: React.ReactNode;
29
+ /**
30
+ * Adds padding to the left component.
31
+ * It can be useful when passing an icon or text in the left component.
32
+ * @default false
33
+ */
34
+ leftHasPadding?: boolean;
35
+ /**
36
+ * The component located on the right side.
37
+ * @default undefined
38
+ */
39
+ right?: React.ReactNode;
40
+ /**
41
+ * Adds padding to the right component.
42
+ * It can be useful when passing an icon or text in the right component.
43
+ * @default false
44
+ */
45
+ rightHasPadding?: boolean;
46
+ /**
47
+ * Whether the textarea is disabled.
48
+ * @default false
49
+ */
50
+ disabled?: boolean;
51
+ /**
52
+ * Shows the loading status.
53
+ * @default false
54
+ */
55
+ loading?: boolean;
56
+ /**
57
+ * The ref of the textarea container.
58
+ * @default undefined
59
+ */
60
+ containerRef?: ForwardedRef<HTMLDivElement>;
61
+ /**
62
+ * The props of the textarea container.
63
+ * @default undefined
64
+ */
65
+ containerProps?: JSX.IntrinsicElements['div'];
66
+ /**
67
+ * The textarea value.
68
+ * @default undefined
69
+ */
70
+ value?: string;
71
+ /**
72
+ * The change event handler.
73
+ * @default undefined
74
+ */
75
+ onChange?: (value: string, e: ChangeEvent<HTMLTextAreaElement>) => void;
76
+ }
77
+
78
+ const TextAreaContainer = styled(InputContainer)`
79
+ height: ${(p) => p.theme.textAreaHeight}em;
80
+ `;
81
+
82
+ const TextAreaField = styled(StyledInput.withComponent('textarea'))`
83
+ padding-top: ${(p) => p.theme.textAreaPaddingVertical}em;
84
+ padding-bottom: ${(p) => p.theme.textAreaPaddingVertical}em;
85
+ line-height: ${(p) => p.theme.lineHeight};
86
+ resize: none;
87
+ `;
88
+
89
+ interface AddonProps {
90
+ hasPadding: boolean;
91
+ }
92
+ const Addon = styled('span', omitEmotionProps('hasPadding'))<AddonProps>`
93
+ display: flex;
94
+ align-items: center;
95
+ user-select: none;
96
+ color: ${(p) => clr(p.theme.inputColorPlaceholder)};
97
+
98
+ svg {
99
+ transform: scale(1.2);
100
+ }
101
+ `;
102
+
103
+ const LeftAddon = styled(Addon)`
104
+ padding-right: ${(p) => p.theme.inputAddonPaddingHorizontal}em;
105
+ ${(p) =>
106
+ p.hasPadding &&
107
+ css`
108
+ padding-left: ${p.theme.inputPaddingHorizontal}em;
109
+ `}
110
+ `;
111
+
112
+ const RightAddon = styled(Addon)`
113
+ padding-left: ${(p) => p.theme.inputAddonPaddingHorizontal}em;
114
+ ${(p) =>
115
+ p.hasPadding &&
116
+ css`
117
+ padding-right: ${p.theme.inputPaddingHorizontal}em;
118
+ `}
119
+ `;
120
+
121
+ /**
122
+ * The multiline input component.
123
+ */
124
+ const TextArea = forwardRef<HTMLTextAreaElement, TextAreaProps>(
125
+ (
126
+ {
127
+ left,
128
+ leftHasPadding = false,
129
+ right,
130
+ rightHasPadding = false,
131
+ disabled = false,
132
+ loading = false,
133
+ containerRef,
134
+ containerProps = {},
135
+ size,
136
+ value,
137
+ onChange = () => {},
138
+ ...rest
139
+ },
140
+ ref
141
+ ) => {
142
+ const [innerContainerRef, mergedContainerRef] =
143
+ useForwardedRef(containerRef);
144
+
145
+ const rightValue = useMemo(
146
+ () => (loading ? <Loading /> : right),
147
+ [loading, right]
148
+ );
149
+
150
+ const rightHasPaddingValue = useMemo(
151
+ () => (loading ? true : rightHasPadding),
152
+ [loading, rightHasPadding]
153
+ );
154
+
155
+ const onFocus = useCallback<FocusEventHandler>(
156
+ (e) => {
157
+ // Focus the next element if the container element was focused.
158
+ // The next element will be the input or button in the addon.
159
+ if (disabled || e.target !== innerContainerRef.current) return;
160
+ const focusableElements = getFocusableElements(
161
+ innerContainerRef.current
162
+ );
163
+ focusableElements[0].focus();
164
+ },
165
+ [disabled, innerContainerRef]
166
+ );
167
+
168
+ const onKeyDown = useCallback<KeyboardEventHandler>(
169
+ (e) => {
170
+ // Focus the previous element if the first element in the input
171
+ // container is focused and the Shift + Tab combination is pressed.
172
+ const focusableElements = getFocusableElements(document);
173
+ const inputFocusableElements = innerContainerRef.current
174
+ ? getFocusableElements(innerContainerRef.current)
175
+ : [];
176
+ const firstInputElementIsFocused =
177
+ inputFocusableElements[0] === document.activeElement;
178
+ if (firstInputElementIsFocused && e.key === 'Tab' && e.shiftKey) {
179
+ const inputContainerIndex = focusableElements.findIndex(
180
+ (el) => el === innerContainerRef.current
181
+ );
182
+ if (inputContainerIndex === 0) return;
183
+ const elementBeforeInputContainer =
184
+ focusableElements[inputContainerIndex - 1];
185
+ elementBeforeInputContainer.focus();
186
+ }
187
+ },
188
+ [innerContainerRef]
189
+ );
190
+
191
+ return (
192
+ <TextAreaContainer
193
+ disabled={disabled}
194
+ size={size}
195
+ tabIndex={!disabled ? 0 : -1}
196
+ onFocus={onFocus}
197
+ onKeyDown={onKeyDown}
198
+ ref={mergedContainerRef}
199
+ {...containerProps}
200
+ >
201
+ {left && (
202
+ <ThemeOverrider overrides={{ buttonPaddingHorizontal: 0.8 }}>
203
+ <LeftAddon hasPadding={leftHasPadding}>{left}</LeftAddon>
204
+ </ThemeOverrider>
205
+ )}
206
+
207
+ <TextAreaField
208
+ disabled={disabled}
209
+ hasLeft={!!left}
210
+ hasRight={!!right}
211
+ value={value || ''}
212
+ onChange={(e) => onChange(e.target.value, e)}
213
+ {...rest}
214
+ ref={ref}
215
+ />
216
+
217
+ {rightValue && (
218
+ <ThemeOverrider overrides={{ buttonPaddingHorizontal: 0.8 }}>
219
+ <RightAddon hasPadding={rightHasPaddingValue}>
220
+ {rightValue}
221
+ </RightAddon>
222
+ </ThemeOverrider>
223
+ )}
224
+ </TextAreaContainer>
225
+ );
226
+ }
227
+ );
228
+
229
+ TextArea.displayName = 'TextArea';
230
+
231
+ export default TextArea;
@@ -0,0 +1,20 @@
1
+ import styled from '@emotion/styled';
2
+ import React, { forwardRef } from 'react';
3
+ import InputSkeleton, { InputSkeletonProps } from '../InputSkeleton';
4
+
5
+ export type TextAreaSkeletonProps = InputSkeletonProps;
6
+
7
+ const StyledTextAreaSkeleton = styled(InputSkeleton)`
8
+ height: ${(p) => p.theme.textAreaHeight}em;
9
+ `;
10
+
11
+ /**
12
+ * Provides a textarea placeholder while a user waits for the content to load.
13
+ */
14
+ const TextAreaSkeleton = forwardRef<HTMLDivElement, TextAreaSkeletonProps>(
15
+ (props, ref) => <StyledTextAreaSkeleton {...props} ref={ref} />
16
+ );
17
+
18
+ TextAreaSkeleton.displayName = 'TextAreaSkeleton';
19
+
20
+ export default TextAreaSkeleton;
@@ -0,0 +1,39 @@
1
+ import { Moon, Sun } from '@os-design/icons';
2
+
3
+ import { useTheme } from '@os-design/theming';
4
+ import React, { forwardRef } from 'react';
5
+
6
+ import Button, { ButtonProps } from '../Button';
7
+
8
+ export type ThemeSwitcherProps = ButtonProps;
9
+
10
+ /**
11
+ * The button to switch the current theme.
12
+ */
13
+ const ThemeSwitcher = forwardRef<HTMLButtonElement, ThemeSwitcherProps>(
14
+ ({ onClick = () => {}, ...rest }, ref) => {
15
+ const { activeTheme, setActiveTheme } = useTheme();
16
+
17
+ return (
18
+ <Button
19
+ type='ghost'
20
+ wide='never'
21
+ onClick={(e) => {
22
+ setActiveTheme(activeTheme === 'light' ? 'dark' : 'light');
23
+ onClick(e);
24
+ }}
25
+ role='switch'
26
+ aria-checked={activeTheme === 'dark'}
27
+ aria-label='Dark theme'
28
+ {...rest}
29
+ ref={ref}
30
+ >
31
+ {activeTheme === 'light' ? <Moon /> : <Sun />}
32
+ </Button>
33
+ );
34
+ }
35
+ );
36
+
37
+ ThemeSwitcher.displayName = 'ThemeSwitcher';
38
+
39
+ export default ThemeSwitcher;
@@ -0,0 +1,142 @@
1
+ import { useTime } from '@os-design/time-picker-utils';
2
+ import { useForwardedRef, useForwardedState } from '@os-design/utils';
3
+ import React, {
4
+ forwardRef,
5
+ useCallback,
6
+ useEffect,
7
+ useMemo,
8
+ useState,
9
+ } from 'react';
10
+ import Button from '../Button';
11
+ import Input, { InputProps } from '../Input';
12
+
13
+ export interface TimePickerProps
14
+ extends Omit<InputProps, 'type' | 'value' | 'defaultValue' | 'onChange'> {
15
+ /**
16
+ * The time notation.
17
+ * @default 12-hour
18
+ */
19
+ notation?: '12-hour' | '24-hour';
20
+ /**
21
+ * The selected date.
22
+ * @default undefined
23
+ */
24
+ value?: Date;
25
+ /**
26
+ * The default value.
27
+ * @default undefined
28
+ */
29
+ defaultValue?: Date;
30
+ /**
31
+ * The change event handler.
32
+ * @default undefined
33
+ */
34
+ onChange?: (value: Date) => void;
35
+ }
36
+
37
+ interface Selection {
38
+ start: number;
39
+ end: number;
40
+ }
41
+
42
+ /**
43
+ * The component to choose a time.
44
+ */
45
+ const TimePicker = forwardRef<HTMLInputElement, TimePickerProps>(
46
+ (
47
+ {
48
+ notation = '12-hour',
49
+ value,
50
+ defaultValue,
51
+ onChange = () => {},
52
+ onSelect = () => {},
53
+ onKeyDown = () => {},
54
+ disabled = false,
55
+ right,
56
+ ...rest
57
+ },
58
+ ref
59
+ ) => {
60
+ const [inputRef, mergedInputRef] = useForwardedRef(ref);
61
+ const [forwardedValue, setForwardedValue] = useForwardedState({
62
+ value,
63
+ defaultValue,
64
+ onChange,
65
+ });
66
+ const [selection, setSelection] = useState<Selection>({ start: 0, end: 0 });
67
+
68
+ const { time, isPm, changePeriod, keyHandler } = useTime({
69
+ notation,
70
+ selection,
71
+ setSelection,
72
+ forwardedValue,
73
+ setForwardedValue,
74
+ });
75
+
76
+ const rightComponent = useMemo(() => {
77
+ if (notation !== '12-hour' && !right) return null;
78
+ return (
79
+ <>
80
+ {notation === '12-hour' && (
81
+ <Button
82
+ type='ghost'
83
+ wide='never'
84
+ size='small'
85
+ disabled={disabled}
86
+ onClick={changePeriod}
87
+ >
88
+ {isPm ? 'PM' : 'AM'}
89
+ </Button>
90
+ )}
91
+ {right}
92
+ </>
93
+ );
94
+ }, [changePeriod, disabled, isPm, notation, right]);
95
+
96
+ const keyDownHandler = useCallback(
97
+ (e) => {
98
+ keyHandler(e.key, e.metaKey);
99
+ onKeyDown(e);
100
+ e.preventDefault();
101
+ },
102
+ [keyHandler, onKeyDown]
103
+ );
104
+
105
+ // Update the selection
106
+ useEffect(() => {
107
+ if (!inputRef.current) return;
108
+ inputRef.current.setSelectionRange(selection.start, selection.end);
109
+ }, [inputRef, selection]);
110
+
111
+ const selectHandler = useCallback(
112
+ (e) => {
113
+ // Update the selection state.
114
+ const { selectionStart, selectionEnd } = e.currentTarget;
115
+ setSelection({ start: selectionStart || 0, end: selectionEnd || 0 });
116
+ onSelect(e);
117
+ },
118
+ [onSelect]
119
+ );
120
+
121
+ return (
122
+ <Input
123
+ type='text'
124
+ inputMode='decimal'
125
+ role='spinbutton'
126
+ minLength={5}
127
+ maxLength={5}
128
+ disabled={disabled}
129
+ value={time}
130
+ right={rightComponent}
131
+ onSelect={selectHandler}
132
+ onKeyDown={keyDownHandler}
133
+ {...rest}
134
+ ref={mergedInputRef}
135
+ />
136
+ );
137
+ }
138
+ );
139
+
140
+ TimePicker.displayName = 'TimePicker';
141
+
142
+ export default TimePicker;
@@ -0,0 +1,41 @@
1
+ import styled from '@emotion/styled';
2
+
3
+ import React, { forwardRef } from 'react';
4
+
5
+ type JsxIFrameProps = Omit<JSX.IntrinsicElements['iframe'], 'ref'>;
6
+ export type VideoProps = JsxIFrameProps;
7
+
8
+ const Container = styled.div`
9
+ position: relative;
10
+ padding-bottom: 56.25%; // 16:9
11
+ height: 0;
12
+ `;
13
+
14
+ const IFrame = styled.iframe`
15
+ position: absolute;
16
+ top: 0;
17
+ left: 0;
18
+ width: 100%;
19
+ height: 100%;
20
+ `;
21
+
22
+ /**
23
+ * The video player.
24
+ */
25
+ const Video = forwardRef<HTMLIFrameElement, VideoProps>(
26
+ ({ id, ...rest }, ref) => (
27
+ <Container>
28
+ <IFrame
29
+ frameBorder={0}
30
+ allow='clipboard-write; autoplay'
31
+ allowFullScreen
32
+ {...rest}
33
+ ref={ref}
34
+ />
35
+ </Container>
36
+ )
37
+ );
38
+
39
+ Video.displayName = 'Video';
40
+
41
+ export default Video;
package/src/index.ts ADDED
@@ -0,0 +1,125 @@
1
+ export { default as Alert } from './Alert';
2
+ export { default as Avatar } from './Avatar';
3
+ export { default as AvatarSkeleton } from './AvatarSkeleton';
4
+ export { default as Breadcrumb } from './Breadcrumb';
5
+ export { default as BreadcrumbItem } from './BreadcrumbItem';
6
+ export { default as Button } from './Button';
7
+ export { default as Checkbox } from './Checkbox';
8
+ export { default as CheckboxSkeleton } from './CheckboxSkeleton';
9
+ export { default as DatePicker } from './DatePicker';
10
+ export { default as Drawer } from './Drawer';
11
+ export { default as Form } from './Form';
12
+ export { default as FormDivider } from './FormDivider';
13
+ export { default as FormItem } from './FormItem';
14
+ export { default as Gallery } from './Gallery';
15
+ export { default as GlobalStyles } from './GlobalStyles';
16
+ export { default as HeaderSkeleton } from './HeaderSkeleton';
17
+ export { default as Image } from './Image';
18
+ export { default as ImageSkeleton } from './ImageSkeleton';
19
+ export { default as Input } from './Input';
20
+ export { default as InputNumber } from './InputNumber';
21
+ export { default as InputPassword } from './InputPassword';
22
+ export { default as InputSearch } from './InputSearch';
23
+ export { default as InputSkeleton } from './InputSkeleton';
24
+ export { default as Layout } from './Layout';
25
+ export { default as Link } from './Link';
26
+ export { default as LinkButton } from './LinkButton';
27
+ export { default as List } from './List';
28
+ export { default as ListItem } from './ListItem';
29
+ export { default as ListItemActions } from './ListItemActions';
30
+ export { default as ListItemLink } from './ListItemLink';
31
+ export { default as ListSkeleton } from './ListSkeleton';
32
+ export { default as LogoLink } from './LogoLink';
33
+ export { default as message } from './message';
34
+ export { default as Menu } from './Menu';
35
+ export { default as MenuDivider } from './MenuDivider';
36
+ export { default as MenuGroup } from './MenuGroup';
37
+ export { default as MenuItem } from './MenuItem';
38
+ export { default as Modal } from './Modal';
39
+ export { default as Navigation } from './Navigation';
40
+ export { default as NavigationItem } from './NavigationItem';
41
+ export { default as PageContent } from './PageContent';
42
+ export { default as PageHeader } from './PageHeader';
43
+ export { default as PageHeaderInputSearch } from './PageHeaderInputSearch';
44
+ export { default as PageHeaderSkeleton } from './PageHeaderSkeleton';
45
+ export { default as ParagraphSkeleton } from './ParagraphSkeleton';
46
+ export { default as Popover } from './Popover';
47
+ export { default as Progress } from './Progress';
48
+ export { default as RadioGroup } from './RadioGroup';
49
+ export { default as Result } from './Result';
50
+ export { default as ScrollButton } from './ScrollButton';
51
+ export { default as Select } from './Select';
52
+ export { default as Skeleton } from './Skeleton';
53
+ export { default as Switch } from './Switch';
54
+ export { default as SwitchSkeleton } from './SwitchSkeleton';
55
+ export { default as Tag } from './Tag';
56
+ export { default as TagLink } from './TagLink';
57
+ export { default as TagList } from './TagList';
58
+ export { default as TagListSkeleton } from './TagListSkeleton';
59
+ export { default as TagSkeleton } from './TagSkeleton';
60
+ export { default as TextArea } from './TextArea';
61
+ export { default as TextAreaSkeleton } from './TextAreaSkeleton';
62
+ export { default as ThemeSwitcher } from './ThemeSwitcher';
63
+ export { default as Video } from './Video';
64
+
65
+ export * from './Alert';
66
+ export * from './Avatar';
67
+ export * from './AvatarSkeleton';
68
+ export * from './Breadcrumb';
69
+ export * from './BreadcrumbItem';
70
+ export * from './Button';
71
+ export * from './Checkbox';
72
+ export * from './CheckboxSkeleton';
73
+ export * from './DatePicker';
74
+ export * from './Drawer';
75
+ export * from './Form';
76
+ export * from './FormDivider';
77
+ export * from './FormItem';
78
+ export * from './Gallery';
79
+ export * from './HeaderSkeleton';
80
+ export * from './Image';
81
+ export * from './ImageSkeleton';
82
+ export * from './Input';
83
+ export * from './InputNumber';
84
+ export * from './InputPassword';
85
+ export * from './InputSearch';
86
+ export * from './InputSkeleton';
87
+ export * from './Layout';
88
+ export * from './Link';
89
+ export * from './LinkButton';
90
+ export * from './List';
91
+ export * from './ListItem';
92
+ export * from './ListItemActions';
93
+ export * from './ListItemLink';
94
+ export * from './ListSkeleton';
95
+ export * from './LogoLink';
96
+ export * from './Menu';
97
+ export * from './MenuDivider';
98
+ export * from './MenuGroup';
99
+ export * from './MenuItem';
100
+ export * from './Modal';
101
+ export * from './Navigation';
102
+ export * from './NavigationItem';
103
+ export * from './PageContent';
104
+ export * from './PageHeader';
105
+ export * from './PageHeaderInputSearch';
106
+ export * from './PageHeaderSkeleton';
107
+ export * from './ParagraphSkeleton';
108
+ export * from './Popover';
109
+ export * from './Progress';
110
+ export * from './RadioGroup';
111
+ export * from './Result';
112
+ export * from './ScrollButton';
113
+ export * from './Select';
114
+ export * from './Skeleton';
115
+ export * from './Switch';
116
+ export * from './SwitchSkeleton';
117
+ export * from './Tag';
118
+ export * from './TagLink';
119
+ export * from './TagList';
120
+ export * from './TagListSkeleton';
121
+ export * from './TagSkeleton';
122
+ export * from './TextArea';
123
+ export * from './TextAreaSkeleton';
124
+ export * from './ThemeSwitcher';
125
+ export * from './Video';
@@ -0,0 +1,50 @@
1
+ import styled from '@emotion/styled';
2
+ import { CheckCircle, CloseCircle, InfoCircle } from '@os-design/icons';
3
+ import { Color, clr, light } from '@os-design/theming';
4
+
5
+ import { omitEmotionProps } from '@os-design/utils';
6
+ import React from 'react';
7
+
8
+ interface AlertIconProps {
9
+ type: 'info' | 'success' | 'error';
10
+ }
11
+
12
+ interface ContainerProps {
13
+ iconColor: Color;
14
+ }
15
+ const Container = styled('i', omitEmotionProps('iconColor'))<ContainerProps>`
16
+ display: flex;
17
+ flex-direction: row;
18
+ align-items: center;
19
+
20
+ margin-right: 0.3em;
21
+ font-size: 1.4em;
22
+ color: ${(p) => clr(p.iconColor)};
23
+ `;
24
+
25
+ const AlertIcon: React.FC<AlertIconProps> = ({ type }) => {
26
+ const { Icon, iconColor } = {
27
+ info: {
28
+ Icon: InfoCircle,
29
+ iconColor: light.alertInfoColorIcon,
30
+ },
31
+ success: {
32
+ Icon: CheckCircle,
33
+ iconColor: light.alertSuccessColorIcon,
34
+ },
35
+ error: {
36
+ Icon: CloseCircle,
37
+ iconColor: light.alertErrorColorIcon,
38
+ },
39
+ }[type];
40
+
41
+ return (
42
+ <Container iconColor={iconColor}>
43
+ <Icon />
44
+ </Container>
45
+ );
46
+ };
47
+
48
+ AlertIcon.displayName = 'AlertIcon';
49
+
50
+ export default AlertIcon;