@skyscanner/backpack-web 38.7.0 → 38.9.0

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.
@@ -16,5 +16,6 @@
16
16
  * limitations under the License.
17
17
  */import BpkAutosuggest from "./src/BpkAutosuggest";
18
18
  import BpkAutosuggestSuggestion from "./src/BpkAutosuggestSuggestion";
19
+ import BpkAutosuggestV2 from "./src/BpkAutosuggestV2/BpkAutosuggest";
19
20
  export default BpkAutosuggest;
20
- export { BpkAutosuggestSuggestion };
21
+ export { BpkAutosuggestSuggestion, BpkAutosuggestV2 };
@@ -0,0 +1,67 @@
1
+ import type { ReactElement, HTMLProps, InputHTMLAttributes, Ref } from 'react';
2
+ export type BpkAutoSuggestTheme = {
3
+ container?: string;
4
+ containerOpen?: string;
5
+ suggestionsContainer?: string;
6
+ suggestionsContainerOpen?: string;
7
+ suggestionsList?: string;
8
+ suggestion?: string;
9
+ suggestionHighlighted?: string;
10
+ sectionContainer?: string;
11
+ sectionTitle?: string;
12
+ desktopSuggestionsContainer?: string;
13
+ desktopSuggestionsList?: string;
14
+ inputTextWrapper?: string;
15
+ inputWrapper?: string;
16
+ label?: string;
17
+ visuallyHidden?: string;
18
+ };
19
+ export type EnterKeyHintType = 'enter' | 'done' | 'go' | 'next' | 'previous' | 'search' | 'send';
20
+ export type BpkInputRenderProps = InputHTMLAttributes<HTMLInputElement> & {
21
+ ref?: Ref<HTMLInputElement>;
22
+ };
23
+ export type BpkAutoSuggestProps<T> = {
24
+ suggestions: T[];
25
+ ariaLabels?: {
26
+ resultsList?: string;
27
+ label?: string;
28
+ clearButton?: string;
29
+ noResults?: string;
30
+ };
31
+ getSuggestionValue: (suggestion: T) => string;
32
+ inputProps: HTMLProps<HTMLInputElement>;
33
+ onSuggestionSelected?: (data?: {
34
+ inputValue: string;
35
+ suggestion?: T;
36
+ }) => void;
37
+ onSuggestionsFetchRequested: (value: string) => void;
38
+ onSuggestionsClearRequested: () => void;
39
+ renderSuggestion: (suggestion: T) => ReactElement;
40
+ id: string;
41
+ enterKeyHint?: EnterKeyHintType;
42
+ getA11yResultsMessage: (resultCount: number) => string;
43
+ defaultValue?: string;
44
+ isDesktop?: boolean;
45
+ onLoad?: (inputValue: string) => void;
46
+ onClick?: () => void;
47
+ renderBesideInput?: () => ReactElement;
48
+ showClear?: boolean;
49
+ theme?: Partial<BpkAutoSuggestTheme>;
50
+ highlightFirstSuggestion?: boolean;
51
+ shouldRenderSuggestions?: (value?: string) => boolean;
52
+ multiSection?: boolean;
53
+ getSectionSuggestions?: (section: T) => T[];
54
+ renderSectionTitle?: (section: T) => ReactElement | null;
55
+ alwaysRenderSuggestions?: boolean;
56
+ onInputValueChange?: (input: {
57
+ method: string;
58
+ newValue: string;
59
+ }) => void;
60
+ renderInputComponent?: (inputProps: BpkInputRenderProps) => ReactElement;
61
+ onSuggestionHighlighted?: (data: {
62
+ suggestion: T | null;
63
+ }) => void;
64
+ focusInputOnSuggestionClick?: boolean;
65
+ };
66
+ declare const BpkAutosuggest: import("react").ForwardRefExoticComponent<BpkAutoSuggestProps<any> & import("react").RefAttributes<HTMLInputElement>>;
67
+ export default BpkAutosuggest;
@@ -0,0 +1,441 @@
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, forwardRef, useRef } from 'react';
20
+ import { useFloating, offset, flip, shift, size, arrow as floatingArrow, FloatingArrow, autoUpdate, FloatingPortal } from '@floating-ui/react';
21
+ import { useCombobox } from 'downshift';
22
+ import { surfaceHighlightDay } from '@skyscanner/bpk-foundations-web/tokens/base.es6';
23
+ import BpkInput from "../../../bpk-component-input";
24
+ import { cssModules } from "../../../bpk-react-utils";
25
+ import STYLES from "./BpkAutosuggest.module.css";
26
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
27
+ const getClassName = cssModules(STYLES);
28
+ const defaultTheme = {
29
+ container: getClassName('bpk-autosuggest__container'),
30
+ containerOpen: getClassName('bpk-autosuggest__container--open'),
31
+ suggestionsContainer: getClassName('bpk-autosuggest__suggestions-container'),
32
+ suggestionsContainerOpen: getClassName('bpk-autosuggest__suggestions-container--open'),
33
+ suggestionsList: getClassName('bpk-autosuggest__suggestions-list'),
34
+ suggestion: getClassName('bpk-autosuggest__suggestion-item'),
35
+ suggestionHighlighted: getClassName('bpk-autosuggest__suggestion-item--highlighted'),
36
+ sectionContainer: getClassName('bpk-autosuggest__section-container'),
37
+ sectionTitle: getClassName('bpk-autosuggest__section-title'),
38
+ input: getClassName('bpk-autosuggest__input'),
39
+ visuallyHidden: getClassName('bpk-autosuggest__visuallyhidden')
40
+ };
41
+ const strokeWidth = 0.0625;
42
+ const BpkAutosuggest = /*#__PURE__*/forwardRef(({
43
+ alwaysRenderSuggestions,
44
+ ariaLabels,
45
+ defaultValue,
46
+ enterKeyHint,
47
+ focusInputOnSuggestionClick = false,
48
+ getA11yResultsMessage,
49
+ getSectionSuggestions,
50
+ getSuggestionValue,
51
+ highlightFirstSuggestion,
52
+ id,
53
+ inputProps,
54
+ isDesktop = true,
55
+ multiSection,
56
+ onClick,
57
+ onInputValueChange,
58
+ onLoad,
59
+ onSuggestionHighlighted,
60
+ onSuggestionSelected,
61
+ onSuggestionsClearRequested,
62
+ onSuggestionsFetchRequested,
63
+ renderBesideInput,
64
+ renderInputComponent,
65
+ renderSectionTitle,
66
+ renderSuggestion,
67
+ shouldRenderSuggestions,
68
+ showClear = false,
69
+ suggestions,
70
+ theme: customTheme = {}
71
+ }, forwardedRef) => {
72
+ const ariaDescribedByLabelId = `${id}-srOnly`;
73
+ const theme = {
74
+ ...defaultTheme,
75
+ ...customTheme
76
+ };
77
+ const arrowRef = useRef(null);
78
+ const previousHighlightedIndexRef = useRef(null);
79
+ const hasInteractedRef = useRef(false);
80
+ const hasLoadedInitiallyRef = useRef(false);
81
+ const suggestionsCount = suggestions.length;
82
+ const hasSuggestions = suggestionsCount > 0;
83
+ function stateReducer(state, actionAndChanges) {
84
+ const {
85
+ changes,
86
+ type
87
+ } = actionAndChanges;
88
+ const shouldForceKeepOpen = alwaysRenderSuggestions && state.inputValue && state.inputValue.length > 0 && hasSuggestions && changes.isOpen === false;
89
+ if (shouldForceKeepOpen) {
90
+ return {
91
+ ...changes,
92
+ isOpen: true
93
+ };
94
+ }
95
+ switch (type) {
96
+ case useCombobox.stateChangeTypes.InputClick:
97
+ return {
98
+ ...changes,
99
+ isOpen: state.isOpen
100
+ };
101
+ default:
102
+ {
103
+ const forceOpen = !isDesktop && !!changes.inputValue;
104
+ return {
105
+ ...changes,
106
+ isOpen: forceOpen ? true : changes.isOpen
107
+ };
108
+ }
109
+ }
110
+ }
111
+ const flattenedSuggestions = multiSection ? suggestions.flatMap(section => getSectionSuggestions?.(section) ?? []) : suggestions;
112
+ const {
113
+ getInputProps,
114
+ getItemProps,
115
+ getLabelProps,
116
+ getMenuProps,
117
+ highlightedIndex,
118
+ inputValue,
119
+ isOpen,
120
+ openMenu,
121
+ setInputValue
122
+ } = useCombobox({
123
+ stateReducer,
124
+ items: flattenedSuggestions,
125
+ itemToString(suggestion) {
126
+ return suggestion ? getSuggestionValue(suggestion) : '';
127
+ },
128
+ async onInputValueChange(changes) {
129
+ const {
130
+ inputValue: newInputValue,
131
+ isOpen: newIsOpen,
132
+ type
133
+ } = changes;
134
+ onInputValueChange?.({
135
+ method: type,
136
+ newValue: newInputValue ?? ''
137
+ });
138
+ if (newInputValue?.length) {
139
+ if (newIsOpen) {
140
+ onSuggestionsFetchRequested(newInputValue);
141
+ }
142
+ } else if (suggestionsCount) {
143
+ onSuggestionsClearRequested();
144
+ }
145
+ },
146
+ onSelectedItemChange(changes) {
147
+ const {
148
+ selectedItem
149
+ } = changes;
150
+ if (selectedItem) {
151
+ setInputValue(getSuggestionValue(selectedItem));
152
+ onSuggestionSelected?.({
153
+ suggestion: selectedItem,
154
+ inputValue
155
+ });
156
+ if (alwaysRenderSuggestions) {
157
+ // Manually clear suggestions or hide menu
158
+ onSuggestionsClearRequested();
159
+ }
160
+ }
161
+ },
162
+ getA11yStatusMessage() {
163
+ return getA11yResultsMessage?.(suggestionsCount) ?? '';
164
+ },
165
+ initialInputValue: defaultValue ?? '',
166
+ id
167
+ });
168
+ const {
169
+ context,
170
+ floatingStyles,
171
+ refs
172
+ } = useFloating({
173
+ placement: 'bottom-start',
174
+ middleware: isDesktop ? [offset(17), flip(), shift(), size({
175
+ apply({
176
+ elements,
177
+ rects
178
+ }) {
179
+ Object.assign(elements.floating.style, {
180
+ width: `${rects.reference.width}px`
181
+ });
182
+ }
183
+ }), floatingArrow({
184
+ element: arrowRef
185
+ })] : [],
186
+ whileElementsMounted: isDesktop ? autoUpdate : undefined
187
+ });
188
+ useEffect(() => {
189
+ if (defaultValue) {
190
+ setInputValue(defaultValue);
191
+ } else {
192
+ setInputValue('');
193
+ }
194
+ }, [defaultValue, setInputValue]);
195
+ useEffect(() => {
196
+ if (!isDesktop) {
197
+ onLoad?.(inputValue);
198
+ }
199
+ if (alwaysRenderSuggestions) {
200
+ hasLoadedInitiallyRef.current = true;
201
+ onSuggestionsFetchRequested(inputValue ?? '');
202
+ } else if (inputValue) {
203
+ onSuggestionsFetchRequested(inputValue);
204
+ }
205
+ // fire track event on load and forget about it after. We don't want to track again when anything (inputValue) changes
206
+ // eslint-disable-next-line react-hooks/exhaustive-deps
207
+ }, []);
208
+ useEffect(() => {
209
+ if (highlightedIndex === previousHighlightedIndexRef.current) return;
210
+ previousHighlightedIndexRef.current = highlightedIndex;
211
+ const currentSuggestion = highlightedIndex != null && highlightedIndex >= 0 ? flattenedSuggestions?.[highlightedIndex] ?? null : null;
212
+ onSuggestionHighlighted?.({
213
+ suggestion: currentSuggestion
214
+ });
215
+ }, [highlightedIndex, flattenedSuggestions, onSuggestionHighlighted]);
216
+ const handleInputInteraction = () => {
217
+ hasInteractedRef.current = true;
218
+ if (shouldRenderSuggestions) {
219
+ shouldRenderSuggestions(inputValue);
220
+ openMenu();
221
+ }
222
+ if (!isOpen && inputValue.length) {
223
+ onSuggestionsFetchRequested(inputValue);
224
+ openMenu();
225
+ } else {
226
+ onClick?.();
227
+ }
228
+
229
+ // Desktop destination autosuggest lives on the homepage and is "loaded/interacted with" via clicking on it
230
+ // Every other use case is within a new screen or modal so is interacted with via the user navigating into the modal/new screen
231
+ if (isDesktop) {
232
+ onLoad?.(inputValue);
233
+ }
234
+ };
235
+ const onKeyDown = e => {
236
+ if (e.key !== 'Enter') {
237
+ return;
238
+ }
239
+ if (e.key === 'Enter' && suggestionsCount) {
240
+ onSuggestionSelected?.({
241
+ suggestion: suggestions[0],
242
+ inputValue
243
+ });
244
+ }
245
+ if (defaultValue) {
246
+ handleInputInteraction();
247
+ } else if (!hasSuggestions) {
248
+ onSuggestionSelected?.();
249
+ }
250
+ };
251
+ const handleSuggestionClick = () => {
252
+ if (!focusInputOnSuggestionClick) {
253
+ document.activeElement?.blur?.();
254
+ }
255
+ };
256
+ const clearSuggestions = e => {
257
+ e?.stopPropagation();
258
+ setInputValue('');
259
+ };
260
+
261
+ // Render suggestions function to render single section suggestion
262
+ const renderSuggestions = ({
263
+ items,
264
+ sectionId,
265
+ sectionIndex,
266
+ sectionTitle,
267
+ startIndex = 0
268
+ }) => items.map((suggestion, localIndex) => {
269
+ const globalIndex = startIndex + localIndex;
270
+ const isFirst = globalIndex === 0;
271
+ const itemId = sectionId ? `item-${sectionIndex}-${localIndex}` : undefined;
272
+ const isHighlighted = highlightedIndex === globalIndex || highlightFirstSuggestion && isFirst && highlightedIndex === -1;
273
+ return /*#__PURE__*/_jsx("li", {
274
+ "aria-labelledby": sectionId && itemId ? `${sectionId} ${itemId}` : undefined,
275
+ ...getItemProps({
276
+ item: suggestion,
277
+ index: globalIndex,
278
+ onClick: handleSuggestionClick,
279
+ 'aria-selected': highlightedIndex === globalIndex
280
+ }),
281
+ className: getClassName(theme.suggestion, isHighlighted && theme.suggestionHighlighted),
282
+ children: itemId ? /*#__PURE__*/_jsx("span", {
283
+ id: itemId,
284
+ children: renderSuggestion(suggestion)
285
+ }) : renderSuggestion(suggestion)
286
+ }, sectionTitle ? `${sectionTitle}-${getSuggestionValue(suggestion)}` : getSuggestionValue(suggestion));
287
+ });
288
+
289
+ // renderSections function to render multi-section suggestions
290
+ const renderSections = sections => {
291
+ let suggestionIndex = 0;
292
+ return sections.map((section, sectionIndex) => {
293
+ const sectionSuggestions = getSectionSuggestions?.(section) ?? [];
294
+ if (sectionSuggestions.length === 0) {
295
+ return null;
296
+ }
297
+ const sectionId = `section-${sectionIndex}`;
298
+ const sectionTitleElement = renderSectionTitle?.(section);
299
+ const sectionTitle = typeof sectionTitleElement === 'string' ? sectionTitleElement : `section-${sectionIndex}`;
300
+ const renderedItems = renderSuggestions({
301
+ items: sectionSuggestions,
302
+ sectionId,
303
+ sectionTitle,
304
+ sectionIndex,
305
+ startIndex: suggestionIndex
306
+ });
307
+ suggestionIndex += sectionSuggestions.length;
308
+ return /*#__PURE__*/_jsxs("section", {
309
+ className: theme.sectionContainer,
310
+ role: "group",
311
+ "aria-labelledby": sectionId,
312
+ children: [/*#__PURE__*/_jsx("div", {
313
+ id: sectionId,
314
+ className: theme.sectionTitle,
315
+ children: sectionTitleElement
316
+ }), renderedItems]
317
+ }, sectionTitle);
318
+ });
319
+ };
320
+ const showSuggestions = hasSuggestions && (alwaysRenderSuggestions && hasLoadedInitiallyRef.current && !hasInteractedRef.current || isOpen);
321
+ const renderList = () => multiSection ? renderSections(suggestions) : renderSuggestions({
322
+ items: suggestions
323
+ });
324
+
325
+ // Render the input component
326
+ const renderInput = () => {
327
+ const inputAriaLabel = inputValue || inputProps.placeholder;
328
+ const {
329
+ className: inputClassName,
330
+ name: inputName,
331
+ onClick: inputOnClick,
332
+ onKeyDown: inputOnKeyDown,
333
+ type: typeFromInputProps,
334
+ ...restInputProps
335
+ } = inputProps;
336
+ const {
337
+ ref: downshiftInputRef,
338
+ value,
339
+ ...finalInputProps
340
+ } = getInputProps({
341
+ onKeyDown,
342
+ ref: forwardedRef,
343
+ onClick: handleInputInteraction,
344
+ onFocus: handleInputInteraction,
345
+ 'aria-describedby': ariaDescribedByLabelId,
346
+ 'aria-label': inputAriaLabel,
347
+ className: inputClassName || theme.input,
348
+ ...restInputProps
349
+ });
350
+ const setInputRef = node => {
351
+ refs.setReference(node);
352
+
353
+ // convert input ref from Downshift
354
+ if (typeof downshiftInputRef === 'function') {
355
+ downshiftInputRef(node);
356
+ } else if (downshiftInputRef && typeof downshiftInputRef === 'object' && 'current' in downshiftInputRef) {
357
+ downshiftInputRef.current = node;
358
+ }
359
+ };
360
+ let normalizedInputValue = '';
361
+ if (Array.isArray(value)) {
362
+ normalizedInputValue = value.join(', ');
363
+ } else if (typeof value === 'string' || typeof value === 'number') {
364
+ normalizedInputValue = value;
365
+ }
366
+ if (renderInputComponent) {
367
+ return renderInputComponent({
368
+ ref: setInputRef,
369
+ enterKeyHint,
370
+ value,
371
+ ...finalInputProps
372
+ });
373
+ }
374
+ return /*#__PURE__*/_jsx("div", {
375
+ className: getClassName(theme.label),
376
+ children: /*#__PURE__*/_jsxs("div", {
377
+ className: getClassName(theme.inputTextWrapper),
378
+ children: [/*#__PURE__*/_jsx("label", {
379
+ "aria-hidden": true,
380
+ ...getLabelProps(),
381
+ children: renderBesideInput?.()
382
+ }), /*#__PURE__*/_jsx("span", {
383
+ className: theme.visuallyHidden,
384
+ id: ariaDescribedByLabelId,
385
+ children: ariaLabels?.label && ariaLabels.label
386
+ }), /*#__PURE__*/_jsx("div", {
387
+ className: getClassName(theme.inputWrapper),
388
+ children: /*#__PURE__*/_jsx(BpkInput, {
389
+ value: normalizedInputValue,
390
+ inputRef: setInputRef,
391
+ clearButtonMode: showClear ? 'whileEditing' : 'never',
392
+ clearButtonLabel: ariaLabels?.clearButton || 'Clear input',
393
+ onClear: clearSuggestions,
394
+ name: inputName || id,
395
+ id: id,
396
+ ...finalInputProps,
397
+ enterKeyHint: enterKeyHint
398
+ })
399
+ })]
400
+ })
401
+ });
402
+ };
403
+ return /*#__PURE__*/_jsxs("div", {
404
+ className: getClassName(theme.container, suggestionsCount && theme.containerOpen),
405
+ children: [renderInput(), showSuggestions && (isDesktop ? /*#__PURE__*/_jsx(FloatingPortal, {
406
+ children: /*#__PURE__*/_jsxs("div", {
407
+ ref: refs.setFloating,
408
+ style: floatingStyles,
409
+ className: getClassName(theme.suggestionsContainer, isDesktop && theme.desktopSuggestionsContainer, showSuggestions && theme.suggestionsContainerOpen),
410
+ children: [/*#__PURE__*/_jsx(FloatingArrow, {
411
+ ref: arrowRef,
412
+ context: context,
413
+ className: getClassName('bpk-autosuggest__arrow'),
414
+ role: "presentation",
415
+ stroke: surfaceHighlightDay,
416
+ strokeWidth: strokeWidth
417
+ }), /*#__PURE__*/_jsx("ul", {
418
+ ...getMenuProps({
419
+ ...(ariaLabels?.resultsList && {
420
+ 'aria-label': ariaLabels.resultsList
421
+ })
422
+ }),
423
+ className: getClassName(theme.suggestionsList, isDesktop && theme.desktopSuggestionsList),
424
+ children: renderList()
425
+ })]
426
+ })
427
+ }) : /*#__PURE__*/_jsx("div", {
428
+ className: getClassName(theme.suggestionsContainer, showSuggestions && theme.suggestionsContainerOpen),
429
+ children: /*#__PURE__*/_jsx("ul", {
430
+ ...getMenuProps({
431
+ ...(ariaLabels?.resultsList && {
432
+ 'aria-label': ariaLabels.resultsList
433
+ })
434
+ }),
435
+ className: getClassName(theme.suggestionsList),
436
+ children: renderList()
437
+ })
438
+ }))]
439
+ });
440
+ });
441
+ export default BpkAutosuggest;
@@ -0,0 +1,18 @@
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
+ .bpk-autosuggest__input{width:100%}.bpk-autosuggest__suggestions-container{border:.0625rem solid #e0e4e9;border-radius:.5rem;background-color:#fff}.bpk-autosuggest__arrow{width:1.5rem;height:1.5rem;fill:#fff}.bpk-autosuggest__arrow[data-hide]{visibility:hidden}.bpk-autosuggest__suggestions-list{min-width:fit-content;margin:0;padding:0;border-radius:.5rem;background-color:#fff;list-style:none;box-shadow:0px 4px 14px 0px rgba(37,32,31,.25);overflow:hidden}.bpk-autosuggest__suggestion-item{cursor:pointer;margin:0;font-size:1rem;line-height:1.5rem;font-weight:400}.bpk-autosuggest__suggestion-item:not(:last-child){box-shadow:0 -1px 0 0 #c1c7cf inset}.bpk-autosuggest__suggestion-item:active{background-color:#eff3f8}.bpk-autosuggest__suggestion-item--highlighted{background-color:#eff3f8}.bpk-autosuggest__suggestion{display:table;width:100%;padding:1rem}.bpk-autosuggest__suggestion--indent{padding-left:2rem}.bpk-autosuggest__suggestion-icon{display:table-cell;margin-right:.5rem;vertical-align:top;fill:#626971}html[dir=rtl] .bpk-autosuggest__suggestion-icon{margin-right:0;margin-left:.5rem}.bpk-autosuggest__suggestion-content{display:table-cell;width:100%;vertical-align:top}.bpk-autosuggest__suggestion-inner{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.bpk-autosuggest__suggestion-value{display:block}.bpk-autosuggest__suggestion-sub-heading{display:table-cell;width:100%;vertical-align:top;margin:0;font-size:.75rem;line-height:1rem;font-weight:400}.bpk-autosuggest__suggestion-tertiary-label{display:table-cell;align-self:center;color:#626971;vertical-align:top;word-break:keep-all;margin:0;font-size:.75rem;line-height:1rem;font-weight:400}.bpk-autosuggest__section-container:not(:first-of-type){border-top:1px solid #c1c7cf}.bpk-autosuggest__visuallyhidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;white-space:nowrap;overflow:hidden;clip:rect(0 0 0 0)}
@@ -101,7 +101,7 @@ const BpkModalInner = ({
101
101
  leadingButton: accessoryViewFinal,
102
102
  trailingButton: closeText ? /*#__PURE__*/_jsx(BpkButtonLink, {
103
103
  onClick: onClose,
104
- onDark: modalStyle === MODAL_STYLING.surfaceContrast,
104
+ alternate: modalStyle === MODAL_STYLING.surfaceContrast,
105
105
  children: closeText
106
106
  }) : /*#__PURE__*/_jsx(BpkCloseButton, {
107
107
  label: closeLabel,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyscanner/backpack-web",
3
- "version": "38.7.0",
3
+ "version": "38.9.0",
4
4
  "description": "Backpack Design System web library",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,7 +25,7 @@
25
25
  "@floating-ui/react": "^0.26.12",
26
26
  "@popperjs/core": "^2.11.8",
27
27
  "@radix-ui/react-compose-refs": "^1.1.1",
28
- "@radix-ui/react-slider": "1.1.2",
28
+ "@radix-ui/react-slider": "1.3.5",
29
29
  "@react-google-maps/api": "^2.19.3",
30
30
  "@skyscanner/bpk-foundations-web": "^22.1.0",
31
31
  "@skyscanner/bpk-svgs": "^20.8.0",
@@ -33,6 +33,7 @@
33
33
  "a11y-focus-store": "^1.0.0",
34
34
  "d3-path": "^3.1.0",
35
35
  "d3-scale": "^4.0.2",
36
+ "downshift": "^9.0.10",
36
37
  "intersection-observer": "^0.12.2",
37
38
  "lodash": "^4.17.20",
38
39
  "lodash.clamp": "^4.0.3",