@spaced-out/ui-design-system 0.1.5 → 0.1.7
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 +15 -0
- package/lib/components/Modal/Modal.js +6 -3
- package/lib/components/Modal/Modal.js.flow +8 -3
- package/lib/components/SearchInput/SearchInput.js +20 -5
- package/lib/components/SearchInput/SearchInput.js.flow +39 -17
- package/lib/components/SearchInput/SearchInput.module.css +33 -0
- package/lib/components/Typeahead/Typeahead.js +16 -5
- package/lib/components/Typeahead/Typeahead.js.flow +21 -5
- package/lib/components/Typeahead/Typeahead.module.css +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
### [0.1.7](https://github.com/spaced-out/ui-design-system/compare/v0.1.6...v0.1.7) (2023-04-05)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* added documentation for link ([b233ce2](https://github.com/spaced-out/ui-design-system/commit/b233ce236a2ef4d8297bf4a333cf280d24fb6c87))
|
|
11
|
+
* modal fix ([a8bcb31](https://github.com/spaced-out/ui-design-system/commit/a8bcb318f23006c502f74b569fa268c44856bb9c))
|
|
12
|
+
|
|
13
|
+
### [0.1.6](https://github.com/spaced-out/ui-design-system/compare/v0.1.5...v0.1.6) (2023-04-05)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* typeahead focus and loading states search input icon changes ([47363ef](https://github.com/spaced-out/ui-design-system/commit/47363efa8b7706f6cc166ffc2b617c796bd342e7))
|
|
19
|
+
|
|
5
20
|
### [0.1.5](https://github.com/spaced-out/ui-design-system/compare/v0.1.4...v0.1.5) (2023-04-04)
|
|
6
21
|
|
|
7
22
|
|
|
@@ -10,6 +10,7 @@ var _reactDomInteractions = require("@floating-ui/react-dom-interactions");
|
|
|
10
10
|
var _useMountTransition = _interopRequireDefault(require("../../hooks/useMountTransition"));
|
|
11
11
|
var _motion = require("../../styles/variables/_motion");
|
|
12
12
|
var _classify = _interopRequireDefault(require("../../utils/classify"));
|
|
13
|
+
var _helpers = require("../../utils/helpers");
|
|
13
14
|
var _Button = require("../Button/Button");
|
|
14
15
|
var _Truncate = require("../Truncate/Truncate");
|
|
15
16
|
var _ModalModule = _interopRequireDefault(require("./Modal.module.css"));
|
|
@@ -60,11 +61,12 @@ const ModalFooter = _ref3 => {
|
|
|
60
61
|
}, children)));
|
|
61
62
|
};
|
|
62
63
|
exports.ModalFooter = ModalFooter;
|
|
63
|
-
const createPortalRoot =
|
|
64
|
+
const createPortalRoot = id => {
|
|
64
65
|
const modalRoot = document.createElement('div');
|
|
65
|
-
modalRoot.setAttribute('id',
|
|
66
|
+
modalRoot.setAttribute('id', `modal-root-${id}`);
|
|
66
67
|
return modalRoot;
|
|
67
68
|
};
|
|
69
|
+
const getModalRoot = id => document.getElementById(`modal-root-${id}`);
|
|
68
70
|
const Modal = _ref4 => {
|
|
69
71
|
let {
|
|
70
72
|
classNames,
|
|
@@ -80,8 +82,9 @@ const Modal = _ref4 => {
|
|
|
80
82
|
floating,
|
|
81
83
|
context
|
|
82
84
|
} = (0, _reactDomInteractions.useFloating)();
|
|
85
|
+
const modalId = (0, _helpers.uuid)();
|
|
83
86
|
const bodyRef = React.useRef(document.querySelector('body'));
|
|
84
|
-
const portalRootRef = React.useRef(
|
|
87
|
+
const portalRootRef = React.useRef(getModalRoot(modalId) || createPortalRoot(modalId));
|
|
85
88
|
const isTransitioning = (0, _useMountTransition.default)(isOpen, parseInt(_motion.motionDurationNormal));
|
|
86
89
|
|
|
87
90
|
// Append portal root on mount
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import useMountTransition from '../../hooks/useMountTransition';
|
|
14
14
|
import {motionDurationNormal} from '../../styles/variables/_motion';
|
|
15
15
|
import classify from '../../utils/classify';
|
|
16
|
+
import {uuid} from '../../utils/helpers';
|
|
16
17
|
import {Button} from '../Button/Button';
|
|
17
18
|
import {Truncate} from '../Truncate/Truncate';
|
|
18
19
|
|
|
@@ -105,13 +106,16 @@ export const ModalFooter = ({
|
|
|
105
106
|
</>
|
|
106
107
|
);
|
|
107
108
|
|
|
108
|
-
const createPortalRoot = () => {
|
|
109
|
+
const createPortalRoot = (id: string) => {
|
|
109
110
|
const modalRoot = document.createElement('div');
|
|
110
|
-
modalRoot.setAttribute('id',
|
|
111
|
+
modalRoot.setAttribute('id', `modal-root-${id}`);
|
|
111
112
|
|
|
112
113
|
return modalRoot;
|
|
113
114
|
};
|
|
114
115
|
|
|
116
|
+
const getModalRoot = (id: string) =>
|
|
117
|
+
document.getElementById(`modal-root-${id}`);
|
|
118
|
+
|
|
115
119
|
export const Modal = ({
|
|
116
120
|
classNames,
|
|
117
121
|
children,
|
|
@@ -123,10 +127,11 @@ export const Modal = ({
|
|
|
123
127
|
initialFocus = -1,
|
|
124
128
|
}: ModalProps): React.Node => {
|
|
125
129
|
const {floating, context} = useFloating();
|
|
130
|
+
const modalId = uuid();
|
|
126
131
|
|
|
127
132
|
const bodyRef = React.useRef(document.querySelector('body'));
|
|
128
133
|
const portalRootRef = React.useRef(
|
|
129
|
-
|
|
134
|
+
getModalRoot(modalId) || createPortalRoot(modalId),
|
|
130
135
|
);
|
|
131
136
|
|
|
132
137
|
const isTransitioning = useMountTransition(
|
|
@@ -5,6 +5,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.SearchInput = void 0;
|
|
7
7
|
var React = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _classify = _interopRequireDefault(require("../../utils/classify"));
|
|
9
|
+
var _CircularLoader = require("../CircularLoader");
|
|
8
10
|
var _Input = require("../Input");
|
|
9
11
|
var _SearchInputModule = _interopRequireDefault(require("./SearchInput.module.css"));
|
|
10
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -19,26 +21,39 @@ const SearchInput = _ref => {
|
|
|
19
21
|
placeholder = 'Search...',
|
|
20
22
|
classNames,
|
|
21
23
|
onClear,
|
|
24
|
+
isLoading,
|
|
25
|
+
size,
|
|
26
|
+
iconLeftName = 'magnifying-glass',
|
|
22
27
|
...searchInputProps
|
|
23
28
|
} = _ref;
|
|
24
29
|
const handleClearClick = () => {
|
|
25
30
|
onClear?.();
|
|
26
31
|
};
|
|
27
|
-
return /*#__PURE__*/React.createElement(
|
|
32
|
+
return /*#__PURE__*/React.createElement("div", {
|
|
33
|
+
className: (0, _classify.default)(_SearchInputModule.default.searchInputWrapper, classNames?.wrapper)
|
|
34
|
+
}, /*#__PURE__*/React.createElement(_Input.Input, _extends({
|
|
28
35
|
type: "text"
|
|
29
36
|
}, searchInputProps, {
|
|
30
37
|
classNames: {
|
|
31
|
-
...classNames,
|
|
32
38
|
iconRight: value && !(disabled || locked) ? _SearchInputModule.default.clickable : '',
|
|
33
|
-
iconLeft: value && !disabled ? _SearchInputModule.default.primaryText : ''
|
|
39
|
+
iconLeft: value && !disabled ? _SearchInputModule.default.primaryText : '',
|
|
40
|
+
box: classNames?.box
|
|
34
41
|
},
|
|
35
42
|
placeholder: placeholder,
|
|
36
43
|
value: value,
|
|
37
44
|
disabled: disabled,
|
|
38
45
|
locked: locked,
|
|
39
|
-
iconLeftName:
|
|
46
|
+
iconLeftName: iconLeftName,
|
|
47
|
+
size: size,
|
|
40
48
|
iconRightName: value && !(disabled || locked) ? 'xmark' : 'fw',
|
|
41
49
|
onIconRightClick: handleClearClick
|
|
42
|
-
}))
|
|
50
|
+
})), isLoading && /*#__PURE__*/React.createElement("div", {
|
|
51
|
+
className: (0, _classify.default)(_SearchInputModule.default.loaderContainer, {
|
|
52
|
+
[_SearchInputModule.default.small]: size === 'small'
|
|
53
|
+
})
|
|
54
|
+
}, /*#__PURE__*/React.createElement(_CircularLoader.CircularLoader, {
|
|
55
|
+
colorToken: "colorFillPrimary",
|
|
56
|
+
size: size
|
|
57
|
+
})));
|
|
43
58
|
};
|
|
44
59
|
exports.SearchInput = SearchInput;
|
|
@@ -2,18 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
|
|
5
|
+
import classify from '../../utils/classify';
|
|
6
|
+
import {CircularLoader} from '../CircularLoader';
|
|
5
7
|
import type {InputProps} from '../Input';
|
|
6
8
|
import {Input} from '../Input';
|
|
7
9
|
|
|
8
10
|
import css from './SearchInput.module.css';
|
|
9
11
|
|
|
10
12
|
|
|
11
|
-
type ClassNames = $ReadOnly<{
|
|
13
|
+
type ClassNames = $ReadOnly<{
|
|
14
|
+
wrapper?: string,
|
|
15
|
+
box?: string,
|
|
16
|
+
iconLeft?: string,
|
|
17
|
+
}>;
|
|
12
18
|
|
|
13
19
|
export type SearchInputProps = {
|
|
14
20
|
...InputProps,
|
|
15
21
|
classNames?: ClassNames,
|
|
16
22
|
onClear?: () => void,
|
|
23
|
+
isLoading?: boolean,
|
|
17
24
|
};
|
|
18
25
|
|
|
19
26
|
export const SearchInput = ({
|
|
@@ -23,6 +30,9 @@ export const SearchInput = ({
|
|
|
23
30
|
placeholder = 'Search...',
|
|
24
31
|
classNames,
|
|
25
32
|
onClear,
|
|
33
|
+
isLoading,
|
|
34
|
+
size,
|
|
35
|
+
iconLeftName = 'magnifying-glass',
|
|
26
36
|
...searchInputProps
|
|
27
37
|
}: SearchInputProps): React.Node => {
|
|
28
38
|
const handleClearClick = () => {
|
|
@@ -30,21 +40,33 @@ export const SearchInput = ({
|
|
|
30
40
|
};
|
|
31
41
|
|
|
32
42
|
return (
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
43
|
+
<div className={classify(css.searchInputWrapper, classNames?.wrapper)}>
|
|
44
|
+
<Input
|
|
45
|
+
type="text"
|
|
46
|
+
{...searchInputProps}
|
|
47
|
+
classNames={{
|
|
48
|
+
iconRight: value && !(disabled || locked) ? css.clickable : '',
|
|
49
|
+
iconLeft: value && !disabled ? css.primaryText : '',
|
|
50
|
+
box: classNames?.box,
|
|
51
|
+
}}
|
|
52
|
+
placeholder={placeholder}
|
|
53
|
+
value={value}
|
|
54
|
+
disabled={disabled}
|
|
55
|
+
locked={locked}
|
|
56
|
+
iconLeftName={iconLeftName}
|
|
57
|
+
size={size}
|
|
58
|
+
iconRightName={value && !(disabled || locked) ? 'xmark' : 'fw'}
|
|
59
|
+
onIconRightClick={handleClearClick}
|
|
60
|
+
/>
|
|
61
|
+
{isLoading && (
|
|
62
|
+
<div
|
|
63
|
+
className={classify(css.loaderContainer, {
|
|
64
|
+
[css.small]: size === 'small',
|
|
65
|
+
})}
|
|
66
|
+
>
|
|
67
|
+
<CircularLoader colorToken="colorFillPrimary" size={size} />
|
|
68
|
+
</div>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
49
71
|
);
|
|
50
72
|
};
|
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
colorTextPrimary
|
|
3
3
|
) from '../../styles/variables/_color.css';
|
|
4
4
|
|
|
5
|
+
@value (
|
|
6
|
+
size42,
|
|
7
|
+
size34
|
|
8
|
+
) from '../../styles/variables/_size.css';
|
|
9
|
+
|
|
10
|
+
@value (
|
|
11
|
+
spaceXXSmall
|
|
12
|
+
) from '../../styles/variables/_space.css';
|
|
13
|
+
|
|
14
|
+
.searchInputWrapper {
|
|
15
|
+
display: flex;
|
|
16
|
+
position: relative;
|
|
17
|
+
align-items: end;
|
|
18
|
+
gap: spaceXXSmall;
|
|
19
|
+
height: fit-content;
|
|
20
|
+
}
|
|
21
|
+
|
|
5
22
|
.clickable {
|
|
6
23
|
cursor: pointer;
|
|
7
24
|
}
|
|
@@ -9,3 +26,19 @@
|
|
|
9
26
|
.primaryText {
|
|
10
27
|
color: colorTextPrimary;
|
|
11
28
|
}
|
|
29
|
+
|
|
30
|
+
.loaderContainer {
|
|
31
|
+
display: flex;
|
|
32
|
+
height: size42;
|
|
33
|
+
width: size42;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
align-items: center;
|
|
37
|
+
margin-right: calc((size42 * -1) - spaceXXSmall);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.loaderContainer.small {
|
|
41
|
+
height: size34;
|
|
42
|
+
width: size34;
|
|
43
|
+
margin-right: calc((size34 * -1) - spaceXXSmall);
|
|
44
|
+
}
|
|
@@ -30,6 +30,8 @@ const Typeahead = _ref => {
|
|
|
30
30
|
onMenuOpen,
|
|
31
31
|
onMenuClose,
|
|
32
32
|
typeaheadInputText = '',
|
|
33
|
+
isLoading,
|
|
34
|
+
menuOpenOffset = 1,
|
|
33
35
|
...inputProps
|
|
34
36
|
} = _ref;
|
|
35
37
|
const typeaheadRef = React.useRef();
|
|
@@ -58,7 +60,7 @@ const Typeahead = _ref => {
|
|
|
58
60
|
}
|
|
59
61
|
});
|
|
60
62
|
setFilteredOptions(optionsFiltered || []);
|
|
61
|
-
}, [typeaheadInputText]);
|
|
63
|
+
}, [typeaheadInputText, menu?.options]);
|
|
62
64
|
return /*#__PURE__*/React.createElement(_clickAway.ClickAway, {
|
|
63
65
|
onChange: onMenuToggle
|
|
64
66
|
}, _ref2 => {
|
|
@@ -71,7 +73,8 @@ const Typeahead = _ref => {
|
|
|
71
73
|
return /*#__PURE__*/React.createElement("div", {
|
|
72
74
|
"data-testid": "Typeahead",
|
|
73
75
|
className: (0, _classify.classify)(_TypeaheadModule.default.typeaheadContainer, classNames?.wrapper),
|
|
74
|
-
ref: typeaheadRef
|
|
76
|
+
ref: typeaheadRef,
|
|
77
|
+
onClickCapture: cancelNext
|
|
75
78
|
}, /*#__PURE__*/React.createElement(_SearchInput.SearchInput, _extends({
|
|
76
79
|
boxRef: reference,
|
|
77
80
|
size: size,
|
|
@@ -79,12 +82,20 @@ const Typeahead = _ref => {
|
|
|
79
82
|
value: typeaheadInputText,
|
|
80
83
|
classNames: {
|
|
81
84
|
box: classNames?.box
|
|
82
|
-
}
|
|
85
|
+
},
|
|
86
|
+
isLoading: isLoading
|
|
83
87
|
}, inputProps, {
|
|
84
88
|
onChange: e => {
|
|
85
89
|
e.stopPropagation();
|
|
86
90
|
onSearch && onSearch(e);
|
|
87
|
-
if (e.target.value.length
|
|
91
|
+
if (e.target.value.length >= menuOpenOffset) {
|
|
92
|
+
onOpen();
|
|
93
|
+
} else {
|
|
94
|
+
clickAway();
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
onFocus: _e => {
|
|
98
|
+
if (typeaheadInputText.length >= menuOpenOffset) {
|
|
88
99
|
onOpen();
|
|
89
100
|
} else {
|
|
90
101
|
clickAway();
|
|
@@ -93,7 +104,7 @@ const Typeahead = _ref => {
|
|
|
93
104
|
onClear: _e => {
|
|
94
105
|
onClear?.();
|
|
95
106
|
}
|
|
96
|
-
})), isOpen && menu && filteredOptions && !!filteredOptions.length && /*#__PURE__*/React.createElement("div", {
|
|
107
|
+
})), isOpen && !isLoading && menu && filteredOptions && !!filteredOptions.length && /*#__PURE__*/React.createElement("div", {
|
|
97
108
|
onClickCapture: cancelNext,
|
|
98
109
|
ref: floating,
|
|
99
110
|
style: {
|
|
@@ -37,6 +37,8 @@ export type TypeaheadProps = {
|
|
|
37
37
|
typeaheadInputText?: string,
|
|
38
38
|
menu?: MenuProps,
|
|
39
39
|
onClear?: () => void,
|
|
40
|
+
isLoading?: boolean,
|
|
41
|
+
menuOpenOffset?: number,
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
export const Typeahead = ({
|
|
@@ -50,6 +52,8 @@ export const Typeahead = ({
|
|
|
50
52
|
onMenuOpen,
|
|
51
53
|
onMenuClose,
|
|
52
54
|
typeaheadInputText = '',
|
|
55
|
+
isLoading,
|
|
56
|
+
menuOpenOffset = 1,
|
|
53
57
|
...inputProps
|
|
54
58
|
}: TypeaheadProps): React.Node => {
|
|
55
59
|
const typeaheadRef = React.useRef();
|
|
@@ -81,7 +85,7 @@ export const Typeahead = ({
|
|
|
81
85
|
}
|
|
82
86
|
});
|
|
83
87
|
setFilteredOptions(optionsFiltered || []);
|
|
84
|
-
}, [typeaheadInputText]);
|
|
88
|
+
}, [typeaheadInputText, menu?.options]);
|
|
85
89
|
|
|
86
90
|
return (
|
|
87
91
|
<ClickAway onChange={onMenuToggle}>
|
|
@@ -90,6 +94,7 @@ export const Typeahead = ({
|
|
|
90
94
|
data-testid="Typeahead"
|
|
91
95
|
className={classify(css.typeaheadContainer, classNames?.wrapper)}
|
|
92
96
|
ref={typeaheadRef}
|
|
97
|
+
onClickCapture={cancelNext}
|
|
93
98
|
>
|
|
94
99
|
<SearchInput
|
|
95
100
|
boxRef={reference}
|
|
@@ -97,11 +102,19 @@ export const Typeahead = ({
|
|
|
97
102
|
placeholder={placeholder}
|
|
98
103
|
value={typeaheadInputText}
|
|
99
104
|
classNames={{box: classNames?.box}}
|
|
105
|
+
isLoading={isLoading}
|
|
100
106
|
{...inputProps}
|
|
101
107
|
onChange={(e) => {
|
|
102
108
|
e.stopPropagation();
|
|
103
109
|
onSearch && onSearch(e);
|
|
104
|
-
if (e.target.value.length
|
|
110
|
+
if (e.target.value.length >= menuOpenOffset) {
|
|
111
|
+
onOpen();
|
|
112
|
+
} else {
|
|
113
|
+
clickAway();
|
|
114
|
+
}
|
|
115
|
+
}}
|
|
116
|
+
onFocus={(_e) => {
|
|
117
|
+
if (typeaheadInputText.length >= menuOpenOffset) {
|
|
105
118
|
onOpen();
|
|
106
119
|
} else {
|
|
107
120
|
clickAway();
|
|
@@ -111,8 +124,11 @@ export const Typeahead = ({
|
|
|
111
124
|
onClear?.();
|
|
112
125
|
}}
|
|
113
126
|
/>
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
{isOpen &&
|
|
128
|
+
!isLoading &&
|
|
129
|
+
menu &&
|
|
130
|
+
filteredOptions &&
|
|
131
|
+
!!filteredOptions.length && (
|
|
116
132
|
<div
|
|
117
133
|
onClickCapture={cancelNext}
|
|
118
134
|
ref={floating}
|
|
@@ -131,7 +147,7 @@ export const Typeahead = ({
|
|
|
131
147
|
onSelect && onSelect(option);
|
|
132
148
|
if (
|
|
133
149
|
!menu.optionsVariant ||
|
|
134
|
-
|
|
150
|
+
menu.optionsVariant === 'normal'
|
|
135
151
|
) {
|
|
136
152
|
clickAway();
|
|
137
153
|
}
|