@skyscanner/backpack-web 34.0.0-premajor.1 → 34.0.0-premajor.2
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,46 +16,25 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { useState,
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
// @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
|
|
23
|
-
import { surfaceHighlightDay } from '@skyscanner/bpk-foundations-web/tokens/base.es6';
|
|
24
|
-
|
|
25
|
-
// @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
|
|
26
|
-
import BpkCloseButton from "../../bpk-component-close-button";
|
|
27
|
-
// @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
|
|
28
|
-
import { BpkButtonLink } from "../../bpk-component-link";
|
|
29
|
-
import BpkText, { TEXT_STYLES } from "../../bpk-component-text";
|
|
30
|
-
import { TransitionInitialMount, cssModules } from "../../bpk-react-utils";
|
|
31
|
-
import { ARROW_ID } from "./constants";
|
|
32
|
-
import STYLES from "./BpkPopover.module.css";
|
|
33
|
-
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
34
|
-
const getClassName = cssModules(STYLES);
|
|
19
|
+
import { useState, useRef } from 'react';
|
|
20
|
+
import { Popover, PopoverContent, PopoverTrigger } from "./PopperUtils";
|
|
21
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
35
22
|
const EVENT_SOURCES = {
|
|
36
23
|
CLOSE_BUTTON: 'CLOSE_BUTTON',
|
|
37
24
|
CLOSE_LINK: 'CLOSE_LINK'
|
|
38
25
|
};
|
|
39
|
-
const bindEventSource = (source, callback) => event => {
|
|
40
|
-
if (event.persist) {
|
|
41
|
-
event.persist();
|
|
42
|
-
}
|
|
43
|
-
callback(event, {
|
|
44
|
-
source
|
|
45
|
-
});
|
|
46
|
-
};
|
|
47
26
|
const BpkPopover = ({
|
|
48
|
-
children,
|
|
49
|
-
className = null,
|
|
50
|
-
closeButtonIcon = true,
|
|
51
|
-
closeButtonProps = {},
|
|
52
|
-
closeButtonText,
|
|
53
|
-
id,
|
|
27
|
+
// children,
|
|
28
|
+
// className = null,
|
|
29
|
+
// closeButtonIcon = true,
|
|
30
|
+
// closeButtonProps = {},
|
|
31
|
+
// closeButtonText,
|
|
32
|
+
// id,
|
|
54
33
|
isOpen = false,
|
|
55
|
-
label,
|
|
56
|
-
labelAsTitle = false,
|
|
57
|
-
onClose,
|
|
58
|
-
padded = true,
|
|
34
|
+
// label,
|
|
35
|
+
// labelAsTitle = false,
|
|
36
|
+
// onClose,
|
|
37
|
+
// padded = true,
|
|
59
38
|
placement = 'bottom',
|
|
60
39
|
showArrow = true,
|
|
61
40
|
target,
|
|
@@ -63,109 +42,68 @@ const BpkPopover = ({
|
|
|
63
42
|
}) => {
|
|
64
43
|
const [isOpenState, setIsOpenState] = useState(isOpen);
|
|
65
44
|
const arrowRef = useRef(null);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const click = useClick(context);
|
|
82
|
-
const dismiss = useDismiss(context);
|
|
45
|
+
|
|
46
|
+
// const { context, floatingStyles, refs } = useFloating({
|
|
47
|
+
// open: isOpenState,
|
|
48
|
+
// onOpenChange: setIsOpenState,
|
|
49
|
+
// placement,
|
|
50
|
+
// middleware: [
|
|
51
|
+
// showArrow && offset(14),
|
|
52
|
+
// flip({ fallbackAxisSideDirection: 'start' }),
|
|
53
|
+
// arrow({ element: arrowRef }),
|
|
54
|
+
// ],
|
|
55
|
+
// whileElementsMounted: autoUpdate,
|
|
56
|
+
// });
|
|
57
|
+
|
|
58
|
+
// const click = useClick(context);
|
|
59
|
+
// const dismiss = useDismiss(context);
|
|
83
60
|
|
|
84
61
|
// Merge all the interactions into prop getters
|
|
85
|
-
const {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
children: label
|
|
132
|
-
}), "\xA0", closeButtonIcon ? /*#__PURE__*/_jsx(BpkCloseButton, {
|
|
133
|
-
label: closeButtonText,
|
|
134
|
-
onClick: () => {
|
|
135
|
-
bindEventSource(EVENT_SOURCES.CLOSE_BUTTON, onClose);
|
|
136
|
-
setIsOpenState(false);
|
|
137
|
-
},
|
|
138
|
-
...closeButtonProps
|
|
139
|
-
}) : /*#__PURE__*/_jsx(BpkButtonLink, {
|
|
140
|
-
onClick: () => {
|
|
141
|
-
bindEventSource(EVENT_SOURCES.CLOSE_LINK, onClose);
|
|
142
|
-
setIsOpenState(false);
|
|
143
|
-
},
|
|
144
|
-
...closeButtonProps,
|
|
145
|
-
children: closeButtonText
|
|
146
|
-
})]
|
|
147
|
-
}) : /*#__PURE__*/_jsx("span", {
|
|
148
|
-
id: labelId,
|
|
149
|
-
className: getClassName('bpk-popover__label'),
|
|
150
|
-
children: label
|
|
151
|
-
}), /*#__PURE__*/_jsx("div", {
|
|
152
|
-
className: bodyClassNames,
|
|
153
|
-
children: children
|
|
154
|
-
}), !labelAsTitle && /*#__PURE__*/_jsx("footer", {
|
|
155
|
-
className: getClassName('bpk-popover__footer'),
|
|
156
|
-
children: /*#__PURE__*/_jsx(BpkButtonLink, {
|
|
157
|
-
onClick: () => {
|
|
158
|
-
bindEventSource(EVENT_SOURCES.CLOSE_LINK, onClose);
|
|
159
|
-
setIsOpenState(false);
|
|
160
|
-
},
|
|
161
|
-
...closeButtonProps,
|
|
162
|
-
children: closeButtonText
|
|
163
|
-
})
|
|
164
|
-
})]
|
|
165
|
-
})
|
|
166
|
-
})
|
|
167
|
-
})
|
|
168
|
-
})]
|
|
169
|
-
});
|
|
62
|
+
// const { getFloatingProps, getReferenceProps } = useInteractions([
|
|
63
|
+
// click,
|
|
64
|
+
// dismiss,
|
|
65
|
+
// ]);
|
|
66
|
+
|
|
67
|
+
// const targetElement = cloneElement(target, {
|
|
68
|
+
// ...getReferenceProps(),
|
|
69
|
+
// ref: refs.setReference,
|
|
70
|
+
// });
|
|
71
|
+
// const classNames = getClassName('bpk-popover', className);
|
|
72
|
+
// const bodyClassNames = getClassName(padded && 'bpk-popover__body--padded');
|
|
73
|
+
|
|
74
|
+
// const labelId = `bpk-popover-label-${id}`;
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
/*#__PURE__*/
|
|
78
|
+
// <>
|
|
79
|
+
// {targetElement}
|
|
80
|
+
// {isOpenState && (
|
|
81
|
+
// <FloatingFocusManager context={context} modal={false}>
|
|
82
|
+
// <div
|
|
83
|
+
// ref={refs.setFloating}
|
|
84
|
+
// style={floatingStyles}
|
|
85
|
+
// {...getFloatingProps()}
|
|
86
|
+
// >
|
|
87
|
+
// </div>
|
|
88
|
+
// </FloatingFocusManager>
|
|
89
|
+
// )}
|
|
90
|
+
// </>
|
|
91
|
+
_jsxs(Popover, {
|
|
92
|
+
open: isOpenState,
|
|
93
|
+
onOpenChange: setIsOpenState,
|
|
94
|
+
arrowRef: arrowRef,
|
|
95
|
+
showArrow: showArrow,
|
|
96
|
+
placement: placement,
|
|
97
|
+
children: [/*#__PURE__*/_jsx(PopoverTrigger, {
|
|
98
|
+
onClick: () => setIsOpenState(v => !v),
|
|
99
|
+
children: target
|
|
100
|
+
}), /*#__PURE__*/_jsx(PopoverContent, {
|
|
101
|
+
setState: setIsOpenState,
|
|
102
|
+
arrowRef: arrowRef,
|
|
103
|
+
showArrow: showArrow,
|
|
104
|
+
...rest
|
|
105
|
+
})]
|
|
106
|
+
})
|
|
107
|
+
);
|
|
170
108
|
};
|
|
171
109
|
export default BpkPopover;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useFloating, autoUpdate, offset, flip, useClick, useDismiss, useRole, useInteractions, useMergeRefs, FloatingPortal, FloatingFocusManager, arrow, FloatingArrow } from '@floating-ui/react';
|
|
3
|
+
|
|
4
|
+
// @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
|
|
5
|
+
import { surfaceHighlightDay } from '@skyscanner/bpk-foundations-web/tokens/base.es6';
|
|
6
|
+
|
|
7
|
+
// @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
|
|
8
|
+
import BpkCloseButton from "../../bpk-component-close-button";
|
|
9
|
+
// @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
|
|
10
|
+
import { BpkButtonLink } from "../../bpk-component-link";
|
|
11
|
+
import BpkText, { TEXT_STYLES } from "../../bpk-component-text";
|
|
12
|
+
import { TransitionInitialMount, cssModules } from "../../bpk-react-utils";
|
|
13
|
+
import { ARROW_ID } from "./constants";
|
|
14
|
+
import STYLES from "./BpkPopover.module.css";
|
|
15
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
16
|
+
const getClassName = cssModules(STYLES);
|
|
17
|
+
export function usePopover({
|
|
18
|
+
arrowRef,
|
|
19
|
+
modal,
|
|
20
|
+
onOpenChange: setControlledOpen,
|
|
21
|
+
open: controlledOpen,
|
|
22
|
+
placement,
|
|
23
|
+
showArrow
|
|
24
|
+
} = {}) {
|
|
25
|
+
const open = controlledOpen;
|
|
26
|
+
const setOpen = setControlledOpen;
|
|
27
|
+
const data = useFloating({
|
|
28
|
+
placement,
|
|
29
|
+
open,
|
|
30
|
+
onOpenChange: setOpen,
|
|
31
|
+
whileElementsMounted: autoUpdate,
|
|
32
|
+
middleware: [showArrow && offset(14), arrow({
|
|
33
|
+
element: arrowRef
|
|
34
|
+
}), flip({
|
|
35
|
+
fallbackAxisSideDirection: 'start'
|
|
36
|
+
})]
|
|
37
|
+
});
|
|
38
|
+
const {
|
|
39
|
+
context
|
|
40
|
+
} = data;
|
|
41
|
+
const click = useClick(context, {
|
|
42
|
+
enabled: controlledOpen == null
|
|
43
|
+
});
|
|
44
|
+
const dismiss = useDismiss(context);
|
|
45
|
+
const role = useRole(context);
|
|
46
|
+
const interactions = useInteractions([click, dismiss, role]);
|
|
47
|
+
return React.useMemo(() => ({
|
|
48
|
+
open,
|
|
49
|
+
setOpen,
|
|
50
|
+
...interactions,
|
|
51
|
+
...data,
|
|
52
|
+
modal
|
|
53
|
+
}), [open, setOpen, interactions, data, modal]);
|
|
54
|
+
}
|
|
55
|
+
const PopoverContext = /*#__PURE__*/React.createContext(null);
|
|
56
|
+
export const usePopoverContext = () => {
|
|
57
|
+
const context = React.useContext(PopoverContext);
|
|
58
|
+
if (context == null) {
|
|
59
|
+
throw new Error('Popover components must be wrapped in <Popover />');
|
|
60
|
+
}
|
|
61
|
+
return context;
|
|
62
|
+
};
|
|
63
|
+
export function Popover({
|
|
64
|
+
children,
|
|
65
|
+
modal = false,
|
|
66
|
+
...restOptions
|
|
67
|
+
}) {
|
|
68
|
+
// This can accept any props as options, e.g. `placement`,
|
|
69
|
+
// or other positioning options.
|
|
70
|
+
const popover = usePopover({
|
|
71
|
+
modal,
|
|
72
|
+
...restOptions
|
|
73
|
+
});
|
|
74
|
+
return /*#__PURE__*/_jsx(PopoverContext.Provider, {
|
|
75
|
+
value: popover,
|
|
76
|
+
children: children
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
export const PopoverTrigger = /*#__PURE__*/React.forwardRef(({
|
|
80
|
+
asChild = false,
|
|
81
|
+
children,
|
|
82
|
+
...props
|
|
83
|
+
}, propRef) => {
|
|
84
|
+
const context = usePopoverContext();
|
|
85
|
+
const childrenRef = children.ref;
|
|
86
|
+
const ref = useMergeRefs([context.refs.setReference, propRef, childrenRef]);
|
|
87
|
+
|
|
88
|
+
// `asChild` allows the user to pass any element as the anchor
|
|
89
|
+
if (asChild && /*#__PURE__*/React.isValidElement(children)) {
|
|
90
|
+
return /*#__PURE__*/React.cloneElement(children, context.getReferenceProps({
|
|
91
|
+
ref,
|
|
92
|
+
...props,
|
|
93
|
+
...children.props,
|
|
94
|
+
'data-state': context.open ? 'open' : 'closed'
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
return /*#__PURE__*/_jsx("div", {
|
|
98
|
+
ref: ref
|
|
99
|
+
// The user can style the trigger based on the state
|
|
100
|
+
,
|
|
101
|
+
"data-state": context.open ? 'open' : 'closed',
|
|
102
|
+
...context.getReferenceProps(props),
|
|
103
|
+
children: children
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
const EVENT_SOURCES = {
|
|
107
|
+
CLOSE_BUTTON: 'CLOSE_BUTTON',
|
|
108
|
+
CLOSE_LINK: 'CLOSE_LINK'
|
|
109
|
+
};
|
|
110
|
+
const bindEventSource = (source, callback) => event => {
|
|
111
|
+
if (event.persist) {
|
|
112
|
+
event.persist();
|
|
113
|
+
}
|
|
114
|
+
callback(event, {
|
|
115
|
+
source
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
export const PopoverContent = /*#__PURE__*/React.forwardRef(({
|
|
119
|
+
arrowRef,
|
|
120
|
+
children,
|
|
121
|
+
className = null,
|
|
122
|
+
closeButtonIcon = true,
|
|
123
|
+
closeButtonProps = {},
|
|
124
|
+
closeButtonText,
|
|
125
|
+
id,
|
|
126
|
+
isOpen = false,
|
|
127
|
+
label,
|
|
128
|
+
labelAsTitle = false,
|
|
129
|
+
onClose,
|
|
130
|
+
padded = true,
|
|
131
|
+
placement = 'bottom',
|
|
132
|
+
setState: setIsOpenState,
|
|
133
|
+
showArrow,
|
|
134
|
+
target,
|
|
135
|
+
...rest
|
|
136
|
+
}, propRef) => {
|
|
137
|
+
// const [isOpenState, setIsOpenState] = React.useState(isOpen);
|
|
138
|
+
|
|
139
|
+
const {
|
|
140
|
+
context: floatingContext,
|
|
141
|
+
...context
|
|
142
|
+
} = usePopoverContext();
|
|
143
|
+
const ref = useMergeRefs([context.refs.setFloating, propRef]);
|
|
144
|
+
const classNames = getClassName('bpk-popover', className);
|
|
145
|
+
const bodyClassNames = getClassName(padded && 'bpk-popover__body--padded');
|
|
146
|
+
const labelId = `bpk-popover-label-${id}`;
|
|
147
|
+
if (!floatingContext.open) return null;
|
|
148
|
+
return /*#__PURE__*/_jsx(FloatingPortal, {
|
|
149
|
+
children: /*#__PURE__*/_jsx(FloatingFocusManager, {
|
|
150
|
+
context: floatingContext,
|
|
151
|
+
modal: context.modal,
|
|
152
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
153
|
+
ref: ref,
|
|
154
|
+
style: {
|
|
155
|
+
...context.floatingStyles
|
|
156
|
+
},
|
|
157
|
+
...context.getFloatingProps(),
|
|
158
|
+
children: /*#__PURE__*/_jsx(TransitionInitialMount, {
|
|
159
|
+
appearClassName: getClassName('bpk-popover--appear'),
|
|
160
|
+
appearActiveClassName: getClassName('bpk-popover--appear-active'),
|
|
161
|
+
transitionTimeout: 200,
|
|
162
|
+
children: /*#__PURE__*/_jsxs("section", {
|
|
163
|
+
id: id,
|
|
164
|
+
tabIndex: -1,
|
|
165
|
+
role: "dialog",
|
|
166
|
+
"aria-labelledby": labelId,
|
|
167
|
+
className: classNames,
|
|
168
|
+
...rest,
|
|
169
|
+
children: [showArrow && /*#__PURE__*/_jsx(FloatingArrow, {
|
|
170
|
+
ref: arrowRef,
|
|
171
|
+
context: floatingContext,
|
|
172
|
+
id: ARROW_ID
|
|
173
|
+
// eslint-disable-next-line @skyscanner/rules/forbid-component-props
|
|
174
|
+
,
|
|
175
|
+
className: getClassName('bpk-popover__arrow'),
|
|
176
|
+
role: "presentation",
|
|
177
|
+
stroke: surfaceHighlightDay,
|
|
178
|
+
strokeWidth: 0.0625
|
|
179
|
+
}), labelAsTitle ? /*#__PURE__*/_jsxs("header", {
|
|
180
|
+
className: getClassName('bpk-popover__header'),
|
|
181
|
+
children: [/*#__PURE__*/_jsx(BpkText, {
|
|
182
|
+
tagName: "h2",
|
|
183
|
+
id: labelId,
|
|
184
|
+
textStyle: TEXT_STYLES.label1,
|
|
185
|
+
children: label
|
|
186
|
+
}), "\xA0", closeButtonIcon ? /*#__PURE__*/_jsx(BpkCloseButton, {
|
|
187
|
+
label: closeButtonText,
|
|
188
|
+
onClick: () => {
|
|
189
|
+
bindEventSource(EVENT_SOURCES.CLOSE_BUTTON, onClose);
|
|
190
|
+
setIsOpenState(false);
|
|
191
|
+
},
|
|
192
|
+
...closeButtonProps
|
|
193
|
+
}) : /*#__PURE__*/_jsx(BpkButtonLink, {
|
|
194
|
+
onClick: () => {
|
|
195
|
+
bindEventSource(EVENT_SOURCES.CLOSE_LINK, onClose);
|
|
196
|
+
setIsOpenState(false);
|
|
197
|
+
},
|
|
198
|
+
...closeButtonProps,
|
|
199
|
+
children: closeButtonText
|
|
200
|
+
})]
|
|
201
|
+
}) : /*#__PURE__*/_jsx("span", {
|
|
202
|
+
id: labelId,
|
|
203
|
+
className: getClassName('bpk-popover__label'),
|
|
204
|
+
children: label
|
|
205
|
+
}), /*#__PURE__*/_jsx("div", {
|
|
206
|
+
className: bodyClassNames,
|
|
207
|
+
children: children
|
|
208
|
+
}), !labelAsTitle && /*#__PURE__*/_jsx("footer", {
|
|
209
|
+
className: getClassName('bpk-popover__footer'),
|
|
210
|
+
children: /*#__PURE__*/_jsx(BpkButtonLink, {
|
|
211
|
+
onClick: () => {
|
|
212
|
+
bindEventSource(EVENT_SOURCES.CLOSE_LINK, onClose);
|
|
213
|
+
setIsOpenState(false);
|
|
214
|
+
},
|
|
215
|
+
...closeButtonProps,
|
|
216
|
+
children: closeButtonText
|
|
217
|
+
})
|
|
218
|
+
})]
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
})
|
|
222
|
+
})
|
|
223
|
+
});
|
|
224
|
+
});
|