@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.
Files changed (104) hide show
  1. package/dist/cjs/InputSearch/index.js +2 -2
  2. package/dist/cjs/InputSearch/index.js.map +1 -1
  3. package/dist/esm/InputSearch/index.js +2 -2
  4. package/dist/esm/InputSearch/index.js.map +1 -1
  5. package/dist/types/InputSearch/index.d.ts.map +1 -1
  6. package/package.json +21 -13
  7. package/src/@types/emotion.d.ts +7 -0
  8. package/src/Alert/index.tsx +112 -0
  9. package/src/Avatar/index.tsx +173 -0
  10. package/src/Avatar/utils/nameToInitials.ts +12 -0
  11. package/src/Avatar/utils/strToHue.ts +13 -0
  12. package/src/AvatarSkeleton/index.tsx +29 -0
  13. package/src/Breadcrumb/index.tsx +93 -0
  14. package/src/BreadcrumbItem/index.tsx +83 -0
  15. package/src/Button/ButtonContent.tsx +91 -0
  16. package/src/Button/index.tsx +225 -0
  17. package/src/Button/utils/useButtonColors.ts +84 -0
  18. package/src/Checkbox/index.tsx +225 -0
  19. package/src/CheckboxSkeleton/index.tsx +50 -0
  20. package/src/DatePicker/DatePickerCalendar.tsx +220 -0
  21. package/src/DatePicker/index.tsx +568 -0
  22. package/src/Drawer/index.tsx +212 -0
  23. package/src/Form/FormConfigContext.ts +16 -0
  24. package/src/Form/index.tsx +49 -0
  25. package/src/FormDivider/index.tsx +74 -0
  26. package/src/FormItem/index.tsx +118 -0
  27. package/src/Gallery/Status.tsx +62 -0
  28. package/src/Gallery/index.tsx +290 -0
  29. package/src/GlobalStyles/index.tsx +17 -0
  30. package/src/GlobalStyles/resetStyles.ts +17 -0
  31. package/src/GlobalStyles/typographyStyles.ts +78 -0
  32. package/src/HeaderSkeleton/index.tsx +64 -0
  33. package/src/Image/index.tsx +104 -0
  34. package/src/ImageSkeleton/index.tsx +22 -0
  35. package/src/Input/index.tsx +330 -0
  36. package/src/Input/utils/getFocusableElements.ts +8 -0
  37. package/src/InputNumber/index.tsx +208 -0
  38. package/src/InputNumber/utils/defaultLocale.ts +9 -0
  39. package/src/InputPassword/index.tsx +201 -0
  40. package/src/InputPassword/utils/defaultLocale.ts +11 -0
  41. package/src/InputSearch/index.tsx +111 -0
  42. package/src/InputSearch/utils/defaultLocale.ts +9 -0
  43. package/src/InputSkeleton/index.tsx +28 -0
  44. package/src/Layout/LayoutContext.ts +21 -0
  45. package/src/Layout/index.tsx +44 -0
  46. package/src/Link/index.tsx +129 -0
  47. package/src/LinkButton/index.tsx +100 -0
  48. package/src/List/WindowScroller.tsx +53 -0
  49. package/src/List/index.tsx +255 -0
  50. package/src/List/utils/bodyPointerEvents.ts +24 -0
  51. package/src/List/utils/frameTimeout.ts +36 -0
  52. package/src/List/utils/useRWLoadNext.ts +38 -0
  53. package/src/ListItem/index.tsx +92 -0
  54. package/src/ListItemActions/index.tsx +207 -0
  55. package/src/ListItemLink/index.tsx +63 -0
  56. package/src/ListSkeleton/index.tsx +115 -0
  57. package/src/LogoLink/index.tsx +93 -0
  58. package/src/LogoLink/logo.example.svg +18 -0
  59. package/src/Menu/index.tsx +128 -0
  60. package/src/Menu/utils/useFocusWithArrows.ts +50 -0
  61. package/src/MenuDivider/index.tsx +22 -0
  62. package/src/MenuGroup/index.tsx +190 -0
  63. package/src/MenuItem/index.tsx +108 -0
  64. package/src/Modal/index.tsx +411 -0
  65. package/src/Modal/utils/defaultLocale.ts +9 -0
  66. package/src/Navigation/index.tsx +214 -0
  67. package/src/Navigation/utils/useScrollFlags.ts +39 -0
  68. package/src/NavigationItem/index.tsx +136 -0
  69. package/src/PageContent/index.tsx +99 -0
  70. package/src/PageHeader/index.tsx +246 -0
  71. package/src/PageHeader/utils/defaultLocale.ts +9 -0
  72. package/src/PageHeaderInputSearch/index.tsx +145 -0
  73. package/src/PageHeaderInputSearch/utils/defaultLocale.ts +16 -0
  74. package/src/PageHeaderSkeleton/index.tsx +33 -0
  75. package/src/ParagraphSkeleton/index.tsx +65 -0
  76. package/src/Popover/index.tsx +243 -0
  77. package/src/Popover/utils/usePopoverPosition.ts +216 -0
  78. package/src/Progress/index.tsx +100 -0
  79. package/src/RadioGroup/index.tsx +165 -0
  80. package/src/RadioGroupSkeleton/index.tsx +36 -0
  81. package/src/Result/index.tsx +109 -0
  82. package/src/ScrollButton/index.tsx +159 -0
  83. package/src/ScrollButton/utils/useContainerPosition.ts +41 -0
  84. package/src/ScrollButton/utils/useVisibility.ts +56 -0
  85. package/src/Select/index.tsx +970 -0
  86. package/src/Select/utils/defaultLocale.ts +11 -0
  87. package/src/Skeleton/index.tsx +52 -0
  88. package/src/Switch/index.tsx +217 -0
  89. package/src/SwitchSkeleton/index.tsx +30 -0
  90. package/src/Tag/index.tsx +75 -0
  91. package/src/TagLink/index.tsx +53 -0
  92. package/src/TagList/index.tsx +95 -0
  93. package/src/TagListSkeleton/index.tsx +38 -0
  94. package/src/TagSkeleton/index.tsx +40 -0
  95. package/src/TextArea/index.tsx +231 -0
  96. package/src/TextAreaSkeleton/index.tsx +20 -0
  97. package/src/ThemeSwitcher/index.tsx +39 -0
  98. package/src/TimePicker/index.tsx +142 -0
  99. package/src/Video/index.tsx +41 -0
  100. package/src/index.ts +125 -0
  101. package/src/message/AlertIcon.tsx +50 -0
  102. package/src/message/Message.tsx +108 -0
  103. package/src/message/index.tsx +64 -0
  104. package/src/message/styles.ts +25 -0
