@primer/components 0.0.0-202192718387 → 0.0.0-2021927193941
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 +8 -2
- package/dist/browser.esm.js +41 -37
- package/dist/browser.esm.js.map +1 -1
- package/dist/browser.umd.js +36 -32
- package/dist/browser.umd.js.map +1 -1
- package/lib/TextInputWithTokens.d.ts +4 -0
- package/lib/TextInputWithTokens.js +77 -17
- package/lib/Token/Token.js +13 -2
- package/lib/Token/TokenBase.js +0 -4
- package/lib/Token/_RemoveTokenButton.js +15 -2
- package/lib/_TextInputWrapper.js +1 -1
- package/lib-esm/TextInputWithTokens.d.ts +4 -0
- package/lib-esm/TextInputWithTokens.js +76 -17
- package/lib-esm/Token/Token.js +13 -2
- package/lib-esm/Token/TokenBase.js +0 -4
- package/lib-esm/Token/_RemoveTokenButton.js +11 -2
- package/lib-esm/_TextInputWrapper.js +1 -1
- package/package.json +2 -1
@@ -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,15 +235,8 @@ function TextInputWithTokensInnerComponent({
|
|
188
235
|
minWidth: minWidthProp,
|
189
236
|
maxWidth: maxWidthProp,
|
190
237
|
variant: variantProp,
|
191
|
-
|
192
|
-
sx: {
|
193
|
-
alignItems: 'center',
|
194
|
-
flexWrap: preventTokenWrapping ? 'nowrap' : 'wrap',
|
195
|
-
gap: '0.25rem',
|
196
|
-
'> *': {
|
197
|
-
flexShrink: 0
|
198
|
-
},
|
199
|
-
...(block ? {
|
238
|
+
onClick: focusInput,
|
239
|
+
sx: { ...(block ? {
|
200
240
|
display: 'flex',
|
201
241
|
width: '100%'
|
202
242
|
} : {}),
|
@@ -209,6 +249,21 @@ function TextInputWithTokensInnerComponent({
|
|
209
249
|
} : {}),
|
210
250
|
...sxProp
|
211
251
|
}
|
252
|
+
}, /*#__PURE__*/_react.default.createElement(_Box.default, {
|
253
|
+
ref: containerRef,
|
254
|
+
display: "flex",
|
255
|
+
sx: {
|
256
|
+
alignItems: 'center',
|
257
|
+
flexWrap: preventTokenWrapping ? 'nowrap' : 'wrap',
|
258
|
+
marginLeft: '-0.25rem',
|
259
|
+
marginBottom: '-0.25rem',
|
260
|
+
flexGrow: 1,
|
261
|
+
'> *': {
|
262
|
+
flexShrink: 0,
|
263
|
+
marginLeft: '0.25rem',
|
264
|
+
marginBottom: '0.25rem'
|
265
|
+
}
|
266
|
+
}
|
212
267
|
}, /*#__PURE__*/_react.default.createElement(_Box.default, {
|
213
268
|
sx: {
|
214
269
|
order: 1,
|
@@ -220,12 +275,13 @@ function TextInputWithTokensInnerComponent({
|
|
220
275
|
ref: combinedInputRef,
|
221
276
|
disabled: disabled,
|
222
277
|
onFocus: handleInputFocus,
|
278
|
+
onBlur: handleInputBlur,
|
223
279
|
onKeyDown: handleInputKeyDown,
|
224
280
|
type: "text",
|
225
281
|
sx: {
|
226
282
|
height: '100%'
|
227
283
|
}
|
228
|
-
}, inputPropsRest))),
|
284
|
+
}, inputPropsRest))), TokenComponent ? visibleTokens.map(({
|
229
285
|
id,
|
230
286
|
...tokenRest
|
231
287
|
}, i) => /*#__PURE__*/_react.default.createElement(TokenComponent, _extends({
|
@@ -233,6 +289,7 @@ function TextInputWithTokensInnerComponent({
|
|
233
289
|
onFocus: handleTokenFocus(i),
|
234
290
|
onBlur: handleTokenBlur,
|
235
291
|
onKeyUp: handleTokenKeyUp,
|
292
|
+
onClick: preventTokenClickPropagation,
|
236
293
|
isSelected: selectedTokenIndex === i,
|
237
294
|
onRemove: () => {
|
238
295
|
handleTokenRemove(id);
|
@@ -240,7 +297,10 @@ function TextInputWithTokensInnerComponent({
|
|
240
297
|
hideRemoveButton: hideTokenRemoveButtons,
|
241
298
|
size: size,
|
242
299
|
tabIndex: 0
|
243
|
-
}, 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));
|
244
304
|
}
|
245
305
|
|
246
306
|
TextInputWithTokensInnerComponent.displayName = "TextInputWithTokensInnerComponent";
|
package/lib/Token/Token.js
CHANGED
@@ -39,7 +39,16 @@ const DefaultTokenStyled = (0, _styledComponents.default)(_TokenBase.default).wi
|
|
39
39
|
const LeadingVisualContainer = (0, _styledComponents.default)('span').withConfig({
|
40
40
|
displayName: "Token__LeadingVisualContainer",
|
41
41
|
componentId: "sc-1dg52pw-1"
|
42
|
-
})(["flex-shrink:0;line-height:0;"]
|
42
|
+
})(["flex-shrink:0;line-height:0;", ""], props => {
|
43
|
+
switch (props.size) {
|
44
|
+
case 'large':
|
45
|
+
case 'extralarge':
|
46
|
+
return (0, _styledComponents.css)(["margin-right:", ";"], (0, _constants.get)('space.2'));
|
47
|
+
|
48
|
+
default:
|
49
|
+
return (0, _styledComponents.css)(["margin-right:", ";"], (0, _constants.get)('space.1'));
|
50
|
+
}
|
51
|
+
});
|
43
52
|
const Token = /*#__PURE__*/(0, _react.forwardRef)((props, forwardedRef) => {
|
44
53
|
const {
|
45
54
|
as,
|
@@ -74,7 +83,9 @@ const Token = /*#__PURE__*/(0, _react.forwardRef)((props, forwardedRef) => {
|
|
74
83
|
isTokenInteractive: (0, _TokenBase.isTokenInteractive)(props)
|
75
84
|
}, !hasMultipleActionTargets ? interactiveTokenProps : {}, rest, {
|
76
85
|
ref: forwardedRef
|
77
|
-
}), LeadingVisual ? /*#__PURE__*/_react.default.createElement(LeadingVisualContainer,
|
86
|
+
}), LeadingVisual ? /*#__PURE__*/_react.default.createElement(LeadingVisualContainer, {
|
87
|
+
size: size
|
88
|
+
}, /*#__PURE__*/_react.default.createElement(LeadingVisual, null)) : null, /*#__PURE__*/_react.default.createElement(_TokenTextContainer.default, hasMultipleActionTargets ? interactiveTokenProps : {}, text), !hideRemoveButton && onRemove ? /*#__PURE__*/_react.default.createElement(_RemoveTokenButton.default, {
|
78
89
|
borderOffset: tokenBorderWidthPx,
|
79
90
|
onClick: onRemoveClick,
|
80
91
|
size: size,
|
package/lib/Token/TokenBase.js
CHANGED
@@ -38,7 +38,6 @@ const variants = (0, _styledSystem.variant)({
|
|
38
38
|
variants: {
|
39
39
|
small: {
|
40
40
|
fontSize: 0,
|
41
|
-
gap: 1,
|
42
41
|
height: tokenSizes.small,
|
43
42
|
// without setting lineHeight to match height, the "x" appears vertically mis-aligned
|
44
43
|
lineHeight: tokenSizes.small,
|
@@ -51,7 +50,6 @@ const variants = (0, _styledSystem.variant)({
|
|
51
50
|
},
|
52
51
|
medium: {
|
53
52
|
fontSize: 0,
|
54
|
-
gap: 1,
|
55
53
|
height: tokenSizes.medium,
|
56
54
|
lineHeight: tokenSizes.medium,
|
57
55
|
paddingLeft: 2,
|
@@ -61,7 +59,6 @@ const variants = (0, _styledSystem.variant)({
|
|
61
59
|
},
|
62
60
|
large: {
|
63
61
|
fontSize: 0,
|
64
|
-
gap: 2,
|
65
62
|
height: tokenSizes.large,
|
66
63
|
lineHeight: tokenSizes.large,
|
67
64
|
paddingLeft: 2,
|
@@ -71,7 +68,6 @@ const variants = (0, _styledSystem.variant)({
|
|
71
68
|
},
|
72
69
|
extralarge: {
|
73
70
|
fontSize: 1,
|
74
|
-
gap: 2,
|
75
71
|
height: tokenSizes.extralarge,
|
76
72
|
lineHeight: tokenSizes.extralarge,
|
77
73
|
paddingLeft: 3,
|
@@ -9,7 +9,7 @@ var _react = _interopRequireDefault(require("react"));
|
|
9
9
|
|
10
10
|
var _octiconsReact = require("@primer/octicons-react");
|
11
11
|
|
12
|
-
var _styledComponents =
|
12
|
+
var _styledComponents = _interopRequireWildcard(require("styled-components"));
|
13
13
|
|
14
14
|
var _styledSystem = require("styled-system");
|
15
15
|
|
@@ -19,6 +19,10 @@ var _sx = _interopRequireDefault(require("../sx"));
|
|
19
19
|
|
20
20
|
var _TokenBase = require("./TokenBase");
|
21
21
|
|
22
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
23
|
+
|
24
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
25
|
+
|
22
26
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
23
27
|
|
24
28
|
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); }
|
@@ -50,7 +54,16 @@ const getTokenButtonIconSize = size => parseInt(_TokenBase.tokenSizes[size || _T
|
|
50
54
|
const StyledTokenButton = _styledComponents.default.span.withConfig({
|
51
55
|
displayName: "_RemoveTokenButton__StyledTokenButton",
|
52
56
|
componentId: "sc-14lvcw1-0"
|
53
|
-
})(["background-color:transparent;font-family:inherit;color:currentColor;cursor:pointer;display:inline-flex;justify-content:center;align-items:center;user-select:none;appearance:none;text-decoration:none;padding:0;transform:", ";align-self:baseline;border:0;border-radius:999px
|
57
|
+
})(["background-color:transparent;font-family:inherit;color:currentColor;cursor:pointer;display:inline-flex;justify-content:center;align-items:center;user-select:none;appearance:none;text-decoration:none;padding:0;transform:", ";align-self:baseline;border:0;border-radius:999px;", " &:hover,&:focus{background-color:", ";}&:active{background-color:", ";}", " ", ""], props => `translate(${props.borderOffset}px, -${props.borderOffset}px)`, props => {
|
58
|
+
switch (props.size) {
|
59
|
+
case 'large':
|
60
|
+
case 'extralarge':
|
61
|
+
return (0, _styledComponents.css)(["margin-left:", ";"], (0, _constants.get)('space.2'));
|
62
|
+
|
63
|
+
default:
|
64
|
+
return (0, _styledComponents.css)(["margin-left:", ";"], (0, _constants.get)('space.1'));
|
65
|
+
}
|
66
|
+
}, (0, _constants.get)('colors.neutral.muted'), (0, _constants.get)('colors.neutral.subtle'), variants, _sx.default);
|
54
67
|
|
55
68
|
const RemoveTokenButton = ({
|
56
69
|
'aria-label': ariaLabel,
|
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 {
|
@@ -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,15 +211,8 @@ function TextInputWithTokensInnerComponent({
|
|
165
211
|
minWidth: minWidthProp,
|
166
212
|
maxWidth: maxWidthProp,
|
167
213
|
variant: variantProp,
|
168
|
-
|
169
|
-
sx: {
|
170
|
-
alignItems: 'center',
|
171
|
-
flexWrap: preventTokenWrapping ? 'nowrap' : 'wrap',
|
172
|
-
gap: '0.25rem',
|
173
|
-
'> *': {
|
174
|
-
flexShrink: 0
|
175
|
-
},
|
176
|
-
...(block ? {
|
214
|
+
onClick: focusInput,
|
215
|
+
sx: { ...(block ? {
|
177
216
|
display: 'flex',
|
178
217
|
width: '100%'
|
179
218
|
} : {}),
|
@@ -186,6 +225,21 @@ function TextInputWithTokensInnerComponent({
|
|
186
225
|
} : {}),
|
187
226
|
...sxProp
|
188
227
|
}
|
228
|
+
}, /*#__PURE__*/React.createElement(Box, {
|
229
|
+
ref: containerRef,
|
230
|
+
display: "flex",
|
231
|
+
sx: {
|
232
|
+
alignItems: 'center',
|
233
|
+
flexWrap: preventTokenWrapping ? 'nowrap' : 'wrap',
|
234
|
+
marginLeft: '-0.25rem',
|
235
|
+
marginBottom: '-0.25rem',
|
236
|
+
flexGrow: 1,
|
237
|
+
'> *': {
|
238
|
+
flexShrink: 0,
|
239
|
+
marginLeft: '0.25rem',
|
240
|
+
marginBottom: '0.25rem'
|
241
|
+
}
|
242
|
+
}
|
189
243
|
}, /*#__PURE__*/React.createElement(Box, {
|
190
244
|
sx: {
|
191
245
|
order: 1,
|
@@ -197,12 +251,13 @@ function TextInputWithTokensInnerComponent({
|
|
197
251
|
ref: combinedInputRef,
|
198
252
|
disabled: disabled,
|
199
253
|
onFocus: handleInputFocus,
|
254
|
+
onBlur: handleInputBlur,
|
200
255
|
onKeyDown: handleInputKeyDown,
|
201
256
|
type: "text",
|
202
257
|
sx: {
|
203
258
|
height: '100%'
|
204
259
|
}
|
205
|
-
}, inputPropsRest))),
|
260
|
+
}, inputPropsRest))), TokenComponent ? visibleTokens.map(({
|
206
261
|
id,
|
207
262
|
...tokenRest
|
208
263
|
}, i) => /*#__PURE__*/React.createElement(TokenComponent, _extends({
|
@@ -210,6 +265,7 @@ function TextInputWithTokensInnerComponent({
|
|
210
265
|
onFocus: handleTokenFocus(i),
|
211
266
|
onBlur: handleTokenBlur,
|
212
267
|
onKeyUp: handleTokenKeyUp,
|
268
|
+
onClick: preventTokenClickPropagation,
|
213
269
|
isSelected: selectedTokenIndex === i,
|
214
270
|
onRemove: () => {
|
215
271
|
handleTokenRemove(id);
|
@@ -217,7 +273,10 @@ function TextInputWithTokensInnerComponent({
|
|
217
273
|
hideRemoveButton: hideTokenRemoveButtons,
|
218
274
|
size: size,
|
219
275
|
tabIndex: 0
|
220
|
-
}, 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));
|
221
280
|
}
|
222
281
|
|
223
282
|
TextInputWithTokensInnerComponent.displayName = "TextInputWithTokensInnerComponent";
|
package/lib-esm/Token/Token.js
CHANGED
@@ -19,7 +19,16 @@ const DefaultTokenStyled = styled(TokenBase).withConfig({
|
|
19
19
|
const LeadingVisualContainer = styled('span').withConfig({
|
20
20
|
displayName: "Token__LeadingVisualContainer",
|
21
21
|
componentId: "sc-1dg52pw-1"
|
22
|
-
})(["flex-shrink:0;line-height:0;"]
|
22
|
+
})(["flex-shrink:0;line-height:0;", ""], props => {
|
23
|
+
switch (props.size) {
|
24
|
+
case 'large':
|
25
|
+
case 'extralarge':
|
26
|
+
return css(["margin-right:", ";"], get('space.2'));
|
27
|
+
|
28
|
+
default:
|
29
|
+
return css(["margin-right:", ";"], get('space.1'));
|
30
|
+
}
|
31
|
+
});
|
23
32
|
const Token = /*#__PURE__*/forwardRef((props, forwardedRef) => {
|
24
33
|
const {
|
25
34
|
as,
|
@@ -54,7 +63,9 @@ const Token = /*#__PURE__*/forwardRef((props, forwardedRef) => {
|
|
54
63
|
isTokenInteractive: isTokenInteractive(props)
|
55
64
|
}, !hasMultipleActionTargets ? interactiveTokenProps : {}, rest, {
|
56
65
|
ref: forwardedRef
|
57
|
-
}), LeadingVisual ? /*#__PURE__*/React.createElement(LeadingVisualContainer,
|
66
|
+
}), LeadingVisual ? /*#__PURE__*/React.createElement(LeadingVisualContainer, {
|
67
|
+
size: size
|
68
|
+
}, /*#__PURE__*/React.createElement(LeadingVisual, null)) : null, /*#__PURE__*/React.createElement(TokenTextContainer, hasMultipleActionTargets ? interactiveTokenProps : {}, text), !hideRemoveButton && onRemove ? /*#__PURE__*/React.createElement(RemoveTokenButton, {
|
58
69
|
borderOffset: tokenBorderWidthPx,
|
59
70
|
onClick: onRemoveClick,
|
60
71
|
size: size,
|
@@ -20,7 +20,6 @@ const variants = variant({
|
|
20
20
|
variants: {
|
21
21
|
small: {
|
22
22
|
fontSize: 0,
|
23
|
-
gap: 1,
|
24
23
|
height: tokenSizes.small,
|
25
24
|
// without setting lineHeight to match height, the "x" appears vertically mis-aligned
|
26
25
|
lineHeight: tokenSizes.small,
|
@@ -33,7 +32,6 @@ const variants = variant({
|
|
33
32
|
},
|
34
33
|
medium: {
|
35
34
|
fontSize: 0,
|
36
|
-
gap: 1,
|
37
35
|
height: tokenSizes.medium,
|
38
36
|
lineHeight: tokenSizes.medium,
|
39
37
|
paddingLeft: 2,
|
@@ -43,7 +41,6 @@ const variants = variant({
|
|
43
41
|
},
|
44
42
|
large: {
|
45
43
|
fontSize: 0,
|
46
|
-
gap: 2,
|
47
44
|
height: tokenSizes.large,
|
48
45
|
lineHeight: tokenSizes.large,
|
49
46
|
paddingLeft: 2,
|
@@ -53,7 +50,6 @@ const variants = variant({
|
|
53
50
|
},
|
54
51
|
extralarge: {
|
55
52
|
fontSize: 1,
|
56
|
-
gap: 2,
|
57
53
|
height: tokenSizes.extralarge,
|
58
54
|
lineHeight: tokenSizes.extralarge,
|
59
55
|
paddingLeft: 3,
|
@@ -2,7 +2,7 @@ function _extends() { _extends = Object.assign || function (target) { for (var i
|
|
2
2
|
|
3
3
|
import React from 'react';
|
4
4
|
import { XIcon } from '@primer/octicons-react';
|
5
|
-
import styled from 'styled-components';
|
5
|
+
import styled, { css } from 'styled-components';
|
6
6
|
import { variant } from 'styled-system';
|
7
7
|
import { get } from '../constants';
|
8
8
|
import sx from '../sx';
|
@@ -34,7 +34,16 @@ const getTokenButtonIconSize = size => parseInt(tokenSizes[size || defaultTokenS
|
|
34
34
|
const StyledTokenButton = styled.span.withConfig({
|
35
35
|
displayName: "_RemoveTokenButton__StyledTokenButton",
|
36
36
|
componentId: "sc-14lvcw1-0"
|
37
|
-
})(["background-color:transparent;font-family:inherit;color:currentColor;cursor:pointer;display:inline-flex;justify-content:center;align-items:center;user-select:none;appearance:none;text-decoration:none;padding:0;transform:", ";align-self:baseline;border:0;border-radius:999px
|
37
|
+
})(["background-color:transparent;font-family:inherit;color:currentColor;cursor:pointer;display:inline-flex;justify-content:center;align-items:center;user-select:none;appearance:none;text-decoration:none;padding:0;transform:", ";align-self:baseline;border:0;border-radius:999px;", " &:hover,&:focus{background-color:", ";}&:active{background-color:", ";}", " ", ""], props => `translate(${props.borderOffset}px, -${props.borderOffset}px)`, props => {
|
38
|
+
switch (props.size) {
|
39
|
+
case 'large':
|
40
|
+
case 'extralarge':
|
41
|
+
return css(["margin-left:", ";"], get('space.2'));
|
42
|
+
|
43
|
+
default:
|
44
|
+
return css(["margin-left:", ";"], get('space.1'));
|
45
|
+
}
|
46
|
+
}, get('colors.neutral.muted'), get('colors.neutral.subtle'), variants, sx);
|
38
47
|
|
39
48
|
const RemoveTokenButton = ({
|
40
49
|
'aria-label': ariaLabel,
|
@@ -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 {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@primer/components",
|
3
|
-
"version": "0.0.0-
|
3
|
+
"version": "0.0.0-2021927193941",
|
4
4
|
"description": "Primer react components",
|
5
5
|
"main": "lib/index.js",
|
6
6
|
"module": "lib-esm/index.js",
|
@@ -132,6 +132,7 @@
|
|
132
132
|
"rollup-plugin-visualizer": "5.5.0",
|
133
133
|
"semver": "7.3.5",
|
134
134
|
"size-limit": "5.0.2",
|
135
|
+
"storybook-addon-performance": "0.16.1",
|
135
136
|
"styled-components": "4.4.1",
|
136
137
|
"typescript": "4.2.2"
|
137
138
|
},
|