@skyscanner/backpack-web 42.9.0 → 42.10.0-dev-v24445021679.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.
Files changed (56) hide show
  1. package/bpk-component-ai-blurb/src/BpkAiBlurb.module.css +1 -1
  2. package/bpk-component-ai-blurb/src/BpkAiBlurbFeedback.js +13 -21
  3. package/bpk-component-bubble/src/BpkBubble.module.css +1 -1
  4. package/bpk-component-calendar/src/BpkCalendarNav.d.ts +1 -1
  5. package/bpk-component-calendar/src/BpkCalendarNav.js +0 -1
  6. package/bpk-component-chatbot-input/index.d.ts +1 -2
  7. package/bpk-component-chatbot-input/src/BpkChatbotInput.d.ts +13 -3
  8. package/bpk-component-chatbot-input/src/BpkChatbotInput.js +18 -98
  9. package/bpk-component-chatbot-input/src/BpkChatbotInput.module.css +1 -1
  10. package/bpk-component-chatbot-input/src/BpkChatbotInputContext.d.ts +9 -0
  11. package/bpk-component-chatbot-input/src/BpkChatbotInputContext.js +26 -0
  12. package/bpk-component-chatbot-input/src/BpkChatbotInputInput.d.ts +3 -0
  13. package/bpk-component-chatbot-input/src/BpkChatbotInputInput.js +125 -0
  14. package/bpk-component-chatbot-input/src/BpkChatbotInputRoot.d.ts +3 -0
  15. package/bpk-component-chatbot-input/src/BpkChatbotInputRoot.js +77 -0
  16. package/bpk-component-chatbot-input/src/BpkChatbotInputToolbar.d.ts +3 -0
  17. package/bpk-component-chatbot-input/src/BpkChatbotInputToolbar.js +33 -0
  18. package/bpk-component-chatbot-input/src/TextAreaField/TextAreaField.d.ts +1 -0
  19. package/bpk-component-chatbot-input/src/TextAreaField/TextAreaField.js +5 -1
  20. package/bpk-component-chatbot-input/src/common-types.d.ts +23 -3
  21. package/bpk-component-chatbot-input/src/hooks/useChatbotInput.d.ts +2 -1
  22. package/bpk-component-chatbot-input/src/hooks/useChatbotInput.js +3 -1
  23. package/bpk-component-chatbot-input/src/hooks/useTextAreaAutoResize.d.ts +2 -1
  24. package/bpk-component-chatbot-input/src/hooks/useTextAreaAutoResize.js +19 -6
  25. package/bpk-component-layout/index.d.ts +4 -0
  26. package/bpk-component-layout/index.js +2 -0
  27. package/bpk-component-layout/src/BpkArkProvider.d.ts +20 -0
  28. package/bpk-component-layout/src/BpkArkProvider.js +112 -0
  29. package/bpk-component-layout/src/BpkLayoutProvider.d.ts +19 -0
  30. package/bpk-component-layout/src/BpkLayoutProvider.js +50 -0
  31. package/bpk-component-layout/src/BpkProvider.d.ts +6 -7
  32. package/bpk-component-layout/src/BpkProvider.js +13 -96
  33. package/bpk-component-layout/src/resolveTextStyle.d.ts +13 -0
  34. package/bpk-component-layout/src/resolveTextStyle.js +265 -0
  35. package/bpk-component-layout/src/theme.js +29 -252
  36. package/bpk-component-layout/src/tokenUtils.js +31 -9
  37. package/bpk-component-select/index.d.ts +5 -0
  38. package/bpk-component-select/index.js +3 -1
  39. package/bpk-component-select/src/BpkSelect.d.ts +18 -0
  40. package/bpk-component-select/src/BpkSelect.js +3 -28
  41. package/bpk-component-select/src/themeAttributes.d.ts +2 -0
  42. package/bpk-component-text/src/BpkText.module.css +1 -1
  43. package/bpk-component-theme-toggle/src/BpkThemeToggle.js +0 -1
  44. package/bpk-scrim-utils/src/focusScope.d.ts +5 -0
  45. package/bpk-scrim-utils/src/focusScope.js +88 -0
  46. package/bpk-scrim-utils/src/focusStore.d.ts +6 -0
  47. package/bpk-scrim-utils/src/focusStore.js +74 -0
  48. package/bpk-scrim-utils/src/withScrim.js +2 -5
  49. package/bpk-stylesheets/base.css +1 -1
  50. package/bpk-stylesheets/font.css +1 -1
  51. package/bpk-stylesheets/font.scss +80 -1
  52. package/bpk-stylesheets/larken.css +1 -1
  53. package/bpk-stylesheets/larken.scss +63 -1
  54. package/package.json +3 -5
  55. package/bpk-component-chatbot-input/src/SendButton/SendButton.d.ts +0 -9
  56. package/bpk-component-chatbot-input/src/SendButton/SendButton.js +0 -47
@@ -15,4 +15,4 @@
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
17
  */
