@automattic/jetpack-components 0.71.0 → 0.72.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.
- package/CHANGELOG.md +17 -1
- package/build/components/action-button/index.d.ts +10 -10
- package/build/components/action-button/index.js +1 -1
- package/build/components/action-popover/types.d.ts +0 -1
- package/build/components/admin-page/types.d.ts +0 -1
- package/build/components/admin-section/types.d.ts +0 -1
- package/build/components/boost-score-graph/uplot-line-chart.js +2 -2
- package/build/components/dot-pager/index.d.ts +14 -0
- package/build/components/dot-pager/index.js +52 -0
- package/build/components/icon-tooltip/index.js +1 -1
- package/build/components/icon-tooltip/types.d.ts +0 -1
- package/build/components/layout/types.d.ts +0 -1
- package/build/components/number-control/index.js +1 -1
- package/build/components/popover/index.d.ts +0 -1
- package/build/components/pricing-table/types.d.ts +0 -1
- package/build/components/product-offer/types.d.ts +0 -1
- package/build/components/product-price/types.d.ts +0 -1
- package/build/components/radio-control/index.d.ts +0 -1
- package/build/components/spinner/index.d.ts +3 -3
- package/build/components/spinner/index.js +1 -1
- package/build/components/split-button/types.d.ts +0 -1
- package/build/components/stat-card/types.d.ts +0 -1
- package/build/components/status/index.d.ts +0 -1
- package/build/components/swipeable/index.d.ts +12 -0
- package/build/components/swipeable/index.js +293 -0
- package/build/components/terms-of-service/index.d.ts +0 -1
- package/build/components/theme-provider/types.d.ts +0 -1
- package/build/components/toggle-control/index.d.ts +0 -1
- package/build/index.d.ts +1 -0
- package/build/index.js +1 -0
- package/components/action-button/index.jsx +1 -1
- package/components/dot-pager/README.md +20 -0
- package/components/dot-pager/index.tsx +147 -0
- package/components/dot-pager/style.scss +80 -0
- package/components/number-control/index.jsx +3 -1
- package/components/swipeable/README.md +34 -0
- package/components/swipeable/index.tsx +425 -0
- package/components/swipeable/style.scss +34 -0
- package/index.ts +1 -0
- package/package.json +4 -4
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Dot pager
|
|
2
|
+
|
|
3
|
+
`DotPager` wraps all its child components into a browsable container that shows only one child at time.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import { DotPager } from '@automattic/jetpack-components';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
function myDotPager() {
|
|
12
|
+
return (
|
|
13
|
+
<DotPager>
|
|
14
|
+
<div>Item 1</div>
|
|
15
|
+
<div>Item 2</div>
|
|
16
|
+
<div>Item 3</div>
|
|
17
|
+
</DotPager>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Button } from '@wordpress/components';
|
|
2
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import React, { Children, useState, useEffect, ReactNode, useCallback, useMemo } from 'react';
|
|
5
|
+
import { Swipeable } from '../swipeable/index.js';
|
|
6
|
+
|
|
7
|
+
import './style.scss';
|
|
8
|
+
|
|
9
|
+
type ControlsProps = {
|
|
10
|
+
currentPage: number;
|
|
11
|
+
numberOfPages: number;
|
|
12
|
+
setCurrentPage: ( page: number ) => void;
|
|
13
|
+
tracksPrefix: string;
|
|
14
|
+
tracksFn: ( eventName: string, data?: Record< string, unknown > ) => void;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const Controls = ( {
|
|
18
|
+
currentPage,
|
|
19
|
+
numberOfPages,
|
|
20
|
+
setCurrentPage,
|
|
21
|
+
tracksPrefix,
|
|
22
|
+
tracksFn,
|
|
23
|
+
}: ControlsProps ) => {
|
|
24
|
+
// Create a map of memoized handlers for each page
|
|
25
|
+
const pageHandlers = useMemo(
|
|
26
|
+
() =>
|
|
27
|
+
Array.from( { length: numberOfPages }, ( _, page ) => () => {
|
|
28
|
+
tracksFn( tracksPrefix + '_dot_click', {
|
|
29
|
+
current_page: currentPage,
|
|
30
|
+
destination_page: page,
|
|
31
|
+
} );
|
|
32
|
+
setCurrentPage( page );
|
|
33
|
+
} ),
|
|
34
|
+
[ numberOfPages, currentPage, tracksFn, tracksPrefix, setCurrentPage ]
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if ( numberOfPages < 2 ) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<ul className="dot-pager__controls" aria-label={ __( 'Pager controls', 'jetpack-components' ) }>
|
|
43
|
+
{ Array.from( { length: numberOfPages }, ( _, page ) => (
|
|
44
|
+
<li key={ `page-${ page }` } aria-current={ page === currentPage ? 'page' : undefined }>
|
|
45
|
+
<Button
|
|
46
|
+
key={ page.toString() }
|
|
47
|
+
className={ clsx( 'dot-pager__control-choose-page', {
|
|
48
|
+
'dot-pager__control-current': page === currentPage,
|
|
49
|
+
} ) }
|
|
50
|
+
disabled={ page === currentPage }
|
|
51
|
+
aria-label={ sprintf(
|
|
52
|
+
/* translators: %1$d: current page number, %2$d: total number of pages */
|
|
53
|
+
__( 'Page %1$d of %2$d', 'jetpack-components' ),
|
|
54
|
+
page + 1,
|
|
55
|
+
numberOfPages
|
|
56
|
+
) }
|
|
57
|
+
onClick={ pageHandlers[ page ] }
|
|
58
|
+
/>
|
|
59
|
+
</li>
|
|
60
|
+
) ) }
|
|
61
|
+
</ul>
|
|
62
|
+
);
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
type DotPagerProps = {
|
|
66
|
+
hasDynamicHeight?: boolean;
|
|
67
|
+
children: ReactNode;
|
|
68
|
+
className?: string;
|
|
69
|
+
onPageSelected?: ( index: number ) => void;
|
|
70
|
+
isClickEnabled?: boolean;
|
|
71
|
+
rotateTime?: number;
|
|
72
|
+
tracksPrefix?: string;
|
|
73
|
+
tracksFn?: ( eventName: string, data?: Record< string, unknown > ) => void;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const DotPager = ( {
|
|
77
|
+
hasDynamicHeight = false,
|
|
78
|
+
children,
|
|
79
|
+
className = '',
|
|
80
|
+
onPageSelected,
|
|
81
|
+
isClickEnabled = false,
|
|
82
|
+
rotateTime = 0,
|
|
83
|
+
tracksPrefix = '',
|
|
84
|
+
tracksFn = () => {},
|
|
85
|
+
...props
|
|
86
|
+
}: DotPagerProps ) => {
|
|
87
|
+
const normalizedChildren = Children.toArray( children ).filter( Boolean );
|
|
88
|
+
const [ currentPage, setCurrentPage ] = useState( 0 );
|
|
89
|
+
const [ isPaused, setIsPaused ] = useState( false );
|
|
90
|
+
const numPages = Children.count( normalizedChildren );
|
|
91
|
+
|
|
92
|
+
useEffect( () => {
|
|
93
|
+
if ( rotateTime > 0 && numPages > 1 && ! isPaused ) {
|
|
94
|
+
const timerId = setTimeout( () => {
|
|
95
|
+
// Add 1 to numPages to account for the clones
|
|
96
|
+
setCurrentPage( ( currentPage + 1 ) % ( numPages + 1 ) );
|
|
97
|
+
}, rotateTime * 1000 );
|
|
98
|
+
|
|
99
|
+
return () => clearTimeout( timerId );
|
|
100
|
+
}
|
|
101
|
+
}, [ currentPage, numPages, rotateTime, isPaused ] );
|
|
102
|
+
|
|
103
|
+
const handleSelectPage = useCallback(
|
|
104
|
+
( index: number ) => {
|
|
105
|
+
setCurrentPage( index );
|
|
106
|
+
onPageSelected?.( index );
|
|
107
|
+
},
|
|
108
|
+
[ onPageSelected ]
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
const handleMouseEnter = useCallback( () => {
|
|
112
|
+
setIsPaused( true );
|
|
113
|
+
}, [] );
|
|
114
|
+
|
|
115
|
+
const handleMouseLeave = useCallback( () => {
|
|
116
|
+
setIsPaused( false );
|
|
117
|
+
}, [] );
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<div
|
|
121
|
+
className={ clsx( 'dot-pager', className ) }
|
|
122
|
+
onMouseEnter={ handleMouseEnter }
|
|
123
|
+
onMouseLeave={ handleMouseLeave }
|
|
124
|
+
{ ...props }
|
|
125
|
+
>
|
|
126
|
+
<Controls
|
|
127
|
+
currentPage={ currentPage }
|
|
128
|
+
numberOfPages={ numPages }
|
|
129
|
+
setCurrentPage={ handleSelectPage }
|
|
130
|
+
tracksPrefix={ tracksPrefix }
|
|
131
|
+
tracksFn={ tracksFn }
|
|
132
|
+
/>
|
|
133
|
+
<Swipeable
|
|
134
|
+
hasDynamicHeight={ hasDynamicHeight }
|
|
135
|
+
onPageSelect={ handleSelectPage }
|
|
136
|
+
currentPage={ currentPage }
|
|
137
|
+
pageClassName="dot-pager__page"
|
|
138
|
+
containerClassName="dot-pager__pages"
|
|
139
|
+
isClickEnabled={ isClickEnabled }
|
|
140
|
+
>
|
|
141
|
+
{ normalizedChildren }
|
|
142
|
+
</Swipeable>
|
|
143
|
+
</div>
|
|
144
|
+
);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
export default DotPager;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
@import '@automattic/jetpack-base-styles/gutenberg-base-styles';
|
|
2
|
+
@import '@automattic/jetpack-base-styles/root-variables';
|
|
3
|
+
|
|
4
|
+
.dot-pager {
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
position: relative;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.dot-pager__page {
|
|
11
|
+
height: 100%;
|
|
12
|
+
transition: opacity 0.5s ease-in-out, visibility 0.5s ease-in-out;
|
|
13
|
+
@include reduce-motion( "transition" );
|
|
14
|
+
opacity: 1;
|
|
15
|
+
visibility: visible;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.dot-pager__controls {
|
|
19
|
+
margin: 0;
|
|
20
|
+
margin-bottom: 16px;
|
|
21
|
+
margin-top: auto;
|
|
22
|
+
display: flex;
|
|
23
|
+
justify-content: center;
|
|
24
|
+
position: absolute;
|
|
25
|
+
bottom: 0px;
|
|
26
|
+
left: 0;
|
|
27
|
+
right: 0;
|
|
28
|
+
z-index: 1;
|
|
29
|
+
li {
|
|
30
|
+
display: inline-flex;
|
|
31
|
+
margin: 0 4px;
|
|
32
|
+
height: 18px;
|
|
33
|
+
align-items: center;
|
|
34
|
+
|
|
35
|
+
&:first-child {
|
|
36
|
+
margin-left: 0;
|
|
37
|
+
}
|
|
38
|
+
&:last-child {
|
|
39
|
+
margin-right: 0;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.dot-pager__control-gap {
|
|
44
|
+
margin-left: auto;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.dot-pager__control-choose-page {
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
|
|
51
|
+
&:disabled {
|
|
52
|
+
cursor: default;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&:focus-visible {
|
|
56
|
+
box-shadow: 0 0 0 2px var(--jp-gray-90);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.dot-pager__control-choose-page {
|
|
61
|
+
border-radius: 50%;
|
|
62
|
+
width: 6px;
|
|
63
|
+
height: 6px;
|
|
64
|
+
padding: 0px;
|
|
65
|
+
background-color: var(--jp-white-off);
|
|
66
|
+
|
|
67
|
+
&:hover {
|
|
68
|
+
background-color: var(--jp-gray-20);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
&.dot-pager__control-current {
|
|
72
|
+
background-color: var(--jp-gray-80);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.dot-pager {
|
|
77
|
+
&__button {
|
|
78
|
+
margin-right: 10px;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -14,7 +14,9 @@ import {
|
|
|
14
14
|
const NumberControl =
|
|
15
15
|
ExperimentalNumberControl ||
|
|
16
16
|
function CustomNumberControl( props ) {
|
|
17
|
-
return
|
|
17
|
+
return (
|
|
18
|
+
<TextControl type="number" inputMode="numeric" { ...props } __next40pxDefaultSize={ true } />
|
|
19
|
+
);
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export default NumberControl;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Swipeable
|
|
2
|
+
|
|
3
|
+
This component is used to add horizontal swipe controls to a list of elements (pages).
|
|
4
|
+
|
|
5
|
+
## Example Usage
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import { Swipeable } from '@automattic/jetpack-components';
|
|
9
|
+
|
|
10
|
+
function Pager() {
|
|
11
|
+
const [ currentPage, setCurrentPage ] = useState( 0 );
|
|
12
|
+
return (
|
|
13
|
+
<Swipeable
|
|
14
|
+
onPageSelect={ ( index ) => {
|
|
15
|
+
setCurrentPage( index );
|
|
16
|
+
} }
|
|
17
|
+
currentPage={ currentPage }
|
|
18
|
+
pageClassName="example-page-component-class"
|
|
19
|
+
>
|
|
20
|
+
<div>Page 1</div>
|
|
21
|
+
<div>Page 2</div>
|
|
22
|
+
<div>Page 3</div>
|
|
23
|
+
</Swipeable>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Props
|
|
29
|
+
|
|
30
|
+
- `onPageSelect` - (function) Function that runs when the page is selected on using a swipe. Useful for updating the current page.
|
|
31
|
+
- `currentPage` - (number) Index of the currently selected/shown page.
|
|
32
|
+
- `hasDynamicHeight` - (bool) Whether height should be changed dynamically.
|
|
33
|
+
- `pageClassName` - _optional_ (string) Optional class attribute of the page component.
|
|
34
|
+
- `containerClassName` - _optional_ (string) Optional class attribute of the page container component.
|