@openedx/paragon 23.6.0 → 23.7.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.
- package/dist/Alert/index.scss +5 -0
- package/dist/Button/_mixins.scss +51 -2
- package/dist/Button/button-group.scss +7 -4
- package/dist/ProductTour/Checkpoint.js +23 -16
- package/dist/ProductTour/Checkpoint.js.map +1 -1
- package/dist/ProductTour/Checkpoint.scss +8 -36
- package/dist/ProductTour/CheckpointActionRow.js +17 -21
- package/dist/ProductTour/CheckpointActionRow.js.map +1 -1
- package/dist/ProductTour/CheckpointHeader.js +57 -0
- package/dist/ProductTour/CheckpointHeader.js.map +1 -0
- package/dist/ProductTour/index.js +120 -20
- package/dist/ProductTour/index.js.map +1 -1
- package/dist/ProductTour/messages.js +10 -0
- package/dist/core.css +56 -31
- package/dist/core.css.map +1 -1
- package/dist/core.min.css +1 -1
- package/dist/withDeprecatedProps.js +11 -3
- package/dist/withDeprecatedProps.js.map +1 -1
- package/lib/build-scss.js +1 -1
- package/package.json +1 -1
- package/src/Alert/index.scss +5 -0
- package/src/Button/_mixins.scss +51 -2
- package/src/Button/button-group.scss +7 -4
- package/src/ProductTour/Checkpoint.jsx +22 -16
- package/src/ProductTour/Checkpoint.scss +8 -36
- package/src/ProductTour/Checkpoint.test.jsx +20 -53
- package/src/ProductTour/CheckpointActionRow.jsx +32 -32
- package/src/ProductTour/CheckpointHeader.jsx +60 -0
- package/src/ProductTour/ProductTour.test.jsx +69 -60
- package/src/ProductTour/README.md +11 -3
- package/src/ProductTour/index.jsx +125 -17
- package/src/ProductTour/messages.js +10 -0
- package/src/withDeprecatedProps.tsx +10 -3
- package/dist/ProductTour/CheckpointBreadcrumbs.js +0 -37
- package/dist/ProductTour/CheckpointBreadcrumbs.js.map +0 -1
- package/dist/TransitionReplace/DemoTransitionReplace.js +0 -32
- package/dist/TransitionReplace/DemoTransitionReplace.js.map +0 -1
- package/src/ProductTour/CheckpointBreadcrumbs.jsx +0 -45
- package/src/TransitionReplace/DemoTransitionReplace.jsx +0 -57
|
@@ -51,9 +51,17 @@ function withDeprecatedProps(WrappedComponent, componentName, deprecatedProps) {
|
|
|
51
51
|
}
|
|
52
52
|
break;
|
|
53
53
|
case DeprTypes.MOVED_AND_FORMAT:
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
{
|
|
55
|
+
const propValue = this.props[propName];
|
|
56
|
+
let warningMessage = `${componentName}: The prop '${propName}' has been moved to '${newName}'`;
|
|
57
|
+
if (expect && !expect(propValue)) {
|
|
58
|
+
warningMessage += ' and expects a new format';
|
|
59
|
+
}
|
|
60
|
+
warningMessage += message ? `. ${message}` : '';
|
|
61
|
+
this.warn(warningMessage);
|
|
62
|
+
acc[newName] = transform ? transform(propValue, this.props) : propValue;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
57
65
|
default:
|
|
58
66
|
acc[propName] = this.props[propName];
|
|
59
67
|
break;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withDeprecatedProps.js","names":["React","DeprTypes","withDeprecatedProps","WrappedComponent","componentName","deprecatedProps","WithDeprecatedProps","Component","displayName","constructor","props","transformProps","bind","warn","message","process","env","NODE_ENV","console","acc","propName","undefined","deprType","newName","expect","transform","MOVED","REMOVED","FORMAT","MOVED_AND_FORMAT","render","children","transformedProps","Object","keys","reduce","createElement"],"sources":["../src/withDeprecatedProps.tsx"],"sourcesContent":["/* eslint no-console: 0 */\nimport React from 'react';\n\nexport enum DeprTypes {\n MOVED = 'MOVED',\n REMOVED = 'REMOVED',\n FORMAT = 'FORMAT',\n MOVED_AND_FORMAT = 'MOVED_AND_FORMAT',\n}\n\nexport interface DeprecatedProps extends Record<string, any> {\n deprType: DeprTypes,\n newName?: string,\n expect?: (propValue: any) => boolean,\n transform?: (propValue: any, allProps: Record<string, any>) => any,\n message?: string,\n}\n\nfunction withDeprecatedProps<T extends Record<string, any>>(\n WrappedComponent: React.ComponentType<any>,\n componentName: string,\n deprecatedProps: Record<string, DeprecatedProps>,\n) : any {\n class WithDeprecatedProps extends React.Component<T> {\n // eslint-disable-next-line react/static-property-placement\n public static displayName = `withDeprecatedProps(${componentName})`;\n\n constructor(props: T) {\n super(props);\n this.transformProps = this.transformProps.bind(this);\n }\n\n warn(message: string) {\n if (process.env.NODE_ENV === 'development') {\n if (console) { console.warn(`[Deprecated] ${message}`); }\n }\n }\n\n transformProps(acc: Record<string, any>, propName: string) : Record<string, any> {\n if (deprecatedProps[propName] === undefined) {\n acc[propName] = this.props[propName];\n return acc;\n }\n\n const {\n deprType,\n newName,\n expect,\n transform,\n message,\n } = deprecatedProps[propName];\n\n switch (deprType) {\n case DeprTypes.MOVED:\n this.warn(`${componentName}: The prop '${propName}' has been moved to '${newName}'.`);\n acc[newName!] = this.props[propName];\n break;\n case DeprTypes.REMOVED:\n this.warn(`${componentName}: The prop '${propName}' has been removed. '${message}'`);\n break;\n case DeprTypes.FORMAT:\n if (!expect!(this.props[propName])) {\n this.warn(`${componentName}: The prop '${propName}' expects a new format. ${message}`);\n acc[propName] = transform!(this.props[propName], this.props);\n } else {\n acc[propName] = this.props[propName];\n }\n break;\n case DeprTypes.MOVED_AND_FORMAT
|
|
1
|
+
{"version":3,"file":"withDeprecatedProps.js","names":["React","DeprTypes","withDeprecatedProps","WrappedComponent","componentName","deprecatedProps","WithDeprecatedProps","Component","displayName","constructor","props","transformProps","bind","warn","message","process","env","NODE_ENV","console","acc","propName","undefined","deprType","newName","expect","transform","MOVED","REMOVED","FORMAT","MOVED_AND_FORMAT","propValue","warningMessage","render","children","transformedProps","Object","keys","reduce","createElement"],"sources":["../src/withDeprecatedProps.tsx"],"sourcesContent":["/* eslint no-console: 0 */\nimport React from 'react';\n\nexport enum DeprTypes {\n MOVED = 'MOVED',\n REMOVED = 'REMOVED',\n FORMAT = 'FORMAT',\n MOVED_AND_FORMAT = 'MOVED_AND_FORMAT',\n}\n\nexport interface DeprecatedProps extends Record<string, any> {\n deprType: DeprTypes,\n newName?: string,\n expect?: (propValue: any) => boolean,\n transform?: (propValue: any, allProps: Record<string, any>) => any,\n message?: string,\n}\n\nfunction withDeprecatedProps<T extends Record<string, any>>(\n WrappedComponent: React.ComponentType<any>,\n componentName: string,\n deprecatedProps: Record<string, DeprecatedProps>,\n) : any {\n class WithDeprecatedProps extends React.Component<T> {\n // eslint-disable-next-line react/static-property-placement\n public static displayName = `withDeprecatedProps(${componentName})`;\n\n constructor(props: T) {\n super(props);\n this.transformProps = this.transformProps.bind(this);\n }\n\n warn(message: string) {\n if (process.env.NODE_ENV === 'development') {\n if (console) { console.warn(`[Deprecated] ${message}`); }\n }\n }\n\n transformProps(acc: Record<string, any>, propName: string) : Record<string, any> {\n if (deprecatedProps[propName] === undefined) {\n acc[propName] = this.props[propName];\n return acc;\n }\n\n const {\n deprType,\n newName,\n expect,\n transform,\n message,\n } = deprecatedProps[propName];\n\n switch (deprType) {\n case DeprTypes.MOVED:\n this.warn(`${componentName}: The prop '${propName}' has been moved to '${newName}'.`);\n acc[newName!] = this.props[propName];\n break;\n case DeprTypes.REMOVED:\n this.warn(`${componentName}: The prop '${propName}' has been removed. '${message}'`);\n break;\n case DeprTypes.FORMAT:\n if (!expect!(this.props[propName])) {\n this.warn(`${componentName}: The prop '${propName}' expects a new format. ${message}`);\n acc[propName] = transform!(this.props[propName], this.props);\n } else {\n acc[propName] = this.props[propName];\n }\n break;\n case DeprTypes.MOVED_AND_FORMAT: {\n const propValue = this.props[propName];\n let warningMessage = `${componentName}: The prop '${propName}' has been moved to '${newName}'`;\n if (expect && !expect(propValue)) {\n warningMessage += ' and expects a new format';\n }\n warningMessage += message ? `. ${message}` : '';\n this.warn(warningMessage);\n acc[newName!] = transform ? transform(propValue, this.props) : propValue;\n break;\n }\n default:\n acc[propName] = this.props[propName];\n break;\n }\n\n return acc;\n }\n\n render() {\n const { children, ...transformedProps } = Object\n .keys(this.props)\n .reduce(this.transformProps, {});\n\n return (\n <WrappedComponent {...transformedProps as T}>\n {this.props.children || children}\n </WrappedComponent>\n );\n }\n }\n\n return WithDeprecatedProps;\n}\n\nexport default withDeprecatedProps;\n"],"mappings":"AAAA;AACA,OAAOA,KAAK,MAAM,OAAO;AAEzB,WAAYC,SAAS,0BAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAATA,SAAS;EAAA,OAATA,SAAS;AAAA;AAerB,SAASC,mBAAmBA,CAC1BC,gBAA0C,EAC1CC,aAAqB,EACrBC,eAAgD,EAC1C;EACN,MAAMC,mBAAmB,SAASN,KAAK,CAACO,SAAS,CAAI;IACnD;IACA,OAAcC,WAAW,GAAG,uBAAuBJ,aAAa,GAAG;IAEnEK,WAAWA,CAACC,KAAQ,EAAE;MACpB,KAAK,CAACA,KAAK,CAAC;MACZ,IAAI,CAACC,cAAc,GAAG,IAAI,CAACA,cAAc,CAACC,IAAI,CAAC,IAAI,CAAC;IACtD;IAEAC,IAAIA,CAACC,OAAe,EAAE;MACpB,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,aAAa,EAAE;QAC1C,IAAIC,OAAO,EAAE;UAAEA,OAAO,CAACL,IAAI,CAAC,gBAAgBC,OAAO,EAAE,CAAC;QAAE;MAC1D;IACF;IAEAH,cAAcA,CAACQ,GAAwB,EAAEC,QAAgB,EAAwB;MAC/E,IAAIf,eAAe,CAACe,QAAQ,CAAC,KAAKC,SAAS,EAAE;QAC3CF,GAAG,CAACC,QAAQ,CAAC,GAAG,IAAI,CAACV,KAAK,CAACU,QAAQ,CAAC;QACpC,OAAOD,GAAG;MACZ;MAEA,MAAM;QACJG,QAAQ;QACRC,OAAO;QACPC,MAAM;QACNC,SAAS;QACTX;MACF,CAAC,GAAGT,eAAe,CAACe,QAAQ,CAAC;MAE7B,QAAQE,QAAQ;QACd,KAAKrB,SAAS,CAACyB,KAAK;UAClB,IAAI,CAACb,IAAI,CAAC,GAAGT,aAAa,eAAegB,QAAQ,wBAAwBG,OAAO,IAAI,CAAC;UACrFJ,GAAG,CAACI,OAAO,CAAE,GAAG,IAAI,CAACb,KAAK,CAACU,QAAQ,CAAC;UACpC;QACF,KAAKnB,SAAS,CAAC0B,OAAO;UACpB,IAAI,CAACd,IAAI,CAAC,GAAGT,aAAa,eAAegB,QAAQ,wBAAwBN,OAAO,GAAG,CAAC;UACpF;QACF,KAAKb,SAAS,CAAC2B,MAAM;UACnB,IAAI,CAACJ,MAAM,CAAE,IAAI,CAACd,KAAK,CAACU,QAAQ,CAAC,CAAC,EAAE;YAClC,IAAI,CAACP,IAAI,CAAC,GAAGT,aAAa,eAAegB,QAAQ,2BAA2BN,OAAO,EAAE,CAAC;YACtFK,GAAG,CAACC,QAAQ,CAAC,GAAGK,SAAS,CAAE,IAAI,CAACf,KAAK,CAACU,QAAQ,CAAC,EAAE,IAAI,CAACV,KAAK,CAAC;UAC9D,CAAC,MAAM;YACLS,GAAG,CAACC,QAAQ,CAAC,GAAG,IAAI,CAACV,KAAK,CAACU,QAAQ,CAAC;UACtC;UACA;QACF,KAAKnB,SAAS,CAAC4B,gBAAgB;UAAE;YAC/B,MAAMC,SAAS,GAAG,IAAI,CAACpB,KAAK,CAACU,QAAQ,CAAC;YACtC,IAAIW,cAAc,GAAG,GAAG3B,aAAa,eAAegB,QAAQ,wBAAwBG,OAAO,GAAG;YAC9F,IAAIC,MAAM,IAAI,CAACA,MAAM,CAACM,SAAS,CAAC,EAAE;cAChCC,cAAc,IAAI,2BAA2B;YAC/C;YACAA,cAAc,IAAIjB,OAAO,GAAG,KAAKA,OAAO,EAAE,GAAG,EAAE;YAC/C,IAAI,CAACD,IAAI,CAACkB,cAAc,CAAC;YACzBZ,GAAG,CAACI,OAAO,CAAE,GAAGE,SAAS,GAAGA,SAAS,CAACK,SAAS,EAAE,IAAI,CAACpB,KAAK,CAAC,GAAGoB,SAAS;YACxE;UACF;QACA;UACEX,GAAG,CAACC,QAAQ,CAAC,GAAG,IAAI,CAACV,KAAK,CAACU,QAAQ,CAAC;UACpC;MACJ;MAEA,OAAOD,GAAG;IACZ;IAEAa,MAAMA,CAAA,EAAG;MACP,MAAM;QAAEC,QAAQ;QAAE,GAAGC;MAAiB,CAAC,GAAGC,MAAM,CAC7CC,IAAI,CAAC,IAAI,CAAC1B,KAAK,CAAC,CAChB2B,MAAM,CAAC,IAAI,CAAC1B,cAAc,EAAE,CAAC,CAAC,CAAC;MAElC,oBACEX,KAAA,CAAAsC,aAAA,CAACnC,gBAAgB;QAAA,GAAK+B;MAAgB,GACnC,IAAI,CAACxB,KAAK,CAACuB,QAAQ,IAAIA,QACR,CAAC;IAEvB;EACF;EAEA,OAAO3B,mBAAmB;AAC5B;AAEA,eAAeJ,mBAAmB","ignoreList":[]}
|
package/lib/build-scss.js
CHANGED
|
@@ -94,7 +94,7 @@ const compileAndWriteStyleSheets = ({
|
|
|
94
94
|
},
|
|
95
95
|
}],
|
|
96
96
|
// For now we can't resolve these warnings as we need to upgrade our 'bootstrap' dependency to do so:
|
|
97
|
-
silenceDeprecations: ['abs-percent', 'color-functions', 'import', 'mixed-decls', 'global-builtin'],
|
|
97
|
+
silenceDeprecations: ['abs-percent', 'color-functions', 'import', 'mixed-decls', 'global-builtin', 'legacy-js-api'],
|
|
98
98
|
});
|
|
99
99
|
|
|
100
100
|
const commonPostCssPlugins = [
|
package/package.json
CHANGED
package/src/Alert/index.scss
CHANGED
|
@@ -15,10 +15,15 @@
|
|
|
15
15
|
border: var(--pgn-size-alert-border-width) solid var(--pgn-alert-border-color, transparent);
|
|
16
16
|
color: inherit;
|
|
17
17
|
background-color: var(--pgn-alert-bg, transparent);
|
|
18
|
+
align-items: center;
|
|
18
19
|
|
|
19
20
|
@include border-radius(var(--pgn-size-alert-border-radius));
|
|
20
21
|
@include pgn-box-shadow(1, "down");
|
|
21
22
|
|
|
23
|
+
&:has(.alert-heading:not(:only-child)) {
|
|
24
|
+
align-items: start;
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
.alert-message-content > :last-child {
|
|
23
28
|
margin-bottom: 0;
|
|
24
29
|
}
|
package/src/Button/_mixins.scss
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
// OVERRIDE FROM BOOTSTRAP
|
|
2
|
-
// No changes made. We do this to keep all button related mixins together,
|
|
3
1
|
//
|
|
2
|
+
// Includes common mixins related to button styles.
|
|
3
|
+
//
|
|
4
|
+
|
|
4
5
|
// Button sizes
|
|
6
|
+
// OVERRIDE FROM BOOTSTRAP
|
|
7
|
+
// No changes made. We do this to keep all button related mixins together,
|
|
5
8
|
@mixin button-size($padding-y, $padding-x, $font-size, $line-height, $button-border-radius) {
|
|
6
9
|
padding: $padding-y $padding-x;
|
|
7
10
|
|
|
@@ -12,3 +15,49 @@
|
|
|
12
15
|
// Manually declare to provide an override to the browser default
|
|
13
16
|
@include border-radius($button-border-radius, 0);
|
|
14
17
|
}
|
|
18
|
+
|
|
19
|
+
// Mixin for button states that affect border radius
|
|
20
|
+
@mixin button-border-radius-0($side) {
|
|
21
|
+
@if $side == 'right' {
|
|
22
|
+
@include border-right-radius(0);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@if $side == 'left' {
|
|
26
|
+
@include border-left-radius(0);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Handle pseudo-classes
|
|
30
|
+
&.btn:not(:disabled, .disabled):focus,
|
|
31
|
+
&.btn:not(:disabled, .disabled):focus::before {
|
|
32
|
+
@if $side == 'left' {
|
|
33
|
+
@include border-left-radius(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@if $side == 'right' {
|
|
37
|
+
@include border-right-radius(0);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
&.btn:not(:disabled, .disabled):active,
|
|
42
|
+
&.btn:not(:disabled, .disabled):active::before {
|
|
43
|
+
@if $side == 'left' {
|
|
44
|
+
@include border-left-radius(0);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@if $side == 'right' {
|
|
48
|
+
@include border-right-radius(0);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Handle .active class
|
|
53
|
+
&.btn:not(:disabled, .disabled).active,
|
|
54
|
+
&.btn:not(:disabled, .disabled).active::before {
|
|
55
|
+
@if $side == 'right' {
|
|
56
|
+
@include border-right-radius(0);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@if $side == 'left' {
|
|
60
|
+
@include border-left-radius(0);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
&:focus,
|
|
16
16
|
&:active,
|
|
17
17
|
&.active {
|
|
18
|
-
z-index:
|
|
18
|
+
z-index: 2;
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -36,14 +36,17 @@
|
|
|
36
36
|
margin-left: calc(var(--pgn-size-btn-border-width) * -1);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// Right border radius for non-last buttons
|
|
40
|
+
> .btn:not(:last-child, .dropdown-toggle, :first-child),
|
|
39
41
|
> .btn:not(:last-child, .dropdown-toggle),
|
|
40
42
|
> .btn-group:not(:last-child) > .btn {
|
|
41
|
-
@include border-
|
|
43
|
+
@include button-border-radius-0('right');
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
// Left border radius for non-first buttons
|
|
47
|
+
> .btn:not(:first-child, .dropdown-toggle),
|
|
45
48
|
> .btn-group:not(:first-child) > .btn {
|
|
46
|
-
@include border-
|
|
49
|
+
@include button-border-radius-0('left');
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
|
|
@@ -5,16 +5,17 @@ import { createPopper } from '@popperjs/core';
|
|
|
5
5
|
import { FormattedMessage } from 'react-intl';
|
|
6
6
|
|
|
7
7
|
import breakpoints from '../utils/breakpoints';
|
|
8
|
-
|
|
9
8
|
import CheckpointActionRow from './CheckpointActionRow';
|
|
10
9
|
import CheckpointBody from './CheckpointBody';
|
|
11
|
-
import
|
|
12
|
-
import CheckpointTitle from './CheckpointTitle';
|
|
10
|
+
import CheckpointHeader from './CheckpointHeader';
|
|
13
11
|
import messages from './messages';
|
|
14
12
|
|
|
15
13
|
const Checkpoint = React.forwardRef(({
|
|
16
14
|
body,
|
|
15
|
+
dismissAltText,
|
|
17
16
|
index,
|
|
17
|
+
onBack,
|
|
18
|
+
onDismiss,
|
|
18
19
|
placement,
|
|
19
20
|
target,
|
|
20
21
|
title,
|
|
@@ -87,7 +88,6 @@ const Checkpoint = React.forwardRef(({
|
|
|
87
88
|
}, [target, checkpointVisible, placement]);
|
|
88
89
|
|
|
89
90
|
const isLastCheckpoint = index + 1 === totalCheckpoints;
|
|
90
|
-
const isOnlyCheckpoint = totalCheckpoints === 1;
|
|
91
91
|
|
|
92
92
|
return (
|
|
93
93
|
<div
|
|
@@ -104,14 +104,17 @@ const Checkpoint = React.forwardRef(({
|
|
|
104
104
|
values={{ step: index + 1 }}
|
|
105
105
|
/>
|
|
106
106
|
</span>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
<CheckpointHeader
|
|
108
|
+
dismissAltText={dismissAltText}
|
|
109
|
+
index={index}
|
|
110
|
+
onDismiss={onDismiss}
|
|
111
|
+
title={title}
|
|
112
|
+
totalCheckpoints={totalCheckpoints}
|
|
113
|
+
/>
|
|
113
114
|
<CheckpointBody>{body}</CheckpointBody>
|
|
114
115
|
<CheckpointActionRow
|
|
116
|
+
onBack={onBack}
|
|
117
|
+
onDismiss={onDismiss}
|
|
115
118
|
isLastCheckpoint={isLastCheckpoint}
|
|
116
119
|
index={index}
|
|
117
120
|
{...props}
|
|
@@ -129,21 +132,23 @@ const Checkpoint = React.forwardRef(({
|
|
|
129
132
|
|
|
130
133
|
Checkpoint.defaultProps = {
|
|
131
134
|
advanceButtonText: null,
|
|
135
|
+
backButtonText: null,
|
|
132
136
|
body: null,
|
|
133
|
-
|
|
137
|
+
dismissAltText: null,
|
|
134
138
|
endButtonText: null,
|
|
135
139
|
placement: 'top',
|
|
136
140
|
title: null,
|
|
137
|
-
showDismissButton: undefined,
|
|
138
141
|
};
|
|
139
142
|
|
|
140
143
|
Checkpoint.propTypes = {
|
|
141
144
|
/** The text displayed on the button used to advance the tour for the given Checkpoint. */
|
|
142
145
|
advanceButtonText: PropTypes.node,
|
|
146
|
+
/** The text displayed on the button used go back in the tour for the given Checkpoint. */
|
|
147
|
+
backButtonText: PropTypes.string,
|
|
143
148
|
/** The text displayed in the body of the Checkpoint */
|
|
144
149
|
body: PropTypes.node,
|
|
145
|
-
/** The text
|
|
146
|
-
|
|
150
|
+
/** The text used in the alt for the icon used to dismiss the tour for the given Checkpoint */
|
|
151
|
+
dismissAltText: PropTypes.string,
|
|
147
152
|
/** The text displayed on the button used to end the tour for the given Checkpoint. */
|
|
148
153
|
endButtonText: PropTypes.node,
|
|
149
154
|
/** The current index of the given Checkpoint */
|
|
@@ -151,6 +156,9 @@ Checkpoint.propTypes = {
|
|
|
151
156
|
/** A function that runs when triggering the `onClick` event of the advance
|
|
152
157
|
* button for the given Checkpoint. */
|
|
153
158
|
onAdvance: PropTypes.func.isRequired,
|
|
159
|
+
/** A function that runs when triggering the `onBack` event of the back
|
|
160
|
+
* button for the given Checkpoint. */
|
|
161
|
+
onBack: PropTypes.func.isRequired,
|
|
154
162
|
/** A function that runs when triggering the `onClick` event of the dismiss
|
|
155
163
|
* button for the given Checkpoint. */
|
|
156
164
|
onDismiss: PropTypes.func.isRequired,
|
|
@@ -168,8 +176,6 @@ Checkpoint.propTypes = {
|
|
|
168
176
|
title: PropTypes.node,
|
|
169
177
|
/** The total number of Checkpoints in a tour */
|
|
170
178
|
totalCheckpoints: PropTypes.number.isRequired,
|
|
171
|
-
/** Enforces visibility of the dismiss button under all circumstances */
|
|
172
|
-
showDismissButton: PropTypes.bool,
|
|
173
179
|
};
|
|
174
180
|
|
|
175
181
|
export default Checkpoint;
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
var(--pgn-size-product-tour-checkpoint-width-border)
|
|
8
8
|
solid var(--pgn-color-product-tour-checkpoint-border);
|
|
9
9
|
border-radius: var(--pgn-size-border-radius-base);
|
|
10
|
-
padding: var(--pgn-spacing-spacer-
|
|
10
|
+
padding: var(--pgn-spacing-spacer-3-5);
|
|
11
11
|
box-shadow: 0 .25rem .5rem var(--pgn-color-product-tour-checkpoint-box-shadow);
|
|
12
12
|
z-index: var(--pgn-elevation-product-tour-checkpoint-zindex);
|
|
13
13
|
max-width: var(--pgn-size-product-tour-checkpoint-width-max);
|
|
@@ -44,39 +44,6 @@
|
|
|
44
44
|
margin-inline-end: var(--pgn-spacing-spacer-2);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
.pgn__checkpoint-breadcrumb {
|
|
48
|
-
height: 6px;
|
|
49
|
-
width: 6px;
|
|
50
|
-
border-radius: 50%;
|
|
51
|
-
|
|
52
|
-
&.pgn__checkpoint-breadcrumb_active {
|
|
53
|
-
background: var(--pgn-color-product-tour-checkpoint-breadcrumb);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
&.pgn__checkpoint-breadcrumb_inactive {
|
|
57
|
-
border: 1px solid var(--pgn-color-product-tour-checkpoint-breadcrumb);
|
|
58
|
-
background: transparent;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
&:not(:first-child) {
|
|
62
|
-
margin-left: map.get($spacers, 1\.5);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
[dir="rtl"] & {
|
|
66
|
-
margin-left: map.get($spacers, 1\.5);
|
|
67
|
-
margin-right: 0;
|
|
68
|
-
|
|
69
|
-
&:last-child {
|
|
70
|
-
margin-left: 0;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
.pgn__checkpoint-breadcrumb-container {
|
|
76
|
-
display: flex;
|
|
77
|
-
align-items: center;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
47
|
.pgn__checkpoint-body {
|
|
81
48
|
color: var(--pgn-color-product-tour-checkpoint-body);
|
|
82
49
|
margin-bottom: map.get($spacers, 3\.5);
|
|
@@ -86,13 +53,18 @@
|
|
|
86
53
|
.pgn__checkpoint-header {
|
|
87
54
|
display: flex;
|
|
88
55
|
justify-content: space-between;
|
|
89
|
-
margin-bottom: map.get($spacers, 2
|
|
56
|
+
margin-bottom: map.get($spacers, 2);
|
|
57
|
+
align-items: center;
|
|
90
58
|
}
|
|
91
59
|
|
|
92
60
|
#pgn__checkpoint-title {
|
|
93
61
|
font-size: var(--pgn-typography-font-size-h3-base);
|
|
94
62
|
margin-inline-end: map.get($spacers, 2\.5);
|
|
95
|
-
margin-bottom:
|
|
63
|
+
margin-bottom: map.get($spacers, 2);;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.pgn__checkpoint-page-index {
|
|
67
|
+
font-size: $small-font-size;
|
|
96
68
|
}
|
|
97
69
|
}
|
|
98
70
|
|
|
@@ -11,6 +11,7 @@ const popperMock = jest.spyOn(popper, 'createPopper');
|
|
|
11
11
|
|
|
12
12
|
describe('Checkpoint', () => {
|
|
13
13
|
const handleAdvance = jest.fn();
|
|
14
|
+
const handleBack = jest.fn();
|
|
14
15
|
const handleDismiss = jest.fn();
|
|
15
16
|
const handleEnd = jest.fn();
|
|
16
17
|
|
|
@@ -29,11 +30,12 @@ describe('Checkpoint', () => {
|
|
|
29
30
|
<div id="target-element">...</div>
|
|
30
31
|
<Checkpoint
|
|
31
32
|
advanceButtonText="Next"
|
|
33
|
+
backButtonText="Back"
|
|
32
34
|
body="Lorem ipsum checkpoint body"
|
|
33
|
-
dismissButtonText="Dismiss"
|
|
34
35
|
endButtonText="End"
|
|
35
36
|
index={1}
|
|
36
37
|
onAdvance={handleAdvance}
|
|
38
|
+
onBack={handleBack}
|
|
37
39
|
onDismiss={handleDismiss}
|
|
38
40
|
onEnd={handleEnd}
|
|
39
41
|
target="#target-element"
|
|
@@ -44,31 +46,22 @@ describe('Checkpoint', () => {
|
|
|
44
46
|
);
|
|
45
47
|
});
|
|
46
48
|
|
|
47
|
-
it('renders
|
|
48
|
-
expect(screen.
|
|
49
|
-
const breadcrumbs = screen.getAllByTestId('pgn__checkpoint-breadcrumb_', { exact: false });
|
|
50
|
-
expect(breadcrumbs.length).toEqual(5);
|
|
51
|
-
expect(breadcrumbs[0].classList).toContain('pgn__checkpoint-breadcrumb_inactive');
|
|
52
|
-
expect(breadcrumbs[1].classList).toContain('pgn__checkpoint-breadcrumb_active');
|
|
53
|
-
expect(breadcrumbs[2].classList).toContain('pgn__checkpoint-breadcrumb_inactive');
|
|
54
|
-
expect(breadcrumbs[3].classList).toContain('pgn__checkpoint-breadcrumb_inactive');
|
|
55
|
-
expect(breadcrumbs[4].classList).toContain('pgn__checkpoint-breadcrumb_inactive');
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('only renders advance and dismiss buttons (i.e. does not render end button)', () => {
|
|
59
|
-
expect(screen.getByRole('button', { name: 'Dismiss' })).toBeInTheDocument();
|
|
49
|
+
it('only renders advance and back buttons (i.e. does not render end button)', () => {
|
|
50
|
+
expect(screen.getByRole('button', { name: 'Back' })).toBeInTheDocument();
|
|
60
51
|
expect(screen.getByRole('button', { name: 'Next' })).toBeInTheDocument();
|
|
61
52
|
});
|
|
62
53
|
|
|
63
|
-
it('
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
54
|
+
it('back button onClick calls handleBack', async () => {
|
|
55
|
+
const user = userEvent.setup();
|
|
56
|
+
const backButton = screen.getByRole('button', { name: 'Back' });
|
|
57
|
+
await user.click(backButton);
|
|
58
|
+
expect(handleBack).toHaveBeenCalledTimes(1);
|
|
67
59
|
});
|
|
68
60
|
|
|
69
61
|
it('advance button onClick calls handleAdvance', async () => {
|
|
62
|
+
const user = userEvent.setup();
|
|
70
63
|
const advanceButton = screen.getByRole('button', { name: 'Next' });
|
|
71
|
-
await
|
|
64
|
+
await user.click(advanceButton);
|
|
72
65
|
expect(handleAdvance).toHaveBeenCalledTimes(1);
|
|
73
66
|
});
|
|
74
67
|
});
|
|
@@ -80,8 +73,9 @@ describe('Checkpoint', () => {
|
|
|
80
73
|
<div id="#last-element" />
|
|
81
74
|
<Checkpoint
|
|
82
75
|
advanceButtonText="Next"
|
|
76
|
+
backButtonText="Back"
|
|
83
77
|
body="Lorem ipsum checkpoint body"
|
|
84
|
-
|
|
78
|
+
dismissAltText="Escape"
|
|
85
79
|
endButtonText="End"
|
|
86
80
|
index={4}
|
|
87
81
|
onAdvance={handleAdvance}
|
|
@@ -95,10 +89,15 @@ describe('Checkpoint', () => {
|
|
|
95
89
|
);
|
|
96
90
|
});
|
|
97
91
|
|
|
98
|
-
it('only renders end button (i.e. neither advance nor
|
|
92
|
+
it('only renders end button (i.e. neither advance nor back buttons)', () => {
|
|
99
93
|
expect(screen.getByText('End', { selector: 'button' })).toBeInTheDocument();
|
|
100
94
|
});
|
|
101
95
|
|
|
96
|
+
it('uses customized alt text on the close icon', () => {
|
|
97
|
+
const closeButton = screen.getByTestId('dismiss-tour');
|
|
98
|
+
expect(closeButton).toHaveAttribute('aria-label', 'Escape');
|
|
99
|
+
});
|
|
100
|
+
|
|
102
101
|
it('end button onClick calls handleEnd', async () => {
|
|
103
102
|
const user = userEvent.setup({ pointerEventsCheck: PointerEventsCheckLevel.Never });
|
|
104
103
|
const endButton = screen.getByText('End', { selector: 'button' });
|
|
@@ -115,7 +114,6 @@ describe('Checkpoint', () => {
|
|
|
115
114
|
<Checkpoint
|
|
116
115
|
advanceButtonText="Next"
|
|
117
116
|
body="Lorem ipsum checkpoint body"
|
|
118
|
-
dismissButtonText="Dismiss"
|
|
119
117
|
endButtonText="End"
|
|
120
118
|
index={0}
|
|
121
119
|
onAdvance={handleAdvance}
|
|
@@ -132,36 +130,5 @@ describe('Checkpoint', () => {
|
|
|
132
130
|
it('only renders end button (i.e. neither advance nor dismiss buttons)', () => {
|
|
133
131
|
expect(screen.getByText('End', { selector: 'button' })).toBeInTheDocument();
|
|
134
132
|
});
|
|
135
|
-
|
|
136
|
-
it('does not render breadcrumbs', () => {
|
|
137
|
-
const breadcrumbs = screen.queryAllByTestId('pgn__checkpoint-breadcrumb_', { exact: false });
|
|
138
|
-
expect(breadcrumbs.length).toEqual(0);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
describe('only one Checkpoint in Tour and showDismissButton set to true', () => {
|
|
143
|
-
it('it renders dismiss button and end button', () => {
|
|
144
|
-
render(
|
|
145
|
-
<IntlProvider locale="en" messages={{}}>
|
|
146
|
-
<div id="#target-element" />
|
|
147
|
-
<Checkpoint
|
|
148
|
-
advanceButtonText="Next"
|
|
149
|
-
body="Lorem ipsum checkpoint body"
|
|
150
|
-
dismissButtonText="Dismiss"
|
|
151
|
-
endButtonText="End"
|
|
152
|
-
index={0}
|
|
153
|
-
onAdvance={handleAdvance}
|
|
154
|
-
onDismiss={handleDismiss}
|
|
155
|
-
onEnd={handleEnd}
|
|
156
|
-
target="#target-element"
|
|
157
|
-
title="Checkpoint title"
|
|
158
|
-
totalCheckpoints={1}
|
|
159
|
-
showDismissButton
|
|
160
|
-
/>
|
|
161
|
-
</IntlProvider>,
|
|
162
|
-
);
|
|
163
|
-
expect(screen.getByText('Dismiss', { selector: 'button' })).toBeInTheDocument();
|
|
164
|
-
expect(screen.getByText('End', { selector: 'button' })).toBeInTheDocument();
|
|
165
|
-
});
|
|
166
133
|
});
|
|
167
134
|
});
|
|
@@ -1,68 +1,68 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
|
|
4
|
+
import ActionRow from '../ActionRow';
|
|
3
5
|
import Button from '../Button';
|
|
4
6
|
|
|
5
7
|
const CheckpointActionRow = React.forwardRef(({
|
|
6
8
|
advanceButtonText,
|
|
7
|
-
|
|
9
|
+
backButtonText,
|
|
8
10
|
endButtonText,
|
|
9
11
|
isLastCheckpoint,
|
|
10
12
|
onAdvance,
|
|
11
|
-
|
|
13
|
+
onBack,
|
|
12
14
|
onEnd,
|
|
13
|
-
showDismissButton,
|
|
14
15
|
index,
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
}) => {
|
|
17
|
+
const isFirstCheckpoint = index === 0;
|
|
18
|
+
return (
|
|
19
|
+
<ActionRow className="pgn__checkpoint-action-row">
|
|
20
|
+
{!isFirstCheckpoint && (
|
|
21
|
+
<Button
|
|
22
|
+
className="pgn__checkpoint-button-back"
|
|
23
|
+
variant="tertiary"
|
|
24
|
+
onClick={onBack}
|
|
25
|
+
>
|
|
26
|
+
{backButtonText}
|
|
27
|
+
</Button>
|
|
28
|
+
)}
|
|
18
29
|
<Button
|
|
19
|
-
|
|
20
|
-
className="pgn__checkpoint-
|
|
21
|
-
onClick={
|
|
30
|
+
autoFocus
|
|
31
|
+
className="pgn__checkpoint-button_advance"
|
|
32
|
+
onClick={isLastCheckpoint ? () => onEnd(index) : () => onAdvance(index)}
|
|
22
33
|
>
|
|
23
|
-
{
|
|
34
|
+
{isLastCheckpoint ? endButtonText : advanceButtonText}
|
|
24
35
|
</Button>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
className="pgn__checkpoint-button_advance"
|
|
29
|
-
variant="primary"
|
|
30
|
-
onClick={isLastCheckpoint ? () => onEnd(index) : () => onAdvance(index)}
|
|
31
|
-
>
|
|
32
|
-
{isLastCheckpoint ? endButtonText : advanceButtonText}
|
|
33
|
-
</Button>
|
|
34
|
-
</div>
|
|
35
|
-
));
|
|
36
|
+
</ActionRow>
|
|
37
|
+
);
|
|
38
|
+
});
|
|
36
39
|
|
|
37
40
|
CheckpointActionRow.defaultProps = {
|
|
38
41
|
advanceButtonText: '',
|
|
39
|
-
|
|
42
|
+
backButtonText: '',
|
|
40
43
|
endButtonText: '',
|
|
41
44
|
isLastCheckpoint: false,
|
|
42
|
-
onAdvance: () => {},
|
|
43
|
-
|
|
44
|
-
onEnd: () => {},
|
|
45
|
-
showDismissButton: undefined,
|
|
45
|
+
onAdvance: () => { },
|
|
46
|
+
onBack: () => { },
|
|
47
|
+
onEnd: () => { },
|
|
46
48
|
index: 0,
|
|
47
49
|
};
|
|
48
50
|
|
|
49
51
|
CheckpointActionRow.propTypes = {
|
|
50
52
|
/** The text displayed on the button used to advance the tour. */
|
|
51
53
|
advanceButtonText: PropTypes.node,
|
|
52
|
-
/** The text displayed on the button used to
|
|
53
|
-
|
|
54
|
+
/** The text displayed on the button used to go back on the tour */
|
|
55
|
+
backButtonText: PropTypes.string,
|
|
54
56
|
/** The text displayed on the button used to end the tour. */
|
|
55
57
|
endButtonText: PropTypes.node,
|
|
56
58
|
/** Whether the parent Checkpoint is the last in the tour. */
|
|
57
59
|
isLastCheckpoint: PropTypes.bool,
|
|
58
60
|
/** A function that runs when triggering the `onClick` event of the advance button. */
|
|
59
61
|
onAdvance: PropTypes.func,
|
|
60
|
-
/** A function that runs when triggering the `onClick` event of the
|
|
61
|
-
|
|
62
|
+
/** A function that runs when triggering the `onClick` event of the back button. */
|
|
63
|
+
onBack: PropTypes.func,
|
|
62
64
|
/** A function that runs when triggering the `onClick` event of the advance button if isLastCheckpoint is true. */
|
|
63
65
|
onEnd: PropTypes.func,
|
|
64
|
-
/** Enforces visibility of the dismiss button under all circumstances */
|
|
65
|
-
showDismissButton: PropTypes.bool,
|
|
66
66
|
/** Allows visibility of last index value for onEnd checkpoint compatibility */
|
|
67
67
|
index: PropTypes.number,
|
|
68
68
|
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { FormattedMessage, useIntl } from 'react-intl';
|
|
4
|
+
|
|
5
|
+
import Icon from '../Icon';
|
|
6
|
+
import IconButton from '../IconButton';
|
|
7
|
+
import { Close } from '../../icons';
|
|
8
|
+
import CheckpointTitle from './CheckpointTitle';
|
|
9
|
+
import messages from './messages';
|
|
10
|
+
|
|
11
|
+
const CheckpointHeader = React.forwardRef(({
|
|
12
|
+
dismissAltText, index, onDismiss, title, totalCheckpoints,
|
|
13
|
+
}) => {
|
|
14
|
+
const intl = useIntl();
|
|
15
|
+
const oneBasedIndex = index + 1;
|
|
16
|
+
const altText = (dismissAltText && typeof dismissAltText === 'string') ? dismissAltText : intl.formatMessage(messages.closeAltText);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
<header className="pgn__checkpoint-header">
|
|
21
|
+
<span className="pgn__checkpoint-page-index">
|
|
22
|
+
<FormattedMessage
|
|
23
|
+
{...messages.pageIndexText}
|
|
24
|
+
values={{ step: oneBasedIndex, totalSteps: totalCheckpoints }}
|
|
25
|
+
/>
|
|
26
|
+
</span>
|
|
27
|
+
<IconButton
|
|
28
|
+
size="sm"
|
|
29
|
+
iconAs={Icon}
|
|
30
|
+
src={Close}
|
|
31
|
+
alt={altText}
|
|
32
|
+
onClick={onDismiss}
|
|
33
|
+
data-testid="dismiss-tour"
|
|
34
|
+
/>
|
|
35
|
+
</header>
|
|
36
|
+
{title && (<CheckpointTitle>{title}</CheckpointTitle>)}
|
|
37
|
+
</>
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
CheckpointHeader.defaultProps = {
|
|
42
|
+
dismissAltText: null,
|
|
43
|
+
title: '',
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
CheckpointHeader.propTypes = {
|
|
47
|
+
/** The text used in the alt for the icon used to dismiss the tour for the given Checkpoint */
|
|
48
|
+
dismissAltText: PropTypes.string,
|
|
49
|
+
/** The current index of the given Checkpoint */
|
|
50
|
+
index: PropTypes.number.isRequired,
|
|
51
|
+
/** A function that runs when triggering the `onClick` event of the dismiss
|
|
52
|
+
* button for the given Checkpoint. */
|
|
53
|
+
onDismiss: PropTypes.func.isRequired,
|
|
54
|
+
/** The text displayed in the title of the Checkpoint */
|
|
55
|
+
title: PropTypes.node,
|
|
56
|
+
/** The total number of Checkpoints in a tour */
|
|
57
|
+
totalCheckpoints: PropTypes.number.isRequired,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default CheckpointHeader;
|