@@ -0,0 +1,330 @@
1
+ import { css } from '@emotion/react';
2
+ import styled from '@emotion/styled';
3
+ import { Loading } from '@os-design/icons';
4
+ import {
5
+ resetFocusStyles,
6
+ sizeStyles,
7
+ transitionStyles,
8
+ WithSize,
9
+ } from '@os-design/styles';
10
+ import { clr, ThemeOverrider } from '@os-design/theming';
11
+ import { omitEmotionProps, useForwardedRef } from '@os-design/utils';
12
+
13
+ import React, {
14
+ ChangeEvent,
15
+ FocusEventHandler,
16
+ ForwardedRef,
17
+ forwardRef,
18
+ KeyboardEventHandler,
19
+ useCallback,
20
+ useMemo,
21
+ } from 'react';
22
+ import getFocusableElements from './utils/getFocusableElements';
23
+
24
+ type JsxInputProps = Omit<
25
+ JSX.IntrinsicElements['input'],
26
+ 'value' | 'onChange' | 'size' | 'ref'
27
+ >;
28
+ export interface InputProps extends JsxInputProps, WithSize {
29
+ /**
30
+ * Type of the input.
31
+ * @default text
32
+ */
33
+ type?: JsxInputProps['type'];
34
+ /**
35
+ * The component located on the left side.
36
+ * @default undefined
37
+ */
38
+ left?: React.ReactNode;
39
+ /**
40
+ * Adds padding to the left component.
41
+ * It can be useful when passing an icon or text in the left component.
42
+ * @default false
43
+ */
44
+ leftHasPadding?: boolean;
45
+ /**
46
+ * The component located on the right side.
47
+ * @default undefined
48
+ */
49
+ right?: React.ReactNode;
50
+ /**
51
+ * Adds padding to the right component.
52
+ * It can be useful when passing an icon or text in the right component.
53
+ * @default false
54
+ */
55
+ rightHasPadding?: boolean;
56
+ /**
57
+ * Whether the input is disabled.
58
+ * @default false
59
+ */
60
+ disabled?: boolean;
61
+ /**
62
+ * Shows the loading status.
63
+ * @default false
64
+ */
65
+ loading?: boolean;
66
+ /**
67
+ * The ref of the input container.
68
+ * @default undefined
69
+ */
70
+ containerRef?: ForwardedRef<HTMLDivElement>;
71
+ /**
72
+ * The props of the input container.
73
+ * @default undefined
74
+ */
75
+ containerProps?: JSX.IntrinsicElements['div'];
76
+ /**
77
+ * The input value.
78
+ * @default undefined
79
+ */
80
+ value?: string;
81
+ /**
82
+ * The change event handler.
83
+ * @default undefined
84
+ */
85
+ onChange?: (value: string, e: ChangeEvent<HTMLInputElement>) => void;
86
+ }
87
+
88
+ const hoverStyles = (p) =>
89
+ !p.disabled &&
90
+ css`
91
+ @media (hover: hover) {
92
+ &:hover {
93
+ border-color: ${clr(p.theme.inputHoverColorBorder)};
94
+ }
95
+ }
96
+ `;
97
+
98
+ const focusStyles = (p) =>
99
+ !p.disabled &&
100
+ css`
101
+ &:focus-within {
102
+ border-color: ${clr(p.theme.inputFocusColorBorder)};
103
+ box-shadow: 0 0 0 0.15em ${clr(p.theme.inputFocusColorShadow)};
104
+ }
105
+ `;
106
+
107
+ const disabledStyles = (p) =>
108
+ p.disabled &&
109
+ css`
110
+ cursor: not-allowed;
111
+ color: ${clr(p.theme.inputDisabledColorText)};
112
+ background-color: ${clr(p.theme.inputDisabledColorBg)};
113
+ border-color: ${clr(p.theme.inputDisabledColorBorder)};
114
+
115
+ input,
116
+ textarea {
117
+ cursor: not-allowed;
118
+ &::placeholder {
119
+ color: ${clr(p.theme.inputDisabledColorPlaceholder)};
120
+ }
121
+ }
122
+ `;
123
+
124
+ type InputContainerProps = Pick<InputProps, 'disabled' | 'size'>;
125
+ export const InputContainer = styled(
126
+ 'div',
127
+ omitEmotionProps('disabled', 'size')
128
+ )<InputContainerProps>`
129
+ ${resetFocusStyles};
130
+
131
+ display: inline-flex;
132
+ width: 100%;
133
+ height: ${(p) => p.theme.baseHeight}em;
134
+ box-sizing: border-box;
135
+ background-color: ${(p) => clr(p.theme.inputColorBg)};
136
+
137
+ border: ${(p) => p.theme.inputBorderWidth}px solid
138
+ ${(p) => clr(p.theme.inputColorBorder)};
139
+ border-radius: ${(p) => p.theme.borderRadius}em;
140
+
141
+ ${hoverStyles};
142
+ ${focusStyles};
143
+ ${disabledStyles};
144
+ ${sizeStyles};
145
+ ${transitionStyles('border-color', 'box-shadow')};
146
+ `;
147
+
148
+ const notHasLeftStyles = (p) =>
149
+ !p.hasLeft &&
150
+ css`
151
+ padding-left: ${p.theme.inputPaddingHorizontal}em;
152
+ `;
153
+
154
+ const notHasRightStyles = (p) =>
155
+ !p.hasRight &&
156
+ css`
157
+ padding-right: ${p.theme.inputPaddingHorizontal}em;
158
+ `;
159
+
160
+ interface StyledInputProps {
161
+ hasLeft?: boolean;
162
+ hasRight?: boolean;
163
+ }
164
+ export const StyledInput = styled(
165
+ 'input',
166
+ omitEmotionProps('hasLeft', 'hasRight')
167
+ )<StyledInputProps>`
168
+ ${resetFocusStyles};
169
+ appearance: none;
170
+ border: none;
171
+ font-size: 1em;
172
+ flex: 1;
173
+ overflow: hidden;
174
+
175
+ color: ${(p) => clr(p.theme.inputColorText)};
176
+ background-color: transparent;
177
+
178
+ &::placeholder {
179
+ color: ${(p) => clr(p.theme.inputColorPlaceholder)};
180
+ }
181
+
182
+ ${notHasLeftStyles};
183
+ ${notHasRightStyles};
184
+ `;
185
+
186
+ interface AddonProps {
187
+ hasPadding: boolean;
188
+ }
189
+ const Addon = styled('span', omitEmotionProps('hasPadding'))<AddonProps>`
190
+ display: flex;
191
+ align-items: center;
192
+ user-select: none;
193
+ color: ${(p) => clr(p.theme.inputColorPlaceholder)};
194
+
195
+ svg {
196
+ transform: scale(1.2);
197
+ }
198
+ `;
199
+
200
+ const LeftAddon = styled(Addon)`
201
+ padding-right: ${(p) => p.theme.inputAddonPaddingHorizontal}em;
202
+ ${(p) =>
203
+ p.hasPadding &&
204
+ css`
205
+ padding-left: ${p.theme.inputPaddingHorizontal}em;
206
+ `}
207
+ `;
208
+
209
+ const RightAddon = styled(Addon)`
210
+ padding-left: ${(p) => p.theme.inputAddonPaddingHorizontal}em;
211
+ ${(p) =>
212
+ p.hasPadding &&
213
+ css`
214
+ padding-right: ${p.theme.inputPaddingHorizontal}em;
215
+ `}
216
+ `;
217
+
218
+ /**
219
+ * The basic input component.
220
+ */
221
+ const Input = forwardRef<HTMLInputElement, InputProps>(
222
+ (
223
+ {
224
+ type = 'text',
225
+ left,
226
+ leftHasPadding = false,
227
+ right,
228
+ rightHasPadding = false,
229
+ disabled = false,
230
+ loading = false,
231
+ containerRef,
232
+ containerProps = {},
233
+ size,
234
+ value,
235
+ onChange = () => {},
236
+ ...rest
237
+ },
238
+ ref
239
+ ) => {
240
+ const [innerContainerRef, mergedContainerRef] =
241
+ useForwardedRef(containerRef);
242
+
243
+ const rightValue = useMemo(
244
+ () => (loading ? <Loading /> : right),
245
+ [loading, right]
246
+ );
247
+
248
+ const rightHasPaddingValue = useMemo(
249
+ () => (loading ? true : rightHasPadding),
250
+ [loading, rightHasPadding]
251
+ );
252
+
253
+ const onFocus = useCallback<FocusEventHandler>(
254
+ (e) => {
255
+ // Focus the next element if the container element was focused.
256
+ // The next element will be the input or button in the addon.
257
+ if (disabled || e.target !== innerContainerRef.current) return;
258
+ const focusableElements = getFocusableElements(
259
+ innerContainerRef.current
260
+ );
261
+ focusableElements[0].focus();
262
+ },
263
+ [disabled, innerContainerRef]
264
+ );
265
+
266
+ const onKeyDown = useCallback<KeyboardEventHandler>(
267
+ (e) => {
268
+ // Focus the previous element if the first element in the input
269
+ // container is focused and the Shift + Tab combination is pressed.
270
+ const focusableElements = getFocusableElements(document);
271
+ const inputFocusableElements = innerContainerRef.current
272
+ ? getFocusableElements(innerContainerRef.current)
273
+ : [];
274
+ const firstInputElementIsFocused =
275
+ inputFocusableElements[0] === document.activeElement;
276
+ if (firstInputElementIsFocused && e.key === 'Tab' && e.shiftKey) {
277
+ const inputContainerIndex = focusableElements.findIndex(
278
+ (el) => el === innerContainerRef.current
279
+ );
280
+ if (inputContainerIndex === 0) return;
281
+ const elementBeforeInputContainer =
282
+ focusableElements[inputContainerIndex - 1];
283
+ elementBeforeInputContainer.focus();
284
+ }
285
+ },
286
+ [innerContainerRef]
287
+ );
288
+
289
+ return (
290
+ <InputContainer
291
+ disabled={disabled}
292
+ size={size}
293
+ tabIndex={!disabled ? 0 : -1}
294
+ onFocus={onFocus}
295
+ onKeyDown={onKeyDown}
296
+ ref={mergedContainerRef}
297
+ {...containerProps}
298
+ >
299
+ {left && (
300
+ <ThemeOverrider overrides={{ buttonPaddingHorizontal: 0.8 }}>
301
+ <LeftAddon hasPadding={leftHasPadding}>{left}</LeftAddon>
302
+ </ThemeOverrider>
303
+ )}
304
+
305
+ <StyledInput
306
+ type={type}
307
+ disabled={disabled}
308
+ hasLeft={!!left}
309
+ hasRight={!!right}
310
+ value={value || ''}
311
+ onChange={(e) => onChange(e.target.value, e)}
312
+ {...rest}
313
+ ref={ref}
314
+ />
315
+
316
+ {rightValue && (
317
+ <ThemeOverrider overrides={{ buttonPaddingHorizontal: 0.8 }}>
318
+ <RightAddon hasPadding={rightHasPaddingValue}>
319
+ {rightValue}
320
+ </RightAddon>
321
+ </ThemeOverrider>
322
+ )}
323
+ </InputContainer>
324
+ );
325
+ }
326
+ );
327
+
328
+ Input.displayName = 'Input';
329
+
330
+ export default Input;
@@ -0,0 +1,8 @@
1
+ const getFocusableElements = (element: ParentNode): HTMLElement[] =>
2
+ [
3
+ ...element.querySelectorAll<HTMLElement>(
4
+ 'a, button, input, textarea, select, details,[tabindex]:not([tabindex="-1"])'
5
+ ),
6
+ ].filter((el) => !el.hasAttribute('disabled'));
7
+
8
+ export default getFocusableElements;
@@ -0,0 +1,208 @@
1
+ import {
2
+ getNextCaret,
3
+ getNextState,
4
+ numberToFormattedString,
5
+ useGetCaretWithinValue,
6
+ useValidate,
7
+ } from '@os-design/input-number-utils';
8
+ import { useForwardedRef } from '@os-design/utils';
9
+ import React, { forwardRef, useEffect, useMemo, useState } from 'react';
10
+ import Input, { InputProps } from '../Input';
11
+ import defaultLocale, { InputNumberLocale } from './utils/defaultLocale';
12
+
13
+ export interface InputNumberProps
14
+ extends Omit<InputProps, 'type' | 'value' | 'onChange'> {
15
+ /**
16
+ * The minimum value.
17
+ * @default 0
18
+ */
19
+ min?: number;
20
+ /**
21
+ * The maximum value.
22
+ * @default 2147483647
23
+ */
24
+ max?: number;
25
+ /**
26
+ * The number of digits after the decimal point.
27
+ * @default 0
28
+ */
29
+ precision?: number;
30
+ /**
31
+ * The string before the number.
32
+ * @default undefined
33
+ */
34
+ prefix?: string;
35
+ /**
36
+ * The string after the number.
37
+ * @default undefined
38
+ */
39
+ suffix?: string;
40
+ /**
41
+ * The decimal separator.
42
+ * @default .
43
+ */
44
+ decimalSeparator?: '.' | ',';
45
+ /**
46
+ * The thousands separator.
47
+ * @default ' '
48
+ */
49
+ thousandsSeparator?: ' ' | '.' | ',' | null;
50
+ /**
51
+ * The locale.
52
+ * @default undefined
53
+ */
54
+ locale?: InputNumberLocale;
55
+ /**
56
+ * The input value.
57
+ * @default undefined
58
+ */
59
+ value?: number | null;
60
+ /**
61
+ * The change event handler.
62
+ * Returns null when the input value is empty.
63
+ * @default undefined
64
+ */
65
+ onChange?: (value: number | null) => void;
66
+ }
67
+
68
+ interface Selection {
69
+ start: number;
70
+ end: number;
71
+ }
72
+
73
+ /**
74
+ * The input for entering a number.
75
+ */
76
+ const InputNumber = forwardRef<HTMLInputElement, InputNumberProps>(
77
+ (
78
+ {
79
+ min = 0,
80
+ max = 2147483647,
81
+ precision = 0,
82
+ prefix = '',
83
+ suffix = '',
84
+ decimalSeparator = '.',
85
+ thousandsSeparator = ' ',
86
+ locale = defaultLocale,
87
+ value = null,
88
+ onChange = () => {},
89
+ onSelect = () => {},
90
+ onFocus = () => {},
91
+ ...rest
92
+ },
93
+ ref
94
+ ) => {
95
+ useValidate({
96
+ min,
97
+ max,
98
+ precision,
99
+ prefix,
100
+ suffix,
101
+ decimalSeparator,
102
+ thousandsSeparator,
103
+ });
104
+
105
+ const options = useMemo(
106
+ () => ({
107
+ min,
108
+ max,
109
+ precision,
110
+ prefix,
111
+ suffix,
112
+ decimalSeparator,
113
+ thousandsSeparator,
114
+ }),
115
+ [
116
+ min,
117
+ max,
118
+ precision,
119
+ prefix,
120
+ suffix,
121
+ decimalSeparator,
122
+ thousandsSeparator,
123
+ ]
124
+ );
125
+
126
+ const [inputRef, mergedInputRef] = useForwardedRef(ref);
127
+ const [valueString, setValueString] = useState<string>(
128
+ numberToFormattedString(value, options)
129
+ );
130
+ const [selection, setSelection] = useState<Selection>({ start: 0, end: 0 });
131
+ const getCaretWithinValue = useGetCaretWithinValue(prefix, suffix);
132
+
133
+ // Update the value
134
+ useEffect(() => {
135
+ setValueString(numberToFormattedString(value, options));
136
+ }, [value, options]);
137
+
138
+ // Update the selection
139
+ useEffect(() => {
140
+ if (!inputRef.current) return;
141
+ inputRef.current.setSelectionRange(selection.start, selection.end);
142
+ }, [inputRef, selection]);
143
+
144
+ return (
145
+ <Input
146
+ onSelect={(e) => {
147
+ // Update the selection state.
148
+ // Don't use `getCaretWithinValue` here to allow a user to copy
149
+ // the input value with a prefix and suffix.
150
+ const { selectionStart, selectionEnd } = e.currentTarget;
151
+ setSelection({ start: selectionStart || 0, end: selectionEnd || 0 });
152
+ onSelect(e);
153
+ }}
154
+ onFocus={(e) => {
155
+ // Move the caret to the end of the input value and before the suffix
156
+ setSelection({
157
+ start: getCaretWithinValue(valueString.length, valueString),
158
+ end: getCaretWithinValue(valueString.length, valueString),
159
+ });
160
+ onFocus(e);
161
+ }}
162
+ value={valueString}
163
+ onChange={(v, e) => {
164
+ // Get a new value as a string and number
165
+ const nextState = getNextState(v, options);
166
+
167
+ // Set the new string value in the input field
168
+ setValueString(nextState.valueString);
169
+
170
+ // Send the new numeric value in the onChange callback
171
+ onChange(nextState.valueNumber);
172
+
173
+ // Update the caret position
174
+ const nextCaret = getCaretWithinValue(
175
+ getNextCaret({
176
+ value: v,
177
+ prevValueString: valueString,
178
+ nextValueString: nextState.valueString,
179
+ prevCaret: selection.end,
180
+ deleteKeyPressed:
181
+ (e.nativeEvent as InputEvent).inputType ===
182
+ 'deleteContentBackward',
183
+ options,
184
+ }),
185
+ nextState.valueString
186
+ );
187
+ setSelection({ start: nextCaret, end: nextCaret });
188
+ }}
189
+ role='spinbutton'
190
+ aria-valuenow={
191
+ value !== undefined && value !== null ? value : undefined
192
+ }
193
+ aria-valuemin={min}
194
+ aria-valuemax={max}
195
+ aria-valuetext={valueString === '' ? locale.emptyLabel : undefined}
196
+ inputMode='decimal'
197
+ autoComplete='off'
198
+ autoCorrect='off'
199
+ {...rest}
200
+ ref={mergedInputRef}
201
+ />
202
+ );
203
+ }
204
+ );
205
+
206
+ InputNumber.displayName = 'InputNumber';
207
+
208
+ export default InputNumber;
@@ -0,0 +1,9 @@
1
+ export interface InputNumberLocale {
2
+ emptyLabel: string;
3
+ }
4
+
5
+ const defaultLocale: InputNumberLocale = {
6
+ emptyLabel: 'Empty',
7
+ };
8
+
9
+ export default defaultLocale;