@spaced-out/ui-design-system 0.1.4 → 0.1.6

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,25 @@
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.6](https://github.com/spaced-out/ui-design-system/compare/v0.1.5...v0.1.6) (2023-04-05)
6
+
7
+
8
+ ### Features
9
+
10
+ * typeahead focus and loading states search input icon changes ([47363ef](https://github.com/spaced-out/ui-design-system/commit/47363efa8b7706f6cc166ffc2b617c796bd342e7))
11
+
12
+ ### [0.1.5](https://github.com/spaced-out/ui-design-system/compare/v0.1.4...v0.1.5) (2023-04-04)
13
+
14
+
15
+ ### Features
16
+
17
+ * in context aleart and banner focus states ([9d3144d](https://github.com/spaced-out/ui-design-system/commit/9d3144dad0cc32f21cfd1ed4284b6eb5da99e742))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * typeahead and dropdown fixes ([fa9d5ed](https://github.com/spaced-out/ui-design-system/commit/fa9d5ed1276fb3381fa71ac2f57c203ca9900dd8))
23
+
5
24
  ### [0.1.4](https://github.com/spaced-out/ui-design-system/compare/v0.1.3...v0.1.4) (2023-04-03)
6
25
 
7
26
 
@@ -27,10 +27,9 @@ const Dropdown = _ref => {
27
27
  menu,
28
28
  onMenuOpen,
29
29
  onMenuClose,
30
- dropdownInputText,
30
+ dropdownInputText = '',
31
31
  ...inputProps
32
32
  } = _ref;
33
- const [inputValue, setInputValue] = React.useState(dropdownInputText || '');
34
33
  const dropdownRef = React.useRef();
35
34
  const {
36
35
  x,
@@ -44,9 +43,6 @@ const Dropdown = _ref => {
44
43
  whileElementsMounted: _reactDom.autoUpdate,
45
44
  middleware: [(0, _reactDom.flip)(), (0, _reactDom.offset)(parseInt(_space.spaceXXSmall))]
46
45
  });
47
- React.useEffect(() => {
48
- setInputValue(dropdownInputText || '');
49
- }, [dropdownInputText]);
50
46
  const onMenuToggle = isOpen => {
51
47
  isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
52
48
  };
@@ -67,7 +63,7 @@ const Dropdown = _ref => {
67
63
  boxRef: reference,
68
64
  size: size,
69
65
  placeholder: placeholder,
70
- value: inputValue,
66
+ value: dropdownInputText,
71
67
  classNames: {
72
68
  box: _DropdownModule.default.inputBox
73
69
  }
@@ -45,10 +45,9 @@ export const Dropdown = ({
45
45
  menu,
46
46
  onMenuOpen,
47
47
  onMenuClose,
48
- dropdownInputText,
48
+ dropdownInputText = '',
49
49
  ...inputProps
50
50
  }: DropdownProps): React.Node => {
51
- const [inputValue, setInputValue] = React.useState(dropdownInputText || '');
52
51
  const dropdownRef = React.useRef();
53
52
  const {x, y, reference, floating, strategy} = useFloating({
54
53
  strategy: 'absolute',
@@ -57,10 +56,6 @@ export const Dropdown = ({
57
56
  middleware: [flip(), offset(parseInt(spaceXXSmall))],
58
57
  });
59
58
 
60
- React.useEffect(() => {
61
- setInputValue(dropdownInputText || '');
62
- }, [dropdownInputText]);
63
-
64
59
  const onMenuToggle = (isOpen: boolean) => {
65
60
  isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
66
61
  };
@@ -77,7 +72,7 @@ export const Dropdown = ({
77
72
  boxRef={reference}
78
73
  size={size}
79
74
  placeholder={placeholder}
80
- value={inputValue}
75
+ value={dropdownInputText}
81
76
  classNames={{box: css.inputBox}}
82
77
  {...inputProps}
83
78
  iconRightName={isOpen ? 'angle-up' : 'angle-down'}
@@ -8,6 +8,7 @@ var React = _interopRequireWildcard(require("react"));
8
8
  var _typography = require("../../types/typography");
9
9
  var _classify = require("../../utils/classify");
10
10
  var _Icon = require("../Icon");
11
+ var _Link = require("../Link");
11
12
  var _Text = require("../Text");
12
13
  var _Truncate = require("../Truncate");
13
14
  var _InContextAlertModule = _interopRequireDefault(require("./InContextAlert.module.css"));
@@ -110,10 +111,10 @@ const InContextAlert = props => {
110
111
  line: 2
111
112
  }, children)), !!(actionText || dismissable) && /*#__PURE__*/React.createElement("div", {
112
113
  className: (0, _classify.classify)(_InContextAlertModule.default.actionContainer, classNames?.actionContainer)
113
- }, !!actionText && /*#__PURE__*/React.createElement(_Text.ButtonTextExtraSmall, {
114
- className: _InContextAlertModule.default.actionText,
115
- onClick: onAction
116
- }, actionText), !!dismissable && /*#__PURE__*/React.createElement(_Icon.Icon, {
114
+ }, !!actionText && /*#__PURE__*/React.createElement(_Link.Link, {
115
+ onClick: onAction,
116
+ color: "primary"
117
+ }, actionText), !!dismissable && /*#__PURE__*/React.createElement(_Icon.ClickableIcon, {
117
118
  color: _typography.TEXT_COLORS.primary,
118
119
  name: "close",
119
120
  size: "small",
@@ -5,8 +5,9 @@ import * as React from 'react';
5
5
  import {TEXT_COLORS} from '../../types/typography';
6
6
  import {classify} from '../../utils/classify';
7
7
  import type {IconType} from '../Icon';
8
- import {Icon} from '../Icon';
9
- import {ButtonTextExtraSmall, SubTitleExtraSmall} from '../Text';
8
+ import {ClickableIcon, Icon} from '../Icon';
9
+ import {Link} from '../Link';
10
+ import {SubTitleExtraSmall} from '../Text';
10
11
  import {Truncate} from '../Truncate';
11
12
 
12
13
  import css from './InContextAlert.module.css';
@@ -172,15 +173,12 @@ export const InContextAlert = (props: InContextAlertProps): React.Node => {
172
173
  )}
173
174
  >
174
175
  {!!actionText && (
175
- <ButtonTextExtraSmall
176
- className={css.actionText}
177
- onClick={onAction}
178
- >
176
+ <Link onClick={onAction} color="primary">
179
177
  {actionText}
180
- </ButtonTextExtraSmall>
178
+ </Link>
181
179
  )}
182
180
  {!!dismissable && (
183
- <Icon
181
+ <ClickableIcon
184
182
  color={TEXT_COLORS.primary}
185
183
  name="close"
186
184
  size="small"
@@ -65,7 +65,6 @@
65
65
  }
66
66
 
67
67
  .closeIcon {
68
- cursor: pointer;
69
68
  margin-left: auto;
70
69
  }
71
70
 
@@ -75,9 +74,3 @@
75
74
  align-items: center;
76
75
  gap: spaceSmall;
77
76
  }
78
-
79
- .actionText {
80
- cursor: pointer;
81
- text-decoration: underline;
82
- white-space: nowrap;
83
- }
@@ -66,7 +66,7 @@ export type LinkProps = {
66
66
  underline?: boolean,
67
67
  target?: AnchorTarget,
68
68
  href?: string,
69
- onClick?: (SyntheticEvent<HTMLElement>) => mixed,
69
+ onClick?: ?(SyntheticEvent<HTMLElement>) => mixed,
70
70
  tabIndex?: number,
71
71
  disabled?: boolean,
72
72
  ...
@@ -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
+ }
@@ -29,11 +29,12 @@ const Typeahead = _ref => {
29
29
  menu,
30
30
  onMenuOpen,
31
31
  onMenuClose,
32
- typeaheadInputText,
32
+ typeaheadInputText = '',
33
+ isLoading,
34
+ menuOpenOffset = 1,
33
35
  ...inputProps
34
36
  } = _ref;
35
37
  const typeaheadRef = React.useRef();
36
- const [inputValue, setInputValue] = React.useState(typeaheadInputText || '');
37
38
  const [filteredOptions, setFilteredOptions] = React.useState(menu?.options);
38
39
  const {
39
40
  x,
@@ -47,28 +48,19 @@ const Typeahead = _ref => {
47
48
  whileElementsMounted: _reactDom.autoUpdate,
48
49
  middleware: [(0, _reactDom.flip)(), (0, _reactDom.offset)(parseInt(_space.spaceXXSmall))]
49
50
  });
50
- const handleSelect = option => {
51
- if (option?.key) {
52
- onSelect && onSelect(option);
53
- setInputValue(option.label);
54
- }
55
- };
56
- React.useEffect(() => {
57
- setInputValue(typeaheadInputText || '');
58
- }, [typeaheadInputText]);
59
51
  const onMenuToggle = isOpen => {
60
52
  isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
61
53
  };
62
54
  React.useEffect(() => {
63
55
  const optionsFiltered = menu?.options && menu.options.filter(option => {
64
- if (!option.label || !inputValue) {
56
+ if (!option.label || !typeaheadInputText) {
65
57
  return true;
66
58
  } else {
67
- return option.label.toLowerCase().indexOf(inputValue.toLowerCase()) !== -1;
59
+ return option.label.toLowerCase().indexOf(typeaheadInputText.toLowerCase()) !== -1;
68
60
  }
69
61
  });
70
62
  setFilteredOptions(optionsFiltered || []);
71
- }, [inputValue]);
63
+ }, [typeaheadInputText, menu?.options]);
72
64
  return /*#__PURE__*/React.createElement(_clickAway.ClickAway, {
73
65
  onChange: onMenuToggle
74
66
  }, _ref2 => {
@@ -81,31 +73,38 @@ const Typeahead = _ref => {
81
73
  return /*#__PURE__*/React.createElement("div", {
82
74
  "data-testid": "Typeahead",
83
75
  className: (0, _classify.classify)(_TypeaheadModule.default.typeaheadContainer, classNames?.wrapper),
84
- ref: typeaheadRef
76
+ ref: typeaheadRef,
77
+ onClickCapture: cancelNext
85
78
  }, /*#__PURE__*/React.createElement(_SearchInput.SearchInput, _extends({
86
79
  boxRef: reference,
87
80
  size: size,
88
81
  placeholder: placeholder,
89
- value: inputValue,
82
+ value: typeaheadInputText,
90
83
  classNames: {
91
84
  box: classNames?.box
92
- }
85
+ },
86
+ isLoading: isLoading
93
87
  }, inputProps, {
94
88
  onChange: e => {
95
89
  e.stopPropagation();
96
- setInputValue(e.target.value);
97
90
  onSearch && onSearch(e);
98
- 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) {
99
99
  onOpen();
100
100
  } else {
101
101
  clickAway();
102
102
  }
103
103
  },
104
104
  onClear: _e => {
105
- setInputValue('');
106
105
  onClear?.();
107
106
  }
108
- })), isOpen && menu && filteredOptions && !!filteredOptions.length && /*#__PURE__*/React.createElement("div", {
107
+ })), isOpen && !isLoading && menu && filteredOptions && !!filteredOptions.length && /*#__PURE__*/React.createElement("div", {
109
108
  onClickCapture: cancelNext,
110
109
  ref: floating,
111
110
  style: {
@@ -118,7 +117,7 @@ const Typeahead = _ref => {
118
117
  }, /*#__PURE__*/React.createElement(_Menu.Menu, _extends({}, menu, {
119
118
  options: filteredOptions,
120
119
  onSelect: option => {
121
- handleSelect(option);
120
+ onSelect && onSelect(option);
122
121
  if (!menu.optionsVariant || menu.optionsVariant === 'normal') {
123
122
  clickAway();
124
123
  }
@@ -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 = ({
@@ -49,12 +51,12 @@ export const Typeahead = ({
49
51
  menu,
50
52
  onMenuOpen,
51
53
  onMenuClose,
52
- typeaheadInputText,
54
+ typeaheadInputText = '',
55
+ isLoading,
56
+ menuOpenOffset = 1,
53
57
  ...inputProps
54
58
  }: TypeaheadProps): React.Node => {
55
59
  const typeaheadRef = React.useRef();
56
-
57
- const [inputValue, setInputValue] = React.useState(typeaheadInputText || '');
58
60
  const [filteredOptions, setFilteredOptions] = React.useState(menu?.options);
59
61
 
60
62
  const {x, y, reference, floating, strategy} = useFloating({
@@ -64,17 +66,6 @@ export const Typeahead = ({
64
66
  middleware: [flip(), offset(parseInt(spaceXXSmall))],
65
67
  });
66
68
 
67
- const handleSelect = (option?: MenuOption) => {
68
- if (option?.key) {
69
- onSelect && onSelect(option);
70
- setInputValue(option.label);
71
- }
72
- };
73
-
74
- React.useEffect(() => {
75
- setInputValue(typeaheadInputText || '');
76
- }, [typeaheadInputText]);
77
-
78
69
  const onMenuToggle = (isOpen: boolean) => {
79
70
  isOpen ? onMenuOpen && onMenuOpen() : onMenuClose && onMenuClose();
80
71
  };
@@ -83,16 +74,18 @@ export const Typeahead = ({
83
74
  const optionsFiltered =
84
75
  menu?.options &&
85
76
  menu.options.filter((option) => {
86
- if (!option.label || !inputValue) {
77
+ if (!option.label || !typeaheadInputText) {
87
78
  return true;
88
79
  } else {
89
80
  return (
90
- option.label.toLowerCase().indexOf(inputValue.toLowerCase()) !== -1
81
+ option.label
82
+ .toLowerCase()
83
+ .indexOf(typeaheadInputText.toLowerCase()) !== -1
91
84
  );
92
85
  }
93
86
  });
94
87
  setFilteredOptions(optionsFiltered || []);
95
- }, [inputValue]);
88
+ }, [typeaheadInputText, menu?.options]);
96
89
 
97
90
  return (
98
91
  <ClickAway onChange={onMenuToggle}>
@@ -101,31 +94,41 @@ export const Typeahead = ({
101
94
  data-testid="Typeahead"
102
95
  className={classify(css.typeaheadContainer, classNames?.wrapper)}
103
96
  ref={typeaheadRef}
97
+ onClickCapture={cancelNext}
104
98
  >
105
99
  <SearchInput
106
100
  boxRef={reference}
107
101
  size={size}
108
102
  placeholder={placeholder}
109
- value={inputValue}
103
+ value={typeaheadInputText}
110
104
  classNames={{box: classNames?.box}}
105
+ isLoading={isLoading}
111
106
  {...inputProps}
112
107
  onChange={(e) => {
113
108
  e.stopPropagation();
114
- setInputValue(e.target.value);
115
109
  onSearch && onSearch(e);
116
- 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) {
117
118
  onOpen();
118
119
  } else {
119
120
  clickAway();
120
121
  }
121
122
  }}
122
123
  onClear={(_e) => {
123
- setInputValue('');
124
124
  onClear?.();
125
125
  }}
126
126
  />
127
-
128
- {isOpen && menu && filteredOptions && !!filteredOptions.length && (
127
+ {isOpen &&
128
+ !isLoading &&
129
+ menu &&
130
+ filteredOptions &&
131
+ !!filteredOptions.length && (
129
132
  <div
130
133
  onClickCapture={cancelNext}
131
134
  ref={floating}
@@ -141,10 +144,10 @@ export const Typeahead = ({
141
144
  {...menu}
142
145
  options={filteredOptions}
143
146
  onSelect={(option) => {
144
- handleSelect(option);
147
+ onSelect && onSelect(option);
145
148
  if (
146
149
  !menu.optionsVariant ||
147
- menu.optionsVariant === 'normal'
150
+ menu.optionsVariant === 'normal'
148
151
  ) {
149
152
  clickAway();
150
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.4",
3
+ "version": "0.1.6",
4
4
  "main": "index.js",
5
5
  "description": "Sense UI components library",
6
6
  "author": {