@skyscanner/backpack-web 42.6.0 → 42.8.0-dev-v24332493292.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 (37) hide show
  1. package/bpk-component-ai-blurb/index.d.ts +3 -0
  2. package/bpk-component-ai-blurb/index.js +20 -0
  3. package/bpk-component-ai-blurb/src/BpkAiBlurb.d.ts +29 -0
  4. package/bpk-component-ai-blurb/src/BpkAiBlurb.js +57 -0
  5. package/bpk-component-ai-blurb/src/BpkAiBlurb.module.css +18 -0
  6. package/bpk-component-ai-blurb/src/BpkAiBlurbEllipsis.d.ts +2 -0
  7. package/bpk-component-ai-blurb/src/BpkAiBlurbEllipsis.js +40 -0
  8. package/bpk-component-ai-blurb/src/BpkAiBlurbFeedback.d.ts +3 -0
  9. package/bpk-component-ai-blurb/src/BpkAiBlurbFeedback.js +74 -0
  10. package/bpk-component-ai-blurb/src/BpkAiBlurbHeader.d.ts +3 -0
  11. package/bpk-component-ai-blurb/src/BpkAiBlurbHeader.js +41 -0
  12. package/bpk-component-ai-blurb/src/BpkAiBlurbRoot.d.ts +3 -0
  13. package/bpk-component-ai-blurb/src/BpkAiBlurbRoot.js +30 -0
  14. package/bpk-component-ai-blurb/src/BpkAiBlurbSummary.d.ts +3 -0
  15. package/bpk-component-ai-blurb/src/BpkAiBlurbSummary.js +54 -0
  16. package/bpk-component-ai-blurb/src/common-types.d.ts +66 -0
  17. package/bpk-component-ai-blurb/src/common-types.js +1 -0
  18. package/bpk-component-aria-live/src/BpkAriaLive.story-helpers.d.ts +11 -0
  19. package/bpk-component-aria-live/src/BpkAriaLive.story-helpers.js +48 -0
  20. package/bpk-component-bubble/src/BpkBubble.module.css +1 -1
  21. package/bpk-component-layout/src/commonProps.d.ts +9 -3
  22. package/bpk-component-layout/src/tokenUtils.js +22 -6
  23. package/bpk-component-layout/src/tokens.d.ts +17 -3
  24. package/bpk-component-layout/src/tokens.js +19 -3
  25. package/bpk-component-spinner/src/SpinnerLayout.story-helpers.d.ts +12 -0
  26. package/bpk-component-spinner/src/SpinnerLayout.story-helpers.js +47 -0
  27. package/bpk-component-spinner/src/SpinnerLayout.story-helpers.module.css +18 -0
  28. package/bpk-component-text/src/BpkText.module.css +1 -1
  29. package/bpk-mixins/_focus-indicator-v2.scss +85 -0
  30. package/bpk-mixins/_index.scss +1 -0
  31. package/bpk-scrim-utils/src/focusScope.d.ts +5 -0
  32. package/bpk-scrim-utils/src/focusScope.js +54 -0
  33. package/bpk-scrim-utils/src/focusStore.d.ts +6 -0
  34. package/bpk-scrim-utils/src/focusStore.js +40 -0
  35. package/bpk-scrim-utils/src/withScrim.js +2 -5
  36. package/bpk-stylesheets/base.css +1 -1
  37. package/package.json +3 -4
