@skyscanner/backpack-web 33.8.0 → 33.8.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 (26) hide show
  1. package/bpk-component-barchart/src/BpkBarchart.js +1 -8
  2. package/bpk-component-close-button/src/BpkCloseButton.js +1 -1
  3. package/bpk-component-datepicker/src/BpkDatepicker.js +0 -3
  4. package/bpk-component-datepicker/src/themeAttributes.js +0 -1
  5. package/bpk-component-loading-button/src/BpkLoadingButton.js +16 -8
  6. package/bpk-component-popover/index.d.ts +5 -0
  7. package/bpk-component-popover/index.js +3 -3
  8. package/bpk-component-popover/src/BpkPopover.d.ts +26 -0
  9. package/bpk-component-popover/src/BpkPopover.js +134 -103
  10. package/bpk-component-popover/src/BpkPopover.module.css +1 -1
  11. package/bpk-component-popover/src/constants.d.ts +5 -0
  12. package/bpk-component-popover/src/constants.js +3 -1
  13. package/bpk-component-popover/src/themeAttributes.d.ts +2 -0
  14. package/bpk-component-popover/src/themeAttributes.js +4 -1
  15. package/bpk-component-price/src/BpkPrice.js +24 -28
  16. package/bpk-component-price/src/BpkPrice.module.css +1 -1
  17. package/bpk-component-scrollable-calendar/src/BpkScrollableCalendarGrid.js +6 -7
  18. package/bpk-component-scrollable-calendar/src/BpkScrollableCalendarGrid.module.css +1 -1
  19. package/bpk-component-scrollable-calendar/src/BpkScrollableCalendarGridList.js +0 -4
  20. package/bpk-component-scrollable-calendar/src/BpkScrollableCalendarGridList.module.css +1 -1
  21. package/bpk-component-slider/src/BpkSlider.d.ts +11 -12
  22. package/bpk-component-slider/src/BpkSlider.js +48 -34
  23. package/bpk-component-slider/src/BpkSlider.module.css +1 -1
  24. package/package.json +4 -3
  25. package/bpk-component-popover/src/BpkPopoverPortal.js +0 -219
  26. package/bpk-component-popover/src/keyboardFocusScope.js +0 -76
@@ -44,7 +44,6 @@ const getMaxYValue = (dataPoints, outlierPercentage) => {
44
44
  };
