@automattic/launchpad 1.1.0 → 1.1.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 (105) hide show
  1. package/dist/cjs/action-components/index.js +2 -1
  2. package/dist/cjs/action-components/index.js.map +1 -1
  3. package/dist/cjs/action-components/share-site-modal/index.js +132 -21
  4. package/dist/cjs/action-components/share-site-modal/index.js.map +1 -1
  5. package/dist/cjs/action-components/share-site-modal/style.scss +23 -116
  6. package/dist/cjs/checklist/index.js +11 -3
  7. package/dist/cjs/checklist/index.js.map +1 -1
  8. package/dist/cjs/checklist-item/index.js +25 -4
  9. package/dist/cjs/checklist-item/index.js.map +1 -1
  10. package/dist/cjs/checklist-item/index.stories.js +2 -5
  11. package/dist/cjs/checklist-item/index.stories.js.map +1 -1
  12. package/dist/cjs/checklist-item/style.scss +14 -29
  13. package/dist/cjs/launchpad-internal.js +2 -2
  14. package/dist/cjs/launchpad-internal.js.map +1 -1
  15. package/dist/cjs/launchpad-internal.stories.js +1 -1
  16. package/dist/cjs/launchpad-internal.stories.js.map +1 -1
  17. package/dist/cjs/launchpad.js +7 -5
  18. package/dist/cjs/launchpad.js.map +1 -1
  19. package/dist/cjs/msw/resolver.js +1 -7
  20. package/dist/cjs/msw/resolver.js.map +1 -1
  21. package/dist/cjs/msw/setup-free.js +1 -1
  22. package/dist/cjs/msw/setup-free.js.map +1 -1
  23. package/dist/cjs/setup-actions.js +4 -9
  24. package/dist/cjs/setup-actions.js.map +1 -1
  25. package/dist/cjs/use-tracking/index.js +4 -0
  26. package/dist/cjs/use-tracking/index.js.map +1 -1
  27. package/dist/esm/action-components/share-site-modal/index.js +137 -26
  28. package/dist/esm/action-components/share-site-modal/index.js.map +1 -1
  29. package/dist/esm/action-components/share-site-modal/style.scss +23 -116
  30. package/dist/esm/checklist/index.js +11 -3
  31. package/dist/esm/checklist/index.js.map +1 -1
  32. package/dist/esm/checklist-item/index.js +28 -7
  33. package/dist/esm/checklist-item/index.js.map +1 -1
  34. package/dist/esm/checklist-item/index.stories.js +3 -6
  35. package/dist/esm/checklist-item/index.stories.js.map +1 -1
  36. package/dist/esm/checklist-item/style.scss +14 -29
  37. package/dist/esm/launchpad-internal.js +2 -2
  38. package/dist/esm/launchpad-internal.js.map +1 -1
  39. package/dist/esm/launchpad-internal.stories.js +1 -1
  40. package/dist/esm/launchpad-internal.stories.js.map +1 -1
  41. package/dist/esm/launchpad.js +9 -7
  42. package/dist/esm/launchpad.js.map +1 -1
  43. package/dist/esm/msw/resolver.js +1 -7
  44. package/dist/esm/msw/resolver.js.map +1 -1
  45. package/dist/esm/msw/setup-free.js +1 -1
  46. package/dist/esm/msw/setup-free.js.map +1 -1
  47. package/dist/esm/setup-actions.js +4 -9
  48. package/dist/esm/setup-actions.js.map +1 -1
  49. package/dist/esm/use-tracking/index.js +4 -0
  50. package/dist/esm/use-tracking/index.js.map +1 -1
  51. package/dist/tsconfig-cjs.tsbuildinfo +1 -1
  52. package/dist/tsconfig.tsbuildinfo +1 -1
  53. package/dist/types/action-components/share-site-modal/index.d.ts +3 -1
  54. package/dist/types/action-components/share-site-modal/index.d.ts.map +1 -1
  55. package/dist/types/checklist/index.d.ts +1 -0
  56. package/dist/types/checklist/index.d.ts.map +1 -1
  57. package/dist/types/checklist-item/index.d.ts +1 -0
  58. package/dist/types/checklist-item/index.d.ts.map +1 -1
  59. package/dist/types/checklist-item/index.stories.d.ts.map +1 -1
  60. package/dist/types/launchpad-internal.d.ts +1 -0
  61. package/dist/types/launchpad-internal.d.ts.map +1 -1
  62. package/dist/types/launchpad.d.ts +2 -1
  63. package/dist/types/launchpad.d.ts.map +1 -1
  64. package/dist/types/msw/resolver.d.ts.map +1 -1
  65. package/dist/types/setup-actions.d.ts.map +1 -1
  66. package/dist/types/types.d.ts +1 -7
  67. package/dist/types/types.d.ts.map +1 -1
  68. package/dist/types/use-tracking/index.d.ts.map +1 -1
  69. package/package.json +30 -23
  70. package/src/action-components/share-site-modal/index.tsx +239 -76
  71. package/src/action-components/share-site-modal/style.scss +23 -116
  72. package/src/checklist/index.tsx +15 -3
  73. package/src/checklist/test/test-checklist.tsx +38 -0
  74. package/src/checklist-item/index.stories.tsx +11 -5
  75. package/src/checklist-item/index.tsx +55 -29
  76. package/src/checklist-item/style.scss +14 -29
  77. package/src/checklist-item/test/index.tsx +1 -20
  78. package/src/launchpad-internal.stories.tsx +1 -1
  79. package/src/launchpad-internal.tsx +6 -1
  80. package/src/launchpad.tsx +15 -7
  81. package/src/msw/resolver.ts +1 -10
  82. package/src/msw/setup-free.ts +1 -1
  83. package/src/setup-actions.ts +4 -9
  84. package/src/test/launchpad.tsx +1 -1
  85. package/src/test/lib/fixtures.ts +7 -7
  86. package/src/types.ts +1 -8
  87. package/src/use-tracking/index.tsx +4 -0
  88. package/dist/cjs/badge/index.js +0 -13
  89. package/dist/cjs/badge/index.js.map +0 -1
  90. package/dist/cjs/badge/style.scss +0 -50
  91. package/dist/cjs/msw/link-in-bio.js +0 -68
  92. package/dist/cjs/msw/link-in-bio.js.map +0 -1
  93. package/dist/esm/badge/index.js +0 -10
  94. package/dist/esm/badge/index.js.map +0 -1
  95. package/dist/esm/badge/style.scss +0 -50
  96. package/dist/esm/msw/link-in-bio.js +0 -66
  97. package/dist/esm/msw/link-in-bio.js.map +0 -1
  98. package/dist/types/badge/index.d.ts +0 -10
  99. package/dist/types/badge/index.d.ts.map +0 -1
  100. package/dist/types/msw/link-in-bio.d.ts +0 -35
  101. package/dist/types/msw/link-in-bio.d.ts.map +0 -1
  102. package/src/badge/index.tsx +0 -25
  103. package/src/badge/style.scss +0 -50
  104. package/src/msw/link-in-bio.ts +0 -66
  105. package/src/test/badge.tsx +0 -50
