@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 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', 'modal-root');
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(document.getElementById('modal-root') || createPortalRoot());
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', 'modal-root');
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
- document.getElementById('modal-root') || createPortalRoot(),
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(_Input.Input, _extends({
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: "magnifying-glass",
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<{box?: string, iconLeft?: string}>;
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
- <Input
34
- type="text"
35
- {...searchInputProps}
36
- classNames={{
37
- ...classNames,
38
- iconRight: value && !(disabled || locked) ? css.clickable : '',
39
- iconLeft: value && !disabled ? css.primaryText : '',
40
- }}
41
- placeholder={placeholder}
42
- value={value}
43
- disabled={disabled}
44
- locked={locked}
45
- iconLeftName="magnifying-glass"
46
- iconRightName={value && !(disabled || locked) ? 'xmark' : 'fw'}
47
- onIconRightClick={handleClearClick}
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 > 0) {
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 > 0) {
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
- {isOpen && menu && filteredOptions && !!filteredOptions.length && (
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
- menu.optionsVariant === 'normal'
150
+ menu.optionsVariant === 'normal'
135
151
  ) {
136
152
  clickAway();
137
153
  }
@@ -7,4 +7,5 @@
7
7
  position: relative;
8
8
  flex-flow: column;
9
9
  width: sizeFluid;
10
+ height: fit-content;
10
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaced-out/ui-design-system",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "main": "index.js",
5
5
  "description": "Sense UI components library",
6
6
  "author": {