18
- .bpk-ai-blurb{display:flex;flex-direction:column;gap:.5rem}.bpk-ai-blurb__header{color:#626971}.bpk-ai-blurb__header svg{fill:currentcolor}.bpk-ai-blurb__summary{display:block}.bpk-ai-blurb__error{display:flex;margin:0;flex-wrap:wrap;align-items:baseline;gap:0 .25rem;font-size:.75rem;line-height:1rem;font-weight:400}.bpk-ai-blurb__feedback-thumb{display:inline-flex;padding:0;align-items:center;border:none;background:none;color:#161616;cursor:pointer;font-size:.75rem;line-height:1rem;font-weight:400}.bpk-ai-blurb__feedback-thumb svg{fill:currentcolor}.bpk-ai-blurb__feedback-thumb:hover{color:#626971}.bpk-ai-blurb__feedback-thumb:focus-visible{outline:.125rem solid #0062e3;outline-offset:.125rem}.bpk-ai-blurb__ellipsis{display:inline;vertical-align:baseline;margin-inline-start:.25rem}.bpk-ai-blurb__ellipsis-dot{display:inline;opacity:0;vertical-align:baseline;animation:bpk-ai-blurb-ellipsis-dot-1 1.2s infinite step-end}@media(prefers-reduced-motion: reduce){.bpk-ai-blurb__ellipsis-dot{opacity:1;animation:none}}.bpk-ai-blurb__ellipsis-dot--2{animation-name:bpk-ai-blurb-ellipsis-dot-2}.bpk-ai-blurb__ellipsis-dot--3{animation-name:bpk-ai-blurb-ellipsis-dot-3}@keyframes bpk-ai-blurb-ellipsis-dot-1{0%{opacity:1}75%{opacity:0}100%{opacity:0}}@keyframes bpk-ai-blurb-ellipsis-dot-2{0%{opacity:0}25%{opacity:1}75%{opacity:0}100%{opacity:0}}@keyframes bpk-ai-blurb-ellipsis-dot-3{0%{opacity:0}50%{opacity:1}75%{opacity:0}100%{opacity:0}}
18
+ .bpk-ai-blurb{display:flex;flex-direction:column;gap:.5rem}.bpk-ai-blurb__header{color:#626971}.bpk-ai-blurb__header svg{fill:currentcolor}.bpk-ai-blurb__summary{display:block}.bpk-ai-blurb__error{display:flex;margin:0;flex-wrap:wrap;align-items:baseline;gap:0 .25rem;font-size:.75rem;line-height:1rem;font-weight:400}.bpk-ai-blurb__ellipsis{display:inline;vertical-align:baseline;margin-inline-start:.25rem}.bpk-ai-blurb__ellipsis-dot{display:inline;opacity:0;vertical-align:baseline;animation:bpk-ai-blurb-ellipsis-dot-1 1.2s infinite step-end}@media(prefers-reduced-motion: reduce){.bpk-ai-blurb__ellipsis-dot{opacity:1;animation:none}}.bpk-ai-blurb__ellipsis-dot--2{animation-name:bpk-ai-blurb-ellipsis-dot-2}.bpk-ai-blurb__ellipsis-dot--3{animation-name:bpk-ai-blurb-ellipsis-dot-3}@keyframes bpk-ai-blurb-ellipsis-dot-1{0%{opacity:1}75%{opacity:0}100%{opacity:0}}@keyframes bpk-ai-blurb-ellipsis-dot-2{0%{opacity:0}25%{opacity:1}75%{opacity:0}100%{opacity:0}}@keyframes bpk-ai-blurb-ellipsis-dot-3{0%{opacity:0}50%{opacity:1}75%{opacity:0}100%{opacity:0}}
@@ -18,14 +18,10 @@
18
18
 
19
19
  import { useState } from 'react';
20
20
  import BpkAriaLive from "../../bpk-component-aria-live";
21
- import BpkSmallThumbsDownIcon from "../../bpk-component-icon/sm/thumbs-down";
22
- import BpkSmallThumbsUpIcon from "../../bpk-component-icon/sm/thumbs-up";
23
21
  import { BpkFlex, BpkSpacing } from "../../bpk-component-layout";
24
22
  import BpkText, { TEXT_STYLES } from "../../bpk-component-text";
25
- import { cssModules } from "../../bpk-react-utils";
26
- import STYLES from "./BpkAiBlurb.module.css";
23
+ import BpkThumbButton from "../../bpk-component-thumb-button";
27
24
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
28
- const getClassName = cssModules(STYLES);
29
25
  const BpkAiBlurbFeedback = ({
30
26
  feedbackText,
31
27
  onFeedback,
@@ -45,22 +41,18 @@ const BpkAiBlurbFeedback = ({
45
41
  children: [/*#__PURE__*/_jsx(BpkText, {
46
42
  textStyle: TEXT_STYLES.caption,
47
43
  children: feedbackText
48
- }), /*#__PURE__*/_jsx("button", {
49
- type: "button",
50
- className: getClassName('bpk-ai-blurb__feedback-thumb'),
51
- onClick: () => handleVote(true),
52
- "aria-label": thumbsUpLabel,
53
- children: /*#__PURE__*/_jsx(BpkSmallThumbsUpIcon, {
54
- "aria-hidden": true
55
- })
56
- }), /*#__PURE__*/_jsx("button", {
57
- type: "button",
58
- className: getClassName('bpk-ai-blurb__feedback-thumb'),
59
- onClick: () => handleVote(false),
60
- "aria-label": thumbsDownLabel,
61
- children: /*#__PURE__*/_jsx(BpkSmallThumbsDownIcon, {
62
- "aria-hidden": true
63
- })
44
+ }), /*#__PURE__*/_jsx(BpkThumbButton, {
45
+ type: "up",
46
+ size: "small",
47
+ iconColor: "primary",
48
+ accessibilityLabel: thumbsUpLabel,
49
+ onClick: () => handleVote(true)
50
+ }), /*#__PURE__*/_jsx(BpkThumbButton, {
51
+ type: "down",
52
+ size: "small",
53
+ iconColor: "primary",
54
+ accessibilityLabel: thumbsDownLabel,
55
+ onClick: () => handleVote(false)
64
56
  })]
65
57
  }), /*#__PURE__*/_jsx(BpkAriaLive, {
66
58
  visible: hasVoted,
@@ -15,4 +15,4 @@
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
17
  */
18
- .bpk-bubble{position:relative;display:inline-flex;width:auto;height:1.25rem;padding:0 .5rem;flex-direction:column;justify-content:center;border-radius:.25rem;background-color:#e70866;font-family:var(--bpk-larken-font-stack, "Larken", "Noto Sans Arabic", "Noto Serif Hebrew", "Noto Serif", "Noto Serif Devanagari", "Noto Serif Thai", "Noto Serif TC", "Noto Serif JP", "Noto Serif KR", "Noto Serif SC", sans-serif);text-align:center;white-space:nowrap;font-size:.75rem;line-height:1rem;font-weight:400}.bpk-bubble__arrow{position:absolute;bottom:-5px;left:50%;transform:translateX(-50%);color:#e70866}
18
+ .bpk-bubble{position:relative;display:inline-flex;width:auto;height:1.25rem;padding:0 .5rem;flex-direction:column;justify-content:center;border-radius:.25rem;background-color:#e70866;font-family:var(--bpk-larken-font-stack, "Larken", sans-serif);text-align:center;white-space:nowrap;font-size:.75rem;line-height:1rem;font-weight:400}.bpk-bubble__arrow{position:absolute;bottom:-5px;left:50%;transform:translateX(-50%);color:#e70866}
@@ -1,5 +1,5 @@
1
1
  import type { ChangeEvent, MouseEvent } from 'react';
2
- type MonthChangeEvent = ChangeEvent<HTMLInputElement> | MouseEvent<HTMLButtonElement>;
2
+ type MonthChangeEvent = ChangeEvent<HTMLSelectElement> | MouseEvent<HTMLButtonElement>;
3
3
  type Props = {
4
4
  changeMonthLabel: string;
5
5
  /**
@@ -20,7 +20,6 @@ import { textColors } from '@skyscanner/bpk-foundations-web/tokens/base.es6';
20
20
  import BpkAriaLive from "../../bpk-component-aria-live";
21
21
  import ArrowLeftIcon from "../../bpk-component-icon/lg/arrow-left";
22
22
  import ArrowRightIcon from "../../bpk-component-icon/lg/arrow-right";
23
- // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
24
23
  import BpkSelect from "../../bpk-component-select";
25
24
  import { cssModules, getDataComponentAttribute } from "../../bpk-react-utils";
26
25
  import { addMonths, formatIsoMonth, getMonthRange, getMonthsInRange, isWithinRange, parseIsoDate, startOfMonth } from "./date-utils";
@@ -1,7 +1,6 @@
1
1
  import BpkChatbotInput from './src/BpkChatbotInput';
2
- export type { BpkChatbotInputProps } from './src/common-types';
2
+ export type { BpkChatbotInputInputProps, BpkChatbotInputNamespace, BpkChatbotInputRootProps, BpkChatbotInputToolbarProps, ChatbotInputType, SendButtonRenderProps, } from './src/common-types';
3
3
  export { CHATBOT_INPUT_TYPES } from './src/common-types';
4
- export type { ChatbotInputType } from './src/common-types';
5
4
  export { useChatbotInputManager } from './src/hooks';
6
5
  export { default as themeAttributes } from './src/themeAttributes';
7
6
  export default BpkChatbotInput;
@@ -1,4 +1,14 @@
1
- import type { BpkChatbotInputProps } from './common-types';
2
- export type { BpkChatbotInputProps };
3
- declare const BpkChatbotInput: ({ inputType, inputValue, isPolling, isSending, loadingAriaLabel, maxCharacters, onInputBlur, onInputChange, onInputClick, onInputFocus, onKeyDown, onSubmit, placeholder, sendAriaLabel, }: BpkChatbotInputProps) => import("react/jsx-runtime").JSX.Element;
1
+ import type { BpkChatbotInputNamespace } from './common-types';
2
+ /**
3
+ * BpkChatbotInput is a composable chatbot input namespace for Backpack.
4
+ *
5
+ * @example
6
+ * <BpkChatbotInput.Root>
7
+ * <BpkChatbotInput.Input {...inputProps} />
8
+ * <BpkChatbotInput.Toolbar>
9
+ * <BpkButton type={BUTTON_TYPES.link}>Attach</BpkButton>
10
+ * </BpkChatbotInput.Toolbar>
11
+ * </BpkChatbotInput.Root>
12
+ */
13
+ declare const BpkChatbotInput: BpkChatbotInputNamespace;
4
14
  export default BpkChatbotInput;
@@ -16,103 +16,23 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import { BpkFlex, BpkSpacing } from "../../bpk-component-layout";
20
- import { cssModules, getDataComponentAttribute } from "../../bpk-react-utils";
21
- import InputField from "./InputField/InputField";
22
- import SendButton from "./SendButton/SendButton";
23
- import TextAreaField from "./TextAreaField/TextAreaField";
24
- import { CHATBOT_INPUT_TYPES } from "./common-types";
25
- import { MAX_CHARACTERS } from "./constants";
26
- import { useChatbotInput } from "./hooks";
27
- import STYLES from "./BpkChatbotInput.module.css";
28
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
29
- const getClassName = cssModules(STYLES);
30
- const BpkChatbotInput = ({
31
- inputType = CHATBOT_INPUT_TYPES.COMPOSER,
32
- inputValue,
33
- isPolling = false,
34
- isSending = false,
35
- loadingAriaLabel,
36
- maxCharacters = MAX_CHARACTERS,
37
- onInputBlur,
38
- onInputChange,
39
- onInputClick = () => {},
40
- onInputFocus,
41
- onKeyDown = () => {},
42
- onSubmit,
43
- placeholder,
44
- sendAriaLabel
45
- }) => {
46
- const {
47
- containerHeight,
48
- handleSubmit,
49
- inputProps,
50
- inputRef,
51
- isCapped,
52
- isCars,
53
- isExpanding,
54
- isOverLimit,
55
- sendButtonDisabled,
56
- textareaHeight
57
- } = useChatbotInput({
58
- placeholder,
59
- inputType,
60
- inputValue,
61
- isPolling,
62
- isSending,
63
- maxCharacters,
64
- onInputBlur,
65
- onInputChange,
66
- onInputClick,
67
- onInputFocus,
68
- onKeyDown,
69
- onSubmit
70
- });
71
- const isComposer = inputType === CHATBOT_INPUT_TYPES.COMPOSER;
72
- const containerClassName = getClassName(isCars ? 'bpk-chatbot-input--cars' : 'bpk-chatbot-input--composer', isComposer && 'bpk-chatbot-input--composer--with-shadow', isOverLimit && !isCars && 'bpk-chatbot-input--composer--overLimit');
73
- const flexProps = isCars ? {
74
- align: 'center',
75
- gap: BpkSpacing.MD,
76
- paddingTop: BpkSpacing.MD,
77
- paddingBottom: BpkSpacing.MD,
78
- paddingEnd: BpkSpacing.MD,
79
- paddingStart: BpkSpacing.Base
80
- } : {
81
- align: isExpanding ? 'flex-end' : 'center',
82
- gap: BpkSpacing.Base,
83
- padding: BpkSpacing.Base
84
- };
85
- const handleContainerEvent = e => {
86
- e.stopPropagation();
87
- };
88
- return /*#__PURE__*/_jsx("div", {
89
- className: containerClassName,
90
- onClick: handleContainerEvent,
91
- onTouchStart: handleContainerEvent,
92
- role: "presentation",
93
- "data-testid": "bpk-chatbot-input-container",
94
- ...getDataComponentAttribute('ChatbotInput'),
95
- children: /*#__PURE__*/_jsxs(BpkFlex, {
96
- ...flexProps,
97
- children: [isCars ? /*#__PURE__*/_jsx(InputField, {
98
- ref: inputRef,
99
- ...inputProps
100
- }) : /*#__PURE__*/_jsx(TextAreaField, {
101
- ref: inputRef,
102
- containerHeight: containerHeight,
103
- textareaHeight: textareaHeight,
104
- isCapped: isCapped,
105
- isExpanding: isExpanding,
106
- isComposer: isComposer,
107
- ...inputProps
108
- }), /*#__PURE__*/_jsx(SendButton, {
109
- isCars: isCars,
110
- disabled: sendButtonDisabled,
111
- onClick: handleSubmit,
112
- ariaLabel: isCars && isPolling ? loadingAriaLabel : sendAriaLabel,
113
- isLoading: !!(isCars && isPolling)
114
- })]
115
- })
116
- });
19
+ import BpkChatbotInputInput from "./BpkChatbotInputInput";
20
+ import BpkChatbotInputRoot from "./BpkChatbotInputRoot";
21
+ import BpkChatbotInputToolbar from "./BpkChatbotInputToolbar";
22
+ /**
23
+ * BpkChatbotInput is a composable chatbot input namespace for Backpack.
24
+ *
25
+ * @example
26
+ * <BpkChatbotInput.Root>
27
+ * <BpkChatbotInput.Input {...inputProps} />
28
+ * <BpkChatbotInput.Toolbar>
29
+ * <BpkButton type={BUTTON_TYPES.link}>Attach</BpkButton>
30
+ * </BpkChatbotInput.Toolbar>
31
+ * </BpkChatbotInput.Root>
32
+ */
33
+ const BpkChatbotInput = {
34
+ Root: BpkChatbotInputRoot,
35
+ Input: BpkChatbotInputInput,
36
+ Toolbar: BpkChatbotInputToolbar
117
37
  };
118
38
  export default BpkChatbotInput;
@@ -15,4 +15,4 @@
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
17
  */
18
- .bpk-chatbot-input--cars{transition:border-color 200ms ease,box-shadow 200ms ease;border:.09375rem solid #c1c7cf;background:#fff;box-shadow:none;box-sizing:border-box;touch-action:manipulation;border-radius:.75rem;border-radius:var(--bpk-chatbot-input-border-radius, 0.75rem)}.bpk-no-touch-support .bpk-chatbot-input--cars:hover:not(:active):not(:disabled){border-color:#0062e3;border-color:var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227))}:global(.bpk-no-touch-support) .bpk-chatbot-input--cars:hover:not(:active):not(:disabled){border-color:#0062e3;border-color:var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227))}.bpk-chatbot-input--cars:active{border-color:#0062e3;border-color:var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227))}.bpk-chatbot-input--cars:focus-within{box-shadow:0 0 0 .03125rem #0062e3;box-shadow:0 0 0 .03125rem var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227));border-color:#0062e3;border-color:var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227))}.bpk-chatbot-input--composer{position:relative;transition:transform .3s cubic-bezier(0.4, 0, 0.2, 1),box-shadow .3s cubic-bezier(0.4, 0, 0.2, 1);border:none;background:#fff;box-sizing:border-box;will-change:transform,box-shadow;border-radius:.75rem;border-radius:var(--bpk-chatbot-input-border-radius, 0.75rem)}.bpk-chatbot-input--composer--with-shadow:focus-within{box-shadow:0px 12px 50px 0px rgba(37,32,31,.25)}.bpk-chatbot-input--composer--overLimit{transform:translateY(-0.25rem)}
18
+ .bpk-chatbot-input--cars{transition:border-color 200ms ease,box-shadow 200ms ease;border:.09375rem solid #c1c7cf;background:#fff;box-shadow:none;box-sizing:border-box;touch-action:manipulation;border-radius:.75rem;border-radius:var(--bpk-chatbot-input-border-radius, 0.75rem)}.bpk-no-touch-support .bpk-chatbot-input--cars:hover:not(:active):not(:disabled){border-color:#0062e3;border-color:var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227))}:global(.bpk-no-touch-support) .bpk-chatbot-input--cars:hover:not(:active):not(:disabled){border-color:#0062e3;border-color:var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227))}.bpk-chatbot-input--cars:active{border-color:#0062e3;border-color:var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227))}.bpk-chatbot-input--cars:focus-within{box-shadow:0 0 0 .03125rem #0062e3;box-shadow:0 0 0 .03125rem var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227));border-color:#0062e3;border-color:var(--bpk-chatbot-input-focus-border-color, rgb(0, 98, 227))}.bpk-chatbot-input--composer{position:relative;transition:transform .3s cubic-bezier(0.4, 0, 0.2, 1),box-shadow .3s cubic-bezier(0.4, 0, 0.2, 1);border:none;background:#fff;box-sizing:border-box;will-change:transform,box-shadow;border-radius:.75rem;border-radius:var(--bpk-chatbot-input-border-radius, 0.75rem)}.bpk-chatbot-input--composer--with-shadow:focus-within{box-shadow:0px 4px 14px 0px rgba(37,32,31,.25)}.bpk-chatbot-input--composer--overLimit{transform:translateY(-0.25rem)}
@@ -0,0 +1,9 @@
1
+ import type { ChatbotInputType } from './common-types';
2
+ type BpkChatbotInputContextValue = {
3
+ inputType: ChatbotInputType;
4
+ isOverLimit: boolean;
5
+ setIsOverLimit: (value: boolean) => void;
6
+ };
7
+ export declare const BpkChatbotInputContext: import("react").Context<BpkChatbotInputContextValue>;
8
+ export declare const useChatbotInputContext: () => BpkChatbotInputContextValue;
9
+ export {};
@@ -0,0 +1,26 @@
1
+ /*
2
+ * Backpack - Skyscanner's Design System
3
+ *
4
+ * Copyright 2016 Skyscanner Ltd
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ import { createContext, useContext } from 'react';
20
+ import { CHATBOT_INPUT_TYPES } from "./common-types";
21
+ export const BpkChatbotInputContext = /*#__PURE__*/createContext({
22
+ inputType: CHATBOT_INPUT_TYPES.COMPOSER,
23
+ isOverLimit: false,
24
+ setIsOverLimit: () => {}
25
+ });
26
+ export const useChatbotInputContext = () => useContext(BpkChatbotInputContext);
@@ -0,0 +1,3 @@
1
+ import type { BpkChatbotInputInputProps } from './common-types';
2
+ declare const BpkChatbotInputInput: ({ inputValue, isPolling, isSending, loadingAriaLabel, maxCharacters, maxLines, onInputBlur, onInputChange, onInputClick, onInputFocus, onKeyDown, onSubmit, placeholder, renderSendButton, sendAriaLabel, }: BpkChatbotInputInputProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default BpkChatbotInputInput;
@@ -0,0 +1,125 @@
1
+ /*
2
+ * Backpack - Skyscanner's Design System
3
+ *
4
+ * Copyright 2016 Skyscanner Ltd
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ import { useEffect } from 'react';
20
+ import BpkButton, { BUTTON_TYPES, SIZE_TYPES } from "../../bpk-component-button";
21
+ import { withButtonAlignment } from "../../bpk-component-icon";
22
+ import ArrowUpIcon from "../../bpk-component-icon/sm/long-arrow-up";
23
+ import { BpkFlex, BpkSpacing } from "../../bpk-component-layout";
24
+ import { getDataComponentAttribute } from "../../bpk-react-utils";
25
+ import { useChatbotInputContext } from "./BpkChatbotInputContext";
26
+ import InputField from "./InputField/InputField";
27
+ import TextAreaField from "./TextAreaField/TextAreaField";
28
+ import { CHATBOT_INPUT_TYPES } from "./common-types";
29
+ import { MAX_CHARACTERS } from "./constants";
30
+ import { useChatbotInput } from "./hooks";
31
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
32
+ const AlignedArrowUpIcon = withButtonAlignment(ArrowUpIcon);
33
+ const BpkChatbotInputInput = ({
34
+ inputValue,
35
+ isPolling = false,
36
+ isSending = false,
37
+ loadingAriaLabel,
38
+ maxCharacters = MAX_CHARACTERS,
39
+ maxLines,
40
+ onInputBlur,
41
+ onInputChange,
42
+ onInputClick = () => {},
43
+ onInputFocus,
44
+ onKeyDown = () => {},
45
+ onSubmit,
46
+ placeholder,
47
+ renderSendButton,
48
+ sendAriaLabel
49
+ }) => {
50
+ const {
51
+ inputType,
52
+ setIsOverLimit
53
+ } = useChatbotInputContext();
54
+ const {
55
+ containerHeight,
56
+ handleSubmit,
57
+ inputProps,
58
+ inputRef,
59
+ isCapped,
60
+ isCars,
61
+ isExpanding,
62
+ isOverLimit,
63
+ sendButtonDisabled,
64
+ textareaHeight
65
+ } = useChatbotInput({
66
+ placeholder,
67
+ inputType,
68
+ inputValue,
69
+ isPolling,
70
+ isSending,
71
+ maxCharacters,
72
+ maxLines,
73
+ onInputBlur,
74
+ onInputChange,
75
+ onInputClick,
76
+ onInputFocus,
77
+ onKeyDown,
78
+ onSubmit
79
+ });
80
+ useEffect(() => {
81
+ setIsOverLimit(isOverLimit);
82
+ }, [isOverLimit, setIsOverLimit]);
83
+ const isComposer = inputType === CHATBOT_INPUT_TYPES.COMPOSER;
84
+ const flexProps = isCars ? {
85
+ align: 'center',
86
+ gap: BpkSpacing.MD
87
+ } : {
88
+ align: isExpanding ? 'flex-end' : 'center',
89
+ gap: BpkSpacing.Base
90
+ };
91
+ return /*#__PURE__*/_jsxs(BpkFlex, {
92
+ width: "100%",
93
+ ...flexProps,
94
+ ...getDataComponentAttribute('ChatbotInput.Input'),
95
+ children: [isCars ? /*#__PURE__*/_jsx(InputField, {
96
+ ref: inputRef,
97
+ ...inputProps
98
+ }) : /*#__PURE__*/_jsx(TextAreaField, {
99
+ ref: inputRef,
100
+ containerHeight: containerHeight,
101
+ textareaHeight: textareaHeight,
102
+ isCapped: isCapped,
103
+ isExpanding: isExpanding,
104
+ isComposer: isComposer,
105
+ maxLines: maxLines,
106
+ ...inputProps
107
+ }), renderSendButton ? renderSendButton({
108
+ disabled: sendButtonDisabled,
109
+ onClick: handleSubmit,
110
+ loading: isPolling,
111
+ ariaLabel: isPolling ? loadingAriaLabel : sendAriaLabel
112
+ }) : /*#__PURE__*/_jsx(BpkButton, {
113
+ type: BUTTON_TYPES.primary,
114
+ size: SIZE_TYPES.small,
115
+ iconOnly: true,
116
+ onClick: handleSubmit,
117
+ disabled: sendButtonDisabled,
118
+ loading: isPolling,
119
+ "aria-label": isPolling ? loadingAriaLabel : sendAriaLabel,
120
+ "data-testid": "bpk-chatbot-input-send",
121
+ children: /*#__PURE__*/_jsx(AlignedArrowUpIcon, {})
122
+ })]
123
+ });
124
+ };
125
+ export default BpkChatbotInputInput;
@@ -0,0 +1,3 @@
1
+ import type { BpkChatbotInputRootProps } from './common-types';
2
+ declare const BpkChatbotInputRoot: ({ align, children, gap, inputType, ...rest }: BpkChatbotInputRootProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default BpkChatbotInputRoot;
@@ -0,0 +1,77 @@
1
+ /*
2
+ * Backpack - Skyscanner's Design System
3
+ *
4
+ * Copyright 2016 Skyscanner Ltd
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ import { useCallback, useMemo, useState } from 'react';
20
+ import { BpkVStack, BpkSpacing } from "../../bpk-component-layout";
21
+ import { cssModules, getDataComponentAttribute } from "../../bpk-react-utils";
22
+ import { BpkChatbotInputContext } from "./BpkChatbotInputContext";
23
+ import { CHATBOT_INPUT_TYPES } from "./common-types";
24
+ import STYLES from "./BpkChatbotInput.module.css";
25
+ import { jsx as _jsx } from "react/jsx-runtime";
26
+ const getClassName = cssModules(STYLES);
27
+ const BpkChatbotInputRoot = ({
28
+ align = 'flex-start',
29
+ children,
30
+ gap = BpkSpacing.Base,
31
+ inputType = CHATBOT_INPUT_TYPES.COMPOSER,
32
+ ...rest
33
+ }) => {
34
+ const isCars = inputType === CHATBOT_INPUT_TYPES.CARS;
35
+ const isComposer = inputType === CHATBOT_INPUT_TYPES.COMPOSER;
36
+ const [isOverLimit, setIsOverLimit] = useState(false);
37
+ const stableSetIsOverLimit = useCallback(value => {
38
+ setIsOverLimit(value);
39
+ }, []);
40
+ const contextValue = useMemo(() => ({
41
+ inputType,
42
+ isOverLimit,
43
+ setIsOverLimit: stableSetIsOverLimit
44
+ }), [inputType, isOverLimit, stableSetIsOverLimit]);
45
+ const containerClassName = getClassName(isCars ? 'bpk-chatbot-input--cars' : 'bpk-chatbot-input--composer', isComposer && 'bpk-chatbot-input--composer--with-shadow', isOverLimit && !isCars && 'bpk-chatbot-input--composer--overLimit');
46
+ const paddingProps = isCars ? {
47
+ paddingTop: BpkSpacing.MD,
48
+ paddingBottom: BpkSpacing.MD,
49
+ paddingEnd: BpkSpacing.MD,
50
+ paddingStart: BpkSpacing.Base
51
+ } : {
52
+ padding: BpkSpacing.Base
53
+ };
54
+ const handleContainerEvent = e => {
55
+ e.stopPropagation();
56
+ };
57
+ return /*#__PURE__*/_jsx(BpkChatbotInputContext.Provider, {
58
+ value: contextValue,
59
+ children: /*#__PURE__*/_jsx("div", {
60
+ className: containerClassName,
61
+ onClick: handleContainerEvent,
62
+ onTouchStart: handleContainerEvent,
63
+ role: "presentation",
64
+ "data-testid": "bpk-chatbot-input-container",
65
+ ...getDataComponentAttribute('ChatbotInput'),
66
+ children: /*#__PURE__*/_jsx(BpkVStack, {
67
+ align: align,
68
+ gap: gap,
69
+ width: "100%",
70
+ ...paddingProps,
71
+ ...rest,
72
+ children: children
73
+ })
74
+ })
75
+ });
76
+ };
77
+ export default BpkChatbotInputRoot;
@@ -0,0 +1,3 @@
1
+ import type { BpkChatbotInputToolbarProps } from './common-types';
2
+ declare const BpkChatbotInputToolbar: ({ children, gap, ...rest }: BpkChatbotInputToolbarProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default BpkChatbotInputToolbar;
@@ -0,0 +1,33 @@
1
+ /*
2
+ * Backpack - Skyscanner's Design System
3
+ *
4
+ * Copyright 2016 Skyscanner Ltd
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ */
18
+
19
+ import { BpkHStack, BpkSpacing } from "../../bpk-component-layout";
20
+ import { getDataComponentAttribute } from "../../bpk-react-utils";
21
+ import { jsx as _jsx } from "react/jsx-runtime";
22
+ const BpkChatbotInputToolbar = ({
23
+ children,
24
+ gap = BpkSpacing.Base,
25
+ ...rest
26
+ }) => /*#__PURE__*/_jsx(BpkHStack, {
27
+ gap: gap,
28
+ width: "100%",
29
+ ...getDataComponentAttribute('ChatbotInput.Toolbar'),
30
+ ...rest,
31
+ children: children
32
+ });
33
+ export default BpkChatbotInputToolbar;
@@ -5,6 +5,7 @@ interface TextAreaFieldProps extends BaseInputFieldProps {
5
5
  isCapped: boolean;
6
6
  isExpanding: boolean;
7
7
  isComposer: boolean;
8
+ maxLines?: number;
8
9
  }
9
10
  declare const TextAreaField: import("react").ForwardRefExoticComponent<TextAreaFieldProps & import("react").RefAttributes<HTMLTextAreaElement>>;
10
11
  export default TextAreaField;
@@ -30,6 +30,7 @@ const TextAreaField = /*#__PURE__*/forwardRef(({
30
30
  isComposer,
31
31
  isExpanding,
32
32
  isOverLimit = false,
33
+ maxLines,
33
34
  onInputBlur,
34
35
  onInputChange,
35
36
  onInputClick,
@@ -84,7 +85,10 @@ const TextAreaField = /*#__PURE__*/forwardRef(({
84
85
  rows: 1,
85
86
  style: {
86
87
  height: `${textareaHeight}px`,
87
- resize: 'none'
88
+ resize: 'none',
89
+ ...(maxLines !== undefined && {
90
+ maxHeight: `${textareaHeight}px`
91
+ })
88
92
  }
89
93
  })]
90
94
  })
@@ -1,11 +1,19 @@
1
- import type { KeyboardEvent } from 'react';
1
+ import type { KeyboardEvent, ReactElement, ReactNode } from 'react';
2
+ import type { Props as BpkButtonProps } from '../../bpk-component-button';
3
+ import type { BpkStackProps } from '../../bpk-component-layout';
2
4
  export declare const CHATBOT_INPUT_TYPES: {
3
5
  readonly CARS: "cars";
4
6
  readonly CARS_COMPOSER: "cars-composer";
5
7
  readonly COMPOSER: "composer";
6
8
  };
7
9
  export type ChatbotInputType = (typeof CHATBOT_INPUT_TYPES)[keyof typeof CHATBOT_INPUT_TYPES];
8
- export type BpkChatbotInputProps = {
10
+ export type SendButtonRenderProps = {
11
+ disabled: boolean;
12
+ onClick: () => void;
13
+ loading: boolean;
14
+ ariaLabel: string;
15
+ };
16
+ export type BpkChatbotInputInputProps = {
9
17
  inputValue: string;
10
18
  /** Accessible label for the loading state button (required for screen readers). */
11
19
  loadingAriaLabel: string;
@@ -18,10 +26,22 @@ export type BpkChatbotInputProps = {
18
26
  placeholder: string;
19
27
  isSending?: boolean;
20
28
  isPolling?: boolean;
21
- inputType?: ChatbotInputType;
22
29
  maxCharacters?: number;
30
+ /** Maximum number of visible lines before the textarea scrolls. Defaults to 4 (expanding to 5 when content exceeds 4 lines). Only applies to multiline input types. */
31
+ maxLines?: number;
23
32
  onInputClick?: () => void;
24
33
  onKeyDown?: (e: KeyboardEvent) => void;
34
+ /** Optional render prop for customising the send button. The consumer should return a BpkButton with the supplied props. When omitted, the default send button is used. */
35
+ renderSendButton?: (props: SendButtonRenderProps) => ReactElement<BpkButtonProps>;
36
+ };
37
+ export type BpkChatbotInputRootProps = BpkStackProps & {
38
+ inputType?: ChatbotInputType;
39
+ };
40
+ export type BpkChatbotInputToolbarProps = BpkStackProps;
41
+ export type BpkChatbotInputNamespace = {
42
+ Root: (props: BpkChatbotInputRootProps) => ReactNode;
43
+ Input: (props: BpkChatbotInputInputProps) => ReactNode;
44
+ Toolbar: (props: BpkChatbotInputToolbarProps) => ReactNode;
25
45
  };
26
46
  export interface BaseInputFieldProps {
27
47
  value: string;
@@ -11,6 +11,7 @@ interface UseChatbotInputOptions {
11
11
  isPolling?: boolean;
12
12
  inputType?: ChatbotInputType;
13
13
  maxCharacters?: number;
14
+ maxLines?: number;
14
15
  onInputClick?: () => void;
15
16
  onKeyDown?: (e: KeyboardEvent) => void;
16
17
  }
@@ -28,5 +29,5 @@ interface UseChatbotInputReturn {
28
29
  textareaHeight: number;
29
30
  isCapped: boolean;
30
31
  }
31
- declare const useChatbotInput: ({ inputType, inputValue, isPolling, isSending, maxCharacters, onInputBlur, onInputChange, onInputClick, onInputFocus, onKeyDown, onSubmit, placeholder, }: UseChatbotInputOptions) => UseChatbotInputReturn;
32
+ declare const useChatbotInput: ({ inputType, inputValue, isPolling, isSending, maxCharacters, maxLines, onInputBlur, onInputChange, onInputClick, onInputFocus, onKeyDown, onSubmit, placeholder, }: UseChatbotInputOptions) => UseChatbotInputReturn;
32
33
  export default useChatbotInput;
@@ -26,6 +26,7 @@ const useChatbotInput = ({
26
26
  isPolling = false,
27
27
  isSending = false,
28
28
  maxCharacters = MAX_CHARACTERS,
29
+ maxLines,
29
30
  onInputBlur,
30
31
  onInputChange,
31
32
  onInputClick = () => {},
@@ -48,7 +49,8 @@ const useChatbotInput = ({
48
49
  } = useTextAreaAutoResize({
49
50
  ref: inputRef,
50
51
  value: inputValue,
51
- enabled: isMultiLine
52
+ enabled: isMultiLine,
53
+ maxLines
52
54
  });
53
55
  const handleSubmit = useCallback(() => {
54
56
  if (inputValue.trim() && !isDisabled && !isOverLimit) {