@@ -3,138 +3,45 @@
3
3
  .share-site-modal__modal {
4
4
  max-width: 640px;
5
5
 
6
- .components-modal__header {
7
- padding: 48px;
8
- }
9
-
10
- .components-modal__content {
11
- margin: 0;
12
- padding: 0;
13
- }
14
-
15
- .share-site-modal__modal-content {
16
- padding: 48px;
17
- padding-bottom: 40px;
18
- display: flex;
19
- flex-direction: column;
20
- gap: 32px;
21
- }
22
-
23
- .share-site-modal__modal-heading {
24
- color: var(--studio-gray-100);
25
- font-family: Recoleta, "Noto Serif", Georgia, "Times New Roman", Times, serif;
26
- font-size: 2rem;
27
- line-height: 40px;
28
- font-weight: 400;
29
- letter-spacing: 0.2px;
30
- margin: 0;
31
- padding-bottom: 8px;
32
- }
33
-
34
- .share-site-modal__modal-domain {
35
- display: flex;
36
- justify-content: center;
37
- align-items: center;
38
- }
39
-
40
- .share-site-modal__modal-body,
41
- .share-site-modal__modal-domain-text {
42
- margin: 0;
43
- color: var(--studio-gray-80);
44
- font-size: 1rem;
45
- line-height: 24px;
46
- }
47
-
48
- .share-site-modal__modal-domain-text {
49
- padding: 0 8px;
50
-
51
- // prevent text overflow
52
- text-overflow: ellipsis;
53
- white-space: nowrap;
54
- overflow: hidden;
55
- }
56
-
57
- .share-site-modal__modal-buttons {
58
- display: flex;
59
- flex-direction: row;
60
- justify-content: end;
61
- gap: 16px;
62
- }
63
-
64
- .share-site-modal__modal-site {
65
- padding: 8px;
66
- background: var(--studio-gray-0);
67
- display: flex;
68
- flex-direction: row;
69
- justify-content: space-between;
70
- align-items: center;
71
- }
72
-
73
- .launchpad__clipboard-button {
74
- opacity: 0;
75
- }
76
-
77
- .launchpad__clipboard-button:focus {
78
- opacity: 1;
79
- }
80
-
81
- .share-site-modal__modal-site:hover {
82
- .launchpad__clipboard-button {
83
- opacity: 1;
6
+ .share-site-modal__modal-input-container {
7
+ input {
8
+ /* Required to tame the WordPress component's outrageously specific font size */
9
+ font-size: $font-body !important;
84
10
  }
85
11
  }
86
12
 
87
- .share-site-modal__modal-customize {
88
- color: var(--studio-blue-50);
89
- font-size: 0.875rem;
90
- display: inline-flex;
91
- flex-direction: row;
92
- justify-content: start;
93
- gap: 6px;
94
- padding: 0;
13
+ .share-site-modal__modal-social {
14
+ flex-wrap: wrap;
95
15
  margin: 0;
96
- margin-top: 16px;
97
- }
98
-
99
- .share-site-modal__modal-upsell {
100
- border-top: 1px solid var(--studio-gray-5);
101
- background: var(--studio-gray-0);
102
- display: flex;
103
- justify-content: center;
104
- align-items: center;
105
- padding: 32px 48px;
106
- gap: 32px;
107
-
108
- .components-button {
109
- height: 42px;
110
- }
111
- }
112
-
113
- .share-site-modal__modal-upsell-content p {
114
- margin-bottom: 0;
16
+ list-style: none;
115
17
  }
116
18
 
117
- .share-site-modal__modal-upsell-content-highlight {
118
- font-weight: bold;
119
- }
120
-
121
- .share-site-modal__modal-view-site {
122
- display: flex;
19
+ .share-site-modal__modal-copy-link,
20
+ .share-site-modal__modal-share-link {
123
21
  gap: 4px;
124
-
22
+ display: inline-flex;
23
+ align-items: center;
125
24
  font-weight: 500;
126
- /* stylelint-disable-next-line */
127
- font-size: 14px;
25
+ padding: 4px 8px;
26
+ font-size: $font-body-small;
128
27
  line-height: 20px;
129
28
  letter-spacing: -0.154px;
130
29
  color: #101517;
30
+ .share-site-modal__modal-icon {
31
+ border-radius: 100%;
32
+ padding: 4px;
33
+ }
34
+ }
35
+
36
+ .share-site-modal__modal-copy-link:disabled {
37
+ opacity: 0.5;
131
38
  }
132
39
 
133
- .share-site-modal__modal-view-site:visited {
40
+ .share-site-modal__modal-share-link:visited {
134
41
  color: #101517;
135
42
  }
136
43
 
137
- .share-site-modal__modal-view-site:hover:not(:disabled) {
44
+ .share-site-modal__modal-share-link:hover:not(:disabled) {
138
45
  text-decoration: underline;
139
46
  }
140
47
  }
@@ -5,13 +5,15 @@ import './style.scss';
5
5
 
6
6
  interface Props {
7
7
  makeLastTaskPrimaryAction?: boolean;
8
+ highlightNextAction?: boolean;
8
9
  children?:
9
10
  | ReactElement< ComponentProps< typeof ChecklistItem > >
10
11
  | ReactElement< ComponentProps< typeof ChecklistItem > >[];
11
12
  }
12
13
 
13
- const Checklist: FC< Props > = ( { children, makeLastTaskPrimaryAction } ) => {
14
+ const Checklist: FC< Props > = ( { children, makeLastTaskPrimaryAction, highlightNextAction } ) => {
14
15
  const lastChildIndex = Children.count( children ) - 1;
16
+ let hasHighlightedItem = false;
15
17
 
16
18
  return (
17
19
  <ul
@@ -21,8 +23,18 @@ const Checklist: FC< Props > = ( { children, makeLastTaskPrimaryAction } ) => {
21
23
  aria-label="Launchpad Checklist"
22
24
  >
23
25
  { Children.map( children || [], ( child, index ) => {
24
- if ( index === lastChildIndex ) {
25
- return cloneElement( child, { isPrimaryAction: makeLastTaskPrimaryAction } );
26
+ const shouldHighlightItem =
27
+ highlightNextAction && ! hasHighlightedItem && child.props.task.completed === false;
28
+
29
+ if ( shouldHighlightItem ) {
30
+ hasHighlightedItem = true;
31
+ }
32
+
33
+ if ( index === lastChildIndex || shouldHighlightItem ) {
34
+ return cloneElement( child, {
35
+ isPrimaryAction: makeLastTaskPrimaryAction,
36
+ isHighlighted: shouldHighlightItem,
37
+ } );
26
38
  }
27
39
  return child;
28
40
  } ) }
@@ -0,0 +1,38 @@
1
+ import { render, screen } from '@testing-library/react';
2
+ import React from 'react';
3
+ import Checklist from '..';
4
+ import ChecklistItem from '../../checklist-item';
5
+
6
+ describe( 'Checklist', () => {
7
+ const createTask = ( id: string, completed = false ) => ( {
8
+ id,
9
+ title: `Task ${ id }`,
10
+ completed,
11
+ onClick: jest.fn(),
12
+ disabled: false,
13
+ } );
14
+
15
+ it( 'highlights the first incomplete task when highlightNextAction is true', () => {
16
+ const tasks = [
17
+ createTask( '1', true ), // completed
18
+ createTask( '2', false ), // should be highlighted
19
+ createTask( '3', false ), // should not be highlighted
20
+ ];
21
+
22
+ render(
23
+ <Checklist highlightNextAction>
24
+ { tasks.map( ( task ) => (
25
+ <ChecklistItem key={ task.id } task={ task } />
26
+ ) ) }
27
+ </Checklist>
28
+ );
29
+
30
+ // Get all checklist items
31
+ const items = screen.getAllByRole( 'listitem' );
32
+
33
+ // Second task should have the highlighted class
34
+ expect( items[ 1 ] ).toHaveClass( 'highlighted' );
35
+ // Third task should not be highlighted
36
+ expect( items[ 2 ] ).not.toHaveClass( 'highlighted' );
37
+ } );
38
+ } );
@@ -1,3 +1,4 @@
1
+ import { Button } from '@wordpress/components';
1
2
  import ChecklistItem from './';
2
3
  import type { Meta, StoryObj } from '@storybook/react';
3
4
 
@@ -79,12 +80,17 @@ export const ExpandedWithAction: Story = {
79
80
  args: {
80
81
  task: baseTask,
81
82
  expandable: {
82
- content: <p>This is the expanded content.</p>,
83
+ content: (
84
+ <>
85
+ <p>This is the expanded content.</p>
86
+ <div>
87
+ <Button variant="primary" onClick={ () => {} }>
88
+ Action
89
+ </Button>
90
+ </div>
91
+ </>
92
+ ),
83
93
  isOpen: true,
84
- action: {
85
- label: 'Next',
86
- onClick: () => {},
87
- },
88
94
  },
89
95
  },
90
96
  };
@@ -1,6 +1,7 @@
1
- import { Badge, Gridicon } from '@automattic/components';
2
- import { Button } from '@wordpress/components';
3
- import { __, isRTL } from '@wordpress/i18n';
1
+ import { Badge } from '@automattic/components';
2
+ import { Button, Icon } from '@wordpress/components';
3
+ import { __, isRTL, sprintf } from '@wordpress/i18n';
4
+ import { check, chevronLeft, chevronRight } from '@wordpress/icons';
4
5
  import clsx from 'clsx';
5
6
  import type { Task, Expandable } from '../types';
6
7
  import type { FC, Key } from 'react';
@@ -11,11 +12,18 @@ interface Props {
11
12
  key?: Key;
12
13
  task: Task;
13
14
  isPrimaryAction?: boolean;
15
+ isHighlighted?: boolean;
14
16
  expandable?: Expandable;
15
17
  onClick?: () => void;
16
18
  }
17
19
 
18
- const ChecklistItem: FC< Props > = ( { task, isPrimaryAction, expandable, onClick } ) => {
20
+ const ChecklistItem: FC< Props > = ( {
21
+ task,
22
+ isPrimaryAction,
23
+ isHighlighted,
24
+ expandable,
25
+ onClick,
26
+ } ) => {
19
27
  const { id, completed, disabled = false, title, subtitle, actionDispatch } = task;
20
28
 
21
29
  // If the task says we should use the Calypso path, ensure we use that link for the button's href.
@@ -48,6 +56,29 @@ const ChecklistItem: FC< Props > = ( { task, isPrimaryAction, expandable, onClic
48
56
  const buttonClassName = isClickable ? '' : 'components-button';
49
57
  const ButtonElement = isClickable ? Button : 'div';
50
58
 
59
+ const getStatusText = () => {
60
+ const taskTitle = typeof title === 'string' ? title : String( title );
61
+
62
+ if ( completed ) {
63
+ /* translators: %s: Task title */
64
+ return sprintf( __( 'Completed: %s', 'launchpad' ), taskTitle );
65
+ }
66
+ if ( disabled ) {
67
+ /* translators: %s: Task title */
68
+ return sprintf( __( 'Not available yet: %s', 'launchpad' ), taskTitle );
69
+ }
70
+ if ( isClickable ) {
71
+ if ( isPrimaryAction ) {
72
+ /* translators: %s: Task title */
73
+ return sprintf( __( 'Start task: %s', 'launchpad' ), taskTitle );
74
+ }
75
+ /* translators: %s: Task title in lowercase */
76
+ return sprintf( __( 'Select to %s', 'launchpad' ), taskTitle.toLowerCase() );
77
+ }
78
+ /* translators: %s: Task title */
79
+ return sprintf( __( 'To do: %s', 'launchpad' ), taskTitle );
80
+ };
81
+
51
82
  return (
52
83
  <li
53
84
  className={ clsx( 'checklist-item__task', {
@@ -56,16 +87,20 @@ const ChecklistItem: FC< Props > = ( { task, isPrimaryAction, expandable, onClic
56
87
  enabled: ! disabled,
57
88
  disabled: disabled,
58
89
  expanded: expandable && expandable.isOpen,
90
+ highlighted: isHighlighted,
59
91
  } ) }
92
+ aria-current={ isHighlighted ? 'step' : undefined }
60
93
  >
61
94
  { isPrimaryAction ? (
62
95
  <ButtonElement
96
+ variant="primary"
63
97
  className={ clsx( 'checklist-item__checklist-primary-button', buttonClassName ) }
64
98
  data-task={ id }
65
99
  onClick={ onClickHandler }
66
100
  { ...buttonProps }
67
101
  >
68
- { title }
102
+ <span className="screen-reader-text">{ getStatusText() }</span>
103
+ <span aria-hidden="true">{ title }</span>
69
104
  </ButtonElement>
70
105
  ) : (
71
106
  <ButtonElement
@@ -75,17 +110,18 @@ const ChecklistItem: FC< Props > = ( { task, isPrimaryAction, expandable, onClic
75
110
  { ...buttonProps }
76
111
  >
77
112
  { completed && (
78
- // show checkmark for completed tasks regardless if they are disabled or kept active
79
- <div className="checklist-item__checkmark-container">
80
- <Gridicon
81
- aria-label={ __( 'Task complete', 'launchpad' ) }
82
- className="checklist-item__checkmark"
83
- icon="checkmark"
84
- size={ 18 }
85
- />
113
+ <div
114
+ className="checklist-item__checkmark-container"
115
+ aria-hidden="true"
116
+ data-testid="checklist-item-checkmark"
117
+ >
118
+ <Icon icon={ check } className="checklist-item__checkmark" size={ 25 } />
86
119
  </div>
87
120
  ) }
88
- <span className="checklist-item__text">{ title }</span>
121
+ <span className="checklist-item__text">
122
+ <span className="screen-reader-text">{ getStatusText() }</span>
123
+ <span aria-hidden="true">{ title }</span>
124
+ </span>
89
125
  { task.badge_text ? <Badge type="info-blue">{ task.badge_text }</Badge> : null }
90
126
  { shouldDisplayTaskCounter && (
91
127
  <span className="checklist-item__counter">
@@ -93,28 +129,18 @@ const ChecklistItem: FC< Props > = ( { task, isPrimaryAction, expandable, onClic
93
129
  </span>
94
130
  ) }
95
131
  { shouldDisplayChevron && (
96
- <Gridicon
97
- aria-label={ __( 'Task enabled', 'launchpad' ) }
132
+ <Icon
133
+ aria-hidden="true"
98
134
  className="checklist-item__chevron"
99
- icon={ `chevron-${ isRTL() ? 'left' : 'right' }` }
100
- size={ 18 }
135
+ icon={ isRTL() ? chevronLeft : chevronRight }
136
+ size={ 25 }
101
137
  />
102
138
  ) }
103
139
  { subtitle && <p className="checklist-item__subtext">{ subtitle }</p> }
104
140
  </ButtonElement>
105
141
  ) }
106
142
  { expandable && expandable.isOpen && (
107
- <div className="checklist-item__expanded-content">
108
- { expandable.content }
109
- { expandable.action && (
110
- <Button
111
- className="checklist-item__checklist-expanded-action-button"
112
- onClick={ expandable.action.onClick }
113
- >
114
- { expandable.action.label }
115
- </Button>
116
- ) }
117
- </div>
143
+ <div className="checklist-item__expanded-content">{ expandable.content }</div>
118
144
  ) }
119
145
  </li>
120
146
  );
@@ -111,7 +111,6 @@
111
111
 
112
112
  .checklist-item__checkmark-container {
113
113
  margin-right: 7px;
114
- width: 20px;
115
114
  display: flex;
116
115
  margin-left: 1px;
117
116
  margin-bottom: -2px;
@@ -191,7 +190,7 @@
191
190
 
192
191
  .checklist-item__chevron,
193
192
  .checklist-item__checkmark {
194
- fill: var(--color-neutral-40);
193
+ fill: var(--color-success);
195
194
  }
196
195
  .checklist-item__counter {
197
196
  color: var(--color-neutral-40);
@@ -208,12 +207,12 @@
208
207
  .checklist-item__task.completed.enabled > a:focus,
209
208
  .checklist-item__task.pending > a:focus {
210
209
  .checklist-item__text {
211
- color: var(--studio-blue-50);
210
+ color: var(--color-accent);
212
211
  }
213
212
 
214
213
  .checklist-item__chevron,
215
214
  .checklist-item__checkmark {
216
- fill: var(--studio-blue-50);
215
+ fill: var(--color-accent);
217
216
  }
218
217
 
219
218
  // change badge color on hover (Choose a Plan step)
@@ -249,44 +248,30 @@
249
248
  font-weight: 600;
250
249
  }
251
250
 
252
- .checklist-item__checklist-expanded-action-button.components-button,
253
251
  .checklist-item__checklist-primary-button.components-button {
254
252
  width: 100%;
253
+ }
254
+
255
+ .checklist-item__checklist-expanded-cta,
256
+ .checklist-item__checklist-primary-button.components-button {
255
257
  font-weight: 500;
256
258
  padding: 11px;
257
259
  margin-top: 12px;
258
- background-color: var(--color-primary);
259
- border-color: var(--color-primary);
260
260
  border-radius: 4px;
261
- color: var(--color-text-inverted);
262
261
  justify-content: center;
263
262
  font-size: $font-body-small;
264
263
  height: auto;
265
264
  line-height: 22px;
265
+ }
266
266
 
267
- &:hover:not([disabled]) {
268
- background-color: var(--color-primary-60);
269
- border-color: var(--color-primary-60);
270
- color: var(--color-text-inverted);
271
- }
272
-
273
- &[disabled] {
274
- background-color: var(--color-primary-10);
275
- border-color: var(--color-primary-10);
276
- color: var(--color-text-inverted);
277
- }
278
-
279
- &:disabled {
280
- opacity: 1;
281
- &:hover {
282
- color: var(--color-text-inverted);
283
- }
284
- }
267
+ // Expanded content
268
+ .checklist-item__checklist-expanded-ctas {
269
+ display: flex;
270
+ gap: 16px;
285
271
  }
286
272
 
287
- .checklist-item__checklist-expanded-action-button.components-button {
288
- display: block;
289
- margin: 16px 0;
273
+ .checklist-item__checklist-expanded-cta {
274
+ flex: 1;
290
275
  }
291
276
 
292
277
  .checklist-item__expanded-content {
@@ -126,7 +126,7 @@ describe( 'ChecklistItem', () => {
126
126
  describe( 'when the task is completed', () => {
127
127
  it( 'shows the task completed icon', () => {
128
128
  renderComponent( { task: buildTask( { completed: true } ) } );
129
- const taskCompleteIcon = screen.queryByLabelText( 'Task complete' );
129
+ const taskCompleteIcon = screen.getByTestId( 'checklist-item-checkmark' );
130
130
 
131
131
  expect( taskCompleteIcon ).toBeVisible();
132
132
  } );
@@ -181,25 +181,6 @@ describe( 'ChecklistItem', () => {
181
181
  expect( screen.getByText( 'Expanded' ) ).toBeVisible();
182
182
  } );
183
183
 
184
- it( 'calls the action click', async () => {
185
- const onClick = jest.fn();
186
- renderComponent( {
187
- expandable: {
188
- isOpen: true,
189
- content: <div>Expanded</div>,
190
- action: {
191
- label: 'Action',
192
- onClick,
193
- },
194
- },
195
- } );
196
-
197
- const actionButton = screen.queryByRole( 'button', { name: 'Action' } )!;
198
- await userEvent.click( actionButton );
199
-
200
- expect( onClick ).toHaveBeenCalled();
201
- } );
202
-
203
184
  it( 'has the expanded class', () => {
204
185
  const { container } = renderComponent( {
205
186
  expandable: { isOpen: true, content: <div>Expanded</div> },
@@ -30,7 +30,7 @@ const meta: Meta< typeof LaunchpadInternal > = {
30
30
  argTypes: {
31
31
  checklistSlug: {
32
32
  defaultValue: 'free',
33
- options: [ 'free', 'link-in-bio' ],
33
+ options: [ 'free' ],
34
34
  control: { type: 'select' },
35
35
  },
36
36
  },
@@ -11,6 +11,7 @@ interface Props {
11
11
  siteSlug: string | null;
12
12
  checklistSlug: string | null;
13
13
  makeLastTaskPrimaryAction?: boolean;
14
+ highlightNextAction?: boolean;
14
15
  taskFilter?: ( tasks: Task[] ) => Task[];
15
16
  useLaunchpadOptions?: UseLaunchpadOptions;
16
17
  launchpadContext: string;
@@ -28,6 +29,7 @@ const LaunchpadInternal: FC< Props > = ( {
28
29
  checklistSlug,
29
30
  taskFilter,
30
31
  makeLastTaskPrimaryAction,
32
+ highlightNextAction,
31
33
  useLaunchpadOptions = {},
32
34
  launchpadContext,
33
35
  } ) => {
@@ -66,7 +68,10 @@ const LaunchpadInternal: FC< Props > = ( {
66
68
  return (
67
69
  <div className="launchpad__checklist-wrapper">
68
70
  { isFetchedAfterMount ? (
69
- <Checklist makeLastTaskPrimaryAction={ makeLastTaskPrimaryAction }>
71
+ <Checklist
72
+ makeLastTaskPrimaryAction={ makeLastTaskPrimaryAction }
73
+ highlightNextAction={ highlightNextAction }
74
+ >
70
75
  { tasks.map( ( task ) => (
71
76
  <ChecklistItem
72
77
  task={ task }
package/src/launchpad.tsx CHANGED
@@ -1,12 +1,11 @@
1
1
  import { recordTracksEvent } from '@automattic/calypso-analytics';
2
2
  import {
3
- LaunchpadNavigator,
4
3
  Site,
5
4
  type SiteSelect,
6
- sortLaunchpadTasksByCompletionStatus,
5
+ defaultSuccessCallback,
7
6
  useSortedLaunchpadTasks,
8
7
  } from '@automattic/data-stores';
9
- import { useDispatch, useSelect } from '@wordpress/data';
8
+ import { useSelect } from '@wordpress/data';
10
9
  import { useState } from 'react';
11
10
  import { ShareSiteModal } from './action-components';
12
11
  import LaunchpadInternal from './launchpad-internal';
@@ -22,6 +21,7 @@ type LaunchpadProps = {
22
21
  onSiteLaunched?: () => void;
23
22
  onTaskClick?: EventHandlers[ 'onTaskClick' ];
24
23
  onPostFilterTasks?: ( tasks: Task[] ) => Task[];
24
+ highlightNextAction?: boolean;
25
25
  };
26
26
 
27
27
  const Launchpad = ( {
@@ -31,11 +31,11 @@ const Launchpad = ( {
31
31
  onSiteLaunched,
32
32
  onTaskClick,
33
33
  onPostFilterTasks,
34
+ highlightNextAction,
34
35
  }: LaunchpadProps ) => {
35
36
  const {
36
37
  data: { checklist },
37
38
  } = useSortedLaunchpadTasks( siteSlug, checklistSlug, launchpadContext );
38
- const { setActiveChecklist } = useDispatch( LaunchpadNavigator.store );
39
39
 
40
40
  const tasklistCompleted = checklist?.every( ( task: Task ) => task.completed ) || false;
41
41
 
@@ -55,7 +55,6 @@ const Launchpad = ( {
55
55
  siteSlug,
56
56
  tracksData,
57
57
  extraActions: {
58
- setActiveChecklist,
59
58
  setShareSiteModalIsOpen,
60
59
  },
61
60
  eventHandlers: {
@@ -72,13 +71,21 @@ const Launchpad = ( {
72
71
  };
73
72
 
74
73
  const launchpadOptions = {
75
- onSuccess: sortLaunchpadTasksByCompletionStatus,
74
+ onSuccess: defaultSuccessCallback,
76
75
  };
77
76
 
77
+ if ( ! launchpadContext ) {
78
+ return null;
79
+ }
80
+ const shareSiteTask = checklist?.find( ( task: Task ) => task.id === 'share_site' ) ?? null;
78
81
  return (
79
82
  <>
80
83
  { shareSiteModalIsOpen && site && (
81
- <ShareSiteModal setModalIsOpen={ setShareSiteModalIsOpen } site={ site } />
84
+ <ShareSiteModal
85
+ setModalIsOpen={ setShareSiteModalIsOpen }
86
+ site={ site }
87
+ task={ shareSiteTask }
88
+ />
82
89
  ) }
83
90
  <LaunchpadInternal
84
91
  site={ site }
@@ -87,6 +94,7 @@ const Launchpad = ( {
87
94
  taskFilter={ taskFilter }
88
95
  useLaunchpadOptions={ launchpadOptions }
89
96
  launchpadContext={ launchpadContext }
97
+ highlightNextAction={ highlightNextAction }
90
98
  />
91
99
  </>
92
100
  );
@@ -1,18 +1,9 @@
1
1
  import { HttpResponse, HttpResponseResolver, delay } from 'msw';
2
- import linkInBio from './link-in-bio';
3
2
  import free from './setup-free';
4
3
 
5
- export const launchpadResolver: HttpResponseResolver = async ( { request } ) => {
6
- const searchParams = new URL( request.url ).searchParams;
7
- const checklistSlug = searchParams.get( 'checklist_slug' );
8
-
4
+ export const launchpadResolver: HttpResponseResolver = async () => {
9
5
  // Random delay to make the UI feel more realistic
10
-
11
6
  await delay();
12
7
 
13
- if ( checklistSlug === 'link-in-bio' ) {
14
- return HttpResponse.json( linkInBio );
15
- }
16
-
17
8
  return HttpResponse.json( free );
18
9
  };
@@ -36,7 +36,7 @@ export default {
36
36
  subtitle: '',
37
37
  badge_text: '',
38
38
  isLaunchTask: false,
39
- calypso_path: '/setup/update-design/designSetup?siteSlug=site62798.wordpress.com',
39
+ calypso_path: '/setup/update-design/design-setup?siteSlug=site62798.wordpress.com',
40
40
  },
41
41
  {
42
42
  id: 'domain_upsell',