@jobber/components 2.78.3 → 2.80.1

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
@@ -8,6 +8,39 @@ menu: Changelog
8
8
  All notable changes to this project will be documented in this file.
9
9
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
10
10
 
11
+ ## [2.80.1](https://github.com/GetJobber/atlantis/compare/@jobber/components@2.80.0...@jobber/components@2.80.1) (2022-04-05)
12
+
13
+
14
+ ### Bug Fixes
15
+
16
+ * disable enter press on chip menu debounce ([#874](https://github.com/GetJobber/atlantis/issues/874)) ([569e4d3](https://github.com/GetJobber/atlantis/commit/569e4d317369fc6af12f2603d9212a159fb88602))
17
+
18
+
19
+
20
+
21
+
22
+ # [2.80.0](https://github.com/GetJobber/atlantis/compare/@jobber/components@2.79.0...@jobber/components@2.80.0) (2022-04-05)
23
+
24
+
25
+ ### Features
26
+
27
+ * **components:** Enable chip navigation with left and right arrow keys ([#872](https://github.com/GetJobber/atlantis/issues/872)) ([065b17b](https://github.com/GetJobber/atlantis/commit/065b17bf55161c85d11346fdd1d41a1c6e01e39d))
28
+
29
+
30
+
31
+
32
+
33
+ # [2.79.0](https://github.com/GetJobber/atlantis/compare/@jobber/components@2.78.3...@jobber/components@2.79.0) (2022-03-25)
34
+
35
+
36
+ ### Features
37
+
38
+ * **components:** create statuslabel component ([#870](https://github.com/GetJobber/atlantis/issues/870)) ([cced9b9](https://github.com/GetJobber/atlantis/commit/cced9b9c1af70432b62766e440f445b949bdd236))
39
+
40
+
41
+
42
+
43
+
11
44
  ## [2.78.3](https://github.com/GetJobber/atlantis/compare/@jobber/components@2.78.2...@jobber/components@2.78.3) (2022-03-17)
12
45
 
13
46
  **Note:** Version bump only for package @jobber/components
@@ -0,0 +1 @@
1
+ export * from "./dist/StatusLabel";
package/StatusLabel.js ADDED
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true,
5
+ });
6
+
7
+ var StatusLabel = require("./dist/StatusLabel");
8
+
9
+ Object.keys(StatusLabel).forEach(function(key) {
10
+ if (key === "default" || key === "__esModule") return;
11
+ Object.defineProperty(exports, key, {
12
+ enumerable: true,
13
+ get: function get() {
14
+ return StatusLabel[key];
15
+ },
16
+ });
17
+ });
@@ -1,4 +1,4 @@
1
- import { MouseEvent, ReactElement } from "react";
1
+ import { KeyboardEvent, MouseEvent, ReactElement } from "react";
2
2
  import { ChipButtonProps } from "./InternalChipButton";
3
3
  import { AvatarProps } from "../Avatar";
4
4
  import { IconProps } from "../Icon";
@@ -12,7 +12,7 @@ export interface InternalChipProps {
12
12
  */
13
13
  readonly active?: boolean;
14
14
  /**
15
- * Makes the chip look and feels uninteractable.
15
+ * Makes the chip look and feel uninteractable.
16
16
  */
17
17
  readonly disabled?: boolean;
18
18
  /**
@@ -35,8 +35,25 @@ export interface InternalChipProps {
35
35
  * Adds a component on the right side of the label.
36
36
  */
37
37
  readonly suffix?: ReactElement<IconProps | ChipButtonProps>;
38
+ /**
39
+ * The label for the interactive chip element for voice over
40
+ */
41
+ readonly ariaLabel?: string;
42
+ /**
43
+ * Allows the chip to be focused.
44
+ *
45
+ * **NOTE**: Clickable chips are focusable by default so you don't need to
46
+ * specify this prop.
47
+ *
48
+ * This has the same effect as HTML [tabindex](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex).
49
+ */
50
+ readonly tabIndex?: number;
38
51
  /**
39
52
  * Callback when the chip itself gets clicked.
40
53
  */
41
54
  onClick?(event: MouseEvent<HTMLDivElement | HTMLInputElement | HTMLButtonElement>): void;
55
+ /**
56
+ * Callback for keyboard interaction with chips (e.g., chip deletion).
57
+ */
58
+ onKeyDown?(event: KeyboardEvent<HTMLDivElement | HTMLButtonElement>): void;
42
59
  }
@@ -1,2 +1,2 @@
1
1
  import { InternalChipProps } from "./ChipTypes";
2
- export declare function InternalChip({ label, active, disabled, invalid, prefix, suffix, onClick, }: InternalChipProps): JSX.Element;
2
+ export declare function InternalChip({ label, active, disabled, invalid, prefix, suffix, tabIndex, ariaLabel, onClick, onKeyDown, }: InternalChipProps): JSX.Element;
@@ -5,7 +5,6 @@ export declare type InternalChipDismissibleProps = Omit<ChipDismissibleProps, "t
5
5
  export interface ChipDismissibleInputProps extends Pick<InternalChipDismissibleProps, "activator" | "isLoadingMore" | "onSearch" | "onLoadMore"> {
6
6
  readonly attachTo: React.RefObject<Element | null>;
7
7
  readonly options: ChipProps[];
8
- onEmptyBackspace(): void;
9
8
  onCustomOptionSelect?(value: string): void;
10
9
  onOptionSelect(value: string): void;
11
10
  }
@@ -1,12 +1,15 @@
1
- import { MouseEvent } from "react";
1
+ import { KeyboardEvent, MouseEvent } from "react";
2
2
  import { InternalChipDismissibleProps } from "../InternalChipDismissibleTypes";
3
3
  export declare function useInternalChipDismissible({ children, selected, onChange, onClick, onCustomAdd, }: InternalChipDismissibleProps): {
4
4
  ref: import("react").RefObject<HTMLDivElement>;
5
5
  sortedVisibleChipOptions: import("../../Chip").ChipProps[];
6
6
  availableChipOptions: import("../../Chip").ChipProps[];
7
- handleChipRemove: (chip: import("../../Chip").ChipProps) => () => void;
7
+ handleChipRemove: (value: string) => () => void;
8
8
  handleChipAdd: (value: string) => void;
9
9
  handleCustomAdd: ((value: string) => void) | undefined;
10
10
  handleChipClick: (value: string) => ((event: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>) => void) | undefined;
11
- handleEmptyBackspace: () => void;
11
+ handleWrapperKeyDown: (event: KeyboardEvent<HTMLDivElement> & {
12
+ target: HTMLElement;
13
+ }) => void;
14
+ handleChipKeyDown: (value: string) => (event: KeyboardEvent<HTMLElement>) => void;
12
15
  };
@@ -1,7 +1,7 @@
1
1
  /// <reference types="lodash" />
2
2
  import React from "react";
3
3
  import { ChipDismissibleInputOptionProps, ChipDismissibleInputProps } from "../InternalChipDismissibleTypes";
4
- export declare function useInternalChipDismissibleInput({ options, isLoadingMore, onEmptyBackspace, onCustomOptionSelect, onOptionSelect, onSearch, }: ChipDismissibleInputProps): {
4
+ export declare function useInternalChipDismissibleInput({ options, isLoadingMore, onCustomOptionSelect, onOptionSelect, onSearch, }: ChipDismissibleInputProps): {
5
5
  menuOpen: boolean;
6
6
  searchValue: string;
7
7
  shouldCancelBlur: boolean;
@@ -26,7 +26,7 @@ var index$4 = require('../Tooltip/index.js');
26
26
  var reactPopper = require('react-popper');
27
27
  var lodash = require('lodash');
28
28
 
29
- var css = "/**\n * Used in the wrapping chips component:\n * - InternalChipSingleSelect\n * - InternalChipMultiSelect\n */\n\n.uhcyg-a-GLRKF_7oHwvMP {\n display: -ms-flexbox;\n display: flex;\n grid-gap: var(--space-small);\n grid-gap: var(--space-small);\n gap: var(--space-small);\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-align: center;\n align-items: center;\n}\n\n._2XfthED8eqbKIyTNoH1aWp {\n display: inline-grid;\n position: relative;\n max-width: 100%;\n box-sizing: border-box;\n padding: var(--space-small);\n border: var(--border-base) solid var(--color-border);\n border-radius: var(--radius-larger);\n color: var(--color-text--secondary);\n text-align: left;\n vertical-align: middle;\n background-color: var(--color-surface);\n transition: var(--timing-base) ease-in-out;\n transition-property: background-color, box-shadow, color;\n grid-template-columns: -webkit-max-content;\n grid-template-columns: max-content;\n -ms-flex-align: center;\n align-items: center;\n grid-gap: var(--space-small);\n grid-gap: var(--space-small);\n gap: var(--space-small);\n}\n\n._4U2lNr3Kk6xnNZTk3Fxgm,\n.fl19i7ccgBu7NZkxnpvcI {\n padding: calc(var(--space-smaller) + var(--space-smallest)) var(--space-small);\n}\n\n._4U2lNr3Kk6xnNZTk3Fxgm {\n grid-template-columns: -webkit-min-content 1fr;\n grid-template-columns: min-content 1fr;\n}\n\n.fl19i7ccgBu7NZkxnpvcI {\n grid-template-columns: 1fr -webkit-min-content;\n grid-template-columns: 1fr min-content;\n}\n\n._4U2lNr3Kk6xnNZTk3Fxgm.fl19i7ccgBu7NZkxnpvcI {\n grid-template-columns: -webkit-min-content 1fr -webkit-min-content;\n grid-template-columns: min-content 1fr min-content;\n}\n\n._3Uf2El5YBbG3DmUWHBhuea,\n._35he2rVDYRU4YQko5r4adP ~ ._2XfthED8eqbKIyTNoH1aWp {\n box-shadow: var(--shadow-base);\n cursor: pointer;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n/**\n * Interaction\n */\n\n._2XfthED8eqbKIyTNoH1aWp:focus,\n._35he2rVDYRU4YQko5r4adP:focus ~ ._2XfthED8eqbKIyTNoH1aWp {\n outline: none;\n}\n\n._3Uf2El5YBbG3DmUWHBhuea:focus,\n._35he2rVDYRU4YQko5r4adP:focus ~ ._2XfthED8eqbKIyTNoH1aWp {\n box-shadow: var(--shadow-focus);\n}\n\n._3Uf2El5YBbG3DmUWHBhuea:hover,\n._3Uf2El5YBbG3DmUWHBhuea:focus,\n._35he2rVDYRU4YQko5r4adP:focus ~ ._2XfthED8eqbKIyTNoH1aWp:not(._18wCcoIrboygQTnIVm8yzS) {\n background-color: var(--color-surface--hover);\n}\n\n/**\n * States\n */\n\n._2XfthED8eqbKIyTNoH1aWp._18wCcoIrboygQTnIVm8yzS {\n border-color: var(--color-surface--reverse);\n color: var(--color-text--reverse);\n background-color: var(--color-surface--reverse);\n}\n\n._2XfthED8eqbKIyTNoH1aWp._1FTJ2ALrm1mVaT7HdMFFGN {\n border-color: var(--color-critical--onSurface);\n color: var(--color-critical--onSurface);\n background-color: var(--color-critical--surface);\n}\n\n._2XfthED8eqbKIyTNoH1aWp.B1ELFzeQy9Ihy9oYcv-px {\n border-color: var(--color-disabled--secondary);\n color: var(--color-disabled);\n background-color: var(--color-disabled--secondary);\n}\n\n._18wCcoIrboygQTnIVm8yzS.B1ELFzeQy9Ihy9oYcv-px {\n border-color: var(--color-disabled);\n color: var(--color-white);\n background-color: var(--color-disabled);\n}\n\n._1FTJ2ALrm1mVaT7HdMFFGN.B1ELFzeQy9Ihy9oYcv-px {\n border-color: var(--color-critical);\n}\n\n/**\n * Input checkbox/radio\n *\n * Hide checkbox on UI but not screen readers and still allow focus state\n */\n\n._35he2rVDYRU4YQko5r4adP {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n -webkit-clip-path: inset(100%);\n clip-path: inset(100%);\n white-space: nowrap;\n}\n\n/**\n * Button\n */\n\n._1M_ek3kiaa7OApx5rwBEc3 {\n display: -ms-flexbox;\n display: flex;\n border-radius: var(--radius-base);\n cursor: pointer;\n transition: background-color 200ms ease;\n}\n\n._1M_ek3kiaa7OApx5rwBEc3:hover,\n._1M_ek3kiaa7OApx5rwBEc3:focus {\n background-color: var(--color-surface--hover);\n}\n\n._1M_ek3kiaa7OApx5rwBEc3:focus,\n._3Uf2El5YBbG3DmUWHBhuea ._1M_ek3kiaa7OApx5rwBEc3:hover {\n box-shadow: var(--shadow-focus);\n outline: none;\n}\n\n/**\n * Override icon default colors.\n *\n * NOTE: This is a workaround since some icons have default colors that we don't\n * want to override until the component color prop overrides it.\n * DO NOT COPY!\n */\n\n._3AG5dSWeyKYD1Xfu9fN_DL > svg {\n fill: var(--color-interactive--subtle);\n}\n\n._3AG5dSWeyKYD1Xfu9fN_DL {\n display: -ms-flexbox;\n display: flex;\n}\n";
29
+ var css = "/**\n * Used in the wrapping chips component:\n * - InternalChipSingleSelect\n * - InternalChipMultiSelect\n */\n\n.uhcyg-a-GLRKF_7oHwvMP {\n display: -ms-flexbox;\n display: flex;\n grid-gap: var(--space-small);\n grid-gap: var(--space-small);\n gap: var(--space-small);\n -ms-flex-wrap: wrap;\n flex-wrap: wrap;\n -ms-flex-align: center;\n align-items: center;\n}\n\n._2XfthED8eqbKIyTNoH1aWp {\n display: inline-grid;\n position: relative;\n max-width: 100%;\n box-sizing: border-box;\n padding: var(--space-small);\n border: var(--border-base) solid var(--color-border);\n border-radius: var(--radius-larger);\n color: var(--color-text--secondary);\n text-align: left;\n vertical-align: middle;\n background-color: var(--color-surface);\n transition: var(--timing-base) ease-in-out;\n transition-property: background-color, box-shadow, color;\n grid-template-columns: -webkit-max-content;\n grid-template-columns: max-content;\n -ms-flex-align: center;\n align-items: center;\n grid-gap: var(--space-small);\n grid-gap: var(--space-small);\n gap: var(--space-small);\n}\n\n._4U2lNr3Kk6xnNZTk3Fxgm,\n.fl19i7ccgBu7NZkxnpvcI {\n padding: calc(var(--space-smaller) + var(--space-smallest)) var(--space-small);\n}\n\n._4U2lNr3Kk6xnNZTk3Fxgm {\n grid-template-columns: -webkit-min-content 1fr;\n grid-template-columns: min-content 1fr;\n}\n\n.fl19i7ccgBu7NZkxnpvcI {\n grid-template-columns: 1fr -webkit-min-content;\n grid-template-columns: 1fr min-content;\n}\n\n._4U2lNr3Kk6xnNZTk3Fxgm.fl19i7ccgBu7NZkxnpvcI {\n grid-template-columns: -webkit-min-content 1fr -webkit-min-content;\n grid-template-columns: min-content 1fr min-content;\n}\n\n._3Uf2El5YBbG3DmUWHBhuea,\n._35he2rVDYRU4YQko5r4adP ~ ._2XfthED8eqbKIyTNoH1aWp {\n box-shadow: var(--shadow-base);\n cursor: pointer;\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n/**\n * Interaction\n */\n\n._3Uf2El5YBbG3DmUWHBhuea:hover,\n._2XfthED8eqbKIyTNoH1aWp:focus {\n outline: none;\n background-color: var(--color-surface--hover);\n}\n\n._2XfthED8eqbKIyTNoH1aWp:focus,\n._35he2rVDYRU4YQko5r4adP:focus ~ ._2XfthED8eqbKIyTNoH1aWp {\n box-shadow: var(--shadow-focus);\n}\n\n._35he2rVDYRU4YQko5r4adP:focus ~ ._2XfthED8eqbKIyTNoH1aWp:not(._18wCcoIrboygQTnIVm8yzS) {\n outline: none;\n background-color: var(--color-surface--hover);\n}\n\n/**\n * States\n */\n\n._2XfthED8eqbKIyTNoH1aWp._18wCcoIrboygQTnIVm8yzS {\n border-color: var(--color-surface--reverse);\n color: var(--color-text--reverse);\n background-color: var(--color-surface--reverse);\n}\n\n._2XfthED8eqbKIyTNoH1aWp._1FTJ2ALrm1mVaT7HdMFFGN {\n border-color: var(--color-critical--onSurface);\n color: var(--color-critical--onSurface);\n background-color: var(--color-critical--surface);\n}\n\n._2XfthED8eqbKIyTNoH1aWp.B1ELFzeQy9Ihy9oYcv-px {\n border-color: var(--color-disabled--secondary);\n color: var(--color-disabled);\n background-color: var(--color-disabled--secondary);\n}\n\n._18wCcoIrboygQTnIVm8yzS.B1ELFzeQy9Ihy9oYcv-px {\n border-color: var(--color-disabled);\n color: var(--color-white);\n background-color: var(--color-disabled);\n}\n\n._1FTJ2ALrm1mVaT7HdMFFGN.B1ELFzeQy9Ihy9oYcv-px {\n border-color: var(--color-critical);\n}\n\n/**\n * Input checkbox/radio\n *\n * Hide checkbox on UI but not screen readers and still allow focus state\n */\n\n._35he2rVDYRU4YQko5r4adP {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n -webkit-clip-path: inset(100%);\n clip-path: inset(100%);\n white-space: nowrap;\n}\n\n/**\n * Button\n */\n\n._1M_ek3kiaa7OApx5rwBEc3 {\n display: -ms-flexbox;\n display: flex;\n border-radius: var(--radius-base);\n cursor: pointer;\n transition: background-color 200ms ease;\n}\n\n._1M_ek3kiaa7OApx5rwBEc3:hover,\n._1M_ek3kiaa7OApx5rwBEc3:focus {\n background-color: var(--color-surface--hover);\n}\n\n._1M_ek3kiaa7OApx5rwBEc3:focus,\n._3Uf2El5YBbG3DmUWHBhuea ._1M_ek3kiaa7OApx5rwBEc3:hover {\n box-shadow: var(--shadow-focus);\n outline: none;\n}\n\n/**\n * Override icon default colors.\n *\n * NOTE: This is a workaround since some icons have default colors that we don't\n * want to override until the component color prop overrides it.\n * DO NOT COPY!\n */\n\n._3AG5dSWeyKYD1Xfu9fN_DL > svg {\n fill: var(--color-interactive--subtle);\n}\n\n._3AG5dSWeyKYD1Xfu9fN_DL {\n display: -ms-flexbox;\n display: flex;\n}\n";
30
30
  var styles = {"wrapper":"uhcyg-a-GLRKF_7oHwvMP","chip":"_2XfthED8eqbKIyTNoH1aWp","hasPrefix":"_4U2lNr3Kk6xnNZTk3Fxgm","hasSuffix":"fl19i7ccgBu7NZkxnpvcI","clickable":"_3Uf2El5YBbG3DmUWHBhuea","input":"_35he2rVDYRU4YQko5r4adP","active":"_18wCcoIrboygQTnIVm8yzS","invalid":"_1FTJ2ALrm1mVaT7HdMFFGN","disabled":"B1ELFzeQy9Ihy9oYcv-px","button":"_1M_ek3kiaa7OApx5rwBEc3","icon":"_3AG5dSWeyKYD1Xfu9fN_DL"};
31
31
  __chunk_2.styleInject(css);
32
32
 
@@ -97,7 +97,7 @@ function InternalChipAffix(_a) {
97
97
 
98
98
  function InternalChip(_a) {
99
99
  var _b;
100
- var label = _a.label, _c = _a.active, active = _c === void 0 ? false : _c, _d = _a.disabled, disabled = _d === void 0 ? false : _d, _e = _a.invalid, invalid = _e === void 0 ? false : _e, prefix = _a.prefix, suffix = _a.suffix, onClick = _a.onClick;
100
+ var label = _a.label, _c = _a.active, active = _c === void 0 ? false : _c, _d = _a.disabled, disabled = _d === void 0 ? false : _d, _e = _a.invalid, invalid = _e === void 0 ? false : _e, prefix = _a.prefix, suffix = _a.suffix, tabIndex = _a.tabIndex, ariaLabel = _a.ariaLabel, onClick = _a.onClick, onKeyDown = _a.onKeyDown;
101
101
  var _f = __chunk_1.__read(React.useState(), 2), truncateRef = _f[0], setTruncateRef = _f[1];
102
102
  var isClickable = onClick && !disabled;
103
103
  var classNames = classnames(styles.chip, (_b = {},
@@ -110,10 +110,7 @@ function InternalChip(_a) {
110
110
  _b));
111
111
  var affixProps = { active: active, invalid: invalid, disabled: disabled };
112
112
  var Tag = onClick ? "button" : "div";
113
- var chip = (React__default.createElement(Tag, __chunk_1.__assign({ className: classNames }, (isClickable && {
114
- onClick: onClick,
115
- disabled: disabled,
116
- }), { "data-testid": "chip-wrapper" }),
113
+ var chip = (React__default.createElement(Tag, __chunk_1.__assign({ className: classNames }, (isClickable && { onClick: onClick, disabled: disabled }), { onKeyDown: onKeyDown, "data-testid": "chip-wrapper", "aria-label": ariaLabel, tabIndex: tabIndex, role: tabIndex !== undefined ? "option" : undefined }),
117
114
  React__default.createElement(InternalChipAffix, __chunk_1.__assign({ affix: prefix }, affixProps)),
118
115
  React__default.createElement(index.Typography, { element: "span", numberOfLines: 1, size: "base" },
119
116
  React__default.createElement("span", { ref: setTruncateRef }, label)),
@@ -226,10 +223,10 @@ function useInternalChipDismissible(_a) {
226
223
  var availableChipOptions = chipOptions.filter(function (chip) { return !selected.includes(chip.value); });
227
224
  var liveAnnounce = hooks.useLiveAnnounce().liveAnnounce;
228
225
  var actions = {
229
- handleChipRemove: function (chip) {
226
+ handleChipRemove: function (value) {
230
227
  return function () {
231
- liveAnnounce(chip.label + " Removed");
232
- onChange(selected.filter(function (val) { return val !== chip.value; }));
228
+ liveAnnounce(value + " Removed");
229
+ onChange(selected.filter(function (val) { return val !== value; }));
233
230
  };
234
231
  },
235
232
  handleChipAdd: function (value) { return onChange(__chunk_1.__spread(selected, [value])); },
@@ -239,8 +236,39 @@ function useInternalChipDismissible(_a) {
239
236
  return;
240
237
  return function (event) { return onClick(event, value); };
241
238
  },
242
- handleEmptyBackspace: function () {
243
- actions.handleChipRemove(sortedVisibleChipOptions[selected.length - 1])();
239
+ handleWrapperKeyDown: function (event) {
240
+ var target = event.target;
241
+ var isInputAndHasValue = target instanceof HTMLInputElement && target.value;
242
+ if (isInputAndHasValue)
243
+ return;
244
+ var nextElementToFocus = target.nextElementSibling;
245
+ var prevElementToFocus = target.previousElementSibling;
246
+ if (event.key === "ArrowLeft" &&
247
+ prevElementToFocus instanceof HTMLElement) {
248
+ prevElementToFocus.focus();
249
+ }
250
+ if (event.key === "ArrowRight" &&
251
+ nextElementToFocus instanceof HTMLElement) {
252
+ nextElementToFocus.focus();
253
+ }
254
+ },
255
+ handleChipKeyDown: function (value) {
256
+ return function (event) {
257
+ if (event.key === "Backspace" || event.key === "Delete") {
258
+ var target = event.target;
259
+ if (target instanceof HTMLElement) {
260
+ var prevElement = target.previousElementSibling;
261
+ var nextElement = target.nextElementSibling;
262
+ if (prevElement instanceof HTMLElement) {
263
+ prevElement.focus();
264
+ }
265
+ else if (nextElement instanceof HTMLElement) {
266
+ nextElement.focus();
267
+ }
268
+ }
269
+ actions.handleChipRemove(value)();
270
+ }
271
+ };
244
272
  },
245
273
  };
246
274
  return __chunk_1.__assign(__chunk_1.__assign({}, actions), { ref: ref,
@@ -249,13 +277,15 @@ function useInternalChipDismissible(_a) {
249
277
  }
250
278
 
251
279
  var menuId = uuid.v1();
280
+ // eslint-disable-next-line max-statements
252
281
  function useInternalChipDismissibleInput(_a) {
253
- var options = _a.options, _b = _a.isLoadingMore, isLoadingMore = _b === void 0 ? false : _b, onEmptyBackspace = _a.onEmptyBackspace, onCustomOptionSelect = _a.onCustomOptionSelect, onOptionSelect = _a.onOptionSelect, onSearch = _a.onSearch;
282
+ var options = _a.options, _b = _a.isLoadingMore, isLoadingMore = _b === void 0 ? false : _b, onCustomOptionSelect = _a.onCustomOptionSelect, onOptionSelect = _a.onOptionSelect, onSearch = _a.onSearch;
254
283
  var _c = __chunk_1.__read(React.useState([]), 2), allOptions = _c[0], setAllOptions = _c[1];
255
284
  var _d = __chunk_1.__read(React.useState(""), 2), searchValue = _d[0], setSearchValue = _d[1];
256
285
  var _e = __chunk_1.__read(React.useState(false), 2), menuOpen = _e[0], setMenuOpen = _e[1];
257
286
  var _f = __chunk_1.__read(React.useState(0), 2), activeIndex = _f[0], setActiveIndex = _f[1];
258
287
  var _g = __chunk_1.__read(React.useState(false), 2), shouldCancelBlur = _g[0], setShouldCancelBlur = _g[1];
288
+ var _h = __chunk_1.__read(React.useState(false), 2), shouldCancelEnter = _h[0], setShouldCancelEnter = _h[1];
259
289
  var canAddCustomOption = onCustomOptionSelect !== undefined && !isLoadingMore;
260
290
  var maxOptionIndex = allOptions.length - 1;
261
291
  var liveAnnounce = hooks.useLiveAnnounce().liveAnnounce;
@@ -292,6 +322,7 @@ function useInternalChipDismissibleInput(_a) {
292
322
  handleSearchChange: function (event) {
293
323
  setActiveIndex(0);
294
324
  setSearchValue(event.currentTarget.value);
325
+ setShouldCancelEnter(true);
295
326
  },
296
327
  handleSetActiveOnMouseOver: function (index) {
297
328
  return function () { return setActiveIndex(index); };
@@ -310,7 +341,11 @@ function useInternalChipDismissibleInput(_a) {
310
341
  },
311
342
  handleKeyDown: function (event) {
312
343
  var callbacks = {
313
- Enter: function () { return actions.handleSelectOption(computed.activeOption); },
344
+ Enter: function () {
345
+ if (shouldCancelEnter)
346
+ return;
347
+ actions.handleSelectOption(computed.activeOption);
348
+ },
314
349
  Tab: function () { return actions.handleSelectOption(computed.activeOption); },
315
350
  ",": function () {
316
351
  if (searchValue.length === 0)
@@ -325,13 +360,22 @@ function useInternalChipDismissibleInput(_a) {
325
360
  ArrowUp: function () { return setActiveIndex(computed.previousOptionIndex); },
326
361
  };
327
362
  if (searchValue.length === 0) {
328
- callbacks.Backspace = function () { return onEmptyBackspace(); };
363
+ callbacks.Backspace = function () {
364
+ var _a;
365
+ // If there's no text left to delete,
366
+ // and delete is pressed again, focus on a chip instead.
367
+ var target = (_a = computed.inputRef.current) === null || _a === void 0 ? void 0 : _a.previousElementSibling;
368
+ if (target instanceof HTMLElement) {
369
+ target.focus();
370
+ }
371
+ };
329
372
  }
330
373
  handleKeydownEvents(callbacks, event);
331
374
  },
332
375
  handleDebouncedSearch: lodash.debounce(function () {
333
376
  onSearch && onSearch(searchValue);
334
377
  setAllOptions(generateOptions(options, searchValue, canAddCustomOption));
378
+ setShouldCancelEnter(false);
335
379
  }, 300),
336
380
  };
337
381
  return __chunk_1.__assign(__chunk_1.__assign(__chunk_1.__assign(__chunk_1.__assign({}, actions), { activeIndex: activeIndex,
@@ -446,7 +490,7 @@ function InternalChipDismissibleInput(props) {
446
490
  return (React__default.createElement(React__default.Fragment, null,
447
491
  React__default.createElement("input", { ref: inputRef, className: styles$1.input, type: "text", role: "combobox", "aria-label": "Press up and down arrow to cycle through the options or type to narrow down the results", "aria-autocomplete": "list", "aria-owns": menuId, "aria-expanded": hasAvailableOptions, "aria-activedescendant": generateDescendantId(activeIndex), value: searchValue, onChange: handleSearchChange, onKeyDown: handleKeyDown, onBlur: lodash.debounce(handleBlur, 200), onFocus: handleOpenMenu, autoFocus: true }),
448
492
  (hasAvailableOptions || isLoadingMore) && (React__default.createElement("div", __chunk_1.__assign({ ref: setPositionedElementRef, className: styles$1.menu, style: popperStyles.popper }, attributes.popper),
449
- React__default.createElement("div", { ref: menuRef, role: "listbox", id: menuId, className: styles$1.menuList },
493
+ React__default.createElement("div", { ref: menuRef, role: "listbox", id: menuId, className: styles$1.menuList, "data-testid": "chip-menu" },
450
494
  allOptions.map(function (option, i) {
451
495
  var _a;
452
496
  return (React__default.createElement("button", { key: option.value, role: "option", id: generateDescendantId(i), className: classnames(styles$1.menuListOption, (_a = {},
@@ -461,10 +505,10 @@ function InternalChipDismissibleInput(props) {
461
505
  }
462
506
 
463
507
  function InternalChipDismissible(props) {
464
- var _a = useInternalChipDismissible(props), availableChipOptions = _a.availableChipOptions, wrapperRef = _a.ref, sortedVisibleChipOptions = _a.sortedVisibleChipOptions, handleChipClick = _a.handleChipClick, handleChipAdd = _a.handleChipAdd, handleChipRemove = _a.handleChipRemove, handleCustomAdd = _a.handleCustomAdd, handleEmptyBackspace = _a.handleEmptyBackspace;
465
- return (React__default.createElement("div", { ref: wrapperRef, className: styles$1.wrapper, "data-testid": "dismissible-chips" },
466
- sortedVisibleChipOptions.map(function (chip) { return (React__default.createElement(ChipDismissible, __chunk_1.__assign({ key: chip.value }, chip, { onClick: handleChipClick(chip.value), onRequestRemove: handleChipRemove(chip) }))); }),
467
- React__default.createElement(InternalChipDismissibleInput, { activator: props.activator, attachTo: wrapperRef, isLoadingMore: props.isLoadingMore, options: availableChipOptions, onOptionSelect: handleChipAdd, onCustomOptionSelect: handleCustomAdd, onEmptyBackspace: handleEmptyBackspace, onSearch: props.onSearch, onLoadMore: props.onLoadMore })));
508
+ var _a = useInternalChipDismissible(props), availableChipOptions = _a.availableChipOptions, wrapperRef = _a.ref, sortedVisibleChipOptions = _a.sortedVisibleChipOptions, handleChipAdd = _a.handleChipAdd, handleChipClick = _a.handleChipClick, handleChipKeyDown = _a.handleChipKeyDown, handleChipRemove = _a.handleChipRemove, handleCustomAdd = _a.handleCustomAdd, handleWrapperKeyDown = _a.handleWrapperKeyDown;
509
+ return (React__default.createElement("div", { ref: wrapperRef, className: styles$1.wrapper, "data-testid": "dismissible-chips", onKeyDown: handleWrapperKeyDown, role: "listbox" },
510
+ sortedVisibleChipOptions.map(function (chip) { return (React__default.createElement(InternalChip, __chunk_1.__assign({ key: chip.value }, chip, { onKeyDown: handleChipKeyDown(chip.value), onClick: handleChipClick(chip.value), ariaLabel: chip.value + ". Press delete or backspace to remove " + chip.value, tabIndex: 0, suffix: React__default.createElement(InternalChipButton, { icon: "remove", invalid: chip.invalid, disabled: chip.disabled, label: chip.label, onClick: handleChipRemove(chip.value) }) }))); }),
511
+ React__default.createElement(InternalChipDismissibleInput, { activator: props.activator, attachTo: wrapperRef, isLoadingMore: props.isLoadingMore, options: availableChipOptions, onOptionSelect: handleChipAdd, onCustomOptionSelect: handleCustomAdd, onSearch: props.onSearch, onLoadMore: props.onLoadMore })));
468
512
  }
469
513
 
470
514
  function Chips(props) {
@@ -0,0 +1,25 @@
1
+ export declare type StatusType = "success" | "warning" | "critical" | "inactive" | "informative";
2
+ export interface StatusLabelType {
3
+ readonly statusLabel: string;
4
+ readonly statusType?: StatusType;
5
+ }
6
+ interface StatusLabelProps {
7
+ /**
8
+ * Text to display
9
+ */
10
+ readonly label: string;
11
+ /**
12
+ * Alignment of label
13
+ *
14
+ * @default "start"
15
+ */
16
+ readonly alignment?: "start" | "end";
17
+ /**
18
+ * Status color of the indicator beside text
19
+ *
20
+ * @default "inactive"
21
+ */
22
+ readonly status: StatusType;
23
+ }
24
+ export declare function StatusLabel({ label, alignment, status, }: StatusLabelProps): JSX.Element;
25
+ export {};
@@ -0,0 +1 @@
1
+ export { StatusLabel } from "./StatusLabel";
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
+
7
+ require('../chunk-b67af3cb.js');
8
+ var React = require('react');
9
+ var React__default = _interopDefault(React);
10
+ var __chunk_2 = require('../chunk-17e02351.js');
11
+ var classnames = _interopDefault(require('classnames'));
12
+ require('../Typography/index.js');
13
+ var index$1 = require('../Text/index.js');
14
+
15
+ var css = ":root {\n --statusLabel-icon-diameter: calc(var(--space-base) - var(--space-smaller));\n}\n\n.NUUO4mR41Qn5Pf0pzjhZe {\n display: -ms-flexbox;\n display: flex;\n -ms-flex-direction: row;\n flex-direction: row;\n -ms-flex-wrap: nowrap;\n flex-wrap: nowrap;\n grid-gap: var(--space-small);\n grid-gap: var(--space-small);\n gap: var(--space-small);\n width: -webkit-fit-content;\n width: -moz-fit-content;\n width: fit-content;\n}\n\n._2XU8xQD0q92o9P2Ej5EdwP {\n width: calc(var(--space-base) - var(--space-smaller));\n width: calc(var(--space-base) - var(--space-smaller));\n width: var(--statusLabel-icon-diameter);\n height: calc(var(--space-base) - var(--space-smaller));\n height: calc(var(--space-base) - var(--space-smaller));\n height: var(--statusLabel-icon-diameter);\n margin-top: var(--space-smallest);\n border-radius: var(--radius-base);\n background-color: var(--color-success);\n -ms-flex-negative: 0;\n flex-shrink: 0;\n}\n\n._3eQHL9hZlneMfEoGaF0dDv {\n -ms-flex-direction: row-reverse;\n flex-direction: row-reverse;\n}\n";
16
+ var styles = {"statusLabelRow":"NUUO4mR41Qn5Pf0pzjhZe","statusIndicator":"_2XU8xQD0q92o9P2Ej5EdwP","labelTextEndAligned":"_3eQHL9hZlneMfEoGaF0dDv"};
17
+ __chunk_2.styleInject(css);
18
+
19
+ function StatusLabel(_a) {
20
+ var label = _a.label, _b = _a.alignment, alignment = _b === void 0 ? "start" : _b, _c = _a.status, status = _c === void 0 ? "inactive" : _c;
21
+ var containerClassNames = classnames(styles.statusLabelRow, alignment === "end" && styles.labelTextEndAligned);
22
+ return (React__default.createElement("div", { role: "status", className: containerClassNames },
23
+ React__default.createElement(StatusLabelIcon, { status: status }),
24
+ React__default.createElement(index$1.Text, { size: "small", align: alignment }, label)));
25
+ }
26
+ function StatusLabelIcon(_a) {
27
+ var status = _a.status;
28
+ return (React__default.createElement("div", { style: { backgroundColor: "var(--color-" + status }, className: styles.statusIndicator }));
29
+ }
30
+
31
+ exports.StatusLabel = StatusLabel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/components",
3
- "version": "2.78.3",
3
+ "version": "2.80.1",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -85,5 +85,5 @@
85
85
  "> 1%",
86
86
  "IE 10"
87
87
  ],
88
- "gitHead": "67a229b18176c2fe701e218a94049fe8a31aa2f9"
88
+ "gitHead": "b5aec350795fb765bcd3487362b962eaa52751e4"
89
89
  }