@@ -0,0 +1,3 @@
1
+ import BpkAiBlurb from './src/BpkAiBlurb';
2
+ export type { BpkAiBlurbRootProps, BpkAiBlurbHeaderProps, BpkAiBlurbSummaryProps, BpkAiBlurbFeedbackProps, BpkAiBlurbNamespace, } from './src/common-types';
3
+ export default BpkAiBlurb;
@@ -0,0 +1,20 @@
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 BpkAiBlurb from "./src/BpkAiBlurb";
20
+ export default BpkAiBlurb;
@@ -0,0 +1,29 @@
1
+ import type { BpkAiBlurbNamespace } from './common-types';
2
+ /**
3
+ * BpkAiBlurb is a composable component for displaying AI-generated summaries.
4
+ *
5
+ * Compose subcomponents to build each state:
6
+ *
7
+ * @example
8
+ * // Loading state
9
+ * <BpkAiBlurb.Root>
10
+ * <BpkAiBlurb.Header title="Summarized by AI" />
11
+ * <BpkAiBlurb.Summary state="thinking" thinkingText="Comparing your shortlist" />
12
+ * </BpkAiBlurb.Root>
13
+ *
14
+ * @example
15
+ * // Success state with feedback
16
+ * <BpkAiBlurb.Root>
17
+ * <BpkAiBlurb.Header title="Summarized by AI" />
18
+ * <BpkAiBlurb.Summary state="aiResponse" aiResponseText={llmText} />
19
+ * <BpkAiBlurb.Feedback
20
+ * feedbackText="Was this helpful?"
21
+ * thankYouText="Thanks for your feedback!"
22
+ * thumbsUpLabel="Thumbs up"
23
+ * thumbsDownLabel="Thumbs down"
24
+ * onFeedback={(positive) => trackEvent(positive ? 'thumb_up' : 'thumb_down')}
25
+ * />
26
+ * </BpkAiBlurb.Root>
27
+ */
28
+ declare const BpkAiBlurb: BpkAiBlurbNamespace;
29
+ export default BpkAiBlurb;
@@ -0,0 +1,57 @@
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 BpkAiBlurbEllipsis from "./BpkAiBlurbEllipsis";
20
+ import BpkAiBlurbFeedback from "./BpkAiBlurbFeedback";
21
+ import BpkAiBlurbHeader from "./BpkAiBlurbHeader";
22
+ import BpkAiBlurbRoot from "./BpkAiBlurbRoot";
23
+ import BpkAiBlurbSummary from "./BpkAiBlurbSummary";
24
+ /**
25
+ * BpkAiBlurb is a composable component for displaying AI-generated summaries.
26
+ *
27
+ * Compose subcomponents to build each state:
28
+ *
29
+ * @example
30
+ * // Loading state
31
+ * <BpkAiBlurb.Root>
32
+ * <BpkAiBlurb.Header title="Summarized by AI" />
33
+ * <BpkAiBlurb.Summary state="thinking" thinkingText="Comparing your shortlist" />
34
+ * </BpkAiBlurb.Root>
35
+ *
36
+ * @example
37
+ * // Success state with feedback
38
+ * <BpkAiBlurb.Root>
39
+ * <BpkAiBlurb.Header title="Summarized by AI" />
40
+ * <BpkAiBlurb.Summary state="aiResponse" aiResponseText={llmText} />
41
+ * <BpkAiBlurb.Feedback
42
+ * feedbackText="Was this helpful?"
43
+ * thankYouText="Thanks for your feedback!"
44
+ * thumbsUpLabel="Thumbs up"
45
+ * thumbsDownLabel="Thumbs down"
46
+ * onFeedback={(positive) => trackEvent(positive ? 'thumb_up' : 'thumb_down')}
47
+ * />
48
+ * </BpkAiBlurb.Root>
49
+ */
50
+ const BpkAiBlurb = {
51
+ Root: BpkAiBlurbRoot,
52
+ Header: BpkAiBlurbHeader,
53
+ Summary: BpkAiBlurbSummary,
54
+ Ellipsis: BpkAiBlurbEllipsis,
55
+ Feedback: BpkAiBlurbFeedback
56
+ };
57
+ export default BpkAiBlurb;
@@ -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-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}}
@@ -0,0 +1,2 @@
1
+ declare const BpkAiBlurbEllipsis: () => import("react/jsx-runtime").JSX.Element;
2
+ export default BpkAiBlurbEllipsis;
@@ -0,0 +1,40 @@
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 { cssModules } from "../../bpk-react-utils";
20
+ import STYLES from "./BpkAiBlurb.module.css";
21
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
22
+ const getClassName = cssModules(STYLES);
23
+
24
+ // Animated three-dot ellipsis for inline use at the end of loading text.
25
+ // Hidden from assistive technology — ensure surrounding text provides context.
26
+ const BpkAiBlurbEllipsis = () => /*#__PURE__*/_jsxs("span", {
27
+ className: getClassName('bpk-ai-blurb__ellipsis'),
28
+ "aria-hidden": "true",
29
+ children: [/*#__PURE__*/_jsx("span", {
30
+ className: getClassName('bpk-ai-blurb__ellipsis-dot'),
31
+ children: "."
32
+ }), /*#__PURE__*/_jsx("span", {
33
+ className: getClassName('bpk-ai-blurb__ellipsis-dot', 'bpk-ai-blurb__ellipsis-dot--2'),
34
+ children: "."
35
+ }), /*#__PURE__*/_jsx("span", {
36
+ className: getClassName('bpk-ai-blurb__ellipsis-dot', 'bpk-ai-blurb__ellipsis-dot--3'),
37
+ children: "."
38
+ })]
39
+ });
40
+ export default BpkAiBlurbEllipsis;
@@ -0,0 +1,3 @@
1
+ import type { BpkAiBlurbFeedbackProps } from './common-types';
2
+ declare const BpkAiBlurbFeedback: ({ feedbackText, onFeedback, thankYouText, thumbsDownLabel, thumbsUpLabel, }: BpkAiBlurbFeedbackProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default BpkAiBlurbFeedback;
@@ -0,0 +1,74 @@
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 { useState } from 'react';
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
+ import { BpkFlex, BpkSpacing } from "../../bpk-component-layout";
24
+ import BpkText, { TEXT_STYLES } from "../../bpk-component-text";
25
+ import { cssModules } from "../../bpk-react-utils";
26
+ import STYLES from "./BpkAiBlurb.module.css";
27
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
28
+ const getClassName = cssModules(STYLES);
29
+ const BpkAiBlurbFeedback = ({
30
+ feedbackText,
31
+ onFeedback,
32
+ thankYouText,
33
+ thumbsDownLabel,
34
+ thumbsUpLabel
35
+ }) => {
36
+ const [hasVoted, setHasVoted] = useState(false);
37
+ const handleVote = positive => {
38
+ setHasVoted(true);
39
+ onFeedback?.(positive);
40
+ };
41
+ return /*#__PURE__*/_jsxs(BpkFlex, {
42
+ align: "center",
43
+ gap: BpkSpacing.SM,
44
+ children: [!hasVoted && /*#__PURE__*/_jsxs(_Fragment, {
45
+ children: [/*#__PURE__*/_jsx(BpkText, {
46
+ textStyle: TEXT_STYLES.caption,
47
+ 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
+ })
64
+ })]
65
+ }), /*#__PURE__*/_jsx(BpkAriaLive, {
66
+ visible: hasVoted,
67
+ children: hasVoted ? /*#__PURE__*/_jsx(BpkText, {
68
+ textStyle: TEXT_STYLES.caption,
69
+ children: thankYouText
70
+ }) : ''
71
+ })]
72
+ });
73
+ };
74
+ export default BpkAiBlurbFeedback;
@@ -0,0 +1,3 @@
1
+ import type { BpkAiBlurbHeaderProps } from './common-types';
2
+ declare const BpkAiBlurbHeader: ({ title }: BpkAiBlurbHeaderProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default BpkAiBlurbHeader;
@@ -0,0 +1,41 @@
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 AiIcon from "../../bpk-component-icon/sm/ai";
20
+ import { BpkFlex, BpkSpacing } from "../../bpk-component-layout";
21
+ import BpkText, { TEXT_STYLES } from "../../bpk-component-text";
22
+ import { cssModules } from "../../bpk-react-utils";
23
+ import STYLES from "./BpkAiBlurb.module.css";
24
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
25
+ const getClassName = cssModules(STYLES);
26
+ const BpkAiBlurbHeader = ({
27
+ title
28
+ }) => /*#__PURE__*/_jsx("div", {
29
+ className: getClassName('bpk-ai-blurb__header'),
30
+ children: /*#__PURE__*/_jsxs(BpkFlex, {
31
+ align: "center",
32
+ gap: BpkSpacing.SM,
33
+ children: [/*#__PURE__*/_jsx(AiIcon, {
34
+ "aria-hidden": true
35
+ }), /*#__PURE__*/_jsx(BpkText, {
36
+ textStyle: TEXT_STYLES.caption,
37
+ children: title
38
+ })]
39
+ })
40
+ });
41
+ export default BpkAiBlurbHeader;
@@ -0,0 +1,3 @@
1
+ import type { BpkAiBlurbRootProps } from './common-types';
2
+ declare const BpkAiBlurbRoot: ({ children }: BpkAiBlurbRootProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default BpkAiBlurbRoot;
@@ -0,0 +1,30 @@
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 { cssModules, getDataComponentAttribute } from "../../bpk-react-utils";
20
+ import STYLES from "./BpkAiBlurb.module.css";
21
+ import { jsx as _jsx } from "react/jsx-runtime";
22
+ const getClassName = cssModules(STYLES);
23
+ const BpkAiBlurbRoot = ({
24
+ children
25
+ }) => /*#__PURE__*/_jsx("div", {
26
+ className: getClassName('bpk-ai-blurb'),
27
+ ...getDataComponentAttribute('AiBlurb'),
28
+ children: children
29
+ });
30
+ export default BpkAiBlurbRoot;
@@ -0,0 +1,3 @@
1
+ import type { BpkAiBlurbSummaryProps } from './common-types';
2
+ declare const BpkAiBlurbSummary: (props: BpkAiBlurbSummaryProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default BpkAiBlurbSummary;
@@ -0,0 +1,54 @@
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 BpkLink from "../../bpk-component-link";
20
+ import BpkText, { TEXT_STYLES } from "../../bpk-component-text";
21
+ import { cssModules } from "../../bpk-react-utils";
22
+ import BpkAiBlurbEllipsis from "./BpkAiBlurbEllipsis";
23
+ import STYLES from "./BpkAiBlurb.module.css";
24
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
25
+ const getClassName = cssModules(STYLES);
26
+ const BpkAiBlurbSummary = props => {
27
+ let content;
28
+ if (props.state === 'aiResponse') {
29
+ content = props.aiResponseText;
30
+ } else if (props.state === 'thinking') {
31
+ content = /*#__PURE__*/_jsxs(BpkText, {
32
+ tagName: "p",
33
+ textStyle: TEXT_STYLES.caption,
34
+ children: [props.thinkingText, /*#__PURE__*/_jsx(BpkAiBlurbEllipsis, {})]
35
+ });
36
+ } else {
37
+ content = /*#__PURE__*/_jsxs("div", {
38
+ className: getClassName('bpk-ai-blurb__error'),
39
+ children: [/*#__PURE__*/_jsx(BpkText, {
40
+ tagName: "span",
41
+ textStyle: TEXT_STYLES.caption,
42
+ children: props.errorText
43
+ }), /*#__PURE__*/_jsx(BpkLink, {
44
+ href: props.errorLinkHref,
45
+ children: props.errorLinkText
46
+ })]
47
+ });
48
+ }
49
+ return /*#__PURE__*/_jsx("div", {
50
+ className: getClassName('bpk-ai-blurb__summary'),
51
+ children: content
52
+ });
53
+ };
54
+ export default BpkAiBlurbSummary;
@@ -0,0 +1,66 @@
1
+ import type { ReactNode } from 'react';
2
+ export type BpkAiBlurbRootProps = {
3
+ /** Content to render inside the AI summary container */
4
+ children: ReactNode;
5
+ };
6
+ export type BpkAiBlurbHeaderProps = {
7
+ /** Title string displayed next to the AI spark icon. Not translated by Backpack. */
8
+ title: string;
9
+ };
10
+ export type BpkAiBlurbSummaryProps = {
11
+ /** Controls which content is displayed. */
12
+ state: 'aiResponse';
13
+ /** AI response content. Consumer controls formatting. */
14
+ aiResponseText: ReactNode;
15
+ } | {
16
+ /** Controls which content is displayed. */
17
+ state: 'thinking';
18
+ /** Text displayed followed by an animated ellipsis. */
19
+ thinkingText: string;
20
+ } | {
21
+ /** Controls which content is displayed. */
22
+ state: 'error';
23
+ /** Text displayed before the error link. */
24
+ errorText: string;
25
+ /** Text for the inline error link. */
26
+ errorLinkText: string;
27
+ /** href for the inline error link. */
28
+ errorLinkHref: string;
29
+ };
30
+ export type BpkAiBlurbFeedbackProps = {
31
+ /** Text displayed before a vote is cast. e.g. "Was this helpful?" — not translated by Backpack. */
32
+ feedbackText: string;
33
+ /** Text displayed after a vote is cast. e.g. "Thanks for your feedback!" — not translated by Backpack. */
34
+ thankYouText: string;
35
+ /** Accessible label for the thumbs-up button. Not translated by Backpack. */
36
+ thumbsUpLabel: string;
37
+ /** Accessible label for the thumbs-down button. Not translated by Backpack. */
38
+ thumbsDownLabel: string;
39
+ /**
40
+ * Called when either thumb button is pressed.
41
+ * `positive` is `true` for thumbs-up, `false` for thumbs-down.
42
+ */
43
+ onFeedback?: (positive: boolean) => void;
44
+ };
45
+ export type BpkAiBlurbNamespace = {
46
+ Root: {
47
+ (props: BpkAiBlurbRootProps): ReactNode;
48
+ displayName?: string;
49
+ };
50
+ Header: {
51
+ (props: BpkAiBlurbHeaderProps): ReactNode;
52
+ displayName?: string;
53
+ };
54
+ Summary: {
55
+ (props: BpkAiBlurbSummaryProps): ReactNode;
56
+ displayName?: string;
57
+ };
58
+ Ellipsis: {
59
+ (): ReactNode;
60
+ displayName?: string;
61
+ };
62
+ Feedback: {
63
+ (props: BpkAiBlurbFeedbackProps): ReactNode;
64
+ displayName?: string;
65
+ };
66
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ import type { ReactElement } from 'react';
2
+ type AriaLiveDemoProps = {
3
+ preamble?: ReactElement | null;
4
+ children: ReactElement;
5
+ className?: string | null;
6
+ style?: {};
7
+ visible?: Boolean;
8
+ [rest: string]: any;
9
+ };
10
+ declare const AriaLiveDemo: ({ children, className, preamble, style, visible, ...rest }: AriaLiveDemoProps) => import("react/jsx-runtime").JSX.Element;
11
+ export default AriaLiveDemo;
@@ -0,0 +1,48 @@
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 { ARIA_LIVE_POLITENESS_SETTINGS } from '..';
20
+ import { cssModules } from "../../bpk-react-utils";
21
+ import BpkAriaLive from "./BpkAriaLive";
22
+ import STYLES from "./BpkAriaLive.stories.module.css";
23
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
24
+ const getClassName = cssModules(STYLES);
25
+ const AriaLiveDemo = ({
26
+ children,
27
+ className = null,
28
+ preamble = null,
29
+ style = undefined,
30
+ visible = false,
31
+ ...rest
32
+ }) => /*#__PURE__*/_jsxs("div", {
33
+ className: getClassName('bpk-storybook-aria-live-demo', className),
34
+ style: style,
35
+ children: [/*#__PURE__*/_jsx("p", {
36
+ children: /*#__PURE__*/_jsx("strong", {
37
+ children: "ARIA live region:"
38
+ })
39
+ }), /*#__PURE__*/_jsx("p", {
40
+ children: visible ? 'This content is relevant to everyone, not just assistive technologies, so it is permanently visible.' : 'This would usually be visually hidden, and only visible to assistive technologies. It is visible here for demo purposes.'
41
+ }), preamble, /*#__PURE__*/_jsx(BpkAriaLive, {
42
+ ...rest,
43
+ visible: true,
44
+ politenessSetting: ARIA_LIVE_POLITENESS_SETTINGS.assertive,
45
+ children: children
46
+ })]
47
+ });
48
+ export default AriaLiveDemo;
@@ -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 SC", "Noto Serif TC", "Noto Serif JP", "Noto Serif KR", 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", "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}
@@ -1,6 +1,6 @@
1
- import type { AriaRole, KeyboardEventHandler, MouseEventHandler } from 'react';
1
+ import type { AriaAttributes, AriaRole, KeyboardEventHandler, MouseEventHandler } from 'react';
2
2
  import type { BpkLayoutBackgroundColor } from './backgroundColors';
3
- import type { BpkSpacingValue, BpkSizeValue, BpkPositionValue, BpkResponsiveValue } from './tokens';
3
+ import type { BpkSpacingValue, BpkSizeValue, BpkPositionValue, BpkPositionKeyword, BpkOverflowValue, BpkZIndexValue, BpkResponsiveValue } from './tokens';
4
4
  import type { TextColor, TextStyle } from '../../bpk-component-text';
5
5
  /**
6
6
  * Common spacing-related props shared by all Backpack layout components
@@ -46,14 +46,20 @@ export interface BpkSpacingProps {
46
46
  * container patterns (e.g. clickable cards, landmark regions).
47
47
  * - BpkBox additionally exposes onFocus and onBlur on its own props type.
48
48
  */
49
- export interface BpkCommonLayoutProps extends BpkSpacingProps {
49
+ export interface BpkCommonLayoutProps extends BpkSpacingProps, AriaAttributes {
50
50
  className?: never;
51
51
  style?: never;
52
+ id?: string;
52
53
  tabIndex?: number;
53
54
  role?: AriaRole;
54
55
  onClick?: MouseEventHandler<HTMLElement>;
55
56
  onKeyDown?: KeyboardEventHandler<HTMLElement>;
56
57
  textStyle?: BpkResponsiveValue<TextStyle>;
58
+ position?: BpkResponsiveValue<BpkPositionKeyword>;
59
+ overflow?: BpkResponsiveValue<BpkOverflowValue>;
60
+ overflowX?: BpkResponsiveValue<BpkOverflowValue>;
61
+ overflowY?: BpkResponsiveValue<BpkOverflowValue>;
62
+ zIndex?: BpkZIndexValue;
57
63
  'data-testid'?: string;
58
64
  'data-cy'?: string;
59
65
  color?: TextColor;
@@ -41,7 +41,9 @@ export const BPK_RESPONSIVE_PROP_GROUPS_BY_COMPONENT = {
41
41
  // Flex container props
42
42
  'flexDirection', 'flexWrap', 'justifyContent', 'alignItems', 'alignContent',
43
43
  // Grid container props
44
- 'gridTemplateColumns', 'gridTemplateRows', 'gridTemplateAreas', 'gridAutoFlow', 'gridAutoRows', 'gridAutoColumns'],
44
+ 'gridTemplateColumns', 'gridTemplateRows', 'gridTemplateAreas', 'gridAutoFlow', 'gridAutoRows', 'gridAutoColumns',
45
+ // Position keyword and overflow (from BpkCommonLayoutProps)
46
+ 'position', 'overflow', 'overflowX', 'overflowY'],
45
47
  item: [
46
48
  // Flex item props
47
49
  'flex', 'flexGrow', 'flexShrink', 'flexBasis', 'order', 'alignSelf', 'justifySelf',
@@ -50,22 +52,28 @@ export const BPK_RESPONSIVE_PROP_GROUPS_BY_COMPONENT = {
50
52
  },
51
53
  // Note: BpkFlex maps its public API props to these Chakra keys.
52
54
  BpkFlex: {
53
- container: ['textStyle', 'flexDirection', 'justifyContent', 'alignItems', 'flexWrap'],
55
+ container: ['textStyle', 'flexDirection', 'justifyContent', 'alignItems', 'flexWrap',
56
+ // Position keyword and overflow (from BpkCommonLayoutProps)
57
+ 'position', 'overflow', 'overflowX', 'overflowY'],
54
58
  item: ['flexGrow', 'flexShrink', 'flexBasis']
55
59
  },
56
60
  // Note: BpkGrid maps its public API props to these Chakra keys.
57
61
  BpkGrid: {
58
- container: ['textStyle', 'justifyContent', 'alignItems', 'gridTemplateColumns', 'gridTemplateRows', 'gridTemplateAreas', 'gridAutoFlow', 'gridAutoRows', 'gridAutoColumns'],
62
+ container: ['textStyle', 'justifyContent', 'alignItems', 'gridTemplateColumns', 'gridTemplateRows', 'gridTemplateAreas', 'gridAutoFlow', 'gridAutoRows', 'gridAutoColumns',
63
+ // Position keyword and overflow (from BpkCommonLayoutProps)
64
+ 'position', 'overflow', 'overflowX', 'overflowY'],
59
65
  item: [
60
66
  // Used when placing the grid itself within a parent grid.
61
67
  'gridColumn', 'gridRow']
62
68
  },
63
69
  BpkGridItem: {
64
- container: ['textStyle']
70
+ container: ['textStyle', 'position', 'overflow', 'overflowX', 'overflowY']
65
71
  },
66
72
  // Note: BpkStack uses Chakra Stack option prop names directly.
67
73
  BpkStack: {
68
- container: ['textStyle', ...StackOptionKeys]
74
+ container: ['textStyle', ...StackOptionKeys,
75
+ // Position keyword and overflow (from BpkCommonLayoutProps)
76
+ 'position', 'overflow', 'overflowX', 'overflowY']
69
77
  }
70
78
  };
71
79
  export const BPK_RESPONSIVE_PROP_KEYS_BY_COMPONENT = {
@@ -101,7 +109,15 @@ function filterToAllowlist(props, allowlist) {
101
109
  export function processBpkComponentProps(props, options) {
102
110
  const processed = processBpkProps(props);
103
111
  const allowlist = BPK_RESPONSIVE_PROP_KEYS_BY_COMPONENT[options.component];
104
- const responsiveSource = options.responsiveProps ? filterToAllowlist(options.responsiveProps, allowlist) : filterToAllowlist(processed, allowlist);
112
+ // When responsiveProps is provided (e.g. BpkFlex maps direction→flexDirection),
113
+ // merge it with any allowlisted props already in `processed` (e.g. position/overflow
114
+ // that come in via ...props and are NOT included in responsiveProps).
115
+ // responsiveProps takes precedence so that explicit prop-name mappings always win.
116
+ const processedAllowlisted = filterToAllowlist(processed, allowlist);
117
+ const responsiveSource = options.responsiveProps ? {
118
+ ...processedAllowlisted,
119
+ ...filterToAllowlist(options.responsiveProps, allowlist)
120
+ } : processedAllowlisted;
105
121
  if (Object.keys(responsiveSource).length === 0) {
106
122
  return processed;
107
123
  }
@@ -47,10 +47,24 @@ export type BpkBreakpointValue = BpkBreakpointToken;
47
47
  */
48
48
  export type BpkSizeValue = `${number}rem` | `${number}%` | 'auto' | 'full' | 'fit-content';
49
49
  /**
50
- * Helper type for position props that can use rem or percentages.
51
- * We intentionally do not allow semantic values like 'auto' here.
50
+ * Helper type for position props that can use rem, percentages, or bare zero.
51
+ * CSS allows `0` without a unit; `'0'` is therefore an explicit allowed value.
52
+ * We intentionally do not allow other semantic values like 'auto' here.
52
53
  */
53
- export type BpkPositionValue = `${number}rem` | `${number}%`;
54
+ export type BpkPositionValue = `${number}rem` | `${number}%` | '0';
55
+ /**
56
+ * CSS `position` property keyword values.
57
+ */
58
+ export type BpkPositionKeyword = 'static' | 'relative' | 'absolute' | 'fixed' | 'sticky';
59
+ /**
60
+ * CSS `overflow` property keyword values.
61
+ */
62
+ export type BpkOverflowValue = 'visible' | 'hidden' | 'scroll' | 'auto' | 'clip';
63
+ /**
64
+ * CSS `z-index` values. Numeric values only; 'auto' is also permitted.
65
+ * Avoid magic numbers — prefer a shared z-index scale in your app.
66
+ */
67
+ export type BpkZIndexValue = number | 'auto';
54
68
  /**
55
69
  * Helper type for flex-basis prop that can use rem, percentages or semantic values.
56
70
  * Excludes 'px' values to enforce design system constraints.
@@ -71,8 +71,22 @@ export const BpkBreakpointToChakraKey = {
71
71
  */
72
72
 
73
73
  /**
74
- * Helper type for position props that can use rem or percentages.
75
- * We intentionally do not allow semantic values like 'auto' here.
74
+ * Helper type for position props that can use rem, percentages, or bare zero.
75
+ * CSS allows `0` without a unit; `'0'` is therefore an explicit allowed value.
76
+ * We intentionally do not allow other semantic values like 'auto' here.
77
+ */
78
+
79
+ /**
80
+ * CSS `position` property keyword values.
81
+ */
82
+
83
+ /**
84
+ * CSS `overflow` property keyword values.
85
+ */
86
+
87
+ /**
88
+ * CSS `z-index` values. Numeric values only; 'auto' is also permitted.
89
+ * Avoid magic numbers — prefer a shared z-index scale in your app.
76
90
  */
77
91
 
78
92
  /**
@@ -131,7 +145,9 @@ export function isValidSizeValue(value) {
131
145
  * @returns {boolean} True if the value is a valid rem or percentage
132
146
  */
133
147
  export function isValidPositionValue(value) {
134
- return /^-?\d+(\.\d+)?rem$/.test(value) ||
148
+ return value === '0' ||
149
+ // bare zero — valid CSS without a unit
150
+ /^-?\d+(\.\d+)?rem$/.test(value) ||
135
151
  // rem values
136
152
  isPercentage(value) // percentage values
137
153
  ;
@@ -0,0 +1,12 @@
1
+ import PropTypes from 'prop-types';
2
+ import type { ReactElement } from 'react';
3
+ type Props = {
4
+ children: Array<ReactElement<any, any>> | ReactElement<any, any>;
5
+ };
6
+ declare const SpinnerLayout: {
7
+ (props: Props): import("react/jsx-runtime").JSX.Element;
8
+ propTypes: {
9
+ children: PropTypes.Validator<NonNullable<PropTypes.ReactNodeLike>>;
10
+ };
11
+ };
12
+ export default SpinnerLayout;
@@ -0,0 +1,47 @@
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 PropTypes from 'prop-types';
20
+ import { Children } from 'react';
21
+ import { cssModules } from "../../bpk-react-utils";
22
+ import SPINNER_TYPES from "./spinnerTypes";
23
+ import STYLES from "./SpinnerLayout.story-helpers.module.css";
24
+ import { jsx as _jsx } from "react/jsx-runtime";
25
+ const getClassName = cssModules(STYLES);
26
+ const SpinnerLayout = props => {
27
+ const {
28
+ children
29
+ } = props;
30
+ return /*#__PURE__*/_jsx("div", {
31
+ className: getClassName('bpk-spinner-layout'),
32
+ children: Children.map(children, child => {
33
+ const classNames = [getClassName('bpk-spinner-layout__spinner')];
34
+ if (child.props.type === SPINNER_TYPES.light) {
35
+ classNames.push(getClassName('bpk-spinner-layout__spinner--light'));
36
+ }
37
+ return /*#__PURE__*/_jsx("div", {
38
+ className: classNames.join(' '),
39
+ children: child
40
+ });
41
+ })
42
+ });
43
+ };
44
+ SpinnerLayout.propTypes = {
45
+ children: PropTypes.node.isRequired
46
+ };
47
+ export default SpinnerLayout;
@@ -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-spinner-layout{display:flex;flex-direction:column}.bpk-spinner-layout__spinner{display:flex;padding:1.5rem;justify-content:center}.bpk-spinner-layout__spinner--light{background-color:#05203c;border-radius:.25rem}
@@ -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-text{margin:0}.bpk-text--xs{font-size:.75rem;line-height:1rem;font-weight:400}.bpk-text--sm{font-size:.875rem;line-height:1.25rem;font-weight:400}.bpk-text--base{font-size:1rem;line-height:1.5rem;font-weight:400}.bpk-text--lg{font-size:1.25rem;line-height:1.75rem;font-weight:400}.bpk-text--xl{font-size:1.5rem;line-height:2rem;font-weight:400}.bpk-text--xxl{font-size:2rem;line-height:2.5rem;font-weight:700}.bpk-text--xxxl{font-size:2.5rem;line-height:3rem;font-weight:700}.bpk-text--xxxxl{font-size:3rem;line-height:3.5rem;font-weight:700;letter-spacing:-0.02em}.bpk-text--xxxxxl{font-size:4rem;line-height:4rem;font-weight:700;letter-spacing:-0.02em}.bpk-text--caption{font-size:.75rem;line-height:1rem;font-weight:400}.bpk-text--footnote{font-size:.875rem;line-height:1.25rem;font-weight:400}.bpk-text--label-1{font-size:1rem;line-height:1.5rem;font-weight:700}.bpk-text--label-2{font-size:.875rem;line-height:1.25rem;font-weight:700}.bpk-text--label-3{font-size:.75rem;line-height:1rem;font-weight:700}.bpk-text--body-default{font-size:1rem;line-height:1.5rem;font-weight:400}.bpk-text--body-longform{font-size:1.25rem;line-height:1.75rem;font-weight:400}.bpk-text--subheading{font-size:1.5rem;line-height:2rem;font-weight:400}.bpk-text--heading-1{font-size:2.5rem;line-height:3rem;font-weight:700}.bpk-text--heading-2{font-size:2rem;line-height:2.5rem;font-weight:700}.bpk-text--heading-3{font-size:1.5rem;line-height:1.75rem;font-weight:700}.bpk-text--heading-4{font-size:1.25rem;line-height:1.5rem;font-weight:700}.bpk-text--heading-5{font-size:1rem;line-height:1.25rem;font-weight:700}.bpk-text--hero-1{font-size:7.5rem;line-height:7.5rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-2{font-size:6rem;line-height:6rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-3{font-size:4.75rem;line-height:4.75rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-4{font-size:4rem;line-height:4rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-5{font-size:3rem;line-height:3rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-6{font-size:2.5rem;line-height:2.5rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--editorial-1{font-family:var(--bpk-larken-font-stack, "Larken", "Noto Sans Arabic", "Noto Serif Hebrew", "Noto Serif", "Noto Serif Devanagari", "Noto Serif Thai", "Noto Serif SC", "Noto Serif TC", "Noto Serif JP", "Noto Serif KR", sans-serif);font-size:3rem;line-height:3.5rem;font-weight:300}.bpk-text--editorial-2{font-family:var(--bpk-larken-font-stack, "Larken", "Noto Sans Arabic", "Noto Serif Hebrew", "Noto Serif", "Noto Serif Devanagari", "Noto Serif Thai", "Noto Serif SC", "Noto Serif TC", "Noto Serif JP", "Noto Serif KR", sans-serif);font-size:2rem;line-height:2.5rem;font-weight:300}.bpk-text--editorial-3{font-family:var(--bpk-larken-font-stack, "Larken", "Noto Sans Arabic", "Noto Serif Hebrew", "Noto Serif", "Noto Serif Devanagari", "Noto Serif Thai", "Noto Serif SC", "Noto Serif TC", "Noto Serif JP", "Noto Serif KR", sans-serif);font-size:1.25rem;line-height:1.75rem;font-weight:400}.bpk-text.bpk-text--text-disabled{color:rgba(0,0,0,.2)}.bpk-text.bpk-text--text-disabled-on-dark{color:hsla(0,0%,100%,.5)}.bpk-text.bpk-text--text-error{color:#e70866}.bpk-text.bpk-text--text-hero{color:#0062e3}.bpk-text.bpk-text--text-link{color:#0062e3}.bpk-text.bpk-text--text-on-dark{color:#fff}.bpk-text.bpk-text--text-on-light{color:#161616}.bpk-text.bpk-text--text-primary{color:#161616}.bpk-text.bpk-text--text-primary-inverse{color:#fff}.bpk-text.bpk-text--text-secondary{color:#626971}.bpk-text.bpk-text--text-success{color:#0c838a}
18
+ .bpk-text{margin:0}.bpk-text--xs{font-size:.75rem;line-height:1rem;font-weight:400}.bpk-text--sm{font-size:.875rem;line-height:1.25rem;font-weight:400}.bpk-text--base{font-size:1rem;line-height:1.5rem;font-weight:400}.bpk-text--lg{font-size:1.25rem;line-height:1.75rem;font-weight:400}.bpk-text--xl{font-size:1.5rem;line-height:2rem;font-weight:400}.bpk-text--xxl{font-size:2rem;line-height:2.5rem;font-weight:700}.bpk-text--xxxl{font-size:2.5rem;line-height:3rem;font-weight:700}.bpk-text--xxxxl{font-size:3rem;line-height:3.5rem;font-weight:700;letter-spacing:-0.02em}.bpk-text--xxxxxl{font-size:4rem;line-height:4rem;font-weight:700;letter-spacing:-0.02em}.bpk-text--caption{font-size:.75rem;line-height:1rem;font-weight:400}.bpk-text--footnote{font-size:.875rem;line-height:1.25rem;font-weight:400}.bpk-text--label-1{font-size:1rem;line-height:1.5rem;font-weight:700}.bpk-text--label-2{font-size:.875rem;line-height:1.25rem;font-weight:700}.bpk-text--label-3{font-size:.75rem;line-height:1rem;font-weight:700}.bpk-text--body-default{font-size:1rem;line-height:1.5rem;font-weight:400}.bpk-text--body-longform{font-size:1.25rem;line-height:1.75rem;font-weight:400}.bpk-text--subheading{font-size:1.5rem;line-height:2rem;font-weight:400}.bpk-text--heading-1{font-size:2.5rem;line-height:3rem;font-weight:700}.bpk-text--heading-2{font-size:2rem;line-height:2.5rem;font-weight:700}.bpk-text--heading-3{font-size:1.5rem;line-height:1.75rem;font-weight:700}.bpk-text--heading-4{font-size:1.25rem;line-height:1.5rem;font-weight:700}.bpk-text--heading-5{font-size:1rem;line-height:1.25rem;font-weight:700}.bpk-text--hero-1{font-size:7.5rem;line-height:7.5rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-2{font-size:6rem;line-height:6rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-3{font-size:4.75rem;line-height:4.75rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-4{font-size:4rem;line-height:4rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-5{font-size:3rem;line-height:3rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--hero-6{font-size:2.5rem;line-height:2.5rem;font-weight:900;letter-spacing:-0.04em}.bpk-text--editorial-1{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);font-size:3rem;line-height:3.5rem;font-weight:300}.bpk-text--editorial-2{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);font-size:2rem;line-height:2.5rem;font-weight:300}.bpk-text--editorial-3{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);font-size:1.25rem;line-height:1.75rem;font-weight:400}.bpk-text.bpk-text--text-disabled{color:rgba(0,0,0,.2)}.bpk-text.bpk-text--text-disabled-on-dark{color:hsla(0,0%,100%,.5)}.bpk-text.bpk-text--text-error{color:#e70866}.bpk-text.bpk-text--text-hero{color:#0062e3}.bpk-text.bpk-text--text-link{color:#0062e3}.bpk-text.bpk-text--text-on-dark{color:#fff}.bpk-text.bpk-text--text-on-light{color:#161616}.bpk-text.bpk-text--text-primary{color:#161616}.bpk-text.bpk-text--text-primary-inverse{color:#fff}.bpk-text.bpk-text--text-secondary{color:#626971}.bpk-text.bpk-text--text-success{color:#0c838a}
@@ -0,0 +1,85 @@
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
+ @use 'tokens';
20
+
21
+ ////
22
+ /// @group focus-indicator-v2
23
+ ////
24
+
25
+ /// V2 focus indicator — base/mobile style.
26
+ /// Applies an accent-coloured outline suitable for inputs, buttons and calendar elements.
27
+ ///
28
+ /// @example scss
29
+ /// .selector {
30
+ /// &:focus-visible {
31
+ /// @include bpk-focus-indicator-v2();
32
+ /// }
33
+ /// }
34
+
35
+ @mixin bpk-focus-indicator-v2 {
36
+ border-color: tokens.$bpk-core-accent-day;
37
+ outline-color: tokens.$bpk-core-accent-day;
38
+ outline-style: auto;
39
+ }
40
+
41
+ /// V2 focus indicator — desktop enhanced style.
42
+ /// Applies an inset focus ring with a canvas-coloured box-shadow gap for higher
43
+ /// visibility on desktop viewports. Typically combined with `bpk-focus-indicator-v2`.
44
+ ///
45
+ /// @example scss
46
+ /// .selector {
47
+ /// &:focus-visible {
48
+ /// @include bpk-focus-indicator-v2();
49
+ ///
50
+ /// @include breakpoints.bpk-breakpoint-above-mobile {
51
+ /// @include bpk-focus-indicator-v2-desktop();
52
+ /// }
53
+ /// }
54
+ /// }
55
+
56
+ @mixin bpk-focus-indicator-v2-desktop {
57
+ outline-color: tokens.$bpk-core-accent-day;
58
+ outline-offset: calc(-1 * tokens.bpk-spacing-sm() * 0.75);
59
+ outline-style: solid;
60
+ outline-width: tokens.bpk-spacing-sm();
61
+ box-shadow: 0 0 0 calc(tokens.$bpk-one-pixel-rem * 2) tokens.$bpk-canvas-day;
62
+ }
63
+
64
+ /// V2 focus indicator — desktop reset.
65
+ /// Resets the desktop inset focus styles so that the base/mobile indicator is
66
+ /// restored. Useful inside mobile-specific breakpoint overrides.
67
+ ///
68
+ /// @example scss
69
+ /// .selector {
70
+ /// &:focus-visible {
71
+ /// @include bpk-focus-indicator-v2();
72
+ /// @include bpk-focus-indicator-v2-desktop();
73
+ ///
74
+ /// @include breakpoints.bpk-breakpoint-mobile {
75
+ /// @include bpk-focus-indicator-v2-desktop-reset();
76
+ /// }
77
+ /// }
78
+ /// }
79
+
80
+ @mixin bpk-focus-indicator-v2-desktop-reset {
81
+ outline-offset: 0;
82
+ outline-style: auto;
83
+ outline-width: initial;
84
+ box-shadow: none;
85
+ }
@@ -23,6 +23,7 @@
23
23
  @forward 'buttons';
24
24
  @forward 'cards';
25
25
  @forward 'chips';
26
+ @forward 'focus-indicator-v2';
26
27
  @forward 'forms';
27
28
  @forward 'icons';
28
29
  @forward 'layers';
@@ -0,0 +1,5 @@
1
+ declare const focusScope: {
2
+ scopeFocus(element: HTMLElement): void;
3
+ unscopeFocus(): void;
4
+ };
5
+ export default focusScope;
@@ -0,0 +1,54 @@
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 { tabbable } from 'tabbable';
20
+ let teardownFn = null;
21
+ function init(element) {
22
+ function focus() {
23
+ const firstTabbable = tabbable(element)[0];
24
+ if (firstTabbable) {
25
+ firstTabbable.focus();
26
+ } else {
27
+ if (!element.hasAttribute('tabindex')) {
28
+ element.setAttribute('tabindex', '-1');
29
+ }
30
+ element.focus();
31
+ }
32
+ }
33
+ function onFocusIn(event) {
34
+ if (element !== event.target && !element.contains(event.target)) {
35
+ focus();
36
+ }
37
+ }
38
+ focus();
39
+ document.addEventListener('focusin', onFocusIn);
40
+ return function teardown() {
41
+ document.removeEventListener('focusin', onFocusIn);
42
+ };
43
+ }
44
+ const focusScope = {
45
+ scopeFocus(element) {
46
+ if (teardownFn) teardownFn();
47
+ teardownFn = init(element);
48
+ },
49
+ unscopeFocus() {
50
+ if (teardownFn) teardownFn();
51
+ teardownFn = null;
52
+ }
53
+ };
54
+ export default focusScope;
@@ -0,0 +1,6 @@
1
+ declare const focusStore: {
2
+ storeFocus(): void;
3
+ clearStoredFocus(): void;
4
+ restoreFocus(): void;
5
+ };
6
+ export default focusStore;
@@ -0,0 +1,40 @@
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
+ let storedFocusElement = null;
20
+ const focusStore = {
21
+ storeFocus() {
22
+ storedFocusElement = document.activeElement;
23
+ },
24
+ clearStoredFocus() {
25
+ storedFocusElement = null;
26
+ },
27
+ restoreFocus() {
28
+ if (!storedFocusElement || typeof storedFocusElement.focus !== 'function') {
29
+ storedFocusElement = null;
30
+ return;
31
+ }
32
+ try {
33
+ storedFocusElement.focus();
34
+ } catch {
35
+ // Element may have been detached from the DOM
36
+ }
37
+ storedFocusElement = null;
38
+ }
39
+ };
40
+ export default focusStore;
@@ -17,13 +17,10 @@
17
17
  */
18
18
 
19
19
  import { Component } from 'react';
20
-
21
- // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
22
- import focusScope from 'a11y-focus-scope';
23
- // @ts-expect-error Untyped import. See `decisions/imports-ts-suppressions.md`.
24
- import focusStore from 'a11y-focus-store';
25
20
  import { cssModules, isDeviceIpad, isDeviceIphone, wrapDisplayName } from "../../bpk-react-utils";
26
21
  import BpkScrim from "./BpkScrim";
22
+ import focusScope from "./focusScope";
23
+ import focusStore from "./focusStore";
27
24
  import { fixBody, lockScroll, restoreScroll, storeScroll, unfixBody, unlockScroll } from "./scroll-utils";
28
25
  import STYLES from "./bpk-scrim-content.module.css";
29
26
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -16,4 +16,4 @@
16
16
  * See the License for the specific language governing permissions and
17
17
  * limitations under the License.
18
18
  *
19
- *//*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}template,[hidden]{display:none}a{background-color:rgba(0,0,0,0);-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}button,input,optgroup,select,textarea{font:inherit;margin:0}optgroup{font-weight:bold}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}html{font-size:100%;box-sizing:border-box}*{box-sizing:inherit}*::before,*::after{box-sizing:inherit}body{color:#161616;font-family:var(--bpk-base-font-stack, "Skyscanner Relative", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans", "Noto Sans Devanagari", "Noto Sans Thai", "Noto Sans SC", "Noto Sans TC", "Noto Sans JP", "Noto Sans KR", -apple-system, BlinkMacSystemFont, "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif);font-size:1rem;line-height:1.3rem}body.scaffold-font-size{font-size:13px}body.enable-font-smoothing{-webkit-font-smoothing:antialiased}:focus-visible{outline:.125rem solid #0062e3;outline-offset:.125rem}.hidden,.hide{display:none !important}.visuallyhidden,.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;white-space:nowrap;overflow:hidden;clip:rect(0 0 0 0)}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus,.visually-hidden.focusable:active,.visually-hidden.focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.invisible{visibility:hidden}.clearfix::before,.clearfix::after{content:"";display:table}.clearfix::after{clear:both}
19
+ *//*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}template,[hidden]{display:none}a{background-color:rgba(0,0,0,0);-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}button,input,optgroup,select,textarea{font:inherit;margin:0}optgroup{font-weight:bold}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}html{font-size:100%;box-sizing:border-box}*{box-sizing:inherit}*::before,*::after{box-sizing:inherit}body{color:#161616;font-family:var(--bpk-base-font-stack, "Skyscanner Relative", "Noto Sans Arabic", "Noto Sans Hebrew", "Noto Sans", "Noto Sans Devanagari", "Noto Sans Thai", "Noto Sans TC", "Noto Sans JP", "Noto Sans KR", "Noto Sans SC", -apple-system, BlinkMacSystemFont, "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif);font-size:1rem;line-height:1.3rem}body.scaffold-font-size{font-size:13px}body.enable-font-smoothing{-webkit-font-smoothing:antialiased}:focus-visible{outline:.125rem solid #0062e3;outline-offset:.125rem}.hidden,.hide{display:none !important}.visuallyhidden,.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;white-space:nowrap;overflow:hidden;clip:rect(0 0 0 0)}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus,.visually-hidden.focusable:active,.visually-hidden.focusable:focus{position:static;width:auto;height:auto;margin:0;overflow:visible;clip:auto}.invisible{visibility:hidden}.clearfix::before,.clearfix::after{content:"";display:table}.clearfix::after{clear:both}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyscanner/backpack-web",
3
- "version": "42.6.0",
3
+ "version": "42.8.0-dev-v24332493292.1",
4
4
  "description": "Backpack Design System web library",
5
5
  "repository": {
6
6
  "type": "git",
@@ -29,10 +29,9 @@
29
29
  "@radix-ui/react-compose-refs": "^1.1.1",
30
30
  "@radix-ui/react-slider": "1.3.5",
31
31
  "@react-google-maps/api": "^2.19.3",
32
- "@skyscanner/bpk-foundations-web": "^24.1.0",
32
+ "@skyscanner/bpk-foundations-web": "^24.4.0",
33
33
  "@skyscanner/bpk-svgs": "^20.11.0",
34
- "a11y-focus-scope": "^1.1.3",
35
- "a11y-focus-store": "^1.0.0",
34
+ "tabbable": "^6.4.0",
36
35
  "d3-path": "^3.1.0",
37
36
  "d3-scale": "^4.0.2",
38
37
  "downshift": "^9.0.10",