@skyscanner/backpack-web 22.1.0 → 22.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,6 +39,7 @@ If you're using a SPA framework like `react-router-dom` or `Next.js` to navigate
39
39
  | blank | bool | false | false |
40
40
  | rel | string | false | null |
41
41
  | alternate | bool | false | false |
42
+ | ref | any | false | null |
42
43
 
43
44
  ### BpkButtonLink
44
45
 
@@ -17,9 +17,9 @@
17
17
  */
18
18
 
19
19
  /* @flow strict */
20
-
21
20
  import PropTypes from 'prop-types';
22
21
  import type { Node } from 'react';
22
+ import { forwardRef } from 'react';
23
23
 
24
24
  import { cssModules } from '../../bpk-react-utils';
25
25
 
@@ -40,7 +40,7 @@ type Props = {
40
40
  alternate: boolean,
41
41
  };
42
42
 
43
- const BpkLink = (props: Props) => {
43
+ const BpkLink = forwardRef((props: Props, ref) => {
44
44
  const {
45
45
  alternate,
46
46
  blank,
@@ -72,12 +72,13 @@ const BpkLink = (props: Props) => {
72
72
  onClick={onClick}
73
73
  target={target}
74
74
  rel={rel}
75
+ ref={ref}
75
76
  {...rest}
76
77
  >
77
78
  {children}
78
79
  </a>
79
80
  );
80
- };
81
+ });
81
82
 
82
83
  BpkLink.propTypes = {
83
84
  children: PropTypes.oneOfType([
@@ -32,15 +32,14 @@ $bpk-spacing-v2: true;
32
32
  @include bpk-themeable-property(
33
33
  background-color,
34
34
  --bpk-navigation-bar-background-color,
35
- $bpk-core-accent-day
35
+ $bpk-surface-default-day
36
36
  );
37
- @include bpk-border-bottom-sm($bpk-line-day);
38
37
 
39
38
  &__title {
40
39
  @include bpk-themeable-property(
41
40
  color,
42
41
  --bpk-navigation-bar-title-color,
43
- $bpk-text-primary-inverse-day
42
+ $bpk-text-primary-day
44
43
  );
45
44
  }
46
45
 
@@ -73,5 +72,7 @@ $bpk-spacing-v2: true;
73
72
  position: sticky;
74
73
  top: 0;
75
74
  z-index: $bpk-zindex-tooltip - 1; // Allow tooltips/modals/... to be displayed above the navigation bar
75
+
76
+ @include bpk-box-shadow-sm;
76
77
  }
77
78
  }
@@ -22,14 +22,14 @@
22
22
  @include bpk-themeable-property(
23
23
  color,
24
24
  --bpk-navigation-bar-button-link-color,
25
- $bpk-text-primary-inverse-day
25
+ $bpk-text-primary-day
26
26
  );
27
27
 
28
28
  @include bpk-hover {
29
29
  @include bpk-themeable-property(
30
30
  color,
31
31
  --bpk-navigation-bar-button-link-hover-color,
32
- $bpk-text-primary-inverse-day
32
+ $bpk-text-primary-day
33
33
  );
34
34
  }
35
35
 
@@ -37,7 +37,7 @@
37
37
  @include bpk-themeable-property(
38
38
  color,
39
39
  --bpk-navigation-bar-button-link-active-color,
40
- $bpk-text-primary-inverse-day
40
+ $bpk-text-primary-day
41
41
  );
42
42
  }
43
43
 
@@ -45,7 +45,7 @@
45
45
  @include bpk-themeable-property(
46
46
  color,
47
47
  --bpk-navigation-bar-button-link-visited-color,
48
- $bpk-text-primary-inverse-day
48
+ $bpk-text-primary-day
49
49
  );
50
50
  }
51
51
  }
