@primer/components 0.0.0-2021927184638 → 0.0.0-2021927202224
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 +16 -4
- package/dist/browser.esm.js +12 -14
- package/dist/browser.esm.js.map +1 -1
- package/dist/browser.umd.js +12 -14
- package/dist/browser.umd.js.map +1 -1
- package/lib/Breadcrumbs.d.ts +8 -7
- package/lib/Breadcrumbs.js +7 -12
- package/lib/TextInputWithTokens.d.ts +4 -0
- package/lib/TextInputWithTokens.js +61 -8
- package/lib/_TextInputWrapper.js +1 -1
- package/lib-esm/Breadcrumbs.d.ts +8 -7
- package/lib-esm/Breadcrumbs.js +8 -13
- package/lib-esm/TextInputWithTokens.d.ts +4 -0
- package/lib-esm/TextInputWithTokens.js +60 -8
- package/lib-esm/_TextInputWrapper.js +1 -1
- package/package.json +1 -1
package/lib/Breadcrumbs.d.ts
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
import * as History from 'history';
|
2
2
|
import React from 'react';
|
3
|
-
import { SystemCommonProps, SystemFlexProps } from './constants';
|
4
3
|
import { SxProp } from './sx';
|
5
4
|
import { ComponentProps } from './utils/types';
|
6
|
-
declare const BreadcrumbsBase: import("styled-components").StyledComponent<"nav", any,
|
7
|
-
export declare type BreadcrumbsProps =
|
8
|
-
|
5
|
+
declare const BreadcrumbsBase: import("styled-components").StyledComponent<"nav", any, SxProp, never>;
|
6
|
+
export declare type BreadcrumbsProps = React.PropsWithChildren<{
|
7
|
+
className?: string;
|
8
|
+
} & SxProp>;
|
9
|
+
declare function Breadcrumbs({ className, children, sx: sxProp }: React.PropsWithChildren<BreadcrumbsProps>): JSX.Element;
|
9
10
|
declare namespace Breadcrumbs {
|
10
11
|
var displayName: string;
|
11
12
|
}
|
12
13
|
declare const BreadcrumbsItem: import("styled-components").StyledComponent<"a", any, {
|
13
14
|
to?: History.LocationDescriptor<unknown> | undefined;
|
14
15
|
selected?: boolean | undefined;
|
15
|
-
} &
|
16
|
+
} & SxProp, never>;
|
16
17
|
export declare type BreadcrumbsItemProps = ComponentProps<typeof BreadcrumbsItem>;
|
17
18
|
declare const _default: typeof Breadcrumbs & {
|
18
19
|
Item: import("styled-components").StyledComponent<"a", any, {
|
19
20
|
to?: History.LocationDescriptor<unknown> | undefined;
|
20
21
|
selected?: boolean | undefined;
|
21
|
-
} &
|
22
|
+
} & SxProp, never>;
|
22
23
|
};
|
23
24
|
export default _default;
|
24
25
|
/**
|
@@ -28,7 +29,7 @@ export declare const Breadcrumb: typeof Breadcrumbs & {
|
|
28
29
|
Item: import("styled-components").StyledComponent<"a", any, {
|
29
30
|
to?: History.LocationDescriptor<unknown> | undefined;
|
30
31
|
selected?: boolean | undefined;
|
31
|
-
} &
|
32
|
+
} & SxProp, never>;
|
32
33
|
};
|
33
34
|
/**
|
34
35
|
* @deprecated Use the `BreadcrumbsProps` type instead
|
package/lib/Breadcrumbs.js
CHANGED
@@ -19,8 +19,6 @@ var _sx = _interopRequireDefault(require("./sx"));
|
|
19
19
|
|
20
20
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
21
21
|
|
22
|
-
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
23
|
-
|
24
22
|
const SELECTED_CLASS = 'selected';
|
25
23
|
|
26
24
|
const Wrapper = _styledComponents.default.li.withConfig({
|
@@ -31,23 +29,20 @@ const Wrapper = _styledComponents.default.li.withConfig({
|
|
31
29
|
const BreadcrumbsBase = _styledComponents.default.nav.withConfig({
|
32
30
|
displayName: "Breadcrumbs__BreadcrumbsBase",
|
33
31
|
componentId: "hwwoo0-1"
|
34
|
-
})(["display:flex;justify-content:space-between;", ";"
|
32
|
+
})(["display:flex;justify-content:space-between;", ";"], _sx.default);
|
35
33
|
|
36
34
|
function Breadcrumbs({
|
37
35
|
className,
|
38
36
|
children,
|
39
|
-
|
40
|
-
...rest
|
37
|
+
sx: sxProp
|
41
38
|
}) {
|
42
|
-
const wrappedChildren = _react.default.Children.map(children, child => /*#__PURE__*/_react.default.createElement(Wrapper,
|
43
|
-
theme: theme
|
44
|
-
}, child));
|
39
|
+
const wrappedChildren = _react.default.Children.map(children, child => /*#__PURE__*/_react.default.createElement(Wrapper, null, child));
|
45
40
|
|
46
|
-
return /*#__PURE__*/_react.default.createElement(BreadcrumbsBase,
|
41
|
+
return /*#__PURE__*/_react.default.createElement(BreadcrumbsBase, {
|
47
42
|
className: className,
|
48
43
|
"aria-label": "Breadcrumbs",
|
49
|
-
|
50
|
-
},
|
44
|
+
sx: sxProp
|
45
|
+
}, /*#__PURE__*/_react.default.createElement(_Box.default, {
|
51
46
|
as: "ol",
|
52
47
|
my: 0,
|
53
48
|
pl: 0
|
@@ -63,7 +58,7 @@ const BreadcrumbsItem = _styledComponents.default.a.attrs(props => ({
|
|
63
58
|
})).withConfig({
|
64
59
|
displayName: "Breadcrumbs__BreadcrumbsItem",
|
65
60
|
componentId: "hwwoo0-2"
|
66
|
-
})(["color:", ";display:inline-block;font-size:", ";text-decoration:none;&:hover{text-decoration:underline;}&.selected{color:", ";pointer-events:none;}", "
|
61
|
+
})(["color:", ";display:inline-block;font-size:", ";text-decoration:none;&:hover{text-decoration:underline;}&.selected{color:", ";pointer-events:none;}", ";"], (0, _constants.get)('colors.accent.fg'), (0, _constants.get)('fontSizes.1'), (0, _constants.get)('colors.fg.default'), _sx.default);
|
67
62
|
|
68
63
|
Breadcrumbs.displayName = 'Breadcrumbs';
|
69
64
|
BreadcrumbsItem.displayName = 'Breadcrumbs.Item';
|
@@ -32,6 +32,10 @@ declare const TextInputWithTokens: React.ForwardRefExoticComponent<Pick<{
|
|
32
32
|
* Whether the remove buttons should be rendered in the tokens
|
33
33
|
*/
|
34
34
|
hideTokenRemoveButtons?: boolean | undefined;
|
35
|
+
/**
|
36
|
+
* The number of tokens to display before truncating
|
37
|
+
*/
|
38
|
+
visibleTokenCount?: number | undefined;
|
35
39
|
} & Pick<Omit<Pick<{
|
36
40
|
[x: string]: any;
|
37
41
|
[x: number]: any;
|
@@ -25,6 +25,8 @@ var _TextInputWrapper = _interopRequireDefault(require("./_TextInputWrapper"));
|
|
25
25
|
|
26
26
|
var _Box = _interopRequireDefault(require("./Box"));
|
27
27
|
|
28
|
+
var _Text = _interopRequireDefault(require("./Text"));
|
29
|
+
|
28
30
|
var _iterateFocusableElements = require("./utils/iterateFocusableElements");
|
29
31
|
|
30
32
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
@@ -35,7 +37,13 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
|
|
35
37
|
|
36
38
|
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
37
39
|
|
38
|
-
|
40
|
+
const overflowCountFontSizeMap = {
|
41
|
+
small: 0,
|
42
|
+
medium: 1,
|
43
|
+
large: 1,
|
44
|
+
extralarge: 2
|
45
|
+
}; // using forwardRef is important so that other components (ex. Autocomplete) can use the ref
|
46
|
+
|
39
47
|
function TextInputWithTokensInnerComponent({
|
40
48
|
icon: IconComponent,
|
41
49
|
contrast,
|
@@ -55,9 +63,11 @@ function TextInputWithTokensInnerComponent({
|
|
55
63
|
minWidth: minWidthProp,
|
56
64
|
maxWidth: maxWidthProp,
|
57
65
|
variant: variantProp,
|
66
|
+
visibleTokenCount,
|
58
67
|
...rest
|
59
68
|
}, externalRef) {
|
60
69
|
const {
|
70
|
+
onBlur,
|
61
71
|
onFocus,
|
62
72
|
onKeyDown,
|
63
73
|
...inputPropsRest
|
@@ -66,6 +76,7 @@ function TextInputWithTokensInnerComponent({
|
|
66
76
|
const localInputRef = (0, _react.useRef)(null);
|
67
77
|
const combinedInputRef = (0, _useCombinedRefs.useCombinedRefs)(localInputRef, ref);
|
68
78
|
const [selectedTokenIndex, setSelectedTokenIndex] = (0, _react.useState)();
|
79
|
+
const [tokensAreTruncated, setTokensAreTruncated] = (0, _react.useState)(Boolean(visibleTokenCount));
|
69
80
|
const {
|
70
81
|
containerRef
|
71
82
|
} = (0, _useFocusZone.useFocusZone)({
|
@@ -126,20 +137,45 @@ function TextInputWithTokensInnerComponent({
|
|
126
137
|
};
|
127
138
|
|
128
139
|
const handleTokenBlur = () => {
|
129
|
-
setSelectedTokenIndex(undefined);
|
140
|
+
setSelectedTokenIndex(undefined); // HACK: wait a tick and check the focused element before hiding truncated tokens
|
141
|
+
// this prevents the tokens from hiding when the user is moving focus between tokens,
|
142
|
+
// but still hides the tokens when the user blurs the token by tabbing out or clicking somewhere else on the page
|
143
|
+
|
144
|
+
setTimeout(() => {
|
145
|
+
var _containerRef$current4;
|
146
|
+
|
147
|
+
if (!((_containerRef$current4 = containerRef.current) !== null && _containerRef$current4 !== void 0 && _containerRef$current4.contains(document.activeElement)) && visibleTokenCount) {
|
148
|
+
setTokensAreTruncated(true);
|
149
|
+
}
|
150
|
+
}, 0);
|
130
151
|
};
|
131
152
|
|
132
|
-
const handleTokenKeyUp =
|
133
|
-
if (
|
153
|
+
const handleTokenKeyUp = event => {
|
154
|
+
if (event.key === 'Escape') {
|
134
155
|
var _ref$current2;
|
135
156
|
|
136
157
|
(_ref$current2 = ref.current) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.focus();
|
137
158
|
}
|
138
159
|
};
|
139
160
|
|
140
|
-
const handleInputFocus =
|
141
|
-
onFocus && onFocus(
|
161
|
+
const handleInputFocus = event => {
|
162
|
+
onFocus && onFocus(event);
|
142
163
|
setSelectedTokenIndex(undefined);
|
164
|
+
visibleTokenCount && setTokensAreTruncated(false);
|
165
|
+
};
|
166
|
+
|
167
|
+
const handleInputBlur = event => {
|
168
|
+
onBlur && onBlur(event); // HACK: wait a tick and check the focused element before hiding truncated tokens
|
169
|
+
// this prevents the tokens from hiding when the user is moving focus from the input to a token,
|
170
|
+
// but still hides the tokens when the user blurs the input by tabbing out or clicking somewhere else on the page
|
171
|
+
|
172
|
+
setTimeout(() => {
|
173
|
+
var _containerRef$current5;
|
174
|
+
|
175
|
+
if (!((_containerRef$current5 = containerRef.current) !== null && _containerRef$current5 !== void 0 && _containerRef$current5.contains(document.activeElement)) && visibleTokenCount) {
|
176
|
+
setTokensAreTruncated(true);
|
177
|
+
}
|
178
|
+
}, 0);
|
143
179
|
};
|
144
180
|
|
145
181
|
const handleInputKeyDown = e => {
|
@@ -177,6 +213,17 @@ function TextInputWithTokensInnerComponent({
|
|
177
213
|
}
|
178
214
|
};
|
179
215
|
|
216
|
+
const focusInput = () => {
|
217
|
+
var _combinedInputRef$cur;
|
218
|
+
|
219
|
+
(_combinedInputRef$cur = combinedInputRef.current) === null || _combinedInputRef$cur === void 0 ? void 0 : _combinedInputRef$cur.focus();
|
220
|
+
};
|
221
|
+
|
222
|
+
const preventTokenClickPropagation = event => {
|
223
|
+
event.stopPropagation();
|
224
|
+
};
|
225
|
+
|
226
|
+
const visibleTokens = tokensAreTruncated ? tokens.slice(0, visibleTokenCount) : tokens;
|
180
227
|
return /*#__PURE__*/_react.default.createElement(_TextInputWrapper.default, {
|
181
228
|
block: block,
|
182
229
|
className: className,
|
@@ -188,6 +235,7 @@ function TextInputWithTokensInnerComponent({
|
|
188
235
|
minWidth: minWidthProp,
|
189
236
|
maxWidth: maxWidthProp,
|
190
237
|
variant: variantProp,
|
238
|
+
onClick: focusInput,
|
191
239
|
sx: { ...(block ? {
|
192
240
|
display: 'flex',
|
193
241
|
width: '100%'
|
@@ -227,12 +275,13 @@ function TextInputWithTokensInnerComponent({
|
|
227
275
|
ref: combinedInputRef,
|
228
276
|
disabled: disabled,
|
229
277
|
onFocus: handleInputFocus,
|
278
|
+
onBlur: handleInputBlur,
|
230
279
|
onKeyDown: handleInputKeyDown,
|
231
280
|
type: "text",
|
232
281
|
sx: {
|
233
282
|
height: '100%'
|
234
283
|
}
|
235
|
-
}, inputPropsRest))),
|
284
|
+
}, inputPropsRest))), TokenComponent ? visibleTokens.map(({
|
236
285
|
id,
|
237
286
|
...tokenRest
|
238
287
|
}, i) => /*#__PURE__*/_react.default.createElement(TokenComponent, _extends({
|
@@ -240,6 +289,7 @@ function TextInputWithTokensInnerComponent({
|
|
240
289
|
onFocus: handleTokenFocus(i),
|
241
290
|
onBlur: handleTokenBlur,
|
242
291
|
onKeyUp: handleTokenKeyUp,
|
292
|
+
onClick: preventTokenClickPropagation,
|
243
293
|
isSelected: selectedTokenIndex === i,
|
244
294
|
onRemove: () => {
|
245
295
|
handleTokenRemove(id);
|
@@ -247,7 +297,10 @@ function TextInputWithTokensInnerComponent({
|
|
247
297
|
hideRemoveButton: hideTokenRemoveButtons,
|
248
298
|
size: size,
|
249
299
|
tabIndex: 0
|
250
|
-
}, tokenRest))) : null
|
300
|
+
}, tokenRest))) : null, tokensAreTruncated ? /*#__PURE__*/_react.default.createElement(_Text.default, {
|
301
|
+
color: "fg.muted",
|
302
|
+
fontSize: size && overflowCountFontSizeMap[size]
|
303
|
+
}, "+", tokens.length - visibleTokens.length) : null));
|
251
304
|
}
|
252
305
|
|
253
306
|
TextInputWithTokensInnerComponent.displayName = "TextInputWithTokensInnerComponent";
|
package/lib/_TextInputWrapper.js
CHANGED
@@ -39,7 +39,7 @@ const sizeVariants = (0, _styledSystem.variant)({
|
|
39
39
|
const TextInputWrapper = _styledComponents.default.span.withConfig({
|
40
40
|
displayName: "_TextInputWrapper__TextInputWrapper",
|
41
41
|
componentId: "sc-5vfcis-0"
|
42
|
-
})(["display:inline-flex;align-items:stretch;min-height:34px;font-size:", ";line-height:20px;color:", ";vertical-align:middle;background-repeat:no-repeat;background-position:right 8px center;border:1px solid ", ";border-radius:", ";outline:none;box-shadow:", ";", " .TextInput-icon{align-self:center;color:", ";margin:0 ", ";flex-shrink:0;}&:focus-within{border-color:", ";box-shadow:", ";}", " ", " ", " @media (min-width:", "){font-size:", ";}", " ", " ", " ", " ", ";"], (0, _constants.get)('fontSizes.1'), (0, _constants.get)('colors.fg.default'), (0, _constants.get)('colors.border.default'), (0, _constants.get)('radii.2'), (0, _constants.get)('shadows.primer.shadow.inset'), props => {
|
42
|
+
})(["display:inline-flex;align-items:stretch;min-height:34px;font-size:", ";line-height:20px;color:", ";vertical-align:middle;background-repeat:no-repeat;background-position:right 8px center;border:1px solid ", ";border-radius:", ";outline:none;box-shadow:", ";cursor:text;", " .TextInput-icon{align-self:center;color:", ";margin:0 ", ";flex-shrink:0;}&:focus-within{border-color:", ";box-shadow:", ";}", " ", " ", " @media (min-width:", "){font-size:", ";}", " ", " ", " ", " ", ";"], (0, _constants.get)('fontSizes.1'), (0, _constants.get)('colors.fg.default'), (0, _constants.get)('colors.border.default'), (0, _constants.get)('radii.2'), (0, _constants.get)('shadows.primer.shadow.inset'), props => {
|
43
43
|
if (props.hasIcon) {
|
44
44
|
return (0, _styledComponents.css)(["padding:0;"]);
|
45
45
|
} else {
|
package/lib-esm/Breadcrumbs.d.ts
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
import * as History from 'history';
|
2
2
|
import React from 'react';
|
3
|
-
import { SystemCommonProps, SystemFlexProps } from './constants';
|
4
3
|
import { SxProp } from './sx';
|
5
4
|
import { ComponentProps } from './utils/types';
|
6
|
-
declare const BreadcrumbsBase: import("styled-components").StyledComponent<"nav", any,
|
7
|
-
export declare type BreadcrumbsProps =
|
8
|
-
|
5
|
+
declare const BreadcrumbsBase: import("styled-components").StyledComponent<"nav", any, SxProp, never>;
|
6
|
+
export declare type BreadcrumbsProps = React.PropsWithChildren<{
|
7
|
+
className?: string;
|
8
|
+
} & SxProp>;
|
9
|
+
declare function Breadcrumbs({ className, children, sx: sxProp }: React.PropsWithChildren<BreadcrumbsProps>): JSX.Element;
|
9
10
|
declare namespace Breadcrumbs {
|
10
11
|
var displayName: string;
|
11
12
|
}
|
12
13
|
declare const BreadcrumbsItem: import("styled-components").StyledComponent<"a", any, {
|
13
14
|
to?: History.LocationDescriptor<unknown> | undefined;
|
14
15
|
selected?: boolean | undefined;
|
15
|
-
} &
|
16
|
+
} & SxProp, never>;
|
16
17
|
export declare type BreadcrumbsItemProps = ComponentProps<typeof BreadcrumbsItem>;
|
17
18
|
declare const _default: typeof Breadcrumbs & {
|
18
19
|
Item: import("styled-components").StyledComponent<"a", any, {
|
19
20
|
to?: History.LocationDescriptor<unknown> | undefined;
|
20
21
|
selected?: boolean | undefined;
|
21
|
-
} &
|
22
|
+
} & SxProp, never>;
|
22
23
|
};
|
23
24
|
export default _default;
|
24
25
|
/**
|
@@ -28,7 +29,7 @@ export declare const Breadcrumb: typeof Breadcrumbs & {
|
|
28
29
|
Item: import("styled-components").StyledComponent<"a", any, {
|
29
30
|
to?: History.LocationDescriptor<unknown> | undefined;
|
30
31
|
selected?: boolean | undefined;
|
31
|
-
} &
|
32
|
+
} & SxProp, never>;
|
32
33
|
};
|
33
34
|
/**
|
34
35
|
* @deprecated Use the `BreadcrumbsProps` type instead
|
package/lib-esm/Breadcrumbs.js
CHANGED
@@ -1,11 +1,9 @@
|
|
1
|
-
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
2
|
-
|
3
1
|
import classnames from 'classnames'; // eslint-disable-next-line import/no-namespace
|
4
2
|
|
5
3
|
import React from 'react';
|
6
4
|
import styled from 'styled-components';
|
7
5
|
import Box from './Box';
|
8
|
-
import {
|
6
|
+
import { get } from './constants';
|
9
7
|
import sx from './sx';
|
10
8
|
const SELECTED_CLASS = 'selected';
|
11
9
|
const Wrapper = styled.li.withConfig({
|
@@ -15,22 +13,19 @@ const Wrapper = styled.li.withConfig({
|
|
15
13
|
const BreadcrumbsBase = styled.nav.withConfig({
|
16
14
|
displayName: "Breadcrumbs__BreadcrumbsBase",
|
17
15
|
componentId: "hwwoo0-1"
|
18
|
-
})(["display:flex;justify-content:space-between;", ";"
|
16
|
+
})(["display:flex;justify-content:space-between;", ";"], sx);
|
19
17
|
|
20
18
|
function Breadcrumbs({
|
21
19
|
className,
|
22
20
|
children,
|
23
|
-
|
24
|
-
...rest
|
21
|
+
sx: sxProp
|
25
22
|
}) {
|
26
|
-
const wrappedChildren = React.Children.map(children, child => /*#__PURE__*/React.createElement(Wrapper,
|
27
|
-
|
28
|
-
}, child));
|
29
|
-
return /*#__PURE__*/React.createElement(BreadcrumbsBase, _extends({
|
23
|
+
const wrappedChildren = React.Children.map(children, child => /*#__PURE__*/React.createElement(Wrapper, null, child));
|
24
|
+
return /*#__PURE__*/React.createElement(BreadcrumbsBase, {
|
30
25
|
className: className,
|
31
26
|
"aria-label": "Breadcrumbs",
|
32
|
-
|
33
|
-
},
|
27
|
+
sx: sxProp
|
28
|
+
}, /*#__PURE__*/React.createElement(Box, {
|
34
29
|
as: "ol",
|
35
30
|
my: 0,
|
36
31
|
pl: 0
|
@@ -45,7 +40,7 @@ const BreadcrumbsItem = styled.a.attrs(props => ({
|
|
45
40
|
})).withConfig({
|
46
41
|
displayName: "Breadcrumbs__BreadcrumbsItem",
|
47
42
|
componentId: "hwwoo0-2"
|
48
|
-
})(["color:", ";display:inline-block;font-size:", ";text-decoration:none;&:hover{text-decoration:underline;}&.selected{color:", ";pointer-events:none;}", "
|
43
|
+
})(["color:", ";display:inline-block;font-size:", ";text-decoration:none;&:hover{text-decoration:underline;}&.selected{color:", ";pointer-events:none;}", ";"], get('colors.accent.fg'), get('fontSizes.1'), get('colors.fg.default'), sx);
|
49
44
|
Breadcrumbs.displayName = 'Breadcrumbs';
|
50
45
|
BreadcrumbsItem.displayName = 'Breadcrumbs.Item';
|
51
46
|
export default Object.assign(Breadcrumbs, {
|
@@ -32,6 +32,10 @@ declare const TextInputWithTokens: React.ForwardRefExoticComponent<Pick<{
|
|
32
32
|
* Whether the remove buttons should be rendered in the tokens
|
33
33
|
*/
|
34
34
|
hideTokenRemoveButtons?: boolean | undefined;
|
35
|
+
/**
|
36
|
+
* The number of tokens to display before truncating
|
37
|
+
*/
|
38
|
+
visibleTokenCount?: number | undefined;
|
35
39
|
} & Pick<Omit<Pick<{
|
36
40
|
[x: string]: any;
|
37
41
|
[x: number]: any;
|
@@ -10,9 +10,16 @@ import { useProvidedRefOrCreate } from './hooks';
|
|
10
10
|
import UnstyledTextInput from './_UnstyledTextInput';
|
11
11
|
import TextInputWrapper from './_TextInputWrapper';
|
12
12
|
import Box from './Box';
|
13
|
+
import Text from './Text';
|
13
14
|
import { isFocusable } from './utils/iterateFocusableElements'; // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
14
15
|
|
15
|
-
|
16
|
+
const overflowCountFontSizeMap = {
|
17
|
+
small: 0,
|
18
|
+
medium: 1,
|
19
|
+
large: 1,
|
20
|
+
extralarge: 2
|
21
|
+
}; // using forwardRef is important so that other components (ex. Autocomplete) can use the ref
|
22
|
+
|
16
23
|
function TextInputWithTokensInnerComponent({
|
17
24
|
icon: IconComponent,
|
18
25
|
contrast,
|
@@ -32,9 +39,11 @@ function TextInputWithTokensInnerComponent({
|
|
32
39
|
minWidth: minWidthProp,
|
33
40
|
maxWidth: maxWidthProp,
|
34
41
|
variant: variantProp,
|
42
|
+
visibleTokenCount,
|
35
43
|
...rest
|
36
44
|
}, externalRef) {
|
37
45
|
const {
|
46
|
+
onBlur,
|
38
47
|
onFocus,
|
39
48
|
onKeyDown,
|
40
49
|
...inputPropsRest
|
@@ -43,6 +52,7 @@ function TextInputWithTokensInnerComponent({
|
|
43
52
|
const localInputRef = useRef(null);
|
44
53
|
const combinedInputRef = useCombinedRefs(localInputRef, ref);
|
45
54
|
const [selectedTokenIndex, setSelectedTokenIndex] = useState();
|
55
|
+
const [tokensAreTruncated, setTokensAreTruncated] = useState(Boolean(visibleTokenCount));
|
46
56
|
const {
|
47
57
|
containerRef
|
48
58
|
} = useFocusZone({
|
@@ -103,20 +113,45 @@ function TextInputWithTokensInnerComponent({
|
|
103
113
|
};
|
104
114
|
|
105
115
|
const handleTokenBlur = () => {
|
106
|
-
setSelectedTokenIndex(undefined);
|
116
|
+
setSelectedTokenIndex(undefined); // HACK: wait a tick and check the focused element before hiding truncated tokens
|
117
|
+
// this prevents the tokens from hiding when the user is moving focus between tokens,
|
118
|
+
// but still hides the tokens when the user blurs the token by tabbing out or clicking somewhere else on the page
|
119
|
+
|
120
|
+
setTimeout(() => {
|
121
|
+
var _containerRef$current4;
|
122
|
+
|
123
|
+
if (!((_containerRef$current4 = containerRef.current) !== null && _containerRef$current4 !== void 0 && _containerRef$current4.contains(document.activeElement)) && visibleTokenCount) {
|
124
|
+
setTokensAreTruncated(true);
|
125
|
+
}
|
126
|
+
}, 0);
|
107
127
|
};
|
108
128
|
|
109
|
-
const handleTokenKeyUp =
|
110
|
-
if (
|
129
|
+
const handleTokenKeyUp = event => {
|
130
|
+
if (event.key === 'Escape') {
|
111
131
|
var _ref$current2;
|
112
132
|
|
113
133
|
(_ref$current2 = ref.current) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.focus();
|
114
134
|
}
|
115
135
|
};
|
116
136
|
|
117
|
-
const handleInputFocus =
|
118
|
-
onFocus && onFocus(
|
137
|
+
const handleInputFocus = event => {
|
138
|
+
onFocus && onFocus(event);
|
119
139
|
setSelectedTokenIndex(undefined);
|
140
|
+
visibleTokenCount && setTokensAreTruncated(false);
|
141
|
+
};
|
142
|
+
|
143
|
+
const handleInputBlur = event => {
|
144
|
+
onBlur && onBlur(event); // HACK: wait a tick and check the focused element before hiding truncated tokens
|
145
|
+
// this prevents the tokens from hiding when the user is moving focus from the input to a token,
|
146
|
+
// but still hides the tokens when the user blurs the input by tabbing out or clicking somewhere else on the page
|
147
|
+
|
148
|
+
setTimeout(() => {
|
149
|
+
var _containerRef$current5;
|
150
|
+
|
151
|
+
if (!((_containerRef$current5 = containerRef.current) !== null && _containerRef$current5 !== void 0 && _containerRef$current5.contains(document.activeElement)) && visibleTokenCount) {
|
152
|
+
setTokensAreTruncated(true);
|
153
|
+
}
|
154
|
+
}, 0);
|
120
155
|
};
|
121
156
|
|
122
157
|
const handleInputKeyDown = e => {
|
@@ -154,6 +189,17 @@ function TextInputWithTokensInnerComponent({
|
|
154
189
|
}
|
155
190
|
};
|
156
191
|
|
192
|
+
const focusInput = () => {
|
193
|
+
var _combinedInputRef$cur;
|
194
|
+
|
195
|
+
(_combinedInputRef$cur = combinedInputRef.current) === null || _combinedInputRef$cur === void 0 ? void 0 : _combinedInputRef$cur.focus();
|
196
|
+
};
|
197
|
+
|
198
|
+
const preventTokenClickPropagation = event => {
|
199
|
+
event.stopPropagation();
|
200
|
+
};
|
201
|
+
|
202
|
+
const visibleTokens = tokensAreTruncated ? tokens.slice(0, visibleTokenCount) : tokens;
|
157
203
|
return /*#__PURE__*/React.createElement(TextInputWrapper, {
|
158
204
|
block: block,
|
159
205
|
className: className,
|
@@ -165,6 +211,7 @@ function TextInputWithTokensInnerComponent({
|
|
165
211
|
minWidth: minWidthProp,
|
166
212
|
maxWidth: maxWidthProp,
|
167
213
|
variant: variantProp,
|
214
|
+
onClick: focusInput,
|
168
215
|
sx: { ...(block ? {
|
169
216
|
display: 'flex',
|
170
217
|
width: '100%'
|
@@ -204,12 +251,13 @@ function TextInputWithTokensInnerComponent({
|
|
204
251
|
ref: combinedInputRef,
|
205
252
|
disabled: disabled,
|
206
253
|
onFocus: handleInputFocus,
|
254
|
+
onBlur: handleInputBlur,
|
207
255
|
onKeyDown: handleInputKeyDown,
|
208
256
|
type: "text",
|
209
257
|
sx: {
|
210
258
|
height: '100%'
|
211
259
|
}
|
212
|
-
}, inputPropsRest))),
|
260
|
+
}, inputPropsRest))), TokenComponent ? visibleTokens.map(({
|
213
261
|
id,
|
214
262
|
...tokenRest
|
215
263
|
}, i) => /*#__PURE__*/React.createElement(TokenComponent, _extends({
|
@@ -217,6 +265,7 @@ function TextInputWithTokensInnerComponent({
|
|
217
265
|
onFocus: handleTokenFocus(i),
|
218
266
|
onBlur: handleTokenBlur,
|
219
267
|
onKeyUp: handleTokenKeyUp,
|
268
|
+
onClick: preventTokenClickPropagation,
|
220
269
|
isSelected: selectedTokenIndex === i,
|
221
270
|
onRemove: () => {
|
222
271
|
handleTokenRemove(id);
|
@@ -224,7 +273,10 @@ function TextInputWithTokensInnerComponent({
|
|
224
273
|
hideRemoveButton: hideTokenRemoveButtons,
|
225
274
|
size: size,
|
226
275
|
tabIndex: 0
|
227
|
-
}, tokenRest))) : null
|
276
|
+
}, tokenRest))) : null, tokensAreTruncated ? /*#__PURE__*/React.createElement(Text, {
|
277
|
+
color: "fg.muted",
|
278
|
+
fontSize: size && overflowCountFontSizeMap[size]
|
279
|
+
}, "+", tokens.length - visibleTokens.length) : null));
|
228
280
|
}
|
229
281
|
|
230
282
|
TextInputWithTokensInnerComponent.displayName = "TextInputWithTokensInnerComponent";
|
@@ -21,7 +21,7 @@ const sizeVariants = variant({
|
|
21
21
|
const TextInputWrapper = styled.span.withConfig({
|
22
22
|
displayName: "_TextInputWrapper__TextInputWrapper",
|
23
23
|
componentId: "sc-5vfcis-0"
|
24
|
-
})(["display:inline-flex;align-items:stretch;min-height:34px;font-size:", ";line-height:20px;color:", ";vertical-align:middle;background-repeat:no-repeat;background-position:right 8px center;border:1px solid ", ";border-radius:", ";outline:none;box-shadow:", ";", " .TextInput-icon{align-self:center;color:", ";margin:0 ", ";flex-shrink:0;}&:focus-within{border-color:", ";box-shadow:", ";}", " ", " ", " @media (min-width:", "){font-size:", ";}", " ", " ", " ", " ", ";"], get('fontSizes.1'), get('colors.fg.default'), get('colors.border.default'), get('radii.2'), get('shadows.primer.shadow.inset'), props => {
|
24
|
+
})(["display:inline-flex;align-items:stretch;min-height:34px;font-size:", ";line-height:20px;color:", ";vertical-align:middle;background-repeat:no-repeat;background-position:right 8px center;border:1px solid ", ";border-radius:", ";outline:none;box-shadow:", ";cursor:text;", " .TextInput-icon{align-self:center;color:", ";margin:0 ", ";flex-shrink:0;}&:focus-within{border-color:", ";box-shadow:", ";}", " ", " ", " @media (min-width:", "){font-size:", ";}", " ", " ", " ", " ", ";"], get('fontSizes.1'), get('colors.fg.default'), get('colors.border.default'), get('radii.2'), get('shadows.primer.shadow.inset'), props => {
|
25
25
|
if (props.hasIcon) {
|
26
26
|
return css(["padding:0;"]);
|
27
27
|
} else {
|