Skip to content

Commit

Permalink
feat: added backtop component (#138)
Browse files Browse the repository at this point in the history
* feat: added backtop component

* docs: added backtop component document

* docs: added backtop component unit test

* test: added backtop component unit test

* update: update unit test

* test: updated backtop component unit test
  • Loading branch information
baiwusanyu-c authored Aug 25, 2023
1 parent 7e828b5 commit c6d2bba
Show file tree
Hide file tree
Showing 19 changed files with 476 additions and 8 deletions.
84 changes: 84 additions & 0 deletions components/Backtop/__test__/backtop.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { afterEach, expect, test, describe, beforeEach, vi } from 'vitest';
import KBacktop from '../src';
import KBacktopSlot from './backtop.test.svelte';
import { tick } from 'svelte';

const initHost = () => {
document.body.style.height = '100px';
document.body.style.overflow = 'auto';
};
beforeEach(() => {
initHost();
});
afterEach(() => {
document.body.innerHTML = '';
});

describe('Test: KBacktop', () => {
vi.mock('svelte', async () => {
const actual = (await vi.importActual('svelte')) as object;
return {
...actual,
// @ts-ignore
onMount: (await import('svelte/internal')).onMount
};
});

test('props: showHeight & right & bottom', async () => {
new KBacktop({
target: document.body,
props: {
right: 66,
bottom: 66,
showHeight: 100
}
});

await tick();
expect(document.documentElement.innerHTML.includes('k-backtop')).not.toBeTruthy();

document.documentElement.scrollTop = 50;
document.documentElement.dispatchEvent(new Event('scroll', { bubbles: true }));
await tick();
expect(document.body.innerHTML.includes('k-backtop')).not.toBeTruthy();

document.documentElement.scrollTop = 110;
document.documentElement.dispatchEvent(new Event('scroll', { bubbles: true }));
await tick();
expect(document.documentElement.innerHTML.includes('k-backtop')).toBeTruthy();
expect(document.documentElement.innerHTML.includes('right: 66px; bottom: 66px;')).toBeTruthy();
});

test('events: click', async () => {
const mockFn = vi.fn();
const instance = new KBacktop({
target: document.body
});
await tick();
instance.$on('click', mockFn);
expect(document.documentElement.innerHTML.includes('k-backtop')).not.toBeTruthy();

document.documentElement.scrollTop = 210;
document.documentElement.dispatchEvent(new Event('scroll', { bubbles: true }));
await tick();
expect(document.documentElement.innerHTML.includes('k-backtop')).toBeTruthy();
const triggerEl = document.body.children[0];
triggerEl.dispatchEvent(new Event('click', { bubbles: true }));
await tick();
expect(mockFn).toBeCalled();
});

test('slot: custom render', async () => {
new KBacktopSlot({
target: document.body
});

await tick();
expect(document.documentElement.innerHTML.includes('k-backtop')).not.toBeTruthy();
document.documentElement.scrollTop = 50;
document.documentElement.dispatchEvent(new Event('scroll', { bubbles: true }));
await tick();
expect(document.documentElement.innerHTML.includes('k-backtop')).toBeTruthy();
expect(document.documentElement.innerHTML.includes('__BACKTO_TEST')).toBeTruthy();
});
});
6 changes: 6 additions & 0 deletions components/Backtop/__test__/backtop.test.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<script>
import { KBacktop } from "../src";
</script>
<KBacktop showHeight="{10}">
<div id="__BACKTO_TEST"></div>
</KBacktop>
40 changes: 40 additions & 0 deletions components/Backtop/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@ikun-ui/backtop",
"version": "0.0.9-beta.2",
"type": "module",
"main": "dist/index.js",
"module": "dist/index.js",
"svelte": "dist/index.js",
"types": "src/index.ts",
"keywords": [
"svelte",
"svelte3",
"web component",
"component",
"react",
"vue",
"svelte-kit",
"dx"
],
"scripts": {
"build": "npm run build:js && npm run build:svelte",
"build:js": "tsc -p . --outDir dist/ --rootDir src/",
"build:svelte": "svelte-strip strip src/ dist",
"publish:npm": "pnpm publish --no-git-checks --access public"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
"@ikun-ui/icon": "workspace:*",
"@ikun-ui/utils": "workspace:*",
"baiwusanyu-utils": "^1.0.14",
"smoke-distance": "^1.0.3"
},
"devDependencies": {
"@tsconfig/svelte": "^5.0.0",
"svelte-strip": "^2.0.0",
"tslib": "^2.6.1",
"typescript": "^5.1.6"
}
}
97 changes: 97 additions & 0 deletions components/Backtop/src/index.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<script lang="ts">
import { getPrefixCls, createCls } from '@ikun-ui/utils';
import { KIcon } from '@ikun-ui/icon';
import { SmokeDistance } from 'smoke-distance'
import type { easingType } from 'smoke-distance'
import {createEventDispatcher, onDestroy, onMount} from "svelte";
export let cls: string = '';
export let attrs: Record<string, string> = {};
export let right: number = 40
export let bottom: number = 40
export let showHeight: number = 200
export let target: string = ''
export let easing: string = 'quartOut'
export let duration: number = 500
let show = false
let targetEl:undefined | HTMLElement = undefined
let container: undefined | Document | HTMLElement = undefined
$: backTopStyle = {
right: `${right}px`,
bottom: `${bottom}px`,
}
const scrollToTop = () => {
if (!targetEl) return
const { scrollTop } = targetEl
const smoke = new SmokeDistance({
from: { scrollTop },
to: { scrollTop: 0 },
easing: easing as easingType,
duration: duration,
onUpdate: (keys: any) => {
if (targetEl)
targetEl.scrollTop = keys.scrollTop
},
})
smoke.start()
}
const dispatch = createEventDispatcher();
const handleClick = (event: MouseEvent) => {
scrollToTop()
dispatch('click', event)
}
const setContainer = () => {
container = document
targetEl = document.documentElement
if (target) {
targetEl = document.querySelector<HTMLElement>(target) ?? undefined
if (!targetEl){
console.error(`[ikun-ui]: backtop component - ${target} does not exist`)
targetEl = document.body
}
container = targetEl
}
}
const handleScroll = () => {
if (targetEl) {
const { scrollTop } = targetEl
show = scrollTop >= showHeight
}
}
handleScroll()
onMount(() => {
setContainer()
container && container.addEventListener('scroll', handleScroll)
})
onDestroy(() => {
container && container.removeEventListener('scroll', handleScroll)
})
const prefixCls = getPrefixCls('backtop');
$: cnames = createCls(prefixCls, {
[`${prefixCls}--base`]: true,
[`${prefixCls}__dark`]: true
}, cls);
</script>

{#if show}
<div class={cnames}
style:right={backTopStyle.right}
style:bottom={backTopStyle.bottom}
aria-hidden="true"
on:click|stopPropagation={handleClick}
{...$$restProps}
{...attrs}>
<slot>
<KIcon icon="i-carbon-arrow-up"/>
</slot>
</div>
{/if}

5 changes: 5 additions & 0 deletions components/Backtop/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="./types" />
import Backtop from './index.svelte';
export { Backtop as KBacktop };

export default Backtop;
5 changes: 5 additions & 0 deletions components/Backtop/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="svelte" />
export type KBacktopProps = {
cls: string;
attrs: Record<string, string>;
};
11 changes: 11 additions & 0 deletions components/Backtop/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "@tsconfig/svelte/tsconfig.json",

"compilerOptions": {
"noImplicitAny": true,
"strict": true,
"declaration": true
},
"include": ["src/**/*.ts", "src/**/*.svelte"],
"exclude": ["node_modules/*", "**/*.spec.ts"]
}
1 change: 1 addition & 0 deletions components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export * from '@ikun-ui/tooltip';
export * from '@ikun-ui/switch';
export * from '@ikun-ui/message-box';
export * from '@ikun-ui/spin';
export * from '@ikun-ui/backtop';
4 changes: 4 additions & 0 deletions docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,10 @@ const components = [
{
text: 'Breadcrumb',
link: '/components/KBreadcrumb'
},
{
text: 'Backtop',
link: '/components/KBacktop'
}
]
},
Expand Down
63 changes: 63 additions & 0 deletions docs/components/KBacktop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
---
title: KBacktop
lang: en-US
---

# KBacktop

A button to back to top.

## Install

::: code-group

```bash [pnpm]
pnpm add @ikun-ui/backtop
```

```bash [yarn]
yarn add @ikun-ui/backtop
```

```bash [npm]
npm install @ikun-ui/backtop
```

:::

## Basic usage

Scroll down to see the bottom-right button.

<demo src="../../../../example/backtop/basic.svelte" github='Backtop'></demo>

## Slot Render

Render custom content via slots.

<demo src="../../../../example/backtop/custom.svelte" github='Backtop'></demo>

## Backtop Props

| Name | Type | Default | Description |
| ---------- | -------- | ---------- | ---------------------------------------------------- |
| right | `number` | `40` | Distance from the right side of the screen. |
| bottom | `number` | `40` | Distance from the bottom of the screen. |
| showHeight | `number` | `200` | Scroll to this height to show the Backtop component. |
| target | `string` | `-` | Scroll target element `id` |
| easing | `string` | `quartOut` | Animation during back to top(TODO) |
| duration | `number` | `500` | Time spent back to top. |
| cls | `string` | `''` | Additional class for |
| attrs | `any` | `{}` | Additional attributes |

## Backtop Events

| Name | Description | Type |
| ----- | --------------------------- | ---------------------------- |
| click | trigger when backtop click. | `(event: MouseEvent)=> void` |

## Backtop Slots

| Name | Description |
| ------- | ------------------------- |
| default | Customize default content |
8 changes: 8 additions & 0 deletions docs/example/backtop/basic.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
import { KBacktop } from '@ikun-ui/backtop';
</script>

<p>
attention to the right _(:з」∠)_
</p>
<KBacktop bottom="100" right="100" showHeight="100"/>
14 changes: 14 additions & 0 deletions docs/example/backtop/custom.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script>
import { KBacktop } from '@ikun-ui/backtop';
import IKun from './ikun.svelte';
</script>

<p>
attention to the right _(:з」∠)_
</p>
<KBacktop
bottom="{20}"
right="{100}"
showHeight="{600}">
<IKun/>
</KBacktop>
Loading

0 comments on commit c6d2bba

Please sign in to comment.