feat: add tour (#6332)
* feat v4 add tour * fix type error * sync tour from antd5.4.6 & fix type error * fix errorpull/6607/head
parent
db4148af5a
commit
698c0ff3b4
|
@ -0,0 +1,30 @@
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import canUseDom from '../../_util/canUseDom';
|
||||||
|
|
||||||
|
let uuid = 0;
|
||||||
|
|
||||||
|
/** Is client side and not jsdom */
|
||||||
|
export const isBrowserClient = process.env.NODE_ENV !== 'test' && canUseDom();
|
||||||
|
|
||||||
|
/** Get unique id for accessibility usage */
|
||||||
|
export function getUUID(): number | string {
|
||||||
|
let retId: string | number;
|
||||||
|
|
||||||
|
// Test never reach
|
||||||
|
/* istanbul ignore if */
|
||||||
|
if (isBrowserClient) {
|
||||||
|
retId = uuid;
|
||||||
|
uuid += 1;
|
||||||
|
} else {
|
||||||
|
retId = 'TEST_OR_SSR';
|
||||||
|
}
|
||||||
|
|
||||||
|
return retId;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useId(id = ref('')) {
|
||||||
|
// Inner id for accessibility usage. Only work in client side
|
||||||
|
const innerId = `vc_unique_${getUUID()}`;
|
||||||
|
|
||||||
|
return id.value || innerId;
|
||||||
|
}
|
|
@ -258,3 +258,6 @@ export { default as Segmented } from './segmented';
|
||||||
|
|
||||||
export type { QRCodeProps } from './qrcode';
|
export type { QRCodeProps } from './qrcode';
|
||||||
export { default as QRCode } from './qrcode';
|
export { default as QRCode } from './qrcode';
|
||||||
|
|
||||||
|
export type { TourProps, TourStepProps } from './tour';
|
||||||
|
export { default as Tour } from './tour';
|
||||||
|
|
|
@ -35,6 +35,11 @@ const localeValues: Locale = {
|
||||||
triggerAsc: 'Click to sort ascending',
|
triggerAsc: 'Click to sort ascending',
|
||||||
cancelSort: 'Click to cancel sorting',
|
cancelSort: 'Click to cancel sorting',
|
||||||
},
|
},
|
||||||
|
Tour: {
|
||||||
|
Next: 'Next',
|
||||||
|
Previous: 'Previous',
|
||||||
|
Finish: 'Finish',
|
||||||
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
okText: 'OK',
|
okText: 'OK',
|
||||||
cancelText: 'Cancel',
|
cancelText: 'Cancel',
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { PickerLocale as DatePickerLocale } from '../date-picker/generatePi
|
||||||
import type { PaginationLocale } from '../pagination/Pagination';
|
import type { PaginationLocale } from '../pagination/Pagination';
|
||||||
import type { TableLocale } from '../table/interface';
|
import type { TableLocale } from '../table/interface';
|
||||||
import type { UploadLocale } from '../upload/interface';
|
import type { UploadLocale } from '../upload/interface';
|
||||||
|
import type { TourLocale } from '../tour/interface';
|
||||||
|
|
||||||
interface TransferLocaleForEmpty {
|
interface TransferLocaleForEmpty {
|
||||||
description: string;
|
description: string;
|
||||||
|
@ -43,6 +44,7 @@ export interface Locale {
|
||||||
copied?: any;
|
copied?: any;
|
||||||
expand?: any;
|
expand?: any;
|
||||||
};
|
};
|
||||||
|
Tour?: TourLocale;
|
||||||
QRCode?: {
|
QRCode?: {
|
||||||
expired?: string;
|
expired?: string;
|
||||||
refresh?: string;
|
refresh?: string;
|
||||||
|
|
|
@ -33,6 +33,11 @@ const localeValues: Locale = {
|
||||||
triggerAsc: 'Clique organiza por ascendente',
|
triggerAsc: 'Clique organiza por ascendente',
|
||||||
cancelSort: 'Clique para cancelar organização',
|
cancelSort: 'Clique para cancelar organização',
|
||||||
},
|
},
|
||||||
|
Tour: {
|
||||||
|
Next: 'Próximo',
|
||||||
|
Previous: 'Anterior',
|
||||||
|
Finish: 'Finalizar',
|
||||||
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
okText: 'OK',
|
okText: 'OK',
|
||||||
cancelText: 'Cancelar',
|
cancelText: 'Cancelar',
|
||||||
|
|
|
@ -35,6 +35,11 @@ const localeValues: Locale = {
|
||||||
triggerAsc: '点击升序',
|
triggerAsc: '点击升序',
|
||||||
cancelSort: '取消排序',
|
cancelSort: '取消排序',
|
||||||
},
|
},
|
||||||
|
Tour: {
|
||||||
|
Next: '下一步',
|
||||||
|
Previous: '上一步',
|
||||||
|
Finish: '结束导览',
|
||||||
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
okText: '确定',
|
okText: '确定',
|
||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
|
|
|
@ -32,6 +32,11 @@ const localeValues: Locale = {
|
||||||
triggerAsc: '點擊升序',
|
triggerAsc: '點擊升序',
|
||||||
cancelSort: '取消排序',
|
cancelSort: '取消排序',
|
||||||
},
|
},
|
||||||
|
Tour: {
|
||||||
|
Next: '下一步',
|
||||||
|
Previous: '上一步',
|
||||||
|
Finish: '結束導覽',
|
||||||
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
okText: '確定',
|
okText: '確定',
|
||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
|
|
|
@ -32,6 +32,11 @@ const localeValues: Locale = {
|
||||||
triggerAsc: '點擊升序',
|
triggerAsc: '點擊升序',
|
||||||
cancelSort: '取消排序',
|
cancelSort: '取消排序',
|
||||||
},
|
},
|
||||||
|
Tour: {
|
||||||
|
Next: '下一步',
|
||||||
|
Previous: '上一步',
|
||||||
|
Finish: '結束導覽',
|
||||||
|
},
|
||||||
Modal: {
|
Modal: {
|
||||||
okText: '確定',
|
okText: '確定',
|
||||||
cancelText: '取消',
|
cancelText: '取消',
|
||||||
|
|
|
@ -94,6 +94,7 @@ export interface AliasToken extends MapToken {
|
||||||
|
|
||||||
boxShadow: string;
|
boxShadow: string;
|
||||||
boxShadowSecondary: string;
|
boxShadowSecondary: string;
|
||||||
|
boxShadowTertiary: string;
|
||||||
|
|
||||||
linkDecoration: CSSProperties['textDecoration'];
|
linkDecoration: CSSProperties['textDecoration'];
|
||||||
linkHoverDecoration: CSSProperties['textDecoration'];
|
linkHoverDecoration: CSSProperties['textDecoration'];
|
||||||
|
|
|
@ -44,7 +44,7 @@ import type { ComponentToken as TooltipComponentToken } from '../../tooltip/styl
|
||||||
import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
|
import type { ComponentToken as TransferComponentToken } from '../../transfer/style';
|
||||||
import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
|
import type { ComponentToken as TypographyComponentToken } from '../../typography/style';
|
||||||
import type { ComponentToken as UploadComponentToken } from '../../upload/style';
|
import type { ComponentToken as UploadComponentToken } from '../../upload/style';
|
||||||
// import type { ComponentToken as TourComponentToken } from '../../tour/style';
|
import type { ComponentToken as TourComponentToken } from '../../tour/style';
|
||||||
import type { ComponentToken as QRCodeComponentToken } from '../../qrcode/style';
|
import type { ComponentToken as QRCodeComponentToken } from '../../qrcode/style';
|
||||||
// import type { ComponentToken as AppComponentToken } from '../../app/style';
|
// import type { ComponentToken as AppComponentToken } from '../../app/style';
|
||||||
import type { ComponentToken as WaveToken } from '../../_util/wave/style';
|
import type { ComponentToken as WaveToken } from '../../_util/wave/style';
|
||||||
|
@ -110,7 +110,7 @@ export interface ComponentTokenMap {
|
||||||
Table?: TableComponentToken;
|
Table?: TableComponentToken;
|
||||||
Space?: SpaceComponentToken;
|
Space?: SpaceComponentToken;
|
||||||
Progress?: ProgressComponentToken;
|
Progress?: ProgressComponentToken;
|
||||||
// Tour?: TourComponentToken;
|
Tour?: TourComponentToken;
|
||||||
QRCode?: QRCodeComponentToken;
|
QRCode?: QRCodeComponentToken;
|
||||||
// App?: AppComponentToken;
|
// App?: AppComponentToken;
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,11 @@ export default function formatToken(derivativeToken: RawMergedToken): AliasToken
|
||||||
0 3px 6px -4px rgba(0, 0, 0, 0.12),
|
0 3px 6px -4px rgba(0, 0, 0, 0.12),
|
||||||
0 9px 28px 8px rgba(0, 0, 0, 0.05)
|
0 9px 28px 8px rgba(0, 0, 0, 0.05)
|
||||||
`,
|
`,
|
||||||
|
boxShadowTertiary: `
|
||||||
|
0 1px 2px 0 rgba(0, 0, 0, 0.03),
|
||||||
|
0 1px 6px -1px rgba(0, 0, 0, 0.02),
|
||||||
|
0 2px 4px 0 rgba(0, 0, 0, 0.02)
|
||||||
|
`,
|
||||||
|
|
||||||
screenXS,
|
screenXS,
|
||||||
screenXSMin: screenXS,
|
screenXSMin: screenXS,
|
||||||
|
|
|
@ -0,0 +1,478 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`renders ./components/tour/demo/basic.tsx extend context correctly 1`] = `
|
||||||
|
Array [
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Begin Tour
|
||||||
|
</span>
|
||||||
|
</button>,
|
||||||
|
<div
|
||||||
|
class="ant-divider ant-divider-horizontal"
|
||||||
|
role="separator"
|
||||||
|
/>,
|
||||||
|
<div
|
||||||
|
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
style="margin-right:8px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Upload
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
style="margin-right:8px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Save
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-icon-only"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="ellipsis"
|
||||||
|
class="anticon anticon-ellipsis"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="ellipsis"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`renders ./components/tour/demo/non-modal.tsx extend context correctly 1`] = `
|
||||||
|
Array [
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Begin non-modal Tour
|
||||||
|
</span>
|
||||||
|
</button>,
|
||||||
|
<div
|
||||||
|
class="ant-divider ant-divider-horizontal"
|
||||||
|
role="separator"
|
||||||
|
/>,
|
||||||
|
<div
|
||||||
|
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
style="margin-right:8px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Upload
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
style="margin-right:8px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Save
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-icon-only"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="ellipsis"
|
||||||
|
class="anticon anticon-ellipsis"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="ellipsis"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`renders ./components/tour/demo/placement.tsx extend context correctly 1`] = `
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Begin Tour
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`renders ./components/tour/demo/render-panel.tsx extend context correctly 1`] = `
|
||||||
|
<div
|
||||||
|
style="display:flex;flex-direction:column;row-gap:16px;background:rgba(50,0,0,0.65);padding:8px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour ant-tour-pure ant-tour-placement-top ant-tour-pure"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
Hello World!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
Hello World?!
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider-active ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Next
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour ant-tour-pure ant-tour-placement-top ant-tour-pure"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-cover"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="tour.png"
|
||||||
|
src="https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
Hello World!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
Hello World?!
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider-active ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-tour-prev-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Previous
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Next
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour ant-tour-pure ant-tour-placement-top ant-tour-pure ant-tour-primary"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-primary ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
Hello World!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
Hello World?!
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider-active ant-tour-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-btn-background-ghost ant-tour-prev-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Previous
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Finish
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
|
@ -0,0 +1,478 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`renders ./components/tour/demo/basic.tsx correctly 1`] = `
|
||||||
|
Array [
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Begin Tour
|
||||||
|
</span>
|
||||||
|
</button>,
|
||||||
|
<div
|
||||||
|
class="ant-divider ant-divider-horizontal"
|
||||||
|
role="separator"
|
||||||
|
/>,
|
||||||
|
<div
|
||||||
|
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
style="margin-right:8px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Upload
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
style="margin-right:8px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Save
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-icon-only"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="ellipsis"
|
||||||
|
class="anticon anticon-ellipsis"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="ellipsis"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`renders ./components/tour/demo/non-modal.tsx correctly 1`] = `
|
||||||
|
Array [
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Begin non-modal Tour
|
||||||
|
</span>
|
||||||
|
</button>,
|
||||||
|
<div
|
||||||
|
class="ant-divider ant-divider-horizontal"
|
||||||
|
role="separator"
|
||||||
|
/>,
|
||||||
|
<div
|
||||||
|
class="ant-space ant-space-horizontal ant-space-align-center"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
style="margin-right:8px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Upload
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
style="margin-right:8px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Save
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-space-item"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-icon-only"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="ellipsis"
|
||||||
|
class="anticon anticon-ellipsis"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="ellipsis"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M176 511a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0zm280 0a56 56 0 10112 0 56 56 0 10-112 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>,
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`renders ./components/tour/demo/placement.tsx correctly 1`] = `
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Begin Tour
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`renders ./components/tour/demo/render-panel.tsx correctly 1`] = `
|
||||||
|
<div
|
||||||
|
style="display:flex;flex-direction:column;row-gap:16px;background:rgba(50,0,0,0.65);padding:8px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour ant-tour-pure ant-tour-placement-top ant-tour-pure"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
Hello World!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
Hello World?!
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider-active ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Next
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour ant-tour-pure ant-tour-placement-top ant-tour-pure"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-cover"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
alt="tour.png"
|
||||||
|
src="https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
Hello World!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
Hello World?!
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider-active ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-tour-prev-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Previous
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Next
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour ant-tour-pure ant-tour-placement-top ant-tour-pure ant-tour-primary"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
role="tooltip"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-primary ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
Hello World!
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
Hello World?!
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider-active ant-tour-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-btn-background-ghost ant-tour-prev-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Previous
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Finish
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
|
@ -0,0 +1,706 @@
|
||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`Tour Primary 1`] = `
|
||||||
|
<body>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
disabled=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour"
|
||||||
|
style="z-index: 1090; opacity: 0;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-primary ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
primary title
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
primary description.
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Finish
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-target-placeholder"
|
||||||
|
style="left: -6px; top: -6px; width: 12px; height: 12px; position: fixed; pointer-events: none;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-mask"
|
||||||
|
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 900; pointer-events: none;"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
style="width: 100%; height: 100%;"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<mask
|
||||||
|
id="ant-tour-mask-test-id"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
fill="white"
|
||||||
|
height="100%"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
class="ant-tour-placeholder-animated"
|
||||||
|
fill="black"
|
||||||
|
height="12"
|
||||||
|
rx="2"
|
||||||
|
width="12"
|
||||||
|
x="-6"
|
||||||
|
y="-6"
|
||||||
|
/>
|
||||||
|
</mask>
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
fill="rgba(0,0,0,0.5)"
|
||||||
|
height="100%"
|
||||||
|
mask="url(#ant-tour-mask-test-id)"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="-6"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="100%"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="-6"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="calc(100vh - 6px)"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="6"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="100%"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="calc(100vw - 6px)"
|
||||||
|
x="6"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
</body>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Tour basic 1`] = `
|
||||||
|
<body>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Show
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
disabled=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
disabled=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Placement
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
</body>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Tour button props onClick 1`] = `
|
||||||
|
<body>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
id="btnName"
|
||||||
|
>
|
||||||
|
finishButton
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
disabled=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
target
|
||||||
|
</button>
|
||||||
|
<div />
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
</body>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Tour custom step pre btn & next btn className & style 1`] = `
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour"
|
||||||
|
style="z-index: 1090; opacity: 0;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
Show in Center
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
Here is the content of Tour.
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider-active ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary ant-btn-sm ant-tour-next-btn customClassName"
|
||||||
|
style="background-color: rgb(69, 69, 255);"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Next
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Tour rtl render component should be rendered correctly in RTL direction 1`] = `null`;
|
||||||
|
|
||||||
|
exports[`Tour single 1`] = `
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
disabled=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour"
|
||||||
|
style="z-index: 1090; opacity: 0;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
cover title
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
cover description.
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-primary ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Finish
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-target-placeholder"
|
||||||
|
style="left: -6px; top: -6px; width: 12px; height: 12px; position: fixed; pointer-events: none;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-mask"
|
||||||
|
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 900; pointer-events: none;"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
style="width: 100%; height: 100%;"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<mask
|
||||||
|
id="ant-tour-mask-test-id"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
fill="white"
|
||||||
|
height="100%"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
class="ant-tour-placeholder-animated"
|
||||||
|
fill="black"
|
||||||
|
height="12"
|
||||||
|
rx="2"
|
||||||
|
width="12"
|
||||||
|
x="-6"
|
||||||
|
y="-6"
|
||||||
|
/>
|
||||||
|
</mask>
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
fill="rgba(0,0,0,0.5)"
|
||||||
|
height="100%"
|
||||||
|
mask="url(#ant-tour-mask-test-id)"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="-6"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="100%"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="-6"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="calc(100vh - 6px)"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="6"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="100%"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="calc(100vw - 6px)"
|
||||||
|
x="6"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
</body>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Tour step support Primary 1`] = `
|
||||||
|
<body>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
disabled=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour"
|
||||||
|
style="z-index: 1090; opacity: 0;"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-primary ant-tour-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-arrow"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
class="ant-tour-inner"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-label="close"
|
||||||
|
class="anticon anticon-close ant-tour-close"
|
||||||
|
role="img"
|
||||||
|
tabindex="-1"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
|
data-icon="close"
|
||||||
|
fill="currentColor"
|
||||||
|
focusable="false"
|
||||||
|
height="1em"
|
||||||
|
viewBox="64 64 896 896"
|
||||||
|
width="1em"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M563.8 512l262.5-312.9c4.4-5.2.7-13.1-6.1-13.1h-79.8c-4.7 0-9.2 2.1-12.3 5.7L511.6 449.8 295.1 191.7c-3-3.6-7.5-5.7-12.3-5.7H203c-6.8 0-10.5 7.9-6.1 13.1L459.4 512 196.9 824.9A7.95 7.95 0 00203 838h79.8c4.7 0 9.2-2.1 12.3-5.7l216.5-258.1 216.5 258.1c3 3.6 7.5 5.7 12.3 5.7h79.8c6.8 0 10.5-7.9 6.1-13.1L563.8 512z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<div
|
||||||
|
class="ant-tour-header"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-title"
|
||||||
|
>
|
||||||
|
primary title
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-description"
|
||||||
|
>
|
||||||
|
primary description.
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-footer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ant-tour-sliders"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider"
|
||||||
|
/>
|
||||||
|
<span
|
||||||
|
class="ant-tour-slider-active ant-tour-slider"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-buttons"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-btn-background-ghost ant-tour-prev-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Previous
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="ant-btn ant-btn-default ant-btn-sm ant-tour-next-btn"
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
Finish
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-target-placeholder"
|
||||||
|
style="left: -6px; top: -6px; width: 12px; height: 12px; position: fixed; pointer-events: none;"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
class="ant-tour-mask"
|
||||||
|
style="position: fixed; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 900; pointer-events: none;"
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
style="width: 100%; height: 100%;"
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<mask
|
||||||
|
id="ant-tour-mask-test-id"
|
||||||
|
>
|
||||||
|
<rect
|
||||||
|
fill="white"
|
||||||
|
height="100%"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
class="ant-tour-placeholder-animated"
|
||||||
|
fill="black"
|
||||||
|
height="12"
|
||||||
|
rx="2"
|
||||||
|
width="12"
|
||||||
|
x="-6"
|
||||||
|
y="-6"
|
||||||
|
/>
|
||||||
|
</mask>
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
fill="rgba(0,0,0,0.5)"
|
||||||
|
height="100%"
|
||||||
|
mask="url(#ant-tour-mask-test-id)"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="-6"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="100%"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="-6"
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="calc(100vh - 6px)"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="100%"
|
||||||
|
x="0"
|
||||||
|
y="6"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
fill="transparent"
|
||||||
|
height="100%"
|
||||||
|
pointer-events="auto"
|
||||||
|
width="calc(100vw - 6px)"
|
||||||
|
x="6"
|
||||||
|
y="0"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
</body>
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`Tour steps is empty 1`] = `
|
||||||
|
<body>
|
||||||
|
<div
|
||||||
|
style="position: absolute; top: 0px; left: 0px; width: 100%;"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
disabled=""
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
`;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { extendTest } from '../../../tests/shared/demoTest';
|
||||||
|
|
||||||
|
extendTest('tour');
|
|
@ -0,0 +1,3 @@
|
||||||
|
import demoTest from '../../../tests/shared/demoTest';
|
||||||
|
|
||||||
|
demoTest('tour');
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { imageDemoTest } from '../../../tests/shared/imageTest';
|
||||||
|
|
||||||
|
describe('Tooltip tour', () => {
|
||||||
|
imageDemoTest('tour');
|
||||||
|
});
|
|
@ -0,0 +1,287 @@
|
||||||
|
import React, { useRef, useEffect } from 'react';
|
||||||
|
import Tour from '..';
|
||||||
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
|
import rtlTest from '../../../tests/shared/rtlTest';
|
||||||
|
import { fireEvent, render, screen } from '../../../tests/utils';
|
||||||
|
import panelRender from '../panelRender';
|
||||||
|
|
||||||
|
describe('Tour', () => {
|
||||||
|
mountTest(Tour);
|
||||||
|
rtlTest(Tour);
|
||||||
|
|
||||||
|
it('single', () => {
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const coverBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button disabled ref={coverBtnRef} type="button">
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
<Tour
|
||||||
|
steps={[
|
||||||
|
{
|
||||||
|
title: 'cover title',
|
||||||
|
description: 'cover description.',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const { getByText, baseElement } = render(<App />);
|
||||||
|
expect(getByText('cover title')).toBeTruthy();
|
||||||
|
expect(getByText('cover description.')).toBeTruthy();
|
||||||
|
expect(baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('steps is empty', () => {
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const coverBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button disabled ref={coverBtnRef} type="button">
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
<Tour steps={[]} />
|
||||||
|
<Tour />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const { baseElement } = render(<App />);
|
||||||
|
expect(baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('button props onClick', () => {
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const coverBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const [btnName, steBtnName] = React.useState<string>('defaultBtn');
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span id="btnName">{btnName}</span>
|
||||||
|
<button disabled ref={coverBtnRef} type="button">
|
||||||
|
target
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Tour
|
||||||
|
steps={[
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
nextButtonProps: {
|
||||||
|
onClick: () => steBtnName('nextButton'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
prevButtonProps: {
|
||||||
|
onClick: () => steBtnName('prevButton'),
|
||||||
|
},
|
||||||
|
nextButtonProps: {
|
||||||
|
onClick: () => steBtnName('finishButton'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const { baseElement } = render(<App />);
|
||||||
|
expect(baseElement.querySelector('#btnName')).toHaveTextContent('defaultBtn');
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
|
||||||
|
expect(baseElement.querySelector('#btnName')).toHaveTextContent('nextButton');
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Previous' }));
|
||||||
|
expect(baseElement.querySelector('#btnName')).toHaveTextContent('prevButton');
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Finish' }));
|
||||||
|
expect(baseElement.querySelector('#btnName')).toHaveTextContent('finishButton');
|
||||||
|
expect(baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Primary', () => {
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const coverBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button disabled ref={coverBtnRef} type="button">
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Tour
|
||||||
|
type="primary"
|
||||||
|
steps={[
|
||||||
|
{
|
||||||
|
title: 'primary title',
|
||||||
|
description: 'primary description.',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const { getByText, baseElement } = render(<App />);
|
||||||
|
expect(getByText('primary description.')).toBeTruthy();
|
||||||
|
expect(baseElement.querySelector('.ant-tour-content')).toHaveClass('ant-tour-primary');
|
||||||
|
expect(baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('step support Primary', () => {
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const coverBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<button disabled ref={coverBtnRef} type="button">
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<Tour
|
||||||
|
type="default"
|
||||||
|
steps={[
|
||||||
|
{
|
||||||
|
title: 'cover title',
|
||||||
|
description: 'cover description.',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'primary title',
|
||||||
|
description: 'primary description.',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const { getByText, container, baseElement } = render(<App />);
|
||||||
|
expect(getByText('cover description.')).toBeTruthy();
|
||||||
|
expect(container.querySelector('.ant-tour-content.ant-tour-primary')).toBeFalsy();
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
|
||||||
|
expect(getByText('primary description.')).toBeTruthy();
|
||||||
|
expect(container.querySelector('.ant-tour-content.ant-tour-primary')).toBeTruthy();
|
||||||
|
expect(baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('basic', () => {
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const coverBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
const placementBtnRef = useRef<HTMLButtonElement>(null);
|
||||||
|
|
||||||
|
const [show, setShow] = React.useState<boolean>();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (show === false) {
|
||||||
|
setShow(true);
|
||||||
|
}
|
||||||
|
}, [show]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setShow(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Show
|
||||||
|
</button>
|
||||||
|
<button disabled ref={coverBtnRef} type="button">
|
||||||
|
Cover
|
||||||
|
</button>
|
||||||
|
<button disabled ref={placementBtnRef} type="button">
|
||||||
|
Placement
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{show && (
|
||||||
|
<Tour
|
||||||
|
steps={[
|
||||||
|
{
|
||||||
|
title: 'Show in Center',
|
||||||
|
description: 'Here is the content of Tour.',
|
||||||
|
target: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'With Cover',
|
||||||
|
description: 'Here is the content of Tour.',
|
||||||
|
target: () => coverBtnRef.current!,
|
||||||
|
cover: (
|
||||||
|
<img
|
||||||
|
alt="tour.png"
|
||||||
|
src="https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Adjust Placement',
|
||||||
|
description: 'Here is the content of Tour which show on the right.',
|
||||||
|
placement: 'right',
|
||||||
|
target: () => placementBtnRef.current!,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const { getByText, container, baseElement } = render(<App />);
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Show' }));
|
||||||
|
expect(getByText('Show in Center')).toBeTruthy();
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
|
||||||
|
expect(getByText('Here is the content of Tour.')).toBeTruthy();
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Next' }));
|
||||||
|
expect(getByText('Adjust Placement')).toBeTruthy();
|
||||||
|
fireEvent.click(screen.getByRole('button', { name: 'Finish' }));
|
||||||
|
expect(container.querySelector('.ant-tour')).toBeFalsy();
|
||||||
|
expect(baseElement).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
it('panelRender should correct render when total is undefined', () => {
|
||||||
|
expect(() => {
|
||||||
|
panelRender({ total: undefined, title: <div>test</div> }, 0, 'default');
|
||||||
|
}).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('custom step pre btn & next btn className & style', () => {
|
||||||
|
const App: React.FC = () => (
|
||||||
|
<Tour
|
||||||
|
steps={[
|
||||||
|
{
|
||||||
|
title: 'Show in Center',
|
||||||
|
description: 'Here is the content of Tour.',
|
||||||
|
nextButtonProps: {
|
||||||
|
className: 'customClassName',
|
||||||
|
style: {
|
||||||
|
backgroundColor: 'rgb(69,69,255)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'With Cover',
|
||||||
|
description: 'Here is the content of Tour.',
|
||||||
|
cover: (
|
||||||
|
<img
|
||||||
|
alt="tour.png"
|
||||||
|
src="https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png"
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const { container } = render(<App />);
|
||||||
|
// className
|
||||||
|
expect(
|
||||||
|
screen.getByRole('button', { name: 'Next' }).className.includes('customClassName'),
|
||||||
|
).toEqual(true);
|
||||||
|
// style
|
||||||
|
expect(screen.getByRole('button', { name: 'Next' }).style.backgroundColor).toEqual(
|
||||||
|
'rgb(69, 69, 255)',
|
||||||
|
);
|
||||||
|
expect(container.firstChild).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,70 @@
|
||||||
|
<docs>
|
||||||
|
---
|
||||||
|
order: 0
|
||||||
|
title:
|
||||||
|
zh-CN: 基本用法
|
||||||
|
en-US: Basic usage
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
最简单的用法。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
The most basic usage.
|
||||||
|
|
||||||
|
|
||||||
|
</docs>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-button type="primary" @click="handleOpen(true)">Begin Tour</a-button>
|
||||||
|
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<a-space>
|
||||||
|
<a-button ref="ref1">Upload</a-button>
|
||||||
|
<a-button ref="ref2" type="primary">Save</a-button>
|
||||||
|
<a-button ref="ref3"><EllipsisOutlined /></a-button>
|
||||||
|
</a-space>
|
||||||
|
|
||||||
|
<a-tour :open="open" :steps="steps" @close="handleOpen(false)" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, createVNode } from 'vue';
|
||||||
|
import { EllipsisOutlined } from '@ant-design/icons-vue';
|
||||||
|
import type { TourProps } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
|
||||||
|
const ref1 = ref(null);
|
||||||
|
const ref2 = ref(null);
|
||||||
|
const ref3 = ref(null);
|
||||||
|
|
||||||
|
const steps: TourProps['steps'] = [
|
||||||
|
{
|
||||||
|
title: 'Upload File',
|
||||||
|
description: 'Put your files here.',
|
||||||
|
cover: createVNode('img', {
|
||||||
|
alt: 'tour.png',
|
||||||
|
src: 'https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png',
|
||||||
|
}),
|
||||||
|
target: () => ref1.value && ref1.value.$el,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Save',
|
||||||
|
description: 'Save your changes.',
|
||||||
|
target: () => ref2.value && ref2.value.$el,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Other Actions',
|
||||||
|
description: 'Click to see other actions.',
|
||||||
|
target: () => ref3.value && ref3.value.$el,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleOpen = (val: boolean): void => {
|
||||||
|
open.value = val;
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,35 @@
|
||||||
|
<template>
|
||||||
|
<demo-sort>
|
||||||
|
<basic />
|
||||||
|
<non-modal />
|
||||||
|
<placement />
|
||||||
|
<Mask />
|
||||||
|
<indicator />
|
||||||
|
</demo-sort>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import Basic from './basic.vue';
|
||||||
|
import NonModal from './non-modal.vue';
|
||||||
|
import Placement from './placement.vue';
|
||||||
|
import Mask from './mask.vue';
|
||||||
|
import Indicator from './indicator.vue';
|
||||||
|
|
||||||
|
import CN from '../index.zh-CN.md';
|
||||||
|
import US from '../index.en-US.md';
|
||||||
|
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
export default defineComponent({
|
||||||
|
CN,
|
||||||
|
US,
|
||||||
|
components: {
|
||||||
|
Basic,
|
||||||
|
NonModal,
|
||||||
|
Placement,
|
||||||
|
Mask,
|
||||||
|
Indicator,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -0,0 +1,70 @@
|
||||||
|
<docs>
|
||||||
|
---
|
||||||
|
order: 4
|
||||||
|
title:
|
||||||
|
zh-CN: 自定义指示器
|
||||||
|
en-US: custom indicator
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
自定义指示器。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
Custom indicator.
|
||||||
|
|
||||||
|
|
||||||
|
</docs>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-button type="primary" @click="handleOpen(true)">Begin Tour</a-button>
|
||||||
|
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<a-space>
|
||||||
|
<a-button ref="ref1">Upload</a-button>
|
||||||
|
<a-button ref="ref2" type="primary">Save</a-button>
|
||||||
|
<a-button ref="ref3"><EllipsisOutlined /></a-button>
|
||||||
|
</a-space>
|
||||||
|
|
||||||
|
<a-tour :open="open" :steps="steps" @close="handleOpen(false)">
|
||||||
|
<template #indicatorsRender="{ current, total }">
|
||||||
|
<span>{{ current + 1 }} / {{ total }}</span>
|
||||||
|
</template>
|
||||||
|
</a-tour>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import { EllipsisOutlined } from '@ant-design/icons-vue';
|
||||||
|
import type { TourProps } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
|
||||||
|
const ref1 = ref(null);
|
||||||
|
const ref2 = ref(null);
|
||||||
|
const ref3 = ref(null);
|
||||||
|
|
||||||
|
const steps: TourProps['steps'] = [
|
||||||
|
{
|
||||||
|
title: 'Upload File',
|
||||||
|
description: 'Put your files here.',
|
||||||
|
target: () => ref1.value && ref1.value.$el,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Save',
|
||||||
|
description: 'Save your changes.',
|
||||||
|
target: () => ref2.value && ref2.value.$el,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Other Actions',
|
||||||
|
description: 'Click to see other actions.',
|
||||||
|
target: () => ref3.value && ref3.value.$el,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleOpen = (val: boolean): void => {
|
||||||
|
open.value = val;
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,86 @@
|
||||||
|
<docs>
|
||||||
|
---
|
||||||
|
order: 3
|
||||||
|
title:
|
||||||
|
zh-CN: 自定义遮罩样式
|
||||||
|
en-US: custom mask style
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
自定义遮罩样式。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
custom mask style.
|
||||||
|
|
||||||
|
|
||||||
|
</docs>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-button type="primary" @click="handleOpen(true)">Begin Tour</a-button>
|
||||||
|
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<a-space>
|
||||||
|
<a-button ref="ref1">Upload</a-button>
|
||||||
|
<a-button ref="ref2" type="primary">Save</a-button>
|
||||||
|
<a-button ref="ref3"><EllipsisOutlined /></a-button>
|
||||||
|
</a-space>
|
||||||
|
|
||||||
|
<a-tour
|
||||||
|
:open="open"
|
||||||
|
:steps="steps"
|
||||||
|
:mask="{
|
||||||
|
style: {
|
||||||
|
boxShadow: 'inset 0 0 15px #333',
|
||||||
|
},
|
||||||
|
color: 'rgba(80, 255, 255, .4)',
|
||||||
|
}"
|
||||||
|
@close="handleOpen(false)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, createVNode } from 'vue';
|
||||||
|
import { EllipsisOutlined } from '@ant-design/icons-vue';
|
||||||
|
import type { TourProps } from 'ant-design-vue';
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
|
||||||
|
const ref1 = ref(null);
|
||||||
|
const ref2 = ref(null);
|
||||||
|
const ref3 = ref(null);
|
||||||
|
|
||||||
|
const steps: TourProps['steps'] = [
|
||||||
|
{
|
||||||
|
title: 'Upload File',
|
||||||
|
description: 'Put your files here.',
|
||||||
|
cover: createVNode('img', {
|
||||||
|
alt: 'tour.png',
|
||||||
|
src: 'https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png',
|
||||||
|
}),
|
||||||
|
target: () => ref1.value && ref1.value.$el,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Save',
|
||||||
|
description: 'Save your changes.',
|
||||||
|
target: () => ref2.value && ref2.value.$el,
|
||||||
|
mask: {
|
||||||
|
style: {
|
||||||
|
boxShadow: 'inset 0 0 15px #fff',
|
||||||
|
},
|
||||||
|
color: 'rgba(40, 0, 255, .4)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Other Actions',
|
||||||
|
description: 'Click to see other actions.',
|
||||||
|
target: () => ref3.value && ref3.value.$el,
|
||||||
|
mask: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleOpen = (val: boolean): void => {
|
||||||
|
open.value = val;
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,69 @@
|
||||||
|
<docs>
|
||||||
|
---
|
||||||
|
order: 1
|
||||||
|
title:
|
||||||
|
zh-CN: 非模态
|
||||||
|
en-US: Non modal
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
使用 `mask={false}` 可以将引导变为非模态,同时为了强调引导本身,建议与 `type="primary"` 组合使用。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
Use `mask={false}` to make Tour non-modal. At the meantime it is recommended to use with `type="primary"` to emphasize the guide itself.
|
||||||
|
|
||||||
|
|
||||||
|
</docs>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-button type="primary" @click="handleOpen(true)">Begin Tour</a-button>
|
||||||
|
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<a-space>
|
||||||
|
<a-button ref="ref1">Upload</a-button>
|
||||||
|
<a-button ref="ref2" type="primary">Save</a-button>
|
||||||
|
<a-button ref="ref3"><EllipsisOutlined /></a-button>
|
||||||
|
</a-space>
|
||||||
|
|
||||||
|
<a-tour :open="open" :mask="false" type="primary" :steps="steps" @close="handleOpen(false)" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, createVNode } from 'vue';
|
||||||
|
import { EllipsisOutlined } from '@ant-design/icons-vue';
|
||||||
|
import type { TourProps } from 'ant-design-vue';
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
|
||||||
|
const ref1 = ref(null);
|
||||||
|
const ref2 = ref(null);
|
||||||
|
const ref3 = ref(null);
|
||||||
|
|
||||||
|
const steps: TourProps['steps'] = [
|
||||||
|
{
|
||||||
|
title: 'Upload File',
|
||||||
|
description: 'Put your files here.',
|
||||||
|
cover: createVNode('img', {
|
||||||
|
alt: 'tour.png',
|
||||||
|
src: 'https://user-images.githubusercontent.com/5378891/197385811-55df8480-7ff4-44bd-9d43-a7dade598d70.png',
|
||||||
|
}),
|
||||||
|
target: () => ref1.value && ref1.value.$el,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Save',
|
||||||
|
description: 'Save your changes.',
|
||||||
|
target: () => ref2.value && ref2.value.$el,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Other Actions',
|
||||||
|
description: 'Click to see other actions.',
|
||||||
|
target: () => ref3.value && ref3.value.$el,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleOpen = (val: boolean): void => {
|
||||||
|
open.value = val;
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,57 @@
|
||||||
|
<docs>
|
||||||
|
---
|
||||||
|
order: 2
|
||||||
|
title:
|
||||||
|
zh-CN: 位置
|
||||||
|
en-US: Placement
|
||||||
|
---
|
||||||
|
|
||||||
|
## zh-CN
|
||||||
|
|
||||||
|
改变引导相对于目标的位置,共有 12 种位置可供选择。当 `target={null}` 时引导将会展示在正中央。
|
||||||
|
|
||||||
|
## en-US
|
||||||
|
|
||||||
|
Change the placement of the guide relative to the target, there are 12 placements available. When `target={null}` the guide will show in the center.
|
||||||
|
|
||||||
|
|
||||||
|
</docs>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<a-button ref="btnRef" type="primary" @click="handleOpen(true)">Begin Tour</a-button>
|
||||||
|
|
||||||
|
<a-tour :open="open" :steps="steps" @close="handleOpen(false)" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue';
|
||||||
|
import type { TourProps } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const open = ref<boolean>(false);
|
||||||
|
|
||||||
|
const btnRef = ref(null);
|
||||||
|
|
||||||
|
const steps: TourProps['steps'] = [
|
||||||
|
{
|
||||||
|
title: 'Center',
|
||||||
|
description: 'Displayed in the center of screen.',
|
||||||
|
target: null,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Right',
|
||||||
|
description: 'On the right of target.',
|
||||||
|
placement: 'right',
|
||||||
|
target: () => btnRef.value && btnRef.value.$el,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Top',
|
||||||
|
description: 'On the top of target.',
|
||||||
|
placement: 'top',
|
||||||
|
target: () => btnRef.value && btnRef.value.$el,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleOpen = (val: boolean): void => {
|
||||||
|
open.value = val;
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
category: Components
|
||||||
|
type: Data Display
|
||||||
|
title: Tour
|
||||||
|
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*8CC_Tbe3_e4AAAAAAAAAAAAADrJ8AQ/original
|
||||||
|
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*nF6hQpM0XtEAAAAAAAAAAAAADrJ8AQ/original
|
||||||
|
---
|
||||||
|
|
||||||
|
A popup component for guiding users through a product. Available since `4.0.0`.
|
||||||
|
|
||||||
|
## When To Use
|
||||||
|
|
||||||
|
Use when you want to guide users through a product.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Tour
|
||||||
|
|
||||||
|
| Property | Description | Type | Default | Version |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| arrow | Whether to show the arrow, including the configuration whether to point to the center of the element | `boolean`\|`{ pointAtCenter: boolean}` | `true` | |
|
||||||
|
| placement | Position of the guide card relative to the target element | `left` `leftTop` `leftBottom` `right` `rightTop` `rightBottom` `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | `bottom` | |
|
||||||
|
| mask | Whether to enable masking, change mask style and fill color by pass custom props | `boolean` \| `{ style?: CSSProperties; color?: string; }` | `true` | |
|
||||||
|
| type | Type, affects the background color and text color | `default` `primary` | `default` | |
|
||||||
|
| open | Open tour | `boolean` | - | |
|
||||||
|
| current | What is the current step | `number` | - | |
|
||||||
|
| scrollIntoViewOptions | support pass custom scrollIntoView options | `boolean` \| `ScrollIntoViewOptions` | `true` | |
|
||||||
|
| indicatorsRender | custom indicator | `v-slot:indicatorsRender="{current, total}"` | - | |
|
||||||
|
| zIndex | Tour's zIndex | `number` | `1001` | |
|
||||||
|
|
||||||
|
### Tour events
|
||||||
|
|
||||||
|
| Events Name | Description | Arguments | Version |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| close | Callback function on shutdown | `Function` | - | |
|
||||||
|
| finish | Callback function on finished | `Function` | - | |
|
||||||
|
| change | Callback when the step changes. Current is the previous step | `(current: number) => void` |
|
||||||
|
|
||||||
|
### TourStep
|
||||||
|
|
||||||
|
| Property | Description | Type | Default | Version |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| target | Get the element the guide card points to. Empty makes it show in center of screen | `() => HTMLElement` `HTMLElement` | - | |
|
||||||
|
| arrow | Whether to show the arrow, including the configuration whether to point to the center of the element | `boolean` `{ pointAtCenter: boolean}` | `true` | |
|
||||||
|
| cover | Displayed pictures or videos | `VueNode` | - | |
|
||||||
|
| title | title | `VueNode` | - | |
|
||||||
|
| description | description | `VueNode` | - | |
|
||||||
|
| placement | Position of the guide card relative to the target element | `left` `leftTop` `leftBottom` `right` `rightTop` `rightBottom` `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | `bottom` | |
|
||||||
|
| mask | Whether to enable masking, change mask style and fill color by pass custom props, the default follows the `mask` property of Tour | `boolean` \| `{ style?: CSSProperties; color?: string; }` | `true` | |
|
||||||
|
| type | Type, affects the background color and text color | `default` `primary` | `default` | |
|
||||||
|
| nextButtonProps | Properties of the Next button | `{ children: VueNode; onClick: Function }` | - | |
|
||||||
|
| prevButtonProps | Properties of the previous button | `{ children: VueNode; onClick: Function }` | - | |
|
||||||
|
| scrollIntoViewOptions | support pass custom scrollIntoView options, the default follows the `scrollIntoViewOptions` property of Tour | `boolean` \| `ScrollIntoViewOptions` | `true` | |
|
||||||
|
|
||||||
|
### TourStep events
|
||||||
|
|
||||||
|
| Events Name | Description | Arguments | Version |
|
||||||
|
| ----------- | ----------------------------- | ---------- | ------- | --- |
|
||||||
|
| close | Callback function on shutdown | `Function` | - | |
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { defineComponent, toRefs } from 'vue';
|
||||||
|
import VCTour from '../vc-tour';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
import TourPanel from './panelRender';
|
||||||
|
import type { TourProps, TourStepProps } from './interface';
|
||||||
|
import { tourProps } from './interface';
|
||||||
|
import useConfigInject from '../config-provider/hooks/useConfigInject';
|
||||||
|
import type { VueNode } from '../_util/type';
|
||||||
|
import { withInstall } from '../_util/type';
|
||||||
|
import useMergedType from './useMergedType';
|
||||||
|
|
||||||
|
// CSSINJS
|
||||||
|
import useStyle from './style';
|
||||||
|
|
||||||
|
export { TourProps, TourStepProps };
|
||||||
|
|
||||||
|
const Tour = defineComponent({
|
||||||
|
name: 'ATour',
|
||||||
|
props: tourProps(),
|
||||||
|
setup(props, { attrs, emit, slots }) {
|
||||||
|
const { current } = toRefs(props);
|
||||||
|
const { prefixCls, direction } = useConfigInject('tour', props);
|
||||||
|
|
||||||
|
// style
|
||||||
|
const [wrapSSR, hashId] = useStyle(prefixCls);
|
||||||
|
|
||||||
|
const { currentMergedType, updateInnerCurrent } = useMergedType({
|
||||||
|
defaultType: props.type,
|
||||||
|
steps: props.steps,
|
||||||
|
current,
|
||||||
|
defaultCurrent: props.defaultCurrent,
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const { steps, current, type, rootClassName, ...restProps } = props;
|
||||||
|
|
||||||
|
const customClassName = classNames(
|
||||||
|
{
|
||||||
|
[`${prefixCls.value}-primary`]: currentMergedType.value === 'primary',
|
||||||
|
[`${prefixCls.value}-rtl`]: direction.value === 'rtl',
|
||||||
|
},
|
||||||
|
hashId.value,
|
||||||
|
rootClassName,
|
||||||
|
);
|
||||||
|
|
||||||
|
const mergedRenderPanel = (stepProps: TourStepProps, stepCurrent: number): VueNode => {
|
||||||
|
return (
|
||||||
|
<TourPanel
|
||||||
|
{...stepProps}
|
||||||
|
type={type}
|
||||||
|
current={stepCurrent}
|
||||||
|
v-slots={{
|
||||||
|
indicatorsRender: slots.indicatorsRender,
|
||||||
|
}}
|
||||||
|
></TourPanel>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const onStepChange = (stepCurrent: number) => {
|
||||||
|
updateInnerCurrent(stepCurrent);
|
||||||
|
emit('change', stepCurrent);
|
||||||
|
};
|
||||||
|
|
||||||
|
return wrapSSR(
|
||||||
|
<VCTour
|
||||||
|
{...attrs}
|
||||||
|
{...restProps}
|
||||||
|
rootClassName={customClassName}
|
||||||
|
prefixCls={prefixCls.value}
|
||||||
|
current={current}
|
||||||
|
defaultCurrent={props.defaultCurrent}
|
||||||
|
animated
|
||||||
|
renderPanel={mergedRenderPanel}
|
||||||
|
onChange={onStepChange}
|
||||||
|
steps={steps}
|
||||||
|
/>,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default withInstall(Tour);
|
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
category: Components
|
||||||
|
type: 数据展示
|
||||||
|
title: Tour
|
||||||
|
subtitle: 漫游式引导
|
||||||
|
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*8CC_Tbe3_e4AAAAAAAAAAAAADrJ8AQ/original
|
||||||
|
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*nF6hQpM0XtEAAAAAAAAAAAAADrJ8AQ/original
|
||||||
|
---
|
||||||
|
|
||||||
|
用于分步引导用户了解产品功能的气泡组件。自 `4.0.0` 版本开始提供该组件。
|
||||||
|
|
||||||
|
## 何时使用
|
||||||
|
|
||||||
|
常用于引导用户了解产品功能。
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### Tour
|
||||||
|
|
||||||
|
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| arrow | 是否显示箭头,包含是否指向元素中心的配置 | `boolean` \| `{ pointAtCenter: boolean}` | `true` | |
|
||||||
|
| placement | 引导卡片相对于目标元素的位置 | `left` `leftTop` `leftBottom` `right` `rightTop` `rightBottom` `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` | `bottom` | |
|
||||||
|
| mask | 是否启用蒙层,也可传入配置改变蒙层样式和填充色 | `boolean` \| `{ style?: CSSProperties; color?: string; }` | `true` | |
|
||||||
|
| type | 类型,影响底色与文字颜色 | `default` \| `primary` | `default` | |
|
||||||
|
| open | 打开引导 | `boolean` | - | |
|
||||||
|
| current | 当前处于哪一步 | `number` | - | |
|
||||||
|
| scrollIntoViewOptions | 是否支持当前元素滚动到视窗内,也可传入配置指定滚动视窗的相关参数 | `boolean` \| `ScrollIntoViewOptions` | `true` | |
|
||||||
|
| indicatorsRender | 自定义指示器 | `v-slot:indicatorsRender="{current, total}"` | - | |
|
||||||
|
| zIndex | Tour 的层级 | `number` | `1001` | |
|
||||||
|
|
||||||
|
### Tour events
|
||||||
|
|
||||||
|
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||||
|
| -------- | ---------------------------------------- | --------------------------- | ---- | --- |
|
||||||
|
| close | 关闭引导时的回调函数 | `Function` | - | |
|
||||||
|
| finish | 引导完成时的回调 | `Function` | - | |
|
||||||
|
| change | 步骤改变时的回调,current 为当前前的步骤 | `(current: number) => void` | - | |
|
||||||
|
|
||||||
|
### TourStep 引导步骤卡片
|
||||||
|
|
||||||
|
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
| target | 获取引导卡片指向的元素,为空时居中于屏幕 | `() => HTMLElement` \| `HTMLElement` | - | |
|
||||||
|
| arrow | 是否显示箭头,包含是否指向元素中心的配置 | `boolean` \| `{ pointAtCenter: boolean}` | `true` | |
|
||||||
|
| cover | 展示的图片或者视频 | `VueNode` | - | |
|
||||||
|
| title | 标题 | `VueNode` | - | |
|
||||||
|
| description | 主要描述部分 | `VueNode` | - | |
|
||||||
|
| placement | 引导卡片相对于目标元素的位置 | `left` `leftTop` `leftBottom` `right` `rightTop` `rightBottom` `top` `topLeft` `topRight` `bottom` `bottomLeft` `bottomRight` `bottom` | | |
|
||||||
|
| mask | 是否启用蒙层,也可传入配置改变蒙层样式和填充色,默认跟随 Tour 的 `mask` 属性 | `boolean` \| `{ style?: CSSProperties; color?: string; }` | `true` | |
|
||||||
|
| type | 类型,影响底色与文字颜色 | `default` \| `primary` | `default` | |
|
||||||
|
| nextButtonProps | 下一步按钮的属性 | `{ children: VueNode; onClick: Function }` | - | |
|
||||||
|
| prevButtonProps | 上一步按钮的属性 | `{ children: VueNode; onClick: Function }` | - | |
|
||||||
|
| scrollIntoViewOptions | 是否支持当前元素滚动到视窗内,也可传入配置指定滚动视窗的相关参数,默认跟随 Tour 的 `scrollIntoViewOptions` 属性 | `boolean` \| `ScrollIntoViewOptions` | `true` | |
|
||||||
|
|
||||||
|
### TourStep events
|
||||||
|
|
||||||
|
| 事件名称 | 说明 | 回调参数 | 版本 |
|
||||||
|
| -------- | -------------------- | ---------- | ---- | --- |
|
||||||
|
| close | 关闭引导时的回调函数 | `Function` | - | |
|
|
@ -0,0 +1,41 @@
|
||||||
|
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
|
||||||
|
import { tourProps as VCTourProps, tourStepProps as VCTourStepProps } from '../vc-tour';
|
||||||
|
import type { VueNode } from '../_util/type';
|
||||||
|
|
||||||
|
export const tourProps = () => ({
|
||||||
|
...VCTourProps(),
|
||||||
|
steps: { type: Array as PropType<TourStepProps[]> },
|
||||||
|
prefixCls: { type: String },
|
||||||
|
current: { type: Number },
|
||||||
|
type: { type: String as PropType<'default' | 'primary'> }, // default 类型,影响底色与文字颜色
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TourProps = Partial<ExtractPropTypes<ReturnType<typeof tourProps>>>;
|
||||||
|
|
||||||
|
export interface TourBtnProps {
|
||||||
|
children?: () => VueNode;
|
||||||
|
onClick?: () => void;
|
||||||
|
className?: string;
|
||||||
|
style?: CSSProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const tourStepProps = () => ({
|
||||||
|
...VCTourStepProps(),
|
||||||
|
cover: { type: Object as PropType<VueNode> }, // 展示的图片或者视频
|
||||||
|
nextButtonProps: {
|
||||||
|
type: Object as PropType<TourBtnProps>,
|
||||||
|
},
|
||||||
|
prevButtonProps: {
|
||||||
|
type: Object as PropType<TourBtnProps>,
|
||||||
|
},
|
||||||
|
current: { type: Number },
|
||||||
|
type: { type: String as PropType<'default' | 'primary'> }, // default 类型,影响底色与文字颜色
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TourStepProps = Partial<ExtractPropTypes<ReturnType<typeof tourStepProps>>>;
|
||||||
|
|
||||||
|
export interface TourLocale {
|
||||||
|
Next: string;
|
||||||
|
Previous: string;
|
||||||
|
Finish: string;
|
||||||
|
}
|
|
@ -0,0 +1,154 @@
|
||||||
|
import { computed, defineComponent, toRefs } from 'vue';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
|
||||||
|
import { tourStepProps } from './interface';
|
||||||
|
import type { TourBtnProps } from './interface';
|
||||||
|
|
||||||
|
import LocaleReceiver from '../locale/LocaleReceiver';
|
||||||
|
import Button from '../button';
|
||||||
|
import type { ButtonProps } from '../button';
|
||||||
|
import defaultLocale from '../locale/en_US';
|
||||||
|
|
||||||
|
import type { VueNode } from '../_util/type';
|
||||||
|
|
||||||
|
const panelRender = defineComponent({
|
||||||
|
props: tourStepProps(),
|
||||||
|
setup(props, { attrs, slots }) {
|
||||||
|
const { current, total } = toRefs(props);
|
||||||
|
|
||||||
|
const isLastStep = computed(() => current.value === total.value - 1);
|
||||||
|
|
||||||
|
const prevButtonProps = props.prevButtonProps as TourBtnProps;
|
||||||
|
const nextButtonProps = props.nextButtonProps as TourBtnProps;
|
||||||
|
|
||||||
|
const prevBtnClick = e => {
|
||||||
|
props.onPrev?.(e);
|
||||||
|
if (typeof prevButtonProps?.onClick === 'function') {
|
||||||
|
prevButtonProps?.onClick();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextBtnClick = e => {
|
||||||
|
if (isLastStep.value) {
|
||||||
|
props.onFinish?.(e);
|
||||||
|
} else {
|
||||||
|
props.onNext?.(e);
|
||||||
|
}
|
||||||
|
if (typeof nextButtonProps?.onClick === 'function') {
|
||||||
|
nextButtonProps?.onClick();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
title,
|
||||||
|
onClose,
|
||||||
|
|
||||||
|
cover,
|
||||||
|
description,
|
||||||
|
type: stepType,
|
||||||
|
arrow,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const prevButtonProps = props.prevButtonProps as TourBtnProps;
|
||||||
|
const nextButtonProps = props.nextButtonProps as TourBtnProps;
|
||||||
|
|
||||||
|
let headerNode: VueNode;
|
||||||
|
if (title) {
|
||||||
|
headerNode = (
|
||||||
|
<div class={`${prefixCls}-header`}>
|
||||||
|
<div class={`${prefixCls}-title`}>{title}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let descriptionNode: VueNode;
|
||||||
|
if (description) {
|
||||||
|
descriptionNode = <div class={`${prefixCls}-description`}>{description}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let coverNode: VueNode;
|
||||||
|
if (cover) {
|
||||||
|
coverNode = <div class={`${prefixCls}-cover`}>{cover}</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mergeIndicatorNode: VueNode;
|
||||||
|
|
||||||
|
if (slots.indicatorsRender) {
|
||||||
|
mergeIndicatorNode = slots.indicatorsRender({ current: current.value, total });
|
||||||
|
} else {
|
||||||
|
mergeIndicatorNode = [...Array.from({ length: total.value }).keys()].map(
|
||||||
|
(stepItem, index) => (
|
||||||
|
<span
|
||||||
|
key={stepItem}
|
||||||
|
class={classNames(
|
||||||
|
index === current.value && `${prefixCls}-indicator-active`,
|
||||||
|
`${prefixCls}-indicator`,
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainBtnType = stepType === 'primary' ? 'default' : 'primary';
|
||||||
|
const secondaryBtnProps: ButtonProps = {
|
||||||
|
type: 'default',
|
||||||
|
ghost: stepType === 'primary',
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LocaleReceiver componentName="Tour" defaultLocale={defaultLocale.Tour}>
|
||||||
|
{contextLocale => (
|
||||||
|
<div
|
||||||
|
{...attrs}
|
||||||
|
class={classNames(
|
||||||
|
stepType === 'primary' ? `${prefixCls}-primary` : '',
|
||||||
|
attrs.class,
|
||||||
|
`${prefixCls}-content`,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{arrow && <div class={`${prefixCls}-arrow`} key="arrow" />}
|
||||||
|
<div class={`${prefixCls}-inner`}>
|
||||||
|
<CloseOutlined class={`${prefixCls}-close`} onClick={onClose} />
|
||||||
|
{coverNode}
|
||||||
|
{headerNode}
|
||||||
|
{descriptionNode}
|
||||||
|
<div class={`${prefixCls}-footer`}>
|
||||||
|
{total.value > 1 && (
|
||||||
|
<div class={`${prefixCls}-indicators`}>{mergeIndicatorNode}</div>
|
||||||
|
)}
|
||||||
|
<div class={`${prefixCls}-buttons`}>
|
||||||
|
{current.value !== 0 ? (
|
||||||
|
<Button
|
||||||
|
{...secondaryBtnProps}
|
||||||
|
{...prevButtonProps}
|
||||||
|
onClick={prevBtnClick}
|
||||||
|
size="small"
|
||||||
|
class={classNames(`${prefixCls}-prev-btn`, prevButtonProps?.className)}
|
||||||
|
>
|
||||||
|
{prevButtonProps?.children ?? contextLocale.Previous}
|
||||||
|
</Button>
|
||||||
|
) : null}
|
||||||
|
<Button
|
||||||
|
type={mainBtnType}
|
||||||
|
{...nextButtonProps}
|
||||||
|
onClick={nextBtnClick}
|
||||||
|
size="small"
|
||||||
|
class={classNames(`${prefixCls}-next-btn`, nextButtonProps?.className)}
|
||||||
|
>
|
||||||
|
{nextButtonProps?.children ??
|
||||||
|
(isLastStep.value ? contextLocale.Finish : contextLocale.Next)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</LocaleReceiver>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default panelRender;
|
|
@ -0,0 +1,250 @@
|
||||||
|
import { TinyColor } from '@ctrl/tinycolor';
|
||||||
|
import type { FullToken, GenerateStyle } from '../../theme/internal';
|
||||||
|
import { genComponentStyleHook, mergeToken } from '../../theme/internal';
|
||||||
|
import { resetComponent } from '../../style';
|
||||||
|
import getArrowStyle, { MAX_VERTICAL_CONTENT_RADIUS } from '../../style/placementArrow';
|
||||||
|
|
||||||
|
export interface ComponentToken {}
|
||||||
|
|
||||||
|
interface TourToken extends FullToken<'Tour'> {
|
||||||
|
tourZIndexPopup: number;
|
||||||
|
indicatorWidth: number;
|
||||||
|
indicatorHeight: number;
|
||||||
|
tourBorderRadius: number;
|
||||||
|
tourCloseSize: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================== Base ===============================
|
||||||
|
const genBaseStyle: GenerateStyle<TourToken> = token => {
|
||||||
|
const {
|
||||||
|
componentCls,
|
||||||
|
lineHeight,
|
||||||
|
padding,
|
||||||
|
paddingXS,
|
||||||
|
borderRadius,
|
||||||
|
borderRadiusXS,
|
||||||
|
colorPrimary,
|
||||||
|
colorText,
|
||||||
|
colorFill,
|
||||||
|
indicatorHeight,
|
||||||
|
indicatorWidth,
|
||||||
|
boxShadowTertiary,
|
||||||
|
tourZIndexPopup,
|
||||||
|
fontSize,
|
||||||
|
colorBgContainer,
|
||||||
|
fontWeightStrong,
|
||||||
|
marginXS,
|
||||||
|
colorTextLightSolid,
|
||||||
|
tourBorderRadius,
|
||||||
|
colorWhite,
|
||||||
|
colorBgTextHover,
|
||||||
|
tourCloseSize,
|
||||||
|
motionDurationSlow,
|
||||||
|
antCls,
|
||||||
|
} = token;
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
[componentCls]: {
|
||||||
|
...resetComponent(token),
|
||||||
|
|
||||||
|
color: colorText,
|
||||||
|
position: 'absolute',
|
||||||
|
zIndex: tourZIndexPopup,
|
||||||
|
display: 'block',
|
||||||
|
visibility: 'visible',
|
||||||
|
fontSize,
|
||||||
|
lineHeight,
|
||||||
|
width: 520,
|
||||||
|
'--antd-arrow-background-color': colorBgContainer,
|
||||||
|
|
||||||
|
'&-pure': {
|
||||||
|
maxWidth: '100%',
|
||||||
|
position: 'relative',
|
||||||
|
},
|
||||||
|
|
||||||
|
[`&${componentCls}-hidden`]: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============================= panel content ============================
|
||||||
|
[`${componentCls}-content`]: {
|
||||||
|
position: 'relative',
|
||||||
|
},
|
||||||
|
[`${componentCls}-inner`]: {
|
||||||
|
textAlign: 'start',
|
||||||
|
textDecoration: 'none',
|
||||||
|
borderRadius: tourBorderRadius,
|
||||||
|
boxShadow: boxShadowTertiary,
|
||||||
|
position: 'relative',
|
||||||
|
backgroundColor: colorBgContainer,
|
||||||
|
border: 'none',
|
||||||
|
backgroundClip: 'padding-box',
|
||||||
|
|
||||||
|
[`${componentCls}-close`]: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: padding,
|
||||||
|
insetInlineEnd: padding,
|
||||||
|
color: token.colorIcon,
|
||||||
|
outline: 'none',
|
||||||
|
width: tourCloseSize,
|
||||||
|
height: tourCloseSize,
|
||||||
|
borderRadius: token.borderRadiusSM,
|
||||||
|
transition: `background-color ${token.motionDurationMid}, color ${token.motionDurationMid}`,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
color: token.colorIconHover,
|
||||||
|
backgroundColor: token.wireframe ? 'transparent' : token.colorFillContent,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-cover`]: {
|
||||||
|
textAlign: 'center',
|
||||||
|
padding: `${padding + tourCloseSize + paddingXS}px ${padding}px 0`,
|
||||||
|
img: {
|
||||||
|
width: '100%',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[`${componentCls}-header`]: {
|
||||||
|
padding: `${padding}px ${padding}px ${paddingXS}px`,
|
||||||
|
|
||||||
|
[`${componentCls}-title`]: {
|
||||||
|
lineHeight,
|
||||||
|
fontSize,
|
||||||
|
fontWeight: fontWeightStrong,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-description`]: {
|
||||||
|
padding: `0 ${padding}px`,
|
||||||
|
lineHeight,
|
||||||
|
wordWrap: 'break-word',
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-footer`]: {
|
||||||
|
padding: `${paddingXS}px ${padding}px ${padding}px`,
|
||||||
|
textAlign: 'end',
|
||||||
|
borderRadius: `0 0 ${borderRadiusXS}px ${borderRadiusXS}px`,
|
||||||
|
display: 'flex',
|
||||||
|
[`${componentCls}-indicators`]: {
|
||||||
|
display: 'inline-block',
|
||||||
|
|
||||||
|
[`${componentCls}-indicator`]: {
|
||||||
|
width: indicatorWidth,
|
||||||
|
height: indicatorHeight,
|
||||||
|
display: 'inline-block',
|
||||||
|
borderRadius: '50%',
|
||||||
|
background: colorFill,
|
||||||
|
'&:not(:last-child)': {
|
||||||
|
marginInlineEnd: indicatorHeight,
|
||||||
|
},
|
||||||
|
'&-active': {
|
||||||
|
background: colorPrimary,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[`${componentCls}-buttons`]: {
|
||||||
|
marginInlineStart: 'auto',
|
||||||
|
[`${antCls}-btn`]: {
|
||||||
|
marginInlineStart: marginXS,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============================= primary type ===========================
|
||||||
|
// `$` for panel, `&$` for pure panel
|
||||||
|
[`${componentCls}-primary, &${componentCls}-primary`]: {
|
||||||
|
'--antd-arrow-background-color': colorPrimary,
|
||||||
|
|
||||||
|
[`${componentCls}-inner`]: {
|
||||||
|
color: colorTextLightSolid,
|
||||||
|
textAlign: 'start',
|
||||||
|
textDecoration: 'none',
|
||||||
|
backgroundColor: colorPrimary,
|
||||||
|
borderRadius,
|
||||||
|
boxShadow: boxShadowTertiary,
|
||||||
|
|
||||||
|
[`${componentCls}-close`]: {
|
||||||
|
color: colorTextLightSolid,
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-indicators`]: {
|
||||||
|
[`${componentCls}-indicator`]: {
|
||||||
|
background: new TinyColor(colorTextLightSolid).setAlpha(0.15).toRgbString(),
|
||||||
|
'&-active': {
|
||||||
|
background: colorTextLightSolid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-prev-btn`]: {
|
||||||
|
color: colorTextLightSolid,
|
||||||
|
borderColor: new TinyColor(colorTextLightSolid).setAlpha(0.15).toRgbString(),
|
||||||
|
backgroundColor: colorPrimary,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: new TinyColor(colorTextLightSolid).setAlpha(0.15).toRgbString(),
|
||||||
|
borderColor: 'transparent',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
[`${componentCls}-next-btn`]: {
|
||||||
|
color: colorPrimary,
|
||||||
|
borderColor: 'transparent',
|
||||||
|
background: colorWhite,
|
||||||
|
|
||||||
|
'&:hover': {
|
||||||
|
background: new TinyColor(colorBgTextHover).onBackground(colorWhite).toRgbString(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============================= mask ===========================
|
||||||
|
[`${componentCls}-mask`]: {
|
||||||
|
[`${componentCls}-placeholder-animated`]: {
|
||||||
|
transition: `all ${motionDurationSlow}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// =========== Limit left and right placement radius ==============
|
||||||
|
[[
|
||||||
|
'&-placement-left',
|
||||||
|
'&-placement-leftTop',
|
||||||
|
'&-placement-leftBottom',
|
||||||
|
'&-placement-right',
|
||||||
|
'&-placement-rightTop',
|
||||||
|
'&-placement-rightBottom',
|
||||||
|
].join(',')]: {
|
||||||
|
[`${componentCls}-inner`]: {
|
||||||
|
borderRadius: Math.min(tourBorderRadius, MAX_VERTICAL_CONTENT_RADIUS),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// ============================= Arrow ===========================
|
||||||
|
getArrowStyle<TourToken>(token, {
|
||||||
|
colorBg: 'var(--antd-arrow-background-color)',
|
||||||
|
contentRadius: tourBorderRadius,
|
||||||
|
limitVerticalRadius: true,
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
// ============================== Export ==============================
|
||||||
|
export default genComponentStyleHook('Tour', token => {
|
||||||
|
const { borderRadiusLG, fontSize, lineHeight } = token;
|
||||||
|
const TourToken = mergeToken<TourToken>(token, {
|
||||||
|
tourZIndexPopup: token.zIndexPopupBase + 70,
|
||||||
|
indicatorWidth: 6,
|
||||||
|
indicatorHeight: 6,
|
||||||
|
tourBorderRadius: borderRadiusLG,
|
||||||
|
tourCloseSize: fontSize * lineHeight,
|
||||||
|
});
|
||||||
|
return [genBaseStyle(TourToken)];
|
||||||
|
});
|
|
@ -0,0 +1,35 @@
|
||||||
|
import useMergedState from '../_util/hooks/useMergedState';
|
||||||
|
import type { TourProps } from './interface';
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
import { computed, watch } from 'vue';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
defaultType?: string;
|
||||||
|
steps?: TourProps['steps'];
|
||||||
|
current?: Ref<number>;
|
||||||
|
defaultCurrent?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the merged type of a step or the default type.
|
||||||
|
*/
|
||||||
|
const useMergedType = ({ defaultType, steps = [], current, defaultCurrent }: Props) => {
|
||||||
|
const [innerCurrent, updateInnerCurrent] = useMergedState<number | undefined>(defaultCurrent, {
|
||||||
|
value: current,
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(current, val => {
|
||||||
|
if (val === undefined) return;
|
||||||
|
updateInnerCurrent(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
const innerType = computed(() => {
|
||||||
|
return typeof innerCurrent.value === 'number' ? steps[innerCurrent.value]?.type : defaultType;
|
||||||
|
});
|
||||||
|
|
||||||
|
const currentMergedType = computed(() => innerType.value ?? defaultType);
|
||||||
|
|
||||||
|
return { currentMergedType, updateInnerCurrent };
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useMergedType;
|
|
@ -0,0 +1,130 @@
|
||||||
|
import type { CSSProperties } from 'vue';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
import type { PosInfo } from './hooks/useTarget';
|
||||||
|
import useId from '../_util/hooks/useId';
|
||||||
|
import Portal from '../_util/PortalWrapper';
|
||||||
|
import { someType, objectType, booleanType } from '../_util/type';
|
||||||
|
|
||||||
|
const COVER_PROPS = {
|
||||||
|
fill: 'transparent',
|
||||||
|
pointerEvents: 'auto',
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface MaskProps {
|
||||||
|
prefixCls?: string;
|
||||||
|
pos: PosInfo; // 获取引导卡片指向的元素
|
||||||
|
rootClassName?: string;
|
||||||
|
showMask?: boolean;
|
||||||
|
style?: CSSProperties;
|
||||||
|
fill?: string;
|
||||||
|
open?: boolean;
|
||||||
|
animated?: boolean | { placeholder: boolean };
|
||||||
|
zIndex?: number;
|
||||||
|
}
|
||||||
|
const Mask = defineComponent({
|
||||||
|
name: 'Mask',
|
||||||
|
props: {
|
||||||
|
prefixCls: { type: String },
|
||||||
|
pos: objectType<PosInfo>(), // 获取引导卡片指向的元素
|
||||||
|
rootClassName: { type: String },
|
||||||
|
showMask: booleanType(),
|
||||||
|
fill: { type: String, default: 'rgba(0,0,0,0.5)' },
|
||||||
|
open: booleanType(),
|
||||||
|
animated: someType<boolean | { placeholder: boolean }>([Boolean, Object]),
|
||||||
|
zIndex: { type: Number },
|
||||||
|
},
|
||||||
|
setup(props, { attrs }) {
|
||||||
|
return () => {
|
||||||
|
const { prefixCls, open, rootClassName, pos, showMask, fill, animated, zIndex } = props;
|
||||||
|
|
||||||
|
const id = useId();
|
||||||
|
const maskId = `${prefixCls}-mask-${id}`;
|
||||||
|
const mergedAnimated = typeof animated === 'object' ? animated?.placeholder : animated;
|
||||||
|
|
||||||
|
console.log(open);
|
||||||
|
return (
|
||||||
|
<Portal
|
||||||
|
visible={open}
|
||||||
|
v-slots={{
|
||||||
|
default: () =>
|
||||||
|
open && (
|
||||||
|
<div
|
||||||
|
{...attrs}
|
||||||
|
class={classNames(`${prefixCls}-mask`, rootClassName, attrs.class)}
|
||||||
|
style={[
|
||||||
|
{
|
||||||
|
position: 'fixed',
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
top: 0,
|
||||||
|
bottom: 0,
|
||||||
|
zIndex,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{showMask ? (
|
||||||
|
<svg
|
||||||
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
height: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<defs>
|
||||||
|
<mask id={maskId}>
|
||||||
|
<rect x="0" y="0" width="100vw" height="100vh" fill="white" />
|
||||||
|
{pos && (
|
||||||
|
<rect
|
||||||
|
x={pos.left}
|
||||||
|
y={pos.top}
|
||||||
|
rx={pos.radius}
|
||||||
|
width={pos.width}
|
||||||
|
height={pos.height}
|
||||||
|
fill="black"
|
||||||
|
class={mergedAnimated ? `${prefixCls}-placeholder-animated` : ''}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</mask>
|
||||||
|
</defs>
|
||||||
|
<rect
|
||||||
|
x="0"
|
||||||
|
y="0"
|
||||||
|
width="100%"
|
||||||
|
height="100%"
|
||||||
|
fill={fill}
|
||||||
|
mask={`url(#${maskId})`}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{/* Block click region */}
|
||||||
|
{pos && (
|
||||||
|
<>
|
||||||
|
<rect {...COVER_PROPS} x="0" y="0" width="100%" height={pos.top} />
|
||||||
|
<rect {...COVER_PROPS} x="0" y="0" width={pos.left} height="100%" />
|
||||||
|
<rect
|
||||||
|
{...COVER_PROPS}
|
||||||
|
x="0"
|
||||||
|
y={pos.top + pos.height}
|
||||||
|
width="100%"
|
||||||
|
height={`calc(100vh - ${pos.top + pos.height}px)`}
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
{...COVER_PROPS}
|
||||||
|
x={pos.left + pos.width}
|
||||||
|
y="0"
|
||||||
|
width={`calc(100vw - ${pos.left + pos.width}px)`}
|
||||||
|
height="100%"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</svg>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Mask;
|
|
@ -0,0 +1,243 @@
|
||||||
|
import { ref, computed, watch, watchEffect, defineComponent, toRefs, shallowRef } from 'vue';
|
||||||
|
import type { CSSProperties, ExtractPropTypes } from 'vue';
|
||||||
|
import type { VueNode } from '../_util/type';
|
||||||
|
import Trigger, { triggerProps } from '../vc-trigger';
|
||||||
|
import classNames from '../_util/classNames';
|
||||||
|
import useMergedState from '../_util/hooks/useMergedState';
|
||||||
|
import useTarget from './hooks/useTarget';
|
||||||
|
import type { Gap } from './hooks/useTarget';
|
||||||
|
import TourStep from './TourStep';
|
||||||
|
import type { TourStepInfo, TourStepProps } from './interface';
|
||||||
|
import Mask from './Mask';
|
||||||
|
import { getPlacements } from './placements';
|
||||||
|
import type { PlacementType } from './placements';
|
||||||
|
import { initDefaultProps } from '../_util/props-util';
|
||||||
|
import useScrollLocker from './hooks/useScrollLocker';
|
||||||
|
import canUseDom from '../_util/canUseDom';
|
||||||
|
import {
|
||||||
|
someType,
|
||||||
|
stringType,
|
||||||
|
arrayType,
|
||||||
|
objectType,
|
||||||
|
functionType,
|
||||||
|
booleanType,
|
||||||
|
} from '../_util/type';
|
||||||
|
|
||||||
|
const CENTER_PLACEHOLDER: CSSProperties = {
|
||||||
|
left: '50%',
|
||||||
|
top: '50%',
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const tourProps = () => {
|
||||||
|
const { builtinPlacements, ...pickedTriggerProps } = triggerProps();
|
||||||
|
return {
|
||||||
|
...pickedTriggerProps,
|
||||||
|
steps: arrayType<TourStepInfo[]>(),
|
||||||
|
open: booleanType(),
|
||||||
|
defaultCurrent: { type: Number },
|
||||||
|
current: { type: Number },
|
||||||
|
onChange: functionType<(current: number) => void>(),
|
||||||
|
onClose: functionType<(current: number) => void>(),
|
||||||
|
onFinish: functionType<() => void>(),
|
||||||
|
mask: someType<boolean | { style?: CSSProperties; color?: string }>([Boolean, Object], true),
|
||||||
|
arrow: someType<boolean | { pointAtCenter: boolean }>([Boolean, Object], true),
|
||||||
|
rootClassName: { type: String },
|
||||||
|
placement: stringType<PlacementType>('bottom'),
|
||||||
|
prefixCls: { type: String, default: 'rc-tour' },
|
||||||
|
renderPanel: functionType<(props: TourStepProps, current: number) => VueNode>(),
|
||||||
|
gap: objectType<Gap>(),
|
||||||
|
animated: someType<boolean | { placeholder: boolean }>([Boolean, Object]),
|
||||||
|
scrollIntoViewOptions: someType<boolean | ScrollIntoViewOptions>([Boolean, Object], true),
|
||||||
|
zIndex: { type: Number, default: 1001 },
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TourProps = Partial<ExtractPropTypes<ReturnType<typeof tourProps>>>;
|
||||||
|
|
||||||
|
const Tour = defineComponent({
|
||||||
|
name: 'Tour',
|
||||||
|
props: initDefaultProps(tourProps(), {}),
|
||||||
|
setup(props) {
|
||||||
|
const { defaultCurrent, placement, mask, scrollIntoViewOptions, open, gap, arrow } =
|
||||||
|
toRefs(props);
|
||||||
|
|
||||||
|
const triggerRef = ref();
|
||||||
|
|
||||||
|
const [mergedCurrent, setMergedCurrent] = useMergedState(0, {
|
||||||
|
value: computed(() => props.current),
|
||||||
|
defaultValue: defaultCurrent.value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [mergedOpen, setMergedOpen] = useMergedState(undefined, {
|
||||||
|
value: computed(() => props.open),
|
||||||
|
postState: origin =>
|
||||||
|
mergedCurrent.value < 0 || mergedCurrent.value >= props.steps.length
|
||||||
|
? false
|
||||||
|
: origin ?? true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const openRef = shallowRef(mergedOpen.value);
|
||||||
|
watchEffect(() => {
|
||||||
|
if (mergedOpen.value && !openRef.value) {
|
||||||
|
setMergedCurrent(0);
|
||||||
|
}
|
||||||
|
openRef.value = mergedOpen.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const curStep = computed(() => (props.steps[mergedCurrent.value] || {}) as TourStepInfo);
|
||||||
|
|
||||||
|
const mergedPlacement = computed(() => curStep.value.placement ?? placement.value);
|
||||||
|
const mergedMask = computed(() => mergedOpen.value && (curStep.value.mask ?? mask.value));
|
||||||
|
const mergedScrollIntoViewOptions = computed(
|
||||||
|
() => curStep.value.scrollIntoViewOptions ?? scrollIntoViewOptions.value,
|
||||||
|
);
|
||||||
|
const [posInfo, targetElement] = useTarget(
|
||||||
|
computed(() => curStep.value.target),
|
||||||
|
open,
|
||||||
|
gap,
|
||||||
|
mergedScrollIntoViewOptions,
|
||||||
|
);
|
||||||
|
|
||||||
|
// ========================= arrow =========================
|
||||||
|
const mergedArrow = computed(() =>
|
||||||
|
targetElement.value
|
||||||
|
? typeof curStep.value.arrow === 'undefined'
|
||||||
|
? arrow.value
|
||||||
|
: curStep.value.arrow
|
||||||
|
: false,
|
||||||
|
);
|
||||||
|
const arrowPointAtCenter = computed(() =>
|
||||||
|
typeof mergedArrow.value === 'object' ? mergedArrow.value.pointAtCenter : false,
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(arrowPointAtCenter, () => {
|
||||||
|
triggerRef.value?.forcePopupAlign();
|
||||||
|
});
|
||||||
|
watch(mergedCurrent, () => {
|
||||||
|
triggerRef.value?.forcePopupAlign();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========================= Change =========================
|
||||||
|
const onInternalChange = (nextCurrent: number) => {
|
||||||
|
setMergedCurrent(nextCurrent);
|
||||||
|
props.onChange?.(nextCurrent);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ========================= lock scroll =========================
|
||||||
|
const lockScroll = computed(() => mergedOpen.value && canUseDom());
|
||||||
|
|
||||||
|
useScrollLocker(lockScroll);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const {
|
||||||
|
prefixCls,
|
||||||
|
steps,
|
||||||
|
onClose,
|
||||||
|
onFinish,
|
||||||
|
rootClassName,
|
||||||
|
renderPanel,
|
||||||
|
animated,
|
||||||
|
zIndex,
|
||||||
|
...restProps
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
// ========================= Render =========================
|
||||||
|
// Skip if not init yet
|
||||||
|
if (targetElement.value === undefined) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setMergedOpen(false);
|
||||||
|
onClose?.(mergedCurrent.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mergedShowMask =
|
||||||
|
typeof mergedMask.value === 'boolean' ? mergedMask.value : !!mergedMask.value;
|
||||||
|
const mergedMaskStyle = typeof mergedMask.value === 'boolean' ? undefined : mergedMask.value;
|
||||||
|
|
||||||
|
// when targetElement is not exist, use body as triggerDOMNode
|
||||||
|
const getTriggerDOMNode = () => {
|
||||||
|
return targetElement.value || document.body;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPopupElement = () => (
|
||||||
|
<TourStep
|
||||||
|
arrow={mergedArrow.value}
|
||||||
|
key="content"
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
total={steps.length}
|
||||||
|
renderPanel={renderPanel}
|
||||||
|
onPrev={() => {
|
||||||
|
onInternalChange(mergedCurrent.value - 1);
|
||||||
|
}}
|
||||||
|
onNext={() => {
|
||||||
|
onInternalChange(mergedCurrent.value + 1);
|
||||||
|
}}
|
||||||
|
onClose={handleClose}
|
||||||
|
current={mergedCurrent.value}
|
||||||
|
onFinish={() => {
|
||||||
|
handleClose();
|
||||||
|
onFinish?.();
|
||||||
|
}}
|
||||||
|
{...curStep.value}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Mask
|
||||||
|
zIndex={zIndex}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
pos={posInfo.value}
|
||||||
|
showMask={mergedShowMask}
|
||||||
|
style={mergedMaskStyle?.style}
|
||||||
|
fill={mergedMaskStyle?.color}
|
||||||
|
open={mergedOpen.value}
|
||||||
|
animated={animated}
|
||||||
|
rootClassName={rootClassName}
|
||||||
|
/>
|
||||||
|
<Trigger
|
||||||
|
builtinPlacements={getPlacements(arrowPointAtCenter.value)}
|
||||||
|
{...restProps}
|
||||||
|
ref={triggerRef}
|
||||||
|
popupStyle={
|
||||||
|
!curStep.value.target
|
||||||
|
? {
|
||||||
|
...curStep.value.style,
|
||||||
|
position: 'fixed',
|
||||||
|
left: CENTER_PLACEHOLDER.left,
|
||||||
|
top: CENTER_PLACEHOLDER.top,
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
}
|
||||||
|
: curStep.value.style
|
||||||
|
}
|
||||||
|
popupPlacement={!curStep.value.target ? 'center' : mergedPlacement.value}
|
||||||
|
popupVisible={mergedOpen.value}
|
||||||
|
popupClassName={classNames(rootClassName, curStep.value.className)}
|
||||||
|
prefixCls={prefixCls}
|
||||||
|
popup={getPopupElement}
|
||||||
|
forceRender={false}
|
||||||
|
destroyPopupOnHide
|
||||||
|
zIndex={zIndex}
|
||||||
|
mask={false}
|
||||||
|
getTriggerDOMNode={getTriggerDOMNode}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class={classNames(rootClassName, `${prefixCls}-target-placeholder`)}
|
||||||
|
style={{
|
||||||
|
...(posInfo.value || CENTER_PLACEHOLDER),
|
||||||
|
position: 'fixed',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Trigger>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Tour;
|
|
@ -0,0 +1,55 @@
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import classNames from '../../_util/classNames';
|
||||||
|
import { tourStepProps } from '../interface';
|
||||||
|
import type { TourStepProps } from '../interface';
|
||||||
|
|
||||||
|
const DefaultPanel = defineComponent({
|
||||||
|
name: 'DefaultPanel',
|
||||||
|
props: tourStepProps(),
|
||||||
|
setup(props, { attrs }) {
|
||||||
|
return () => {
|
||||||
|
const { prefixCls, current, total, title, description, onClose, onPrev, onNext, onFinish } =
|
||||||
|
props as TourStepProps;
|
||||||
|
return (
|
||||||
|
<div {...attrs} class={classNames(`${prefixCls}-content`, attrs.class)}>
|
||||||
|
<div class={`${prefixCls}-inner`}>
|
||||||
|
<button type="button" onClick={onClose} aria-label="Close" class={`${prefixCls}-close`}>
|
||||||
|
<span class={`${prefixCls}-close-x`}>×</span>
|
||||||
|
</button>
|
||||||
|
<div class={`${prefixCls}-header`}>
|
||||||
|
<div class={`${prefixCls}-title`}>{title}</div>
|
||||||
|
</div>
|
||||||
|
<div class={`${prefixCls}-description`}>{description}</div>
|
||||||
|
<div class={`${prefixCls}-footer`}>
|
||||||
|
<div class={`${prefixCls}-sliders`}>
|
||||||
|
{total > 1
|
||||||
|
? [...Array.from({ length: total }).keys()].map((item, index) => {
|
||||||
|
return <span key={item} class={index === current ? 'active' : ''} />;
|
||||||
|
})
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
<div class={`${prefixCls}-buttons`}>
|
||||||
|
{current !== 0 ? (
|
||||||
|
<button class={`${prefixCls}-prev-btn`} onClick={onPrev}>
|
||||||
|
Prev
|
||||||
|
</button>
|
||||||
|
) : null}
|
||||||
|
{current === total - 1 ? (
|
||||||
|
<button class={`${prefixCls}-finish-btn`} onClick={onFinish}>
|
||||||
|
Finish
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<button class={`${prefixCls}-next-btn`} onClick={onNext}>
|
||||||
|
Next
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default DefaultPanel;
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import DefaultPanel from './DefaultPanel';
|
||||||
|
import { tourStepProps } from '../interface';
|
||||||
|
|
||||||
|
const TourStep = defineComponent({
|
||||||
|
name: 'TourStep',
|
||||||
|
props: tourStepProps(),
|
||||||
|
setup(props, { attrs }) {
|
||||||
|
return () => {
|
||||||
|
const { current, renderPanel } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{typeof renderPanel === 'function' ? (
|
||||||
|
renderPanel({ ...attrs, ...props }, current)
|
||||||
|
) : (
|
||||||
|
<DefaultPanel {...attrs} {...props} />
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default TourStep;
|
|
@ -0,0 +1,44 @@
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
import { computed, watchEffect } from 'vue';
|
||||||
|
import { updateCSS, removeCSS } from '../../vc-util/Dom/dynamicCSS';
|
||||||
|
import getScrollBarSize from '../../_util/getScrollBarSize';
|
||||||
|
|
||||||
|
const UNIQUE_ID = `vc-util-locker-${Date.now()}`;
|
||||||
|
|
||||||
|
let uuid = 0;
|
||||||
|
|
||||||
|
/**../vc-util/Dom/dynam
|
||||||
|
* Test usage export. Do not use in your production
|
||||||
|
*/
|
||||||
|
export function isBodyOverflowing() {
|
||||||
|
return (
|
||||||
|
document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight) &&
|
||||||
|
window.innerWidth > document.body.offsetWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useScrollLocker(lock?: Ref<boolean>) {
|
||||||
|
const mergedLock = computed(() => !!lock && !!lock.value);
|
||||||
|
const id = computed(() => {
|
||||||
|
uuid += 1;
|
||||||
|
return `${UNIQUE_ID}_${uuid}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
if (mergedLock.value) {
|
||||||
|
const scrollbarSize = getScrollBarSize();
|
||||||
|
const isOverflow = isBodyOverflowing();
|
||||||
|
|
||||||
|
updateCSS(
|
||||||
|
`
|
||||||
|
html body {
|
||||||
|
overflow-y: hidden;
|
||||||
|
${isOverflow ? `width: calc(100% - ${scrollbarSize}px);` : ''}
|
||||||
|
}`,
|
||||||
|
id.value,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
removeCSS(id.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
import { computed, watchEffect, watch } from 'vue';
|
||||||
|
import type { Ref } from 'vue';
|
||||||
|
import { isInViewPort } from '../util';
|
||||||
|
import type { TourStepInfo } from '..';
|
||||||
|
|
||||||
|
import useState from '../../_util/hooks/useState';
|
||||||
|
|
||||||
|
export interface Gap {
|
||||||
|
offset?: number;
|
||||||
|
radius?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PosInfo {
|
||||||
|
left: number;
|
||||||
|
top: number;
|
||||||
|
height: number;
|
||||||
|
width: number;
|
||||||
|
radius: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function useTarget(
|
||||||
|
target: Ref<TourStepInfo['target']>,
|
||||||
|
open: Ref<boolean>,
|
||||||
|
gap?: Ref<Gap>,
|
||||||
|
scrollIntoViewOptions?: Ref<boolean | ScrollIntoViewOptions>,
|
||||||
|
): [Ref<PosInfo>, Ref<HTMLElement>] {
|
||||||
|
// ========================= Target =========================
|
||||||
|
// We trade `undefined` as not get target by function yet.
|
||||||
|
// `null` as empty target.
|
||||||
|
const [targetElement, setTargetElement] = useState<null | HTMLElement | undefined>(undefined);
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
const nextElement = typeof target.value === 'function' ? (target.value as any)() : target.value;
|
||||||
|
|
||||||
|
setTargetElement(nextElement || null);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ========================= Align ==========================
|
||||||
|
const [posInfo, setPosInfo] = useState<PosInfo>(null);
|
||||||
|
|
||||||
|
const updatePos = () => {
|
||||||
|
if (targetElement.value) {
|
||||||
|
// Exist target element. We should scroll and get target position
|
||||||
|
if (!isInViewPort(targetElement.value) && open.value) {
|
||||||
|
targetElement.value.scrollIntoView(scrollIntoViewOptions.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { left, top, width, height } = targetElement.value.getBoundingClientRect();
|
||||||
|
const nextPosInfo: PosInfo = { left, top, width, height, radius: 0 };
|
||||||
|
|
||||||
|
setPosInfo(nextPosInfo);
|
||||||
|
} else {
|
||||||
|
// Not exist target which means we just show in center
|
||||||
|
setPosInfo(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
updatePos();
|
||||||
|
// update when window resize
|
||||||
|
window.addEventListener('resize', updatePos);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', updatePos);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
open,
|
||||||
|
val => {
|
||||||
|
updatePos();
|
||||||
|
// update when window resize
|
||||||
|
if (val) {
|
||||||
|
window.addEventListener('resize', updatePos);
|
||||||
|
} else {
|
||||||
|
window.removeEventListener('resize', updatePos);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
// ======================== PosInfo =========================
|
||||||
|
const mergedPosInfo = computed(() => {
|
||||||
|
if (!posInfo.value) {
|
||||||
|
return posInfo.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gapOffset = gap.value?.offset || 6;
|
||||||
|
const gapRadius = gap.value?.radius || 2;
|
||||||
|
|
||||||
|
return {
|
||||||
|
left: posInfo.value.left - gapOffset,
|
||||||
|
top: posInfo.value.top - gapOffset,
|
||||||
|
width: posInfo.value.width + gapOffset * 2,
|
||||||
|
height: posInfo.value.height + gapOffset * 2,
|
||||||
|
radius: gapRadius,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return [mergedPosInfo, targetElement];
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
import Tour from './Tour';
|
||||||
|
export type { TourProps } from './Tour';
|
||||||
|
export { tourProps } from './Tour';
|
||||||
|
export type { TourStepInfo, TourStepProps } from './interface';
|
||||||
|
export { tourStepInfo, tourStepProps } from './interface';
|
||||||
|
export default Tour;
|
|
@ -0,0 +1,36 @@
|
||||||
|
import type { ExtractPropTypes, CSSProperties } from 'vue';
|
||||||
|
import type { PlacementType } from './placements';
|
||||||
|
import type { VueNode } from '../_util/type';
|
||||||
|
import { someType, stringType, objectType, functionType } from '../_util/type';
|
||||||
|
|
||||||
|
export const tourStepInfo = () => ({
|
||||||
|
arrow: someType<boolean | { pointAtCenter: boolean }>([Boolean, Object]),
|
||||||
|
target: someType<HTMLElement | (() => HTMLElement) | null | (() => null)>([
|
||||||
|
String,
|
||||||
|
Function,
|
||||||
|
Object,
|
||||||
|
]),
|
||||||
|
title: someType<string | VueNode>([String, Object]),
|
||||||
|
description: someType<string | VueNode>([String, Object]),
|
||||||
|
placement: stringType<PlacementType>(),
|
||||||
|
mask: someType<boolean | { style?: CSSProperties; color?: string }>([Object, Boolean], true),
|
||||||
|
className: { type: String },
|
||||||
|
style: objectType<CSSProperties>(),
|
||||||
|
scrollIntoViewOptions: someType<boolean | ScrollIntoViewOptions>([Boolean, Object]),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TourStepInfo = Partial<ExtractPropTypes<ReturnType<typeof tourStepInfo>>>;
|
||||||
|
|
||||||
|
export const tourStepProps = () => ({
|
||||||
|
...tourStepInfo(),
|
||||||
|
prefixCls: { type: String },
|
||||||
|
total: { type: Number },
|
||||||
|
current: { type: Number },
|
||||||
|
onClose: functionType<(e: MouseEvent) => void>(),
|
||||||
|
onFinish: functionType<(e: MouseEvent) => void>(),
|
||||||
|
renderPanel: functionType<(step: any, current: number) => VueNode>(),
|
||||||
|
onPrev: functionType<(e: MouseEvent) => void>(),
|
||||||
|
onNext: functionType<(e: MouseEvent) => void>(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TourStepProps = Partial<ExtractPropTypes<ReturnType<typeof tourStepProps>>>;
|
|
@ -0,0 +1,135 @@
|
||||||
|
export type PlacementType =
|
||||||
|
| 'left'
|
||||||
|
| 'leftTop'
|
||||||
|
| 'leftBottom'
|
||||||
|
| 'right'
|
||||||
|
| 'rightTop'
|
||||||
|
| 'rightBottom'
|
||||||
|
| 'top'
|
||||||
|
| 'topLeft'
|
||||||
|
| 'topRight'
|
||||||
|
| 'bottom'
|
||||||
|
| 'bottomLeft'
|
||||||
|
| 'bottomRight'
|
||||||
|
| 'center';
|
||||||
|
|
||||||
|
const targetOffset = [0, 0];
|
||||||
|
|
||||||
|
export type AlignPointTopBottom = 't' | 'b' | 'c';
|
||||||
|
export type AlignPointLeftRight = 'l' | 'r' | 'c';
|
||||||
|
|
||||||
|
/** Two char of 't' 'b' 'c' 'l' 'r'. Example: 'lt' */
|
||||||
|
export type AlignPoint = `${AlignPointTopBottom}${AlignPointLeftRight}`;
|
||||||
|
|
||||||
|
export interface AlignType {
|
||||||
|
/**
|
||||||
|
* move point of source node to align with point of target node.
|
||||||
|
* Such as ['tr','cc'], align top right point of source node with center point of target node.
|
||||||
|
* Point can be 't'(top), 'b'(bottom), 'c'(center), 'l'(left), 'r'(right) */
|
||||||
|
points?: (string | AlignPoint)[];
|
||||||
|
/**
|
||||||
|
* offset source node by offset[0] in x and offset[1] in y.
|
||||||
|
* If offset contains percentage string value, it is relative to sourceNode region.
|
||||||
|
*/
|
||||||
|
offset?: number[];
|
||||||
|
/**
|
||||||
|
* offset target node by offset[0] in x and offset[1] in y.
|
||||||
|
* If targetOffset contains percentage string value, it is relative to targetNode region.
|
||||||
|
*/
|
||||||
|
targetOffset?: number[];
|
||||||
|
/**
|
||||||
|
* If adjustX field is true, will adjust source node in x direction if source node is invisible.
|
||||||
|
* If adjustY field is true, will adjust source node in y direction if source node is invisible.
|
||||||
|
*/
|
||||||
|
overflow?: {
|
||||||
|
adjustX?: boolean | number;
|
||||||
|
adjustY?: boolean | number;
|
||||||
|
shiftX?: boolean | number;
|
||||||
|
shiftY?: boolean | number;
|
||||||
|
};
|
||||||
|
/** Auto adjust arrow position */
|
||||||
|
autoArrow?: boolean;
|
||||||
|
/**
|
||||||
|
* Config visible region check of html node. Default `visible`:
|
||||||
|
* - `visible`: The visible region of user browser window. Use `clientHeight` for check.
|
||||||
|
* - `scroll`: The whole region of the html scroll area. Use `scrollHeight` for check.
|
||||||
|
*/
|
||||||
|
htmlRegion?: 'visible' | 'scroll';
|
||||||
|
/**
|
||||||
|
* Whether use css right instead of left to position
|
||||||
|
*/
|
||||||
|
useCssRight?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether use css bottom instead of top to position
|
||||||
|
*/
|
||||||
|
useCssBottom?: boolean;
|
||||||
|
/**
|
||||||
|
* Whether use css transform instead of left/top/right/bottom to position if browser supports.
|
||||||
|
* Defaults to false.
|
||||||
|
*/
|
||||||
|
useCssTransform?: boolean;
|
||||||
|
ignoreShake?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BuildInPlacements = Record<string, AlignType>;
|
||||||
|
|
||||||
|
const basePlacements: BuildInPlacements = {
|
||||||
|
left: {
|
||||||
|
points: ['cr', 'cl'],
|
||||||
|
offset: [-8, 0],
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
points: ['cl', 'cr'],
|
||||||
|
offset: [8, 0],
|
||||||
|
},
|
||||||
|
top: {
|
||||||
|
points: ['bc', 'tc'],
|
||||||
|
offset: [0, -8],
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
points: ['tc', 'bc'],
|
||||||
|
offset: [0, 8],
|
||||||
|
},
|
||||||
|
topLeft: {
|
||||||
|
points: ['bl', 'tl'],
|
||||||
|
offset: [0, -8],
|
||||||
|
},
|
||||||
|
leftTop: {
|
||||||
|
points: ['tr', 'tl'],
|
||||||
|
offset: [-8, 0],
|
||||||
|
},
|
||||||
|
topRight: {
|
||||||
|
points: ['br', 'tr'],
|
||||||
|
offset: [0, -8],
|
||||||
|
},
|
||||||
|
rightTop: {
|
||||||
|
points: ['tl', 'tr'],
|
||||||
|
offset: [8, 0],
|
||||||
|
},
|
||||||
|
bottomRight: {
|
||||||
|
points: ['tr', 'br'],
|
||||||
|
offset: [0, 8],
|
||||||
|
},
|
||||||
|
rightBottom: {
|
||||||
|
points: ['bl', 'br'],
|
||||||
|
offset: [8, 0],
|
||||||
|
},
|
||||||
|
bottomLeft: {
|
||||||
|
points: ['tl', 'bl'],
|
||||||
|
offset: [0, 8],
|
||||||
|
},
|
||||||
|
leftBottom: {
|
||||||
|
points: ['br', 'bl'],
|
||||||
|
offset: [-8, 0],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export function getPlacements(arrowPointAtCenter = false) {
|
||||||
|
const placements: BuildInPlacements = {};
|
||||||
|
Object.keys(basePlacements).forEach(key => {
|
||||||
|
placements[key] = { ...basePlacements[key], autoArrow: arrowPointAtCenter, targetOffset };
|
||||||
|
});
|
||||||
|
return placements;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const placements = getPlacements();
|
|
@ -0,0 +1,7 @@
|
||||||
|
export function isInViewPort(element: HTMLElement) {
|
||||||
|
const viewWidth = window.innerWidth || document.documentElement.clientWidth;
|
||||||
|
const viewHeight = window.innerHeight || document.documentElement.clientHeight;
|
||||||
|
const { top, right, bottom, left } = element.getBoundingClientRect();
|
||||||
|
|
||||||
|
return top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight;
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import type { CSSProperties, HTMLAttributes, PropType } from 'vue';
|
import type { HTMLAttributes } from 'vue';
|
||||||
import { computed, defineComponent, inject, provide, shallowRef } from 'vue';
|
import { computed, defineComponent, inject, provide, shallowRef } from 'vue';
|
||||||
import PropTypes from '../_util/vue-types';
|
import { triggerProps, noop } from './interface';
|
||||||
import contains from '../vc-util/Dom/contains';
|
import contains from '../vc-util/Dom/contains';
|
||||||
import raf from '../_util/raf';
|
import raf from '../_util/raf';
|
||||||
import {
|
import {
|
||||||
|
@ -21,17 +21,6 @@ import { cloneElement } from '../_util/vnode';
|
||||||
import supportsPassive from '../_util/supportsPassive';
|
import supportsPassive from '../_util/supportsPassive';
|
||||||
import { useInjectTrigger, useProvidePortal } from './context';
|
import { useInjectTrigger, useProvidePortal } from './context';
|
||||||
|
|
||||||
function noop() {}
|
|
||||||
function returnEmptyString() {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
function returnDocument(element) {
|
|
||||||
if (element) {
|
|
||||||
return element.ownerDocument;
|
|
||||||
}
|
|
||||||
return window.document;
|
|
||||||
}
|
|
||||||
const ALL_HANDLERS = [
|
const ALL_HANDLERS = [
|
||||||
'onClick',
|
'onClick',
|
||||||
'onMousedown',
|
'onMousedown',
|
||||||
|
@ -47,46 +36,7 @@ export default defineComponent({
|
||||||
name: 'Trigger',
|
name: 'Trigger',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
props: {
|
props: triggerProps(),
|
||||||
action: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).def([]),
|
|
||||||
showAction: PropTypes.any.def([]),
|
|
||||||
hideAction: PropTypes.any.def([]),
|
|
||||||
getPopupClassNameFromAlign: PropTypes.any.def(returnEmptyString),
|
|
||||||
onPopupVisibleChange: Function as PropType<(open: boolean) => void>,
|
|
||||||
afterPopupVisibleChange: PropTypes.func.def(noop),
|
|
||||||
popup: PropTypes.any,
|
|
||||||
popupStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
|
||||||
prefixCls: PropTypes.string.def('rc-trigger-popup'),
|
|
||||||
popupClassName: PropTypes.string.def(''),
|
|
||||||
popupPlacement: String,
|
|
||||||
builtinPlacements: PropTypes.object,
|
|
||||||
popupTransitionName: String,
|
|
||||||
popupAnimation: PropTypes.any,
|
|
||||||
mouseEnterDelay: PropTypes.number.def(0),
|
|
||||||
mouseLeaveDelay: PropTypes.number.def(0.1),
|
|
||||||
zIndex: Number,
|
|
||||||
focusDelay: PropTypes.number.def(0),
|
|
||||||
blurDelay: PropTypes.number.def(0.15),
|
|
||||||
getPopupContainer: Function,
|
|
||||||
getDocument: PropTypes.func.def(returnDocument),
|
|
||||||
forceRender: { type: Boolean, default: undefined },
|
|
||||||
destroyPopupOnHide: { type: Boolean, default: false },
|
|
||||||
mask: { type: Boolean, default: false },
|
|
||||||
maskClosable: { type: Boolean, default: true },
|
|
||||||
// onPopupAlign: PropTypes.func.def(noop),
|
|
||||||
popupAlign: PropTypes.object.def(() => ({})),
|
|
||||||
popupVisible: { type: Boolean, default: undefined },
|
|
||||||
defaultPopupVisible: { type: Boolean, default: false },
|
|
||||||
maskTransitionName: String,
|
|
||||||
maskAnimation: String,
|
|
||||||
stretch: String,
|
|
||||||
alignPoint: { type: Boolean, default: undefined }, // Maybe we can support user pass position in the future
|
|
||||||
autoDestroy: { type: Boolean, default: false },
|
|
||||||
mobile: Object,
|
|
||||||
getTriggerDOMNode: Function as PropType<(d?: HTMLElement) => HTMLElement>,
|
|
||||||
// portal context will change
|
|
||||||
tryPopPortal: Boolean, // no need reactive
|
|
||||||
},
|
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const align = computed(() => {
|
const align = computed(() => {
|
||||||
const { popupPlacement, popupAlign, builtinPlacements } = props;
|
const { popupPlacement, popupAlign, builtinPlacements } = props;
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
// based on rc-trigger 5.2.10
|
// based on rc-trigger 5.2.10
|
||||||
import Trigger from './Trigger';
|
import Trigger from './Trigger';
|
||||||
|
import { triggerProps } from './interface';
|
||||||
|
import type { TriggerProps } from './interface';
|
||||||
|
|
||||||
|
export { triggerProps };
|
||||||
|
export type { TriggerProps };
|
||||||
export default Trigger;
|
export default Trigger;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import type { CSSProperties, TransitionProps } from 'vue';
|
import type { CSSProperties, ExtractPropTypes, TransitionProps, PropType } from 'vue';
|
||||||
import type { VueNode } from '../_util/type';
|
import type { VueNode } from '../_util/type';
|
||||||
|
import PropTypes from '../_util/vue-types';
|
||||||
|
|
||||||
/** Two char of 't' 'b' 'c' 'l' 'r'. Example: 'lt' */
|
/** Two char of 't' 'b' 'c' 'l' 'r'. Example: 'lt' */
|
||||||
export type AlignPoint = string;
|
export type AlignPoint = string;
|
||||||
|
@ -70,3 +71,59 @@ export interface MobileConfig {
|
||||||
popupStyle?: CSSProperties;
|
popupStyle?: CSSProperties;
|
||||||
popupRender?: (originNode: VueNode) => VueNode;
|
popupRender?: (originNode: VueNode) => VueNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function returnEmptyString() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function returnDocument(element) {
|
||||||
|
if (element) {
|
||||||
|
return element.ownerDocument;
|
||||||
|
}
|
||||||
|
return window.document;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function noop() {}
|
||||||
|
|
||||||
|
export const triggerProps = () => ({
|
||||||
|
action: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]).def([]),
|
||||||
|
showAction: PropTypes.any.def([]),
|
||||||
|
hideAction: PropTypes.any.def([]),
|
||||||
|
getPopupClassNameFromAlign: PropTypes.any.def(returnEmptyString),
|
||||||
|
onPopupVisibleChange: Function as PropType<(open: boolean) => void>,
|
||||||
|
afterPopupVisibleChange: PropTypes.func.def(noop),
|
||||||
|
popup: PropTypes.any,
|
||||||
|
popupStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
|
||||||
|
prefixCls: PropTypes.string.def('rc-trigger-popup'),
|
||||||
|
popupClassName: PropTypes.string.def(''),
|
||||||
|
popupPlacement: String,
|
||||||
|
builtinPlacements: PropTypes.object,
|
||||||
|
popupTransitionName: String,
|
||||||
|
popupAnimation: PropTypes.any,
|
||||||
|
mouseEnterDelay: PropTypes.number.def(0),
|
||||||
|
mouseLeaveDelay: PropTypes.number.def(0.1),
|
||||||
|
zIndex: Number,
|
||||||
|
focusDelay: PropTypes.number.def(0),
|
||||||
|
blurDelay: PropTypes.number.def(0.15),
|
||||||
|
getPopupContainer: Function,
|
||||||
|
getDocument: PropTypes.func.def(returnDocument),
|
||||||
|
forceRender: { type: Boolean, default: undefined },
|
||||||
|
destroyPopupOnHide: { type: Boolean, default: false },
|
||||||
|
mask: { type: Boolean, default: false },
|
||||||
|
maskClosable: { type: Boolean, default: true },
|
||||||
|
// onPopupAlign: PropTypes.func.def(noop),
|
||||||
|
popupAlign: PropTypes.object.def(() => ({})),
|
||||||
|
popupVisible: { type: Boolean, default: undefined },
|
||||||
|
defaultPopupVisible: { type: Boolean, default: false },
|
||||||
|
maskTransitionName: String,
|
||||||
|
maskAnimation: String,
|
||||||
|
stretch: String,
|
||||||
|
alignPoint: { type: Boolean, default: undefined }, // Maybe we can support user pass position in the future
|
||||||
|
autoDestroy: { type: Boolean, default: false },
|
||||||
|
mobile: Object,
|
||||||
|
getTriggerDOMNode: Function as PropType<(d?: HTMLElement) => HTMLElement>,
|
||||||
|
// portal context will change
|
||||||
|
tryPopPortal: Boolean, // no need reactive
|
||||||
|
});
|
||||||
|
|
||||||
|
export type TriggerProps = Partial<ExtractPropTypes<ReturnType<typeof triggerProps>>>;
|
||||||
|
|
Loading…
Reference in New Issue