45
45
  class BpkBarchart extends Component {
46
46
  static defaultProps = {
47
- className: null,
48
47
  leadingScrollIndicatorClassName: null,
49
48
  trailingScrollIndicatorClassName: null,
50
49
  outlierPercentage: null,
@@ -99,7 +98,6 @@ class BpkBarchart extends Component {
99
98
  render() {
100
99
  const {
101
100
  BarComponent,
102
- className,
103
101
  data,
104
102
  disableDataTable,
105
103
  getBarLabel,
@@ -134,10 +132,6 @@ class BpkBarchart extends Component {
134
132
  right: 0,
135
133
  bottom: xAxisMargin
136
134
  });
137
- const classNames = [getClassName('bpk-barchart')];
138
- if (className) {
139
- classNames.push(className);
140
- }
141
135
  const width = this.state.width - margin.left - margin.right;
142
136
  const height = this.state.height - margin.bottom - margin.top;
143
137
  const maxYValue = getMaxYValue(data.map(d => d[yScaleDataKey]), outlierPercentage);
@@ -156,7 +150,7 @@ class BpkBarchart extends Component {
156
150
  yAxisLabel: yAxisLabel
157
151
  }), /*#__PURE__*/_jsxs("svg", {
158
152
  xmlns: "http://www.w3.org/2000/svg",
159
- className: classNames.join(' '),
153
+ className: getClassName('bpk-barchart'),
160
154
  width: this.state.width,
161
155
  height: this.state.height,
162
156
  ref: svgEl => {
@@ -236,7 +230,6 @@ BpkBarchart.propTypes = {
236
230
  yAxisLabel: PropTypes.string.isRequired,
237
231
  initialWidth: PropTypes.number.isRequired,
238
232
  initialHeight: PropTypes.number.isRequired,
239
- className: PropTypes.string,
240
233
  leadingScrollIndicatorClassName: PropTypes.string,
241
234
  trailingScrollIndicatorClassName: PropTypes.string,
242
235
  /**
@@ -56,7 +56,7 @@ BpkCloseButton.propTypes = {
56
56
  onClick: PropTypes.func.isRequired,
57
57
  className: PropTypes.string,
58
58
  customIcon: PropTypes.func,
59
- onDark: PropTypes.Boolean
59
+ onDark: PropTypes.bool
60
60
  };
61
61
  BpkCloseButton.defaultProps = {
62
62
  className: null,
@@ -21,7 +21,6 @@ import BpkBreakpoint, { BREAKPOINTS } from "../../bpk-component-breakpoint";
21
21
  import { composeCalendar, BpkCalendarGridHeader, BpkCalendarGrid, BpkCalendarDate, withCalendarState, CALENDAR_SELECTION_TYPE, DateUtils, BpkCalendarNav } from "../../bpk-component-calendar";
22
22
  import BpkInput, { withOpenEvents } from "../../bpk-component-input";
23
23
  import BpkModal from "../../bpk-component-modal";
24
- // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
25
24
  import BpkPopover from "../../bpk-component-popover";
26
25
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
27
26
  const Input = withOpenEvents(BpkInput);
@@ -242,12 +241,10 @@ class BpkDatepicker extends Component {
242
241
  }) : /*#__PURE__*/_jsx(BpkPopover, {
243
242
  id: `${id}-popover`,
244
243
  target: input,
245
- renderTarget: renderTarget,
246
244
  onClose: this.props.onClose || this.onClose,
247
245
  isOpen: this.state.isOpen,
248
246
  label: title,
249
247
  closeButtonText: closeButtonText,
250
- tabIndex: 0,
251
248
  ...rest,
252
249
  children: /*#__PURE__*/_jsx(Calendar, {
253
250
  ...calendarProps,
@@ -18,6 +18,5 @@
18
18
 
19
19
  import { themeAttributes as calendarAttributes } from "../../bpk-component-calendar";
20
20
  import { themeAttributes as modalAttributes } from "../../bpk-component-modal";
21
- // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
22
21
  import { themeAttributes as popoverAttributes } from "../../bpk-component-popover";
23
22
  export default [...calendarAttributes, ...popoverAttributes, ...modalAttributes].filter((attribute, index, attributes) => attributes.indexOf(attribute) === index);
@@ -60,14 +60,22 @@ const getLoadingIcon = props => {
60
60
  const BpkLoadingButton = props => {
61
61
  const {
62
62
  children,
63
+ destructive,
63
64
  disabled,
65
+ featured,
64
66
  icon,
65
67
  iconDisabled,
66
68
  iconLoading,
67
69
  iconOnly,
68
70
  iconPosition,
69
71
  large,
72
+ link,
73
+ linkOnDark,
70
74
  loading,
75
+ primaryOnDark,
76
+ primaryOnLight,
77
+ secondary,
78
+ secondaryOnDark,
71
79
  ...rest
72
80
  } = props;
73
81
  const showBtnDisabled = disabled || loading;
@@ -77,28 +85,28 @@ const BpkLoadingButton = props => {
77
85
  const loadingIcon = getLoadingIcon(props);
78
86
  const iconClassNames = getClassName('bpk-loading-button__icon');
79
87
  let type = BUTTON_TYPES.primary;
80
- if (props.link) {
88
+ if (link) {
81
89
  type = BUTTON_TYPES.link;
82
90
  }
83
- if (props.linkOnDark) {
91
+ if (linkOnDark) {
84
92
  type = BUTTON_TYPES.linkOnDark;
85
93
  }
86
- if (props.featured) {
94
+ if (featured) {
87
95
  type = BUTTON_TYPES.featured;
88
96
  }
89
- if (props.destructive) {
97
+ if (destructive) {
90
98
  type = BUTTON_TYPES.destructive;
91
99
  }
92
- if (props.secondaryOnDark) {
100
+ if (secondaryOnDark) {
93
101
  type = BUTTON_TYPES.secondaryOnDark;
94
102
  }
95
- if (props.secondary) {
103
+ if (secondary) {
96
104
  type = BUTTON_TYPES.secondary;
97
105
  }
98
- if (props.primaryOnLight) {
106
+ if (primaryOnLight) {
99
107
  type = BUTTON_TYPES.primaryOnLight;
100
108
  }
101
- if (props.primaryOnDark) {
109
+ if (primaryOnDark) {
102
110
  type = BUTTON_TYPES.primaryOnDark;
103
111
  }
104
112
  return /*#__PURE__*/_jsx(BpkButtonV2, {
@@ -0,0 +1,5 @@
1
+ import BpkPopover, { type Props } from './src/BpkPopover';
2
+ import themeAttributes from './src/themeAttributes';
3
+ export type BpkPopoverProps = Props;
4
+ export { themeAttributes, };
5
+ export default BpkPopover;
@@ -14,7 +14,7 @@
14
14
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
- */import BpkPopoverPortal, { propTypes as bpkPopoverPortalPropTypes, defaultProps as bpkPopoverPortalDefaultProps } from "./src/BpkPopoverPortal";
17
+ */import BpkPopover from "./src/BpkPopover";
18
18
  import themeAttributes from "./src/themeAttributes";
19
- export { themeAttributes, bpkPopoverPortalPropTypes, bpkPopoverPortalDefaultProps };
20
- export default BpkPopoverPortal;
19
+ export { themeAttributes };
20
+ export default BpkPopover;
@@ -0,0 +1,26 @@
1
+ import type { SyntheticEvent, ReactNode, ReactElement } from 'react';
2
+ import type { Placement } from '@floating-ui/react';
3
+ declare const EVENT_SOURCES: {
4
+ CLOSE_BUTTON: string;
5
+ CLOSE_LINK: string;
6
+ };
7
+ export type Props = {
8
+ children: ReactNode;
9
+ closeButtonText: string;
10
+ id: string;
11
+ label: string;
12
+ onClose: (event: SyntheticEvent<HTMLButtonElement>, props: {
13
+ source: (typeof EVENT_SOURCES)[keyof typeof EVENT_SOURCES];
14
+ }) => void;
15
+ className?: string | null;
16
+ closeButtonIcon?: boolean;
17
+ closeButtonProps?: Object;
18
+ isOpen?: boolean;
19
+ labelAsTitle?: boolean;
20
+ padded?: boolean;
21
+ placement?: Placement;
22
+ showArrow?: Boolean;
23
+ target: ReactElement<any>;
24
+ };
25
+ declare const BpkPopover: ({ children, className, closeButtonIcon, closeButtonProps, closeButtonText, id, isOpen, label, labelAsTitle, onClose, padded, placement, showArrow, target, ...rest }: Props) => JSX.Element;
26
+ export default BpkPopover;
@@ -14,20 +14,30 @@
14
14
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
- */import PropTypes from 'prop-types';
17
+ */
18
+
19
+ import { useState, useRef, cloneElement, isValidElement } from 'react';
20
+ import { useFloating, autoUpdate, offset, useClick, useDismiss, useInteractions, FloatingFocusManager, arrow, FloatingArrow, flip, shift } from '@floating-ui/react';
21
+ import { surfaceHighlightDay } from '@skyscanner/bpk-foundations-web/tokens/base.es6';
22
+
23
+ // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
18
24
  import BpkCloseButton from "../../bpk-component-close-button";
25
+ // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
19
26
  import { BpkButtonLink } from "../../bpk-component-link";
20
27
  import BpkText, { TEXT_STYLES } from "../../bpk-component-text";
21
28
  import { TransitionInitialMount, cssModules } from "../../bpk-react-utils";
22
29
  import { ARROW_ID } from "./constants";
23
30
  import STYLES from "./BpkPopover.module.css";
24
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
31
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
25
32
  const getClassName = cssModules(STYLES);
26
33
  const EVENT_SOURCES = {
27
34
  CLOSE_BUTTON: 'CLOSE_BUTTON',
28
35
  CLOSE_LINK: 'CLOSE_LINK'
29
36
  };
30
- const bindEventSource = (source, callback) => event => {
37
+
38
+ // The stroke width is used to set the border width of the arrow.
39
+ const strokeWidth = 0.0625;
40
+ const bindEventSource = (source, callback, event) => {
31
41
  if (event.persist) {
32
42
  event.persist();
33
43
  }
@@ -35,110 +45,131 @@ const bindEventSource = (source, callback) => event => {
35
45
  source
36
46
  });
37
47
  };
38
- const BpkPopover = props => {
48
+ const BpkPopover = ({
49
+ children,
50
+ className = null,
51
+ closeButtonIcon = true,
52
+ closeButtonProps = {},
53
+ closeButtonText,
54
+ id,
55
+ isOpen = false,
56
+ label,
57
+ labelAsTitle = false,
58
+ onClose,
59
+ padded = true,
60
+ placement = 'bottom',
61
+ showArrow = true,
62
+ target,
63
+ ...rest
64
+ }) => {
65
+ const [isOpenState, setIsOpenState] = useState(isOpen);
66
+ const arrowRef = useRef(null);
39
67
  const {
40
- children,
41
- className,
42
- closeButtonIcon,
43
- closeButtonProps,
44
- closeButtonText,
45
- id,
46
- label,
47
- labelAsTitle,
48
- onClose,
49
- padded,
50
- ...rest
51
- } = props;
52
- const classNames = [getClassName('bpk-popover')];
53
- const bodyClassNames = [];
54
-
55
- // outer classNames
56
- if (className) {
57
- classNames.push(className);
58
- }
68
+ context,
69
+ floatingStyles,
70
+ refs
71
+ } = useFloating({
72
+ open: isOpenState,
73
+ onOpenChange: setIsOpenState,
74
+ placement,
75
+ middleware: [showArrow && offset(17), flip({
76
+ crossAxis: true
77
+ }), shift(), showArrow && arrow({
78
+ element: arrowRef
79
+ })],
80
+ whileElementsMounted: autoUpdate
81
+ });
82
+ const click = useClick(context);
83
+ const dismiss = useDismiss(context);
59
84
 
60
- // inner classNames
61
- if (padded) {
62
- bodyClassNames.push(getClassName('bpk-popover__body--padded'));
63
- }
85
+ // Merge all the interactions into prop getters
86
+ const {
87
+ getFloatingProps,
88
+ getReferenceProps
89
+ } = useInteractions([click, dismiss]);
90
+ const targetElement = /*#__PURE__*/isValidElement(target) ? ( /*#__PURE__*/cloneElement(target, {
91
+ ...getReferenceProps(),
92
+ // @ts-ignore - we're adding a popover ref to the target element so we can position the popover relative to it
93
+ ref: refs.setReference
94
+ })) : /*#__PURE__*/_jsx("div", {
95
+ ref: refs.setReference,
96
+ ...getReferenceProps(),
97
+ children: target
98
+ });
99
+ const classNames = getClassName('bpk-popover', className);
100
+ const bodyClassNames = getClassName(padded && 'bpk-popover__body--padded');
64
101
  const labelId = `bpk-popover-label-${id}`;
65
- return /*#__PURE__*/_jsx(TransitionInitialMount, {
66
- appearClassName: getClassName('bpk-popover--appear'),
67
- appearActiveClassName: getClassName('bpk-popover--appear-active'),
68
- transitionTimeout: 200,
69
- children: /*#__PURE__*/_jsxs("section", {
70
- id: id,
71
- tabIndex: "-1",
72
- role: "dialog",
73
- "aria-labelledby": labelId,
74
- className: classNames.join(' '),
75
- ...rest,
76
- children: [/*#__PURE__*/_jsx("span", {
77
- id: ARROW_ID,
78
- className: getClassName('bpk-popover__arrow'),
79
- role: "presentation",
80
- "data-popper-arrow": true
81
- }), labelAsTitle ? /*#__PURE__*/_jsxs("header", {
82
- className: getClassName('bpk-popover__header'),
83
- children: [/*#__PURE__*/_jsx(BpkText, {
84
- tagName: "h2",
85
- id: labelId,
86
- textStyle: TEXT_STYLES.label1,
87
- children: label
88
- }), "\xA0", closeButtonIcon ? /*#__PURE__*/_jsx(BpkCloseButton
89
- // TODO: className to be removed
90
- // eslint-disable-next-line @skyscanner/rules/forbid-component-props
91
- , {
92
- className: getClassName('bpk-popover__close-button'),
93
- label: closeButtonText,
94
- onClick: bindEventSource(EVENT_SOURCES.CLOSE_BUTTON, props.onClose),
95
- ...closeButtonProps
96
- }) : /*#__PURE__*/_jsx(BpkButtonLink, {
97
- onClick: bindEventSource(EVENT_SOURCES.CLOSE_LINK, props.onClose),
98
- ...closeButtonProps,
99
- children: closeButtonText
100
- })]
101
- }) : /*#__PURE__*/_jsx("span", {
102
- id: labelId,
103
- className: getClassName('bpk-popover__label'),
104
- children: label
105
- }), /*#__PURE__*/_jsx("div", {
106
- className: bodyClassNames.join(' '),
107
- children: children
108
- }), !labelAsTitle && /*#__PURE__*/_jsx("footer", {
109
- className: getClassName('bpk-popover__footer'),
110
- children: /*#__PURE__*/_jsx(BpkButtonLink, {
111
- onClick: bindEventSource(EVENT_SOURCES.CLOSE_LINK, props.onClose),
112
- ...closeButtonProps,
113
- children: closeButtonText
102
+ return /*#__PURE__*/_jsxs(_Fragment, {
103
+ children: [targetElement, isOpenState && /*#__PURE__*/_jsx(FloatingFocusManager, {
104
+ context: context,
105
+ modal: false,
106
+ children: /*#__PURE__*/_jsx("div", {
107
+ ref: refs.setFloating,
108
+ style: floatingStyles,
109
+ ...getFloatingProps(),
110
+ children: /*#__PURE__*/_jsx(TransitionInitialMount, {
111
+ appearClassName: getClassName('bpk-popover--appear'),
112
+ appearActiveClassName: getClassName('bpk-popover--appear-active'),
113
+ transitionTimeout: 200,
114
+ children: /*#__PURE__*/_jsxs("section", {
115
+ id: id,
116
+ tabIndex: -1,
117
+ role: "dialog",
118
+ "aria-labelledby": labelId,
119
+ className: classNames,
120
+ ...rest,
121
+ children: [showArrow && /*#__PURE__*/_jsx(FloatingArrow, {
122
+ ref: arrowRef,
123
+ context: context,
124
+ id: ARROW_ID,
125
+ className: getClassName('bpk-popover__arrow'),
126
+ role: "presentation",
127
+ stroke: surfaceHighlightDay,
128
+ strokeWidth: strokeWidth
129
+ }), labelAsTitle ? /*#__PURE__*/_jsxs("header", {
130
+ className: getClassName('bpk-popover__header'),
131
+ children: [/*#__PURE__*/_jsx(BpkText, {
132
+ tagName: "h2",
133
+ id: labelId,
134
+ textStyle: TEXT_STYLES.label1,
135
+ children: label
136
+ }), "\xA0", closeButtonIcon ? /*#__PURE__*/_jsx(BpkCloseButton, {
137
+ label: closeButtonText,
138
+ onClick: event => {
139
+ bindEventSource(EVENT_SOURCES.CLOSE_BUTTON, onClose, event);
140
+ setIsOpenState(false);
141
+ },
142
+ ...closeButtonProps
143
+ }) : /*#__PURE__*/_jsx(BpkButtonLink, {
144
+ onClick: event => {
145
+ bindEventSource(EVENT_SOURCES.CLOSE_LINK, onClose, event);
146
+ setIsOpenState(false);
147
+ },
148
+ ...closeButtonProps,
149
+ children: closeButtonText
150
+ })]
151
+ }) : /*#__PURE__*/_jsx("span", {
152
+ id: labelId,
153
+ className: getClassName('bpk-popover__label'),
154
+ children: label
155
+ }), /*#__PURE__*/_jsx("div", {
156
+ className: bodyClassNames,
157
+ children: children
158
+ }), !labelAsTitle && /*#__PURE__*/_jsx("footer", {
159
+ className: getClassName('bpk-popover__footer'),
160
+ children: /*#__PURE__*/_jsx(BpkButtonLink, {
161
+ onClick: event => {
162
+ bindEventSource(EVENT_SOURCES.CLOSE_LINK, onClose, event);
163
+ setIsOpenState(false);
164
+ },
165
+ ...closeButtonProps,
166
+ children: closeButtonText
167
+ })
168
+ })]
169
+ })
114
170
  })
115
- })]
116
- })
171
+ })
172
+ })]
117
173
  });
118
174
  };
119
- export const propTypes = {
120
- children: PropTypes.node.isRequired,
121
- closeButtonText: PropTypes.string.isRequired,
122
- id: PropTypes.string.isRequired,
123
- label: PropTypes.string.isRequired,
124
- onClose: PropTypes.func.isRequired,
125
- className: PropTypes.string,
126
- closeButtonIcon: PropTypes.bool,
127
- closeButtonProps: PropTypes.object,
128
- labelAsTitle: PropTypes.bool,
129
- padded: PropTypes.bool
130
- };
131
- export const defaultProps = {
132
- className: null,
133
- closeButtonIcon: true,
134
- closeButtonProps: null,
135
- labelAsTitle: false,
136
- padded: true
137
- };
138
- BpkPopover.propTypes = {
139
- ...propTypes
140
- };
141
- BpkPopover.defaultProps = {
142
- ...defaultProps
143
- };
144
175
  export default BpkPopover;
@@ -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-popover-portal{z-index:900}@media(max-width: 32rem){.bpk-popover-portal{margin-right:1rem;margin-left:1rem}}.bpk-popover{transition:opacity 200ms ease-in-out;outline:0;opacity:1;border:.0625rem solid #e0e4e9;background-color:#fff;border-radius:.5rem;box-shadow:0px 4px 14px 0px rgba(37,32,31,.25)}@media(min-width: 32.0625rem){.bpk-popover{max-width:32rem;transition:opacity 50ms ease-in-out}}.bpk-popover--appear{opacity:0}.bpk-popover--appear-active{opacity:1}.bpk-popover__arrow{position:absolute;width:1.5rem;height:1.5rem;transform:rotate(45deg);border:.0625rem solid rgba(0,0,0,0);background:inherit}.bpk-popover-portal[data-popper-placement=top] .bpk-popover__arrow{bottom:-0.6875rem;border-right-color:#e0e4e9;border-bottom-color:#e0e4e9}.bpk-popover-portal[data-popper-placement=right] .bpk-popover__arrow{left:-0.6875rem;border-bottom-color:#e0e4e9;border-left-color:#e0e4e9}.bpk-popover-portal[data-popper-placement=bottom] .bpk-popover__arrow{top:-0.6875rem;border-top-color:#e0e4e9;border-left-color:#e0e4e9}.bpk-popover-portal[data-popper-placement=left] .bpk-popover__arrow{right:-0.6875rem;border-top-color:#e0e4e9;border-right-color:#e0e4e9}.bpk-popover__arrow[data-hide]{visibility:hidden}.bpk-popover__body--padded{padding:1rem}.bpk-popover__header{display:flex;padding:1rem;justify-content:space-between;box-shadow:0 -1px 0 0 #e0e4e9 inset}.bpk-popover__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0)}.bpk-popover__close-button{float:right}html[dir=rtl] .bpk-popover__close-button{float:left}.bpk-popover__footer{padding:.5rem 1rem;text-align:right;box-shadow:0 1px 0 0 #e0e4e9 inset}html[dir=rtl] .bpk-popover__footer{text-align:left}
18
+ .bpk-popover-portal{z-index:900}@media(max-width: 32rem){.bpk-popover-portal{margin-right:1rem;margin-left:1rem}}.bpk-popover{transition:opacity 200ms ease-in-out;outline:0;background-color:#fff;opacity:1;border-radius:.5rem;box-shadow:0px 4px 14px 0px rgba(37,32,31,.25)}@media(min-width: 32.0625rem){.bpk-popover{max-width:32rem;transition:opacity 50ms ease-in-out}}.bpk-popover--appear{opacity:0}.bpk-popover--appear-active{opacity:1}.bpk-popover__arrow{width:1.5rem;height:1.5rem;fill:#fff}.bpk-popover__arrow[data-hide]{visibility:hidden}.bpk-popover__body--padded{padding:1rem}.bpk-popover__header{display:flex;padding:1rem;justify-content:space-between;box-shadow:0 -1px 0 0 #e0e4e9 inset}.bpk-popover__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0)}.bpk-popover__footer{padding:.5rem 1rem;text-align:right;box-shadow:0 1px 0 0 #e0e4e9 inset}html[dir=rtl] .bpk-popover__footer{text-align:left}
@@ -0,0 +1,5 @@
1
+ export declare const ARROW_ID = "js-bpk-popover-arrow";
2
+ declare const _default: {
3
+ ARROW_ID: string;
4
+ };
5
+ export default _default;
@@ -14,7 +14,9 @@
14
14
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
- */export const ARROW_ID = 'js-bpk-popover-arrow';
17
+ */
18
+
19
+ export const ARROW_ID = 'js-bpk-popover-arrow';
18
20
  export default {
19
21
  ARROW_ID
20
22
  };
@@ -0,0 +1,2 @@
1
+ declare const _default: any[];
2
+ export default _default;
@@ -14,5 +14,8 @@
14
14
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
- */import { themeAttributes as linkAttributes } from "../../bpk-component-link";
17
+ */
18
+
19
+ // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
20
+ import { themeAttributes as linkAttributes } from "../../bpk-component-link";
18
21
  export default [...linkAttributes];
@@ -42,22 +42,20 @@ const BpkPrice = props => {
42
42
  ...rest,
43
43
  children: [/*#__PURE__*/_jsxs("div", {
44
44
  className: getClassName(previousPrice && 'bpk-price__leading', isAlignRight && 'bpk-price__leading--right', leadingClassName),
45
- children: [previousPrice && /*#__PURE__*/_jsx(BpkText
46
- // TODO: className to be removed
47
- // eslint-disable-next-line @skyscanner/rules/forbid-component-props
48
- , {
45
+ children: [previousPrice && /*#__PURE__*/_jsx("span", {
49
46
  className: getClassName('bpk-price__previous-price'),
50
- textStyle: isSmall ? TEXT_STYLES.xs : TEXT_STYLES.sm,
51
- tagName: "span",
52
- children: previousPrice
53
- }), previousPrice && leadingText && /*#__PURE__*/_jsx(BpkText, {
54
- textStyle: isSmall ? TEXT_STYLES.xs : TEXT_STYLES.sm,
55
- tagName: "span"
56
- // TODO: className to be removed
57
- // eslint-disable-next-line @skyscanner/rules/forbid-component-props
58
- ,
47
+ children: /*#__PURE__*/_jsx(BpkText, {
48
+ textStyle: isSmall ? TEXT_STYLES.xs : TEXT_STYLES.sm,
49
+ tagName: "span",
50
+ children: previousPrice
51
+ })
52
+ }), previousPrice && leadingText && /*#__PURE__*/_jsx("span", {
59
53
  className: getClassName('bpk-price__separator'),
60
- children: "\uD802\uDD1F"
54
+ children: /*#__PURE__*/_jsx(BpkText, {
55
+ textStyle: isSmall ? TEXT_STYLES.xs : TEXT_STYLES.sm,
56
+ tagName: "span",
57
+ children: "\uD802\uDD1F"
58
+ })
61
59
  }), leadingText && /*#__PURE__*/_jsx(BpkText, {
62
60
  textStyle: isSmall ? TEXT_STYLES.xs : TEXT_STYLES.sm,
63
61
  tagName: "span",
@@ -65,22 +63,20 @@ const BpkPrice = props => {
65
63
  })]
66
64
  }), /*#__PURE__*/_jsxs("div", {
67
65
  className: getClassName(isAlignRight && 'bpk-price__column-container'),
68
- children: [/*#__PURE__*/_jsx(BpkText, {
69
- textStyle: isSmall ? TEXT_STYLES.heading4 : TEXT_STYLES.xxl
70
- // TODO: className to be removed
71
- // eslint-disable-next-line @skyscanner/rules/forbid-component-props
72
- ,
66
+ children: [/*#__PURE__*/_jsx("span", {
73
67
  className: getClassName('bpk-price__price', !isAlignRight && 'bpk-price__spacing'),
74
- tagName: "span",
75
- children: price
76
- }), trailingText && /*#__PURE__*/_jsx(BpkText, {
77
- textStyle: isSmall ? TEXT_STYLES.xs : TEXT_STYLES.sm,
78
- tagName: "span"
79
- // TODO: className to be removed
80
- // eslint-disable-next-line @skyscanner/rules/forbid-component-props
81
- ,
68
+ children: /*#__PURE__*/_jsx(BpkText, {
69
+ textStyle: isSmall ? TEXT_STYLES.heading4 : TEXT_STYLES.xxl,
70
+ tagName: "span",
71
+ children: price
72
+ })
73
+ }), trailingText && /*#__PURE__*/_jsx("span", {
82
74
  className: getClassName('bpk-price__trailing'),
83
- children: trailingText
75
+ children: /*#__PURE__*/_jsx(BpkText, {
76
+ textStyle: isSmall ? TEXT_STYLES.xs : TEXT_STYLES.sm,
77
+ tagName: "span",
78
+ children: trailingText
79
+ })
84
80
  })]
85
81
  })]
86
82
  });
@@ -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-price{display:flex;flex-direction:column;color:#626971}.bpk-price--right{text-align:right}html[dir=rtl] .bpk-price--right{text-align:left}.bpk-price__leading{display:flex;flex-direction:row}.bpk-price__leading--right{flex-direction:row-reverse}.bpk-price__previous-price{text-decoration-line:line-through}.bpk-price__separator{margin:0 .25rem}.bpk-price__column-container{display:flex;flex-direction:column}.bpk-price__price{color:#161616;word-break:break-all}.bpk-price__spacing::after{content:"";margin-right:.25rem}html[dir=rtl] .bpk-price__spacing::after{margin-right:unset;margin-left:.25rem}.bpk-price__trailing{white-space:nowrap}
18
+ .bpk-price{display:flex;flex-direction:column;color:#626971}.bpk-price--right{text-align:right}html[dir=rtl] .bpk-price--right{text-align:left}.bpk-price__leading{display:flex;flex-direction:row}.bpk-price__leading--right{display:flex;flex-direction:row-reverse}.bpk-price__previous-price{display:flex;text-decoration-line:line-through}.bpk-price__separator{display:flex;margin:0 .25rem}.bpk-price__column-container{display:flex;flex-direction:column}.bpk-price__price{display:contents;color:#161616;word-break:break-all}.bpk-price__spacing::after{content:"";margin-right:.25rem}html[dir=rtl] .bpk-price__spacing::after{margin-right:unset;margin-left:.25rem}.bpk-price__trailing{display:contents;white-space:nowrap}
@@ -32,14 +32,13 @@ const BpkScrollableCalendarGrid = ({
32
32
  const classNames = getClassName('bpk-scrollable-calendar-grid', className);
33
33
  return /*#__PURE__*/_jsxs("div", {
34
34
  className: classNames,
35
- children: [/*#__PURE__*/_jsx(BpkText
36
- // TODO: className to be removed
37
- // eslint-disable-next-line @skyscanner/rules/forbid-component-props
38
- , {
35
+ children: [/*#__PURE__*/_jsx("span", {
39
36
  className: getClassName('bpk-scrollable-calendar-grid__title'),
40
- tagName: "h1",
41
- textStyle: TEXT_STYLES.heading4,
42
- children: formatMonth(month)
37
+ children: /*#__PURE__*/_jsx(BpkText, {
38
+ tagName: "h1",
39
+ textStyle: TEXT_STYLES.heading4,
40
+ children: formatMonth(month)
41
+ })
43
42
  }), /*#__PURE__*/_jsx(BpkCalendarGrid, {
44
43
  month: month,
45
44
  ignoreOutsideDate: true,
@@ -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-scrollable-calendar-grid{width:100%;border-collapse:separate;border-spacing:0}.bpk-scrollable-calendar-grid__title{margin-top:1.5rem}
18
+ .bpk-scrollable-calendar-grid{width:100%;border-collapse:separate;border-spacing:0}.bpk-scrollable-calendar-grid__title{display:block;margin-top:1.5rem}
@@ -83,10 +83,6 @@ const BpkScrollableCalendarGridList = props => {
83
83
  focusedDate: focusedDate,
84
84
  preventKeyboardFocus: rest.preventKeyboardFocus,
85
85
  "aria-hidden": index !== 1
86
- // TODO: className to be removed
87
- // eslint-disable-next-line @skyscanner/rules/forbid-component-props
88
- ,
89
- className: getClassName('bpk-scrollable-calendar-grid-list__item')
90
86
  })
91
87
  });
92
88
  const calculateOffsetInPixels = numberOfMonths => {
@@ -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-scrollable-calendar-grid-list{position:relative;width:100%;height:100%;min-height:26.25rem;overflow-x:hidden;box-sizing:border-box;-ms-overflow-style:-ms-autohiding-scrollbar}.bpk-scrollable-calendar-grid-list__item{display:inline-table}
18
+ .bpk-scrollable-calendar-grid-list{position:relative;width:100%;height:100%;min-height:26.25rem;overflow-x:hidden;box-sizing:border-box;-ms-overflow-style:-ms-autohiding-scrollbar}
@@ -1,16 +1,15 @@
1
1
  /// <reference types="react" />
2
- import PropTypes from 'prop-types';
3
- type Props = {
4
- className?: string | null;
2
+ export type Props = {
3
+ max: number;
4
+ min: number;
5
+ minDistance?: number;
6
+ step?: number;
7
+ onChange: (value: number[] | number) => void;
8
+ onAfterChange?: (value: number[] | number) => void;
9
+ value: number[] | number;
10
+ ariaLabel: string[];
11
+ ariaValuetext?: string[];
5
12
  [rest: string]: any;
6
13
  };
7
- declare const BpkSlider: {
8
- (props: Props): JSX.Element;
9
- propTypes: {
10
- className: PropTypes.Requireable<string>;
11
- };
12
- defaultProps: {
13
- className: null;
14
- };
15
- };
14
+ declare const BpkSlider: ({ ariaLabel, ariaValuetext, max, min, minDistance, onAfterChange, onChange, step, value, ...rest }: Props) => JSX.Element;
16
15
  export default BpkSlider;
@@ -16,45 +16,59 @@
16
16
  * limitations under the License.
17
17
  */
18
18
 
19
- import PropTypes from 'prop-types';
20
-
21
- // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
22
- import Slider from 'react-slider';
19
+ import * as Slider from '@radix-ui/react-slider';
23
20
  import { cssModules, isRTL } from "../../bpk-react-utils";
24
21
  import STYLES from "./BpkSlider.module.css";
25
- import { jsx as _jsx } from "react/jsx-runtime";
22
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
26
23
  const getClassName = cssModules(STYLES);
27
- const BpkSlider = props => {
28
- const {
29
- className,
30
- ...rest
31
- } = props;
24
+ const BpkSlider = ({
25
+ ariaLabel,
26
+ ariaValuetext,
27
+ max,
28
+ min,
29
+ minDistance,
30
+ onAfterChange,
31
+ onChange,
32
+ step,
33
+ value,
34
+ ...rest
35
+ }) => {
32
36
  const invert = isRTL();
33
- const classNames = [getClassName('bpk-slider')];
34
- const thumbClassNames = [getClassName('bpk-slider__handle')];
35
- const trackClassNames = [getClassName('bpk-slider__bar')];
36
- const isRange = (rest.value || rest.defaultValue || []).length > 1;
37
- if (isRange) {
38
- classNames.push(getClassName('bpk-slider--range'));
39
- }
40
- if (className) {
41
- classNames.push(getClassName(className));
42
- }
43
- return /*#__PURE__*/_jsx(Slider, {
37
+ const currentValue = Array.isArray(value) ? value : [value];
38
+ const processSliderValues = (sliderValues, callback) => {
39
+ const val = sliderValues.length === 1 ? sliderValues[0] : sliderValues;
40
+ if (callback) {
41
+ callback(val);
42
+ }
43
+ };
44
+ const handleOnChange = sliderValues => {
45
+ processSliderValues(sliderValues, onChange);
46
+ };
47
+ const handleOnAfterChange = sliderValues => {
48
+ processSliderValues(sliderValues, onAfterChange);
49
+ };
50
+ return /*#__PURE__*/_jsxs(Slider.Root, {
51
+ className: getClassName('bpk-slider'),
52
+ defaultValue: currentValue,
53
+ min: min,
54
+ max: max,
55
+ step: step || 1,
56
+ onValueChange: handleOnChange,
57
+ onValueCommit: handleOnAfterChange,
58
+ inverted: invert,
59
+ minStepsBetweenThumbs: minDistance,
44
60
  ...rest,
45
- withTracks: true,
46
- snapDragDisabled: false,
47
- invert: invert,
48
- className: classNames.join(' '),
49
- thumbClassName: thumbClassNames.join(' '),
50
- thumbActiveClassName: getClassName('bpk-slider__handle--active'),
51
- trackClassName: trackClassNames.join(' ')
61
+ children: [/*#__PURE__*/_jsx(Slider.Track, {
62
+ className: getClassName('bpk-slider__track'),
63
+ children: /*#__PURE__*/_jsx(Slider.Range, {
64
+ className: getClassName('bpk-slider__range')
65
+ })
66
+ }), currentValue.map((val, index) => /*#__PURE__*/_jsx(Slider.Thumb, {
67
+ "aria-label": ariaLabel[index],
68
+ "aria-valuetext": ariaValuetext ? ariaValuetext[index] : val.toString(),
69
+ className: getClassName('bpk-slider__thumb'),
70
+ "aria-valuenow": currentValue[index]
71
+ }, ariaLabel[index]))]
52
72
  });
53
73
  };
54
- BpkSlider.propTypes = {
55
- className: PropTypes.string
56
- };
57
- BpkSlider.defaultProps = {
58
- className: null
59
- };
60
74
  export default BpkSlider;
@@ -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-slider{height:1.25rem;-webkit-tap-highlight-color:rgba(0,0,0,0)}.bpk-slider__handle{display:flex;width:1.25rem;height:1.25rem;justify-content:center;align-items:center;border-radius:50%;background-color:#0062e3;cursor:pointer;box-shadow:0px 1px 3px 0px rgba(37,32,31,.3)}.bpk-slider__handle::after{position:absolute;content:"";width:2.5rem;height:2.5rem;border-radius:50%}.bpk-slider__handle--active{transform:scale(1.2) translate3d(0, 0, 0);background-color:#154679}.bpk-slider__bar{top:calc(50% - 0.125rem);height:.25rem;border-radius:.5rem;background-color:#c1c7cf}.bpk-slider>div[class$="0"]{background-color:#0062e3;background-color:var(--bpk-slider-bar-color, rgb(0, 98, 227))}.bpk-slider--range>div[class$="0"]{background-color:#c1c7cf}.bpk-slider--range>div[class$="1"]{background-color:#0062e3;background-color:var(--bpk-slider-bar-color, rgb(0, 98, 227))}
18
+ .bpk-slider{position:relative;display:flex;height:1.25rem;align-items:center;-webkit-tap-highlight-color:rgba(0,0,0,0);touch-action:none;user-select:none}.bpk-slider__track{position:relative;height:.25rem;flex-grow:1;background-color:#c1c7cf}.bpk-slider__range{position:absolute;height:100%;background-color:#0062e3}.bpk-slider__thumb{display:block;width:1.25rem;height:1.25rem;border-radius:50%;background-color:#0062e3;box-shadow:0px 1px 3px 0px rgba(37,32,31,.3)}.bpk-slider__thumb::after{position:absolute;content:"";width:2.5rem;height:2.5rem;border-radius:50%}.bpk-slider__thumb:active{transform:scale(1.2) translate3d(0, 0, 0);background-color:#154679}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyscanner/backpack-web",
3
- "version": "33.8.0",
3
+ "version": "33.8.1",
4
4
  "description": "Backpack Design System web library",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,7 +22,9 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@popperjs/core": "^2.11.5",
25
+ "@floating-ui/react": "^0.26.12",
26
+ "@popperjs/core": "^2.11.8",
27
+ "@radix-ui/react-slider": "^1.1.2",
26
28
  "@react-google-maps/api": "^2.12.0",
27
29
  "@skyscanner/bpk-foundations-web": "^17.11.0",
28
30
  "@skyscanner/bpk-svgs": "^19.3.0",
@@ -39,7 +41,6 @@
39
41
  "object-assign": "^4.1.1",
40
42
  "prop-types": "^15.7.2",
41
43
  "react-autosuggest": "^9.4.3",
42
- "react-slider": "^2.0.6",
43
44
  "react-table": "^7.8.0",
44
45
  "react-virtualized-auto-sizer": "1.0.20",
45
46
  "react-window": "^1.8.7"
@@ -1,219 +0,0 @@
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
- */import PropTypes from 'prop-types';
18
- import { Component } from 'react';
19
- import { createPopper } from '@popperjs/core';
20
- import focusStore from 'a11y-focus-store';
21
- import { Portal, cssModules } from "../../bpk-react-utils";
22
- import BpkPopover from "./BpkPopover";
23
- import keyboardFocusScope from "./keyboardFocusScope";
24
- import STYLES from "./BpkPopover.module.css";
25
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
26
- const getClassName = cssModules(STYLES);
27
- class BpkPopoverPortal extends Component {
28
- constructor() {
29
- super();
30
- this.popper = null;
31
- this.previousTargetElement = null;
32
- }
33
- onRender = (popoverElement, targetElement) => {
34
- this.position(popoverElement, targetElement);
35
- };
36
-
37
- // The order of events here is as follows:
38
- // - `onClose` is called by `Portal`
39
- // - The consumer changes `isOpen` to `false`
40
- // - `beforeClose` is called by `Portal`
41
- // - `beforeClose` calls the `done` callback which closes the `Portal`
42
-
43
- // `onClose` is called by the `Portal` to inform the consumer that `isOpen` should be made false.
44
- // Before we pass this information to the consumer, we want to note if restoring focus should be suppressed
45
- onClose = (event, information) => {
46
- // If the user has clicked outside the popover then we don't want focus to be restored
47
- // otherwise it will be stolen back from the element they clicked on.
48
- // Here we suppress restoring focus before the consumer is told about the close and updates state.
49
- this.suppressRestoreFocus = information.source === 'DOCUMENT_CLICK';
50
- if (this.props.onClose) {
51
- this.props.onClose(event, information);
52
- }
53
- };
54
-
55
- // `beforeClose` is called by the `Portal` when `isOpen` is changed to false.
56
- // As a result, `onClose` is called first, followed by `beforeClose`.
57
- beforeClose = done => {
58
- if (this.popper) {
59
- this.popper.destroy();
60
- this.popper = null;
61
- this.previousTargetElement = null;
62
- }
63
- keyboardFocusScope.unscopeFocus();
64
- if (!this.suppressRestoreFocus) {
65
- focusStore.restoreFocus();
66
- this.suppressRestoreFocus = false;
67
- }
68
- done();
69
- };
70
- position(popoverElement, targetElement) {
71
- if (!targetElement) {
72
- return;
73
- }
74
- const targetElementHasChanged = targetElement !== this.previousTargetElement;
75
- if (targetElementHasChanged && this.popper) {
76
- this.popper.destroy();
77
- this.popper = null;
78
- }
79
-
80
- // Custom modifier that makes the arrow display at the edge of the target.
81
- const applyArrowHide = {
82
- name: 'applyArrowHide',
83
- enabled: true,
84
- phase: 'write',
85
- fn({
86
- state
87
- }) {
88
- const {
89
- arrow
90
- } = state.elements;
91
- if (arrow) {
92
- if (state.modifiersData.arrow.centerOffset !== 0) {
93
- arrow.setAttribute('data-hide', '');
94
- } else {
95
- arrow.removeAttribute('data-hide');
96
- }
97
- }
98
- }
99
- };
100
-
101
- // The default modifiers for the popper
102
- // Note that GPU acceleration should be disabled otherwise Popper will use `translate3d`
103
- // which can cause blurriness in Safari and Chrome.
104
- const stdModifiers = [{
105
- name: 'computeStyles',
106
- options: {
107
- gpuAcceleration: false
108
- }
109
- }, {
110
- name: 'offset',
111
- options: {
112
- offset: [0, 17]
113
- }
114
- }, applyArrowHide];
115
- if (!this.popper) {
116
- this.popper = createPopper(targetElement, popoverElement, {
117
- placement: this.props.placement,
118
- onFirstUpdate: () => {
119
- if (targetElement) {
120
- targetElement.focus();
121
- }
122
- focusStore.storeFocus();
123
- keyboardFocusScope.scopeFocus(popoverElement);
124
- },
125
- modifiers: this.props.popperModifiers ? [...this.props.popperModifiers, ...stdModifiers] : stdModifiers
126
- });
127
- }
128
- this.previousTargetElement = targetElement;
129
- if (this.popper) {
130
- this.popper.update();
131
- }
132
- }
133
- render() {
134
- const {
135
- isOpen,
136
- onClose,
137
- placement,
138
- popperModifiers,
139
- portalClassName,
140
- portalStyle,
141
- renderTarget,
142
- target,
143
- ...rest
144
- } = this.props;
145
- const classNames = [getClassName('bpk-popover-portal')];
146
- if (portalClassName) {
147
- classNames.push(portalClassName);
148
- }
149
- return /*#__PURE__*/_jsxs(_Fragment, {
150
- children: [typeof target !== 'function' && target, /*#__PURE__*/_jsx(Portal, {
151
- beforeClose: this.beforeClose
152
- // TODO: className to be removed
153
- // eslint-disable-next-line @skyscanner/rules/forbid-component-props
154
- ,
155
- className: classNames.join(' '),
156
- isOpen: isOpen,
157
- onClose: this.onClose,
158
- onRender: this.onRender,
159
- style: portalStyle,
160
- renderTarget: renderTarget,
161
- target: target,
162
- children: /*#__PURE__*/_jsx(BpkPopover, {
163
- onClose: this.onClose,
164
- ...rest
165
- })
166
- })]
167
- });
168
- }
169
- }
170
- export const propTypes = {
171
- // BpkPopover props - when migrating the popover to TS, we can import the type from BpkPopover
172
- children: PropTypes.node.isRequired,
173
- closeButtonText: PropTypes.string.isRequired,
174
- id: PropTypes.string.isRequired,
175
- label: PropTypes.string.isRequired,
176
- onClose: PropTypes.func.isRequired,
177
- className: PropTypes.string,
178
- closeButtonIcon: PropTypes.bool,
179
- closeButtonProps: PropTypes.object,
180
- labelAsTitle: PropTypes.bool,
181
- padded: PropTypes.bool,
182
- // BpkPopoverPortal additional props
183
- /**
184
- * In order to attach the popover to a regular DOM element, provide a function which returns it to `target`.
185
- * `target` can be a DOM element with a `ref` attached to it or a function that returns a DOM element.
186
- */
187
- target: PropTypes.oneOfType([PropTypes.func, PropTypes.node]).isRequired,
188
- isOpen: PropTypes.bool.isRequired,
189
- placement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
190
- portalStyle: PropTypes.object,
191
- portalClassName: PropTypes.string,
192
- renderTarget: PropTypes.func,
193
- /**
194
- * Please refer to the [documentation](https://popper.js.org/docs/v2/modifiers/) for the underlying positioning library "Popper.js".
195
- * You can achieve various behaviours such as allowing the popover to overflow the viewport etc.
196
- */
197
- popperModifiers: PropTypes.arrayOf(PropTypes.object)
198
- };
199
- export const defaultProps = {
200
- // BpkPopover props - when migrating the popover to TS, we can import the type from BpkPopover
201
- className: null,
202
- closeButtonIcon: true,
203
- closeButtonProps: null,
204
- labelAsTitle: false,
205
- padded: true,
206
- // BpkPopoverPortal additional props
207
- placement: 'bottom',
208
- portalStyle: null,
209
- portalClassName: null,
210
- renderTarget: null,
211
- popperModifiers: null
212
- };
213
- BpkPopoverPortal.propTypes = {
214
- ...propTypes
215
- };
216
- BpkPopoverPortal.defaultProps = {
217
- ...defaultProps
218
- };
219
- export default BpkPopoverPortal;
@@ -1,76 +0,0 @@
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
- // This code is based on that from `a11y-focus-scope`.
20
- // Instead of completely preventing focus leaving the target element,
21
- // it only prevents it leaving due to keyboard events.
22
- // Clicks outside the target element will move focus as normal.
23
-
24
- import focusin from 'focusin';
25
- import tabbable from 'tabbable';
26
- let polyfilled = false;
27
- let focusTrapped = false;
28
- const init = element => {
29
- // lazily polyfill focusin for firefox
30
- if (!polyfilled) {
31
- focusin.polyfill();
32
- polyfilled = true;
33
- }
34
- const focus = () => {
35
- (tabbable(element)[0] || element).focus();
36
- };
37
- const enableFocusTrapping = () => {
38
- focusTrapped = true;
39
- };
40
- const disableFocusTrapping = () => {
41
- focusTrapped = false;
42
- };
43
- const checkFocus = event => {
44
- if (!focusTrapped) {
45
- return;
46
- }
47
- if (element !== event.target && !element.contains(event.target)) {
48
- focus();
49
- }
50
- };
51
- focus();
52
-
53
- // As we only want to trap focus for keyboard navigation, we enable focus trapping on keydown and disable it again on keyup.
54
- // This means that focus is trapped when pressing the tab key, but not trapped for other navigation events such as mouse clicks.
55
- document.addEventListener('keydown', enableFocusTrapping);
56
- document.addEventListener('focusin', checkFocus);
57
- document.addEventListener('keyup', disableFocusTrapping);
58
- return () => {
59
- document.removeEventListener('keydown', enableFocusTrapping);
60
- document.removeEventListener('focusin', checkFocus);
61
- document.removeEventListener('keyup', disableFocusTrapping);
62
- };
63
- };
64
- let teardownFn;
65
- const scopeFocus = element => {
66
- if (teardownFn) teardownFn();
67
- teardownFn = init(element);
68
- };
69
- const unscopeFocus = () => {
70
- if (teardownFn) teardownFn();
71
- teardownFn = null;
72
- };
73
- export default {
74
- scopeFocus,
75
- unscopeFocus
76
- };