@@ -22,14 +22,14 @@
22
22
  @include bpk-themeable-property(
23
23
  color,
24
24
  --bpk-navigation-bar-icon-button-color,
25
- $bpk-text-primary-inverse-day
25
+ $bpk-text-primary-day
26
26
  );
27
27
 
28
28
  @include bpk-hover {
29
29
  @include bpk-themeable-property(
30
30
  color,
31
31
  --bpk-navigation-bar-icon-button-hover-color,
32
- $bpk-text-primary-inverse-day
32
+ $bpk-text-primary-day
33
33
  );
34
34
  }
35
35
 
@@ -37,7 +37,7 @@
37
37
  @include bpk-themeable-property(
38
38
  color,
39
39
  --bpk-navigation-bar-icon-button-active-color,
40
- $bpk-text-primary-inverse-day
40
+ $bpk-text-primary-day
41
41
  );
42
42
  }
43
43
  }
@@ -35,6 +35,13 @@ export default () => (
35
35
  value={2.3}
36
36
  />
37
37
 
38
+ // Subtitle only rating
39
+ <BpkRating
40
+ ariaLabel="4.8 2,420 reviews"
41
+ value={4.8}
42
+ subtitle="2,420 reviews"
43
+ />
44
+
38
45
  // Show scale rating
39
46
  <BpkRating
40
47
  ariaLabel="3.8 Good 530 reviews"
@@ -68,8 +75,8 @@ export default () => (
68
75
  | Property | PropType | Required | Default Value |
69
76
  | --------- | --------------------- | -------- | ----------------- |
70
77
  | ariaLabel | string | true | - |
71
- | title | oneOfType(string, node) | true | - |
72
78
  | value | oneOfType(string, number) | true | - |
79
+ | title | oneOfType(string, node) | false | - |
73
80
  | className | string | false | null |
74
81
  | ratingScale | oneOf(RATING_SCALES) | false | RATING_SCALES.zeroToFive |
75
82
  | size | oneOf(RATING_SIZES) | false | RATING_SIZES.base |
@@ -51,7 +51,7 @@ type Props = {
51
51
  showScale: ?boolean,
52
52
  size: $Values<typeof RATING_SIZES>,
53
53
  subtitle: ?string,
54
- title: string | Node,
54
+ title: ?string | Node,
55
55
  value: string | number,
56
56
  };
57
57
 
@@ -71,7 +71,7 @@ const BpkRating = (props: Props) => {
71
71
  const classNames = getClassName(
72
72
  'bpk-rating',
73
73
  className,
74
- size === RATING_SIZES.large && subtitle && 'bpk-rating--large',
74
+ size === RATING_SIZES.large && title && subtitle && 'bpk-rating--large',
75
75
  );
76
76
  const valueStyles = getClassName('bpk-rating__value');
77
77
  const scaleStyles = getClassName('bpk-rating__scale');
@@ -80,6 +80,7 @@ const BpkRating = (props: Props) => {
80
80
  size === RATING_SIZES.large && 'bpk-rating__text-wrapper--large',
81
81
  );
82
82
  const titleStyles = getClassName(
83
+ subtitle && 'bpk-rating__title--with-subtitle',
83
84
  size === RATING_SIZES.large && 'bpk-rating__title--large',
84
85
  );
85
86
  const subtitleStyles = getClassName(
@@ -132,14 +133,16 @@ const BpkRating = (props: Props) => {
132
133
  </BpkText>
133
134
 
134
135
  <div className={textWrapperStyles}>
135
- <BpkText
136
- textStyle={titleTextSize}
137
- className={titleStyles}
138
- tagName="span"
139
- aria-hidden="true"
140
- >
141
- {title}
142
- </BpkText>
136
+ {title && (
137
+ <BpkText
138
+ textStyle={titleTextSize}
139
+ className={titleStyles}
140
+ tagName="span"
141
+ aria-hidden="true"
142
+ >
143
+ {title}
144
+ </BpkText>
145
+ )}
143
146
 
144
147
  {subtitle && (
145
148
  <BpkText
@@ -158,13 +161,13 @@ const BpkRating = (props: Props) => {
158
161
 
159
162
  BpkRating.propTypes = {
160
163
  ariaLabel: PropTypes.string.isRequired,
161
- title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]).isRequired,
162
164
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
163
165
  className: PropTypes.string,
164
166
  ratingScale: PropTypes.oneOf(Object.keys(RATING_SCALES)),
165
167
  size: PropTypes.oneOf(Object.keys(RATING_SIZES)),
166
168
  subtitle: PropTypes.string,
167
169
  showScale: PropTypes.bool,
170
+ title: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
168
171
  };
169
172
 
170
173
  BpkRating.defaultProps = {
@@ -173,6 +176,7 @@ BpkRating.defaultProps = {
173
176
  size: RATING_SIZES.base,
174
177
  subtitle: null,
175
178
  showScale: true,
179
+ title: null,
176
180
  };
177
181
 
178
182
  export default BpkRating;
@@ -59,28 +59,25 @@ $bpk-spacing-v2: true;
59
59
  }
60
60
 
61
61
  &__title {
62
+ &--with-subtitle {
63
+ padding-right: bpk-spacing-md();
64
+
65
+ @include bpk-rtl {
66
+ padding-right: 0;
67
+ padding-left: bpk-spacing-md();
68
+ }
69
+ }
70
+
62
71
  &--large {
63
72
  padding-top: $bpk-one-pixel-rem;
64
73
  }
65
74
  }
66
75
 
67
76
  &__subtitle {
68
- padding-left: bpk-spacing-md();
69
77
  color: $bpk-text-secondary-day;
70
78
 
71
- @include bpk-rtl {
72
- padding-right: bpk-spacing-md();
73
- padding-left: 0;
74
- }
75
-
76
79
  &--large {
77
- padding-top: $bpk-one-pixel-rem;
78
- padding-left: 0;
79
-
80
- @include bpk-rtl {
81
- padding-right: 0;
82
- padding-left: 0;
83
- }
80
+ // padding-top: $bpk-one-pixel-rem;
84
81
  }
85
82
  }
86
83
  }
@@ -26,30 +26,28 @@ class MyComponent extends Component {
26
26
  this.state = {
27
27
  isOpen: false,
28
28
  };
29
-
30
29
  }
31
30
 
32
31
  onOpen = () => {
33
32
  this.setState({
34
33
  isOpen: true,
35
34
  });
36
- }
35
+ };
37
36
 
38
37
  onClose = () => {
39
38
  this.setState({
40
39
  isOpen: false,
41
40
  });
42
- }
41
+ };
43
42
 
44
43
  render() {
45
44
  return (
46
45
  <div>
47
46
  <BpkButton onClick={this.onOpen}>Open portal</BpkButton>
48
- <Portal
49
- isOpen={this.state.isOpen}
50
- onClose={this.onClose}
51
- >
52
- <div>I'm now appended to <BpkCode>document.body</BpkCode></div>
47
+ <Portal isOpen={this.state.isOpen} onClose={this.onClose}>
48
+ <div>
49
+ I'm now appended to <BpkCode>document.body</BpkCode>
50
+ </div>
53
51
  </Portal>
54
52
  </div>
55
53
  );
@@ -57,19 +55,25 @@ class MyComponent extends Component {
57
55
  }
58
56
  ```
59
57
 
58
+ **NOTE:** Events used to bubble up from the portal into the parent component. Due to the way React works, events do not
59
+ bubble up into the component in the DOM where the portal is rendered (i.e. render target), but instead they bubble up
60
+ into the parent component in the shadow DOM, that is the component where you added the `Portal` in your React code. To
61
+ avoid confusion and bugs caused by this behaviour, we have prevented mouse and keyboard events from bubbling up outside
62
+ the portal.
63
+
60
64
  ### Props
61
65
 
62
- | Property | PropType | Required | Default Value |
63
- | --------------------- | ----------------------- | -------- | ------------- |
64
- | children | node | true | - |
65
- | isOpen | bool | true | - |
66
- | beforeClose | func | false | null |
67
- | onClose | func | false | noop |
68
- | onOpen | func | false | noop |
69
- | onRender | func | false | noop |
70
- | renderTarget | func | false | null |
71
- | target | oneOf([function, node]) | false | null |
72
- | closeOnEscPressed | bool | false | true |
66
+ | Property | PropType | Required | Default Value |
67
+ | ----------------- | ----------------------- | -------- | ------------- |
68
+ | children | node | true | - |
69
+ | isOpen | bool | true | - |
70
+ | beforeClose | func | false | null |
71
+ | onClose | func | false | noop |
72
+ | onOpen | func | false | noop |
73
+ | onRender | func | false | noop |
74
+ | renderTarget | func | false | null |
75
+ | target | oneOf([function, node]) | false | null |
76
+ | closeOnEscPressed | bool | false | true |
73
77
 
74
78
  ## `cssModules.js`
75
79
 
@@ -86,9 +90,7 @@ const getClassName = cssModules(STYLES);
86
90
 
87
91
  const MyComponent = (props) => (
88
92
  <div className={getClassName('MyComponent')}>
89
- <div className={getClassName('MyComponent__inner')}>
90
- {props.children}
91
- </div>
93
+ <div className={getClassName('MyComponent__inner')}>{props.children}</div>
92
94
  </div>
93
95
  );
94
96
  ```
@@ -97,9 +99,7 @@ With CSS modules:
97
99
 
98
100
  ```html
99
101
  <div class="_35WloynrPDta8fhSfoHEgE">
100
- <div class="_1ghNYY7jOYzUneVCT4piQ9">
101
- Some text.
102
- </div>
102
+ <div class="_1ghNYY7jOYzUneVCT4piQ9">Some text.</div>
103
103
  </div>
104
104
  ```
105
105
 
@@ -107,9 +107,7 @@ Without CSS modules:
107
107
 
108
108
  ```html
109
109
  <div class="MyComponent">
110
- <div class="MyComponent__inner">
111
- Some text.
112
- </div>
110
+ <div class="MyComponent__inner">Some text.</div>
113
111
  </div>
114
112
  ```
115
113
 
@@ -123,8 +121,13 @@ import STYLES from './MyComponent.scss';
123
121
  const getClassNames = cssModules(STYLES);
124
122
 
125
123
  const MyComponent = (props) => (
126
- <div className={getClassName('MyComponent', props.disabled && 'MyComponent--disabled')}>
127
- {props.children}
124
+ <div
125
+ className={getClassName(
126
+ 'MyComponent',
127
+ props.disabled && 'MyComponent--disabled',
128
+ )}
129
+ >
130
+ {props.children}
128
131
  </div>
129
132
  );
130
133
  ```
@@ -263,7 +263,22 @@ class Portal extends Component {
263
263
  return null;
264
264
  }
265
265
 
266
- return createPortal(children, portalElement);
266
+ const stopPropagationHandler = (e) => e.stopPropagation();
267
+
268
+ return createPortal(
269
+ <div
270
+ onClick={stopPropagationHandler}
271
+ onMouseDown={stopPropagationHandler}
272
+ onMouseUp={stopPropagationHandler}
273
+ onKeyDown={stopPropagationHandler}
274
+ onKeyUp={stopPropagationHandler}
275
+ tabIndex={-1}
276
+ role="none"
277
+ >
278
+ {children}
279
+ </div>,
280
+ portalElement,
281
+ );
267
282
  }
268
283
  }
269
284
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skyscanner/backpack-web",
3
- "version": "22.1.0",
3
+ "version": "22.3.0",
4
4
  "description": "Backpack Design System web library",
5
5
  "repository": {
6
6
  "type": "git",