@teamturing/react-kit 2.19.14 → 2.19.16

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.
@@ -23,6 +23,7 @@ const Dialog = ({
23
23
  isOpen,
24
24
  onDismiss,
25
25
  size = 'm',
26
+ initialFocusRef,
26
27
  sx
27
28
  }, ref) => {
28
29
  const handleDismiss = useCallback(() => onDismiss?.(), [onDismiss]);
@@ -45,7 +46,7 @@ const Dialog = ({
45
46
  }, [handleDismiss]);
46
47
  useFocusTrap({
47
48
  containerRef: dialogRef,
48
- initialFocusRef: closeButtonRef,
49
+ initialFocusRef: initialFocusRef || closeButtonRef,
49
50
  disabled: !isOpen
50
51
  });
51
52
  useEffect(() => {
@@ -1,7 +1,7 @@
1
1
  import { forwardRef, createContext, isValidElement, cloneElement } from 'react';
2
2
  import useRelocation from '../../hook/useRelocation.js';
3
3
  import Checkbox from '../Checkbox/index.js';
4
- import OverlaySelectInput from '../OverlaySelectInput/index.js';
4
+ import SearchSelectInput from '../SearchSelectInput/index.js';
5
5
  import Select from '../Select/index.js';
6
6
  import TextInput from '../TextInput/index.js';
7
7
  import View from '../View/index.js';
@@ -28,7 +28,7 @@ const FormControl = ({
28
28
  successMessage: FormControlSuccessMessage
29
29
  }
30
30
  });
31
- const inputComponentCandidates = [TextInput, Select, OverlaySelectInput, Checkbox, ...additionalInputComponentCandidates];
31
+ const inputComponentCandidates = [TextInput, Select, SearchSelectInput, Checkbox, ...additionalInputComponentCandidates];
32
32
  const InputComponent = restComponents.find(component => inputComponentCandidates.some(candidate => /*#__PURE__*/isValidElement(component) && component.type === candidate));
33
33
  const isHorizontalLayoutNeeded = /*#__PURE__*/isValidElement(InputComponent) && InputComponent.type === Checkbox;
34
34
  return /*#__PURE__*/jsxRuntimeExports.jsx(FormControlContext.Provider, {
@@ -55,6 +55,13 @@ const OverlayPopper = ({
55
55
  };
56
56
  const defaultPopperProps = {
57
57
  onClick: handleOverlayToggle,
58
+ onKeyDown: e => {
59
+ if (['ArrowUp', 'ArrowDown'].includes(e.key)) {
60
+ e.preventDefault();
61
+ openOverlay();
62
+ }
63
+ e.stopPropagation();
64
+ },
58
65
  tabIndex: 0,
59
66
  ...{
60
67
  ref: refs.setReference
@@ -21,6 +21,7 @@ const Pagination = ({
21
21
  onPreviousClick = noop,
22
22
  onNextClick = noop,
23
23
  renderPage = (page, i) => /*#__PURE__*/jsxRuntimeExports.jsx(PaginationPage, {
24
+ type: 'button',
24
25
  onClick: () => onPageClick(page, i),
25
26
  selected: i === currentPageIndex,
26
27
  children: page.label
@@ -62,6 +63,7 @@ const Pagination = ({
62
63
  sx: sx,
63
64
  children: [renderPreviousPageDirection({
64
65
  previousPageDirectionProps: {
66
+ type: 'button',
65
67
  onClick: () => onPreviousClick(currentPageIndex),
66
68
  disabled: currentPageIndex === 0
67
69
  }
@@ -99,6 +101,7 @@ const Pagination = ({
99
101
  originalIndex
100
102
  }) => renderPaginationPage(page, originalIndex))], renderNextPageDirection({
101
103
  nextPageDirectionProps: {
104
+ type: 'button',
102
105
  onClick: () => onNextClick(currentPageIndex),
103
106
  disabled: currentPageIndex === totalPageCount - 1
104
107
  }
@@ -42,6 +42,7 @@ const Pill = ({
42
42
  hasRemoveButton: !isNullable(propOnRemove),
43
43
  disabled: disabled,
44
44
  ...props,
45
+ type: 'button',
45
46
  children: [typeof LeadingVisual !== 'string' && reactIsExports.isValidElementType(LeadingVisual) ? /*#__PURE__*/jsxRuntimeExports.jsx(LeadingVisual, {}) : LeadingVisual, /*#__PURE__*/jsxRuntimeExports.jsx("span", {
46
47
  title: children?.toString(),
47
48
  children: children
@@ -1,19 +1,24 @@
1
1
  import { forwardRef, useRef } from 'react';
2
2
  import SvgChevronDown from '../../packages/icons/esm/ChevronDown.js';
3
+ import SvgSearch from '../../packages/icons/esm/Search.js';
3
4
  import { forcePixelValue } from '../../packages/utils/esm/forcePixelValue.js';
4
5
  import { isFunction } from '../../packages/utils/esm/isFunction.js';
5
6
  import { isNullable } from '../../packages/utils/esm/isNullable.js';
6
7
  import { noop } from '../../packages/utils/esm/noop.js';
8
+ import { scrollIntoView } from '../../packages/utils/esm/scrollIntoView.js';
7
9
  import { r as reactIsExports } from '../../node_modules/react-is/index.js';
8
- import styled, { css } from 'styled-components';
10
+ import styled, { css, useTheme } from 'styled-components';
9
11
  import useProvidedOrCreatedRef from '../../hook/useProvidedOrCreatedRef.js';
12
+ import HorizontalDivider from '../HorizontalDivider/index.js';
10
13
  import Overlay from '../Overlay/index.js';
11
14
  import OverlayPopper from '../OverlayPopper/index.js';
15
+ import Space from '../Space/index.js';
12
16
  import StyledIcon from '../StyledIcon/index.js';
17
+ import TextInput from '../TextInput/index.js';
13
18
  import View from '../View/index.js';
14
19
  import { j as jsxRuntimeExports } from '../../node_modules/react/jsx-runtime.js';
15
20
 
16
- const OverlaySelectInput = ({
21
+ const SearchSelectInput = ({
17
22
  validationStatus,
18
23
  leadingVisual: LeadingVisual,
19
24
  children,
@@ -22,8 +27,13 @@ const OverlaySelectInput = ({
22
27
  focusZoneSettings,
23
28
  onOpen,
24
29
  onClose,
30
+ searchInputProps,
31
+ value,
32
+ renderValue = value => value?.toString(),
25
33
  ...props
26
34
  }, ref) => {
35
+ const theme = useTheme();
36
+ const hasLeadingVisual = !isNullable(LeadingVisual);
27
37
  const valueInputRef = useProvidedOrCreatedRef(ref);
28
38
  const labelInputRef = useRef(null);
29
39
  const focusInput = () => {
@@ -36,8 +46,6 @@ const OverlaySelectInput = ({
36
46
  } = props;
37
47
  const handleSelect = item => {
38
48
  if (labelInputRef.current && valueInputRef.current) {
39
- labelInputRef.current.setAttribute('value', item.label);
40
-
41
49
  /**
42
50
  * ! valueInput의 native onChange를 trigger하려고 했으나 작동하지 않음.
43
51
  * ! 일단 Custom onChange를 만들어서 해결.
@@ -47,22 +55,87 @@ const OverlaySelectInput = ({
47
55
  onChange?.(item);
48
56
  }
49
57
  };
58
+ const listContainerRef = useRef(null);
59
+ const searchInputRef = useRef(null);
60
+ const activeDescendantRef = useRef();
50
61
  return /*#__PURE__*/jsxRuntimeExports.jsx(OverlayPopper, {
51
- focusTrapSettings: focusTrapSettings,
52
- focusZoneSettings: focusZoneSettings,
62
+ focusTrapSettings: {
63
+ initialFocusRef: searchInputRef,
64
+ restoreFocusOnCleanUp: true,
65
+ ...focusTrapSettings
66
+ },
67
+ focusZoneSettings: {
68
+ containerRef: listContainerRef,
69
+ activeDescendantFocus: searchInputRef,
70
+ focusOutBehavior: 'stop',
71
+ onActiveDescendantChanged: (current, previous) => {
72
+ activeDescendantRef.current = current;
73
+ if (current && listContainerRef.current) {
74
+ current.style.backgroundColor = theme.colors['bg/selected/subtle'];
75
+ scrollIntoView({
76
+ childrenRef: current,
77
+ scrollContainerRef: listContainerRef.current,
78
+ options: {
79
+ behavior: 'auto',
80
+ direction: 'vertical',
81
+ offset: 0
82
+ }
83
+ });
84
+ }
85
+ if (previous && current !== previous) {
86
+ previous.style.backgroundColor = '';
87
+ }
88
+ },
89
+ focusableElementFilter: elem => {
90
+ return elem instanceof HTMLElement;
91
+ },
92
+ ...focusZoneSettings
93
+ },
53
94
  onOpen: onOpen,
54
95
  onClose: onClose,
55
- renderOverlay: (overlayProps, _, {
96
+ renderOverlay: (overlayProps, overlayHandler, {
56
97
  elements
57
- }) => /*#__PURE__*/jsxRuntimeExports.jsx(Overlay, {
98
+ }) => /*#__PURE__*/jsxRuntimeExports.jsxs(Overlay, {
58
99
  ...overlayProps,
100
+ maxHeight: 200,
101
+ sx: {
102
+ display: 'flex',
103
+ flexDirection: 'column'
104
+ },
59
105
  style: {
60
106
  ...overlayProps.style,
61
107
  width: elements?.reference?.getBoundingClientRect().width
62
108
  },
63
- children: children?.({
64
- handleSelect
65
- })
109
+ children: [/*#__PURE__*/jsxRuntimeExports.jsx(Space, {
110
+ p: 2,
111
+ sx: {
112
+ flexGrow: 0,
113
+ flexShrink: 0,
114
+ flexBasis: 'auto'
115
+ },
116
+ children: /*#__PURE__*/jsxRuntimeExports.jsx(TextInput, {
117
+ ref: searchInputRef,
118
+ leadingVisual: SvgSearch,
119
+ onKeyDown: e => {
120
+ if (e.code === 'Enter' && activeDescendantRef.current) {
121
+ const activeDescendantEvent = new KeyboardEvent(e.type, e.nativeEvent);
122
+ activeDescendantRef.current?.dispatchEvent(activeDescendantEvent);
123
+ }
124
+ },
125
+ ...searchInputProps
126
+ })
127
+ }), /*#__PURE__*/jsxRuntimeExports.jsx(HorizontalDivider, {}), /*#__PURE__*/jsxRuntimeExports.jsx(View, {
128
+ ref: listContainerRef,
129
+ sx: {
130
+ flexGrow: 1,
131
+ flexShrink: 1,
132
+ flexBasis: 'auto',
133
+ overflowY: 'auto'
134
+ },
135
+ children: children?.({
136
+ handleSelect
137
+ }, overlayHandler)
138
+ })]
66
139
  }),
67
140
  children: (popperProps, {
68
141
  openOverlay
@@ -71,13 +144,14 @@ const OverlaySelectInput = ({
71
144
  tabIndex: disabled ? -1 : 0,
72
145
  disabled: disabled,
73
146
  onClick: focusInput,
74
- hasLeadingVisual: !isNullable(LeadingVisual),
147
+ hasLeadingVisual: hasLeadingVisual,
75
148
  validationStatus: validationStatus,
76
149
  onKeyDown: e => {
77
150
  if (['ArrowUp', 'ArrowDown'].includes(e.key)) {
78
151
  e.preventDefault();
79
152
  openOverlay();
80
153
  }
154
+ e.stopPropagation();
81
155
  },
82
156
  children: [/*#__PURE__*/jsxRuntimeExports.jsx(View, {
83
157
  sx: {
@@ -93,17 +167,42 @@ const OverlaySelectInput = ({
93
167
  }
94
168
  },
95
169
  children: typeof LeadingVisual !== 'string' && reactIsExports.isValidElementType(LeadingVisual) ? /*#__PURE__*/jsxRuntimeExports.jsx(LeadingVisual, {}) : LeadingVisual
96
- }), /*#__PURE__*/jsxRuntimeExports.jsx(BaseInput, {
97
- id: id,
98
- ref: labelInputRef,
99
- onChange: noop,
100
- autoComplete: 'off',
101
- tabIndex: -1,
170
+ }), /*#__PURE__*/jsxRuntimeExports.jsxs(View, {
171
+ sx: {
172
+ display: 'flex',
173
+ alignItems: 'center',
174
+ paddingTop: 3,
175
+ paddingRight: 10,
176
+ paddingBottom: 3,
177
+ paddingLeft: hasLeadingVisual ? 2 : 4,
178
+ whiteSpace: 'pre',
179
+ textOverflow: 'ellipsis',
180
+ width: '100%'
181
+ },
102
182
  onClick: e => {
103
183
  popperProps.onClick?.(e);
104
- props.onClick?.(e);
105
184
  },
106
- placeholder: placeholder
185
+ children: [!isNullable(renderValue(value)) ? /*#__PURE__*/jsxRuntimeExports.jsx(View, {
186
+ sx: {
187
+ flex: '0 1 auto',
188
+ maxWidth: '100%',
189
+ textOverflow: 'ellipsis',
190
+ whiteSpace: 'pre',
191
+ overflow: 'hidden'
192
+ },
193
+ children: renderValue(value)
194
+ }) : null, /*#__PURE__*/jsxRuntimeExports.jsx(BaseInput, {
195
+ id: id,
196
+ ref: labelInputRef,
197
+ readOnly: true,
198
+ onChange: noop,
199
+ autoComplete: 'off',
200
+ tabIndex: -1,
201
+ onClick: e => {
202
+ props.onClick?.(e);
203
+ },
204
+ placeholder: !isNullable(renderValue(value)) ? '' : placeholder
205
+ })]
107
206
  }), /*#__PURE__*/jsxRuntimeExports.jsx(StyledIcon, {
108
207
  sx: {
109
208
  position: 'absolute',
@@ -120,7 +219,8 @@ const OverlaySelectInput = ({
120
219
  isFunction(ref) ? ref(e) : null;
121
220
  valueInputRef.current = e;
122
221
  },
123
- type: 'hidden'
222
+ type: 'hidden',
223
+ defaultValue: value
124
224
  })]
125
225
  })
126
226
  });
@@ -142,6 +242,8 @@ const TextInputWrapper = styled.div`
142
242
  cursor: default;
143
243
  input {
144
244
  cursor: default;
245
+
246
+ flex: 1;
145
247
  }
146
248
  display: inline-flex;
147
249
  align-items: center;
@@ -223,9 +325,6 @@ const TextInputWrapper = styled.div`
223
325
 
224
326
  ${props => props.hasLeadingVisual && css`
225
327
  padding-left: ${forcePixelValue(props.theme.space[4])};
226
- input {
227
- padding-left: ${forcePixelValue(props.theme.space[2])};
228
- }
229
328
  `}
230
329
 
231
330
  transition: color 100ms, background-color 100ms;
@@ -241,31 +340,19 @@ const UnstyledInput = styled.input`
241
340
  border-radius: inherit;
242
341
  color: inherit;
243
342
  transition: inherit;
343
+ width: 100%;
244
344
 
245
345
  border: 0;
346
+ padding: 0;
246
347
  background-color: transparent;
247
- width: 100%;
248
348
  &:focus {
249
349
  outline: 0;
250
350
  }
251
351
  `;
252
352
  const BaseInput = styled(UnstyledInput)`
253
- padding-top: ${({
254
- theme
255
- }) => forcePixelValue(theme.space[3])};
256
- padding-right: ${({
257
- theme
258
- }) => forcePixelValue(theme.space[10])};
259
- padding-bottom: ${({
260
- theme
261
- }) => forcePixelValue(theme.space[3])};
262
- padding-left: ${({
263
- theme
264
- }) => forcePixelValue(theme.space[4])};
265
-
266
353
  white-space: pre;
267
354
  text-overflow: ellipsis;
268
355
  `;
269
- var OverlaySelectInput$1 = /*#__PURE__*/forwardRef(OverlaySelectInput);
356
+ var SearchSelectInput$1 = /*#__PURE__*/forwardRef(SearchSelectInput);
270
357
 
271
- export { OverlaySelectInput$1 as default };
358
+ export { SearchSelectInput$1 as default };
@@ -39,6 +39,7 @@ const TabItem = ({
39
39
  onClick?.(e);
40
40
  };
41
41
  return /*#__PURE__*/jsxRuntimeExports.jsx(BaseTabItem, {
42
+ type: 'button',
42
43
  role: 'tab',
43
44
  ref: ref,
44
45
  variant: variant,
package/esm/index.js CHANGED
@@ -22,9 +22,9 @@ export { default as ItemList } from './core/ItemList/index.js';
22
22
  export { default as MotionView } from './core/MotionView/index.js';
23
23
  export { default as Overlay } from './core/Overlay/index.js';
24
24
  export { default as OverlayPopper } from './core/OverlayPopper/index.js';
25
- export { default as OverlaySelectInput } from './core/OverlaySelectInput/index.js';
26
25
  export { default as Pagination } from './core/Pagination/index.js';
27
26
  export { default as Pill } from './core/Pill/index.js';
27
+ export { default as SearchSelectInput } from './core/SearchSelectInput/index.js';
28
28
  export { default as Select } from './core/Select/index.js';
29
29
  export { default as Space } from './core/Space/index.js';
30
30
  export { default as Spinner } from './core/Spinner/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teamturing/react-kit",
3
- "version": "2.19.14",
3
+ "version": "2.19.16",
4
4
  "description": "React components, hooks for create teamturing web application",
5
5
  "author": "Sungchang Park <psch300@gmail.com> (https://github.com/psch300)",
6
6
  "homepage": "https://github.com/weareteamturing/bombe#readme",
@@ -62,5 +62,5 @@
62
62
  "react-is": "^18.2.0",
63
63
  "styled-system": "^5.1.5"
64
64
  },
65
- "gitHead": "73771f9a29466d5aa4a9e075623a6543d173004c"
65
+ "gitHead": "882bff67f13764f7af42f5b8e39c417d344a1815"
66
66
  }