@spaced-out/ui-design-system 0.1.116 → 0.1.118

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,20 @@
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.118](https://github.com/spaced-out/ui-design-system/compare/v0.1.117...v0.1.118) (2024-08-05)
6
+
7
+
8
+ ### Features
9
+
10
+ * 🍪 chip enhancements ([#250](https://github.com/spaced-out/ui-design-system/issues/250)) ([a18fae8](https://github.com/spaced-out/ui-design-system/commit/a18fae893703092d6221f09043e62cc86308ae67))
11
+
12
+ ### [0.1.117](https://github.com/spaced-out/ui-design-system/compare/v0.1.116...v0.1.117) (2024-07-30)
13
+
14
+
15
+ ### Features
16
+
17
+ * wrapAfter prop in button tabs ([#248](https://github.com/spaced-out/ui-design-system/issues/248)) ([af99d41](https://github.com/spaced-out/ui-design-system/commit/af99d41270ae97e92d3a0e0e0bf07c1a02af0b33))
18
+
5
19
  ### [0.1.116](https://github.com/spaced-out/ui-design-system/compare/v0.1.115...v0.1.116) (2024-07-25)
6
20
 
7
21
 
@@ -15,7 +15,7 @@ export type ButtonTabProps = {
15
15
  classNames?: ClassNames,
16
16
  children?: React.Node,
17
17
  disabled?: boolean,
18
- onButtonTabSelect?: ?(id: string, e?: SyntheticEvent<HTMLElement>) => mixed,
18
+ onButtonTabSelect?: ?(id: string, e?: ?SyntheticEvent<HTMLElement>) => mixed,
19
19
  iconName?: string,
20
20
  iconType?: IconType,
21
21
  size?: 'medium' | 'small',
@@ -66,8 +66,9 @@
66
66
  .buttonTabWrapper.isSelected {
67
67
  background-color: colorFillSecondary;
68
68
  color: colorTextPrimary;
69
- border-width: borderWidthPrimary borderWidthPrimary borderWidthPrimary
70
- borderWidthNone;
69
+ border-top-width: borderWidthPrimary;
70
+ border-right-width: borderWidthPrimary;
71
+ border-bottom-width: borderWidthPrimary;
71
72
  border-style: solid;
72
73
  border-color: colorBorderPrimary;
73
74
  }
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ButtonTabDropdown = void 0;
7
+ var React = _interopRequireWildcard(require("react"));
8
+ var _react2 = require("@floating-ui/react");
9
+ var _lodash = require("lodash");
10
+ var _space = require("../../styles/variables/_space");
11
+ var _clickAway = require("../../utils/click-away");
12
+ var _Menu = require("../Menu");
13
+ var _ButtonTab = require("./ButtonTab");
14
+ 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); }
15
+ 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; }
16
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : 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); }
17
+ const ButtonTabDropdown = _ref => {
18
+ let {
19
+ title,
20
+ anchorPosition = 'bottom-end',
21
+ ...buttonTabProps
22
+ } = _ref;
23
+ const menuBtnRef = React.useRef();
24
+ const {
25
+ size,
26
+ children,
27
+ selectedButtonTabId,
28
+ onButtonTabSelect: onTabSelect
29
+ } = buttonTabProps;
30
+ const childrenArray = React.Children.toArray(children);
31
+ const menuOptions = childrenArray.map(child => {
32
+ const {
33
+ id,
34
+ children,
35
+ disabled,
36
+ iconName,
37
+ iconType,
38
+ classNames,
39
+ size: buttonSize
40
+ } = child.props;
41
+ return {
42
+ key: id,
43
+ disabled,
44
+ classNames,
45
+ label: children,
46
+ iconLeft: iconName,
47
+ iconLeftType: iconType,
48
+ customComponent: children,
49
+ optionSize: buttonSize ?? size
50
+ };
51
+ });
52
+ const moreTabSelectedId = (0, _lodash.includes)(menuOptions.map(_ref2 => {
53
+ let {
54
+ key
55
+ } = _ref2;
56
+ return key;
57
+ }), selectedButtonTabId) ? 'more-tab' : selectedButtonTabId;
58
+ const {
59
+ x,
60
+ y,
61
+ refs,
62
+ strategy
63
+ } = (0, _react2.useFloating)({
64
+ open: true,
65
+ strategy: 'absolute',
66
+ placement: anchorPosition,
67
+ whileElementsMounted: _react2.autoUpdate,
68
+ middleware: [(0, _react2.shift)(), (0, _react2.flip)(), (0, _react2.offset)(parseInt(_space.spaceXXSmall))]
69
+ });
70
+ return /*#__PURE__*/React.createElement(_clickAway.ClickAway, null, _ref3 => {
71
+ let {
72
+ isOpen,
73
+ onOpen,
74
+ cancelNext,
75
+ clickAway
76
+ } = _ref3;
77
+ return /*#__PURE__*/React.createElement("div", {
78
+ "data-testid": "ButtonTabDropdown",
79
+ ref: menuBtnRef
80
+ }, /*#__PURE__*/React.createElement(_ButtonTab.ButtonTab, _extends({}, buttonTabProps, {
81
+ ref: refs.setReference,
82
+ selectedButtonTabId: moreTabSelectedId,
83
+ onButtonTabSelect: (id, e) => {
84
+ e?.stopPropagation();
85
+ onOpen();
86
+ }
87
+ }), title), isOpen && /*#__PURE__*/React.createElement("div", {
88
+ onClickCapture: cancelNext,
89
+ ref: refs.setFloating,
90
+ style: {
91
+ display: 'flex',
92
+ position: strategy,
93
+ top: y ?? _space.spaceNone,
94
+ left: x ?? _space.spaceNone
95
+ }
96
+ }, /*#__PURE__*/React.createElement(_Menu.Menu, {
97
+ onSelect: (option, e) => {
98
+ onTabSelect && onTabSelect(option.key, e);
99
+ clickAway();
100
+ },
101
+ size: size,
102
+ options: menuOptions,
103
+ onTabOut: clickAway,
104
+ selectedKeys: [selectedButtonTabId ?? '']
105
+ })));
106
+ });
107
+ };
108
+ exports.ButtonTabDropdown = ButtonTabDropdown;
@@ -0,0 +1,125 @@
1
+ // @flow strict
2
+
3
+ import * as React from 'react';
4
+ import {
5
+ // $FlowFixMe[untyped-import]
6
+ autoUpdate,
7
+ // $FlowFixMe[untyped-import]
8
+ flip,
9
+ // $FlowFixMe[untyped-import]
10
+ offset,
11
+ // $FlowFixMe[untyped-import]
12
+ shift,
13
+ // $FlowFixMe[untyped-import]
14
+ useFloating,
15
+ } from '@floating-ui/react';
16
+ import {includes} from 'lodash';
17
+
18
+ import {spaceNone, spaceXXSmall} from '../../styles/variables/_space';
19
+ import {ClickAway} from '../../utils/click-away';
20
+ import type {AnchorType} from '../ButtonDropdown';
21
+ import {Menu} from '../Menu';
22
+
23
+ import type {ButtonTabProps} from './ButtonTab';
24
+ import {ButtonTab} from './ButtonTab';
25
+
26
+
27
+ export type ButtonTabDropdownProps = {
28
+ ...ButtonTabProps,
29
+ title: string,
30
+ anchorPosition?: AnchorType,
31
+ ...
32
+ };
33
+
34
+ export const ButtonTabDropdown = ({
35
+ title,
36
+ anchorPosition = 'bottom-end',
37
+ ...buttonTabProps
38
+ }: ButtonTabDropdownProps): React.Node => {
39
+ const menuBtnRef = React.useRef();
40
+ const {
41
+ size,
42
+ children,
43
+ selectedButtonTabId,
44
+ onButtonTabSelect: onTabSelect,
45
+ } = buttonTabProps;
46
+ const childrenArray = React.Children.toArray(children);
47
+ const menuOptions = childrenArray.map((child) => {
48
+ const {
49
+ id,
50
+ children,
51
+ disabled,
52
+ iconName,
53
+ iconType,
54
+ classNames,
55
+ size: buttonSize,
56
+ } = child.props;
57
+ return {
58
+ key: id,
59
+ disabled,
60
+ classNames,
61
+ label: children,
62
+ iconLeft: iconName,
63
+ iconLeftType: iconType,
64
+ customComponent: children,
65
+ optionSize: buttonSize ?? size,
66
+ };
67
+ });
68
+ const moreTabSelectedId = includes(
69
+ menuOptions.map(({key}) => key),
70
+ selectedButtonTabId,
71
+ )
72
+ ? 'more-tab'
73
+ : selectedButtonTabId;
74
+
75
+ const {x, y, refs, strategy} = useFloating({
76
+ open: true,
77
+ strategy: 'absolute',
78
+ placement: anchorPosition,
79
+ whileElementsMounted: autoUpdate,
80
+ middleware: [shift(), flip(), offset(parseInt(spaceXXSmall))],
81
+ });
82
+
83
+ return (
84
+ <ClickAway>
85
+ {({isOpen, onOpen, cancelNext, clickAway}) => (
86
+ <div data-testid="ButtonTabDropdown" ref={menuBtnRef}>
87
+ <ButtonTab
88
+ {...buttonTabProps}
89
+ ref={refs.setReference}
90
+ selectedButtonTabId={moreTabSelectedId}
91
+ onButtonTabSelect={(id, e) => {
92
+ e?.stopPropagation();
93
+ onOpen();
94
+ }}
95
+ >
96
+ {title}
97
+ </ButtonTab>
98
+ {isOpen && (
99
+ <div
100
+ onClickCapture={cancelNext}
101
+ ref={refs.setFloating}
102
+ style={{
103
+ display: 'flex',
104
+ position: strategy,
105
+ top: y ?? spaceNone,
106
+ left: x ?? spaceNone,
107
+ }}
108
+ >
109
+ <Menu
110
+ onSelect={(option, e) => {
111
+ onTabSelect && onTabSelect(option.key, e);
112
+ clickAway();
113
+ }}
114
+ size={size}
115
+ options={menuOptions}
116
+ onTabOut={clickAway}
117
+ selectedKeys={[selectedButtonTabId ?? '']}
118
+ />
119
+ </div>
120
+ )}
121
+ </div>
122
+ )}
123
+ </ClickAway>
124
+ );
125
+ };
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.ButtonTabs = void 0;
7
7
  var React = _interopRequireWildcard(require("react"));
8
8
  var _classify = _interopRequireDefault(require("../../utils/classify"));
9
+ var _ButtonTabDropdown = require("./ButtonTabDropdown");
9
10
  var _ButtonTabsModule = _interopRequireDefault(require("./ButtonTabs.module.css"));
10
11
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
12
  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); }
@@ -19,18 +20,35 @@ const ButtonTabs = /*#__PURE__*/React.forwardRef((_ref, ref) => {
19
20
  size = 'medium',
20
21
  disabled,
21
22
  selectedButtonTabId,
22
- onButtonTabSelect
23
+ onButtonTabSelect,
24
+ wrapAfter,
25
+ wrapTabTitle = 'more',
26
+ anchorPosition
23
27
  } = _ref;
24
28
  const childrenArray = React.Children.toArray(children);
25
- const childrenWithProps = childrenArray.map((child, index) => {
29
+ let unwrappedNodes = childrenArray;
30
+ let wrappedNodes = [];
31
+ if (typeof wrapAfter === 'number' && wrapAfter > -1) {
32
+ unwrappedNodes = childrenArray.slice(0, wrapAfter);
33
+ wrappedNodes = childrenArray.slice(wrapAfter);
34
+ if (wrappedNodes.length) {
35
+ unwrappedNodes.push( /*#__PURE__*/React.createElement(_ButtonTabDropdown.ButtonTabDropdown, {
36
+ id: "more-tab",
37
+ title: wrapTabTitle,
38
+ iconName: "ellipsis-vertical",
39
+ anchorPosition: anchorPosition
40
+ }, wrappedNodes));
41
+ }
42
+ }
43
+ const childrenWithProps = unwrappedNodes.map((child, index) => {
26
44
  if ( /*#__PURE__*/React.isValidElement(child)) {
27
45
  const {
28
46
  disabled: disabledChild,
29
47
  classNames: classNamesChild
30
48
  } = child.props;
31
49
  const isFirst = index === 0;
32
- const isLast = index === childrenArray.length - 1;
33
- const isSingleChild = childrenArray.length === 1;
50
+ const isLast = index === unwrappedNodes.length - 1;
51
+ const isSingleChild = unwrappedNodes.length === 1;
34
52
  return /*#__PURE__*/React.cloneElement(child, {
35
53
  ...child.props,
36
54
  isFluid,
@@ -3,6 +3,9 @@
3
3
  import * as React from 'react';
4
4
 
5
5
  import classify from '../../utils/classify';
6
+ import type {AnchorType} from '../ButtonDropdown';
7
+
8
+ import {ButtonTabDropdown} from './ButtonTabDropdown';
6
9
 
7
10
  import css from './ButtonTabs.module.css';
8
11
 
@@ -16,7 +19,10 @@ export type ButtonTabsProps = {
16
19
  size?: 'medium' | 'small',
17
20
  disabled?: boolean,
18
21
  selectedButtonTabId?: string,
19
- onButtonTabSelect?: ?(id: string, e?: SyntheticEvent<HTMLElement>) => mixed,
22
+ onButtonTabSelect?: ?(id: string, e?: ?SyntheticEvent<HTMLElement>) => mixed,
23
+ wrapAfter?: number,
24
+ wrapTabTitle?: string,
25
+ anchorPosition?: AnchorType,
20
26
  };
21
27
 
22
28
  export const ButtonTabs: React$AbstractComponent<
@@ -32,18 +38,42 @@ export const ButtonTabs: React$AbstractComponent<
32
38
  disabled,
33
39
  selectedButtonTabId,
34
40
  onButtonTabSelect,
41
+ wrapAfter,
42
+ wrapTabTitle = 'more',
43
+ anchorPosition,
35
44
  }: ButtonTabsProps,
36
45
  ref,
37
46
  ): React.Node => {
38
47
  const childrenArray = React.Children.toArray(children);
39
48
 
40
- const childrenWithProps = childrenArray.map((child, index) => {
49
+ let unwrappedNodes = childrenArray;
50
+ let wrappedNodes = [];
51
+
52
+ if (typeof wrapAfter === 'number' && wrapAfter > -1) {
53
+ unwrappedNodes = childrenArray.slice(0, wrapAfter);
54
+ wrappedNodes = childrenArray.slice(wrapAfter);
55
+
56
+ if (wrappedNodes.length) {
57
+ unwrappedNodes.push(
58
+ <ButtonTabDropdown
59
+ id="more-tab"
60
+ title={wrapTabTitle}
61
+ iconName="ellipsis-vertical"
62
+ anchorPosition={anchorPosition}
63
+ >
64
+ {wrappedNodes}
65
+ </ButtonTabDropdown>,
66
+ );
67
+ }
68
+ }
69
+
70
+ const childrenWithProps = unwrappedNodes.map((child, index) => {
41
71
  if (React.isValidElement(child)) {
42
72
  const {disabled: disabledChild, classNames: classNamesChild} =
43
73
  child.props;
44
74
  const isFirst = index === 0;
45
- const isLast = index === childrenArray.length - 1;
46
- const isSingleChild = childrenArray.length === 1;
75
+ const isLast = index === unwrappedNodes.length - 1;
76
+ const isSingleChild = unwrappedNodes.length === 1;
47
77
 
48
78
  return React.cloneElement(child, {
49
79
  ...child.props,
@@ -32,16 +32,42 @@ const Chip = /*#__PURE__*/React.forwardRef((_ref, ref) => {
32
32
  iconName = '',
33
33
  iconType = 'regular',
34
34
  showStatusIndicator,
35
- disableHoverState = false,
36
35
  dismissable = false,
37
36
  onDismiss = () => null,
38
37
  onClick,
39
38
  disabled,
40
- ...rest
39
+ disableHoverState = !onClick,
40
+ // There is no reason for hover state to be active when there is no click handler attached
41
+ ...restProps
41
42
  } = _ref;
43
+ /**
44
+ * Note (Nishant): Why we are using a `div` to render a onclick element instead of a `button`?
45
+ *
46
+ * Rendering the `Chip` component as a button directly would have been ideal, as it would
47
+ * have naturally handled interactivity and accessibility for clickable chips(which has an onClick). However,
48
+ * the `Chip` component includes a `CloseIcon`, which itself is a button. Nesting a `<button>`
49
+ * inside another `<button>` is semantically incorrect and would lead to improper HTML structure.
50
+ *
51
+ * Instead, we use a `<div>` with `role="button"` to maintain proper semantic behavior and
52
+ * avoid nesting buttons. While `role="button"` provides the appropriate semantics, it does
53
+ * not automatically handle keyboard interactions. Therefore, we manually handle `Enter`
54
+ * and `Space` key events to ensure the component is fully accessible and keyboard-compliant.
55
+ *
56
+ * Although this method might seem less conventional, it simplifies implementation and ensures
57
+ * backward compatibility while adhering to accessibility standards.
58
+ */
59
+ const handleKeyDown = event => {
60
+ const {
61
+ key
62
+ } = event;
63
+ if (key === 'Enter' || key === ' ') {
64
+ event.preventDefault(); // Prevent default action for Enter and Space keys
65
+ onClick?.(event);
66
+ }
67
+ };
42
68
  return /*#__PURE__*/React.createElement("div", _extends({
43
69
  "data-testid": "Chip"
44
- }, rest, {
70
+ }, restProps, {
45
71
  ref: ref,
46
72
  className: (0, _classify.classify)(_ChipModule.default.chipWrapper, {
47
73
  [_ChipModule.default.primary]: semantic === CHIP_SEMANTIC.primary,
@@ -57,7 +83,10 @@ const Chip = /*#__PURE__*/React.forwardRef((_ref, ref) => {
57
83
  [_ChipModule.default.disabled]: disabled,
58
84
  [_ChipModule.default.noHoverState]: showStatusIndicator || disableHoverState
59
85
  }, classNames?.wrapper),
60
- onClick: onClick
86
+ onClick: onClick,
87
+ onKeyDown: handleKeyDown,
88
+ tabIndex: showStatusIndicator || disableHoverState ? undefined : 0,
89
+ role: showStatusIndicator || disableHoverState ? undefined : 'button'
61
90
  }), showStatusIndicator && size !== 'small' && /*#__PURE__*/React.createElement(_StatusIndicator.StatusIndicator, {
62
91
  status: semantic,
63
92
  classNames: {
@@ -55,6 +55,7 @@ export type SmallChipProps = {
55
55
  };
56
56
 
57
57
  export type ChipProps = MediumChipProps | SmallChipProps;
58
+
58
59
  export const Chip: React$AbstractComponent<ChipProps, HTMLDivElement> =
59
60
  React.forwardRef<ChipProps, HTMLDivElement>(
60
61
  (
@@ -66,76 +67,105 @@ export const Chip: React$AbstractComponent<ChipProps, HTMLDivElement> =
66
67
  iconName = '',
67
68
  iconType = 'regular',
68
69
  showStatusIndicator,
69
- disableHoverState = false,
70
70
  dismissable = false,
71
71
  onDismiss = () => null,
72
72
  onClick,
73
73
  disabled,
74
- ...rest
74
+ disableHoverState = !onClick, // There is no reason for hover state to be active when there is no click handler attached
75
+ ...restProps
75
76
  }: ChipProps,
76
77
  ref,
77
- ): React.Node => (
78
- <div
79
- data-testid="Chip"
80
- {...rest}
81
- ref={ref}
82
- className={classify(
83
- css.chipWrapper,
84
- {
85
- [css.primary]: semantic === CHIP_SEMANTIC.primary,
86
- [css.information]: semantic === CHIP_SEMANTIC.information,
87
- [css.success]: semantic === CHIP_SEMANTIC.success,
88
- [css.warning]: semantic === CHIP_SEMANTIC.warning,
89
- [css.danger]: semantic === CHIP_SEMANTIC.danger,
90
- [css.secondary]: semantic === CHIP_SEMANTIC.secondary,
91
- [css.medium]: size === 'medium',
92
- [css.small]: size === 'small',
93
- [css.dismissable]: dismissable,
94
- [css.withIcon]: !!iconName && size !== 'small',
95
- [css.disabled]: disabled,
96
- [css.noHoverState]: showStatusIndicator || disableHoverState,
97
- },
98
- classNames?.wrapper,
99
- )}
100
- onClick={onClick}
101
- >
102
- {showStatusIndicator && size !== 'small' && (
103
- <StatusIndicator
104
- status={semantic}
105
- classNames={{
106
- wrapper: classify(
107
- css.statusIndicatorBlock,
108
- classNames?.statusIndicator,
109
- ),
110
- }}
111
- disabled={disabled}
112
- />
113
- )}
78
+ ): React.Node => {
79
+ /**
80
+ * Note (Nishant): Why we are using a `div` to render a onclick element instead of a `button`?
81
+ *
82
+ * Rendering the `Chip` component as a button directly would have been ideal, as it would
83
+ * have naturally handled interactivity and accessibility for clickable chips(which has an onClick). However,
84
+ * the `Chip` component includes a `CloseIcon`, which itself is a button. Nesting a `<button>`
85
+ * inside another `<button>` is semantically incorrect and would lead to improper HTML structure.
86
+ *
87
+ * Instead, we use a `<div>` with `role="button"` to maintain proper semantic behavior and
88
+ * avoid nesting buttons. While `role="button"` provides the appropriate semantics, it does
89
+ * not automatically handle keyboard interactions. Therefore, we manually handle `Enter`
90
+ * and `Space` key events to ensure the component is fully accessible and keyboard-compliant.
91
+ *
92
+ * Although this method might seem less conventional, it simplifies implementation and ensures
93
+ * backward compatibility while adhering to accessibility standards.
94
+ */
95
+ const handleKeyDown = (event: SyntheticKeyboardEvent<HTMLElement>) => {
96
+ const {key} = event;
97
+ if (key === 'Enter' || key === ' ') {
98
+ event.preventDefault(); // Prevent default action for Enter and Space keys
99
+ onClick?.(event);
100
+ }
101
+ };
102
+
103
+ return (
104
+ <div
105
+ data-testid="Chip"
106
+ {...restProps}
107
+ ref={ref}
108
+ className={classify(
109
+ css.chipWrapper,
110
+ {
111
+ [css.primary]: semantic === CHIP_SEMANTIC.primary,
112
+ [css.information]: semantic === CHIP_SEMANTIC.information,
113
+ [css.success]: semantic === CHIP_SEMANTIC.success,
114
+ [css.warning]: semantic === CHIP_SEMANTIC.warning,
115
+ [css.danger]: semantic === CHIP_SEMANTIC.danger,
116
+ [css.secondary]: semantic === CHIP_SEMANTIC.secondary,
117
+ [css.medium]: size === 'medium',
118
+ [css.small]: size === 'small',
119
+ [css.dismissable]: dismissable,
120
+ [css.withIcon]: !!iconName && size !== 'small',
121
+ [css.disabled]: disabled,
122
+ [css.noHoverState]: showStatusIndicator || disableHoverState,
123
+ },
124
+ classNames?.wrapper,
125
+ )}
126
+ onClick={onClick}
127
+ onKeyDown={handleKeyDown}
128
+ tabIndex={showStatusIndicator || disableHoverState ? undefined : 0}
129
+ role={showStatusIndicator || disableHoverState ? undefined : 'button'}
130
+ >
131
+ {showStatusIndicator && size !== 'small' && (
132
+ <StatusIndicator
133
+ status={semantic}
134
+ classNames={{
135
+ wrapper: classify(
136
+ css.statusIndicatorBlock,
137
+ classNames?.statusIndicator,
138
+ ),
139
+ }}
140
+ disabled={disabled}
141
+ />
142
+ )}
114
143
 
115
- {iconName && size !== 'small' && (
116
- <Icon
117
- className={classify(css.chipIcon, classNames?.icon)}
118
- name={iconName}
119
- type={iconType}
120
- size="small"
121
- />
122
- )}
123
- <Truncate>{children}</Truncate>
144
+ {iconName && size !== 'small' && (
145
+ <Icon
146
+ className={classify(css.chipIcon, classNames?.icon)}
147
+ name={iconName}
148
+ type={iconType}
149
+ size="small"
150
+ />
151
+ )}
152
+ <Truncate>{children}</Truncate>
124
153
 
125
- {dismissable && size !== 'small' && (
126
- <CloseIcon
127
- className={css.dismissIcon}
128
- type={iconType}
129
- size="small"
130
- ariaLabel="Dismiss"
131
- onClick={(event) => {
132
- event.stopPropagation();
133
- if (!disabled && onDismiss) {
134
- onDismiss(event);
135
- }
136
- }}
137
- />
138
- )}
139
- </div>
140
- ),
154
+ {dismissable && size !== 'small' && (
155
+ <CloseIcon
156
+ className={css.dismissIcon}
157
+ type={iconType}
158
+ size="small"
159
+ ariaLabel="Dismiss"
160
+ onClick={(event) => {
161
+ event.stopPropagation();
162
+ if (!disabled && onDismiss) {
163
+ onDismiss(event);
164
+ }
165
+ }}
166
+ />
167
+ )}
168
+ </div>
169
+ );
170
+ },
141
171
  );
@@ -12,7 +12,8 @@
12
12
  colorGrayLightest,
13
13
  colorFillNone,
14
14
  colorTextDisabled,
15
- colorFillDisabled
15
+ colorFillDisabled,
16
+ colorFocusPrimary
16
17
  ) from '../../styles/variables/_color.css';
17
18
  @value (
18
19
  spaceNone,
@@ -28,6 +29,11 @@
28
29
  size26
29
30
  ) from '../../styles/variables/_size.css';
30
31
 
32
+ @value (
33
+ borderWidthNone,
34
+ borderWidthTertiary
35
+ ) from '../../styles/variables/_border.css';
36
+
31
37
  .chipWrapper {
32
38
  composes: formLabelSmall from '../../styles/typography.module.css';
33
39
  composes: motionEaseInEaseOut from '../../styles/animation.module.css';
@@ -41,6 +47,12 @@
41
47
  cursor: pointer;
42
48
  }
43
49
 
50
+ .chipWrapper:focus {
51
+ outline: none;
52
+ box-shadow: borderWidthNone borderWidthNone borderWidthNone
53
+ borderWidthTertiary colorFocusPrimary;
54
+ }
55
+
44
56
  .medium {
45
57
  height: size26;
46
58
  min-height: size26;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spaced-out/ui-design-system",
3
- "version": "0.1.116",
3
+ "version": "0.1.118",
4
4
  "main": "index.js",
5
5
  "description": "Sense UI components library",
6
6
  "author": {