From c6d2bba05b20b50c6ee3d90126c31d107609ff54 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E7=99=BD=E9=9B=BE=E4=B8=89=E8=AF=AD?=
<32354856+baiwusanyu-c@users.noreply.github.com>
Date: Fri, 25 Aug 2023 15:23:11 +0800
Subject: [PATCH] feat: added backtop component (#138)
* 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
---
components/Backtop/__test__/backtop.spec.ts | 84 ++++++++++++++++
.../Backtop/__test__/backtop.test.svelte | 6 ++
components/Backtop/package.json | 40 ++++++++
components/Backtop/src/index.svelte | 97 +++++++++++++++++++
components/Backtop/src/index.ts | 5 +
components/Backtop/src/types.d.ts | 5 +
components/Backtop/tsconfig.json | 11 +++
components/index.ts | 1 +
docs/.vitepress/config.ts | 4 +
docs/components/KBacktop.md | 63 ++++++++++++
docs/example/backtop/basic.svelte | 8 ++
docs/example/backtop/custom.svelte | 14 +++
docs/example/backtop/ikun.svelte | 78 +++++++++++++++
package.json | 3 +-
play/src/routes/+page.svelte | 3 +
pnpm-lock.yaml | 39 +++++++-
preset/src/shortcuts/avatar.ts | 4 +-
preset/src/shortcuts/backtop.ts | 8 ++
preset/src/shortcuts/index.ts | 11 ++-
19 files changed, 476 insertions(+), 8 deletions(-)
create mode 100644 components/Backtop/__test__/backtop.spec.ts
create mode 100644 components/Backtop/__test__/backtop.test.svelte
create mode 100644 components/Backtop/package.json
create mode 100644 components/Backtop/src/index.svelte
create mode 100644 components/Backtop/src/index.ts
create mode 100644 components/Backtop/src/types.d.ts
create mode 100644 components/Backtop/tsconfig.json
create mode 100644 docs/components/KBacktop.md
create mode 100644 docs/example/backtop/basic.svelte
create mode 100644 docs/example/backtop/custom.svelte
create mode 100644 docs/example/backtop/ikun.svelte
create mode 100644 preset/src/shortcuts/backtop.ts
diff --git a/components/Backtop/__test__/backtop.spec.ts b/components/Backtop/__test__/backtop.spec.ts
new file mode 100644
index 00000000..8947f851
--- /dev/null
+++ b/components/Backtop/__test__/backtop.spec.ts
@@ -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();
+ });
+});
diff --git a/components/Backtop/__test__/backtop.test.svelte b/components/Backtop/__test__/backtop.test.svelte
new file mode 100644
index 00000000..3d5cc8c6
--- /dev/null
+++ b/components/Backtop/__test__/backtop.test.svelte
@@ -0,0 +1,6 @@
+
+
+
+
diff --git a/components/Backtop/package.json b/components/Backtop/package.json
new file mode 100644
index 00000000..7407748a
--- /dev/null
+++ b/components/Backtop/package.json
@@ -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"
+ }
+}
diff --git a/components/Backtop/src/index.svelte b/components/Backtop/src/index.svelte
new file mode 100644
index 00000000..9134b7e4
--- /dev/null
+++ b/components/Backtop/src/index.svelte
@@ -0,0 +1,97 @@
+
+
+{#if show}
+
+
+
+
+
+{/if}
+
diff --git a/components/Backtop/src/index.ts b/components/Backtop/src/index.ts
new file mode 100644
index 00000000..5aaebd43
--- /dev/null
+++ b/components/Backtop/src/index.ts
@@ -0,0 +1,5 @@
+///
+import Backtop from './index.svelte';
+export { Backtop as KBacktop };
+
+export default Backtop;
diff --git a/components/Backtop/src/types.d.ts b/components/Backtop/src/types.d.ts
new file mode 100644
index 00000000..d597b114
--- /dev/null
+++ b/components/Backtop/src/types.d.ts
@@ -0,0 +1,5 @@
+///
+export type KBacktopProps = {
+ cls: string;
+ attrs: Record;
+};
diff --git a/components/Backtop/tsconfig.json b/components/Backtop/tsconfig.json
new file mode 100644
index 00000000..7ee47446
--- /dev/null
+++ b/components/Backtop/tsconfig.json
@@ -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"]
+}
diff --git a/components/index.ts b/components/index.ts
index 9bc82e3a..96485d5f 100644
--- a/components/index.ts
+++ b/components/index.ts
@@ -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';
diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
index da95306c..0fce89ac 100644
--- a/docs/.vitepress/config.ts
+++ b/docs/.vitepress/config.ts
@@ -73,6 +73,10 @@ const components = [
{
text: 'Breadcrumb',
link: '/components/KBreadcrumb'
+ },
+ {
+ text: 'Backtop',
+ link: '/components/KBacktop'
}
]
},
diff --git a/docs/components/KBacktop.md b/docs/components/KBacktop.md
new file mode 100644
index 00000000..29303652
--- /dev/null
+++ b/docs/components/KBacktop.md
@@ -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.
+
+
+
+## Slot Render
+
+Render custom content via slots.
+
+
+
+## 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 |
diff --git a/docs/example/backtop/basic.svelte b/docs/example/backtop/basic.svelte
new file mode 100644
index 00000000..0f660e0c
--- /dev/null
+++ b/docs/example/backtop/basic.svelte
@@ -0,0 +1,8 @@
+
+
+
+ attention to the right _(:з」∠)_
+
+
diff --git a/docs/example/backtop/custom.svelte b/docs/example/backtop/custom.svelte
new file mode 100644
index 00000000..f27aea9b
--- /dev/null
+++ b/docs/example/backtop/custom.svelte
@@ -0,0 +1,14 @@
+
+
+
+ attention to the right _(:з」∠)_
+
+
+
+
diff --git a/docs/example/backtop/ikun.svelte b/docs/example/backtop/ikun.svelte
new file mode 100644
index 00000000..5d4f7b3f
--- /dev/null
+++ b/docs/example/backtop/ikun.svelte
@@ -0,0 +1,78 @@
+
diff --git a/package.json b/package.json
index 06f41b33..0a481c2c 100644
--- a/package.json
+++ b/package.json
@@ -104,7 +104,8 @@
"@ikun-ui/tag": "workspace:*",
"@ikun-ui/tooltip": "workspace:*",
"@ikun-ui/spin": "workspace:*",
- "@ikun-ui/breadcrumb-item": "workspace:*"
+ "@ikun-ui/breadcrumb-item": "workspace:*",
+ "@ikun-ui/backtop": "workspace:*"
},
"devDependencies": {
"@playwright/test": "^1.37.0",
diff --git a/play/src/routes/+page.svelte b/play/src/routes/+page.svelte
index cbcebf28..c40afb65 100644
--- a/play/src/routes/+page.svelte
+++ b/play/src/routes/+page.svelte
@@ -21,6 +21,7 @@
import { KMsgBox } from '@ikun-ui/message-box';
import { KRadio } from '@ikun-ui/radio';
import { KSpin } from '@ikun-ui/spin';
+ import { KBacktop } from '@ikun-ui/backtop';
import 'virtual:uno.css';
let checked = true;
@@ -210,3 +211,5 @@
ToggleSpin
+
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 5c01cc65..a9890c4c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -11,6 +11,9 @@ importers:
'@ikun-ui/avatar':
specifier: workspace:*
version: link:components/Avatar
+ '@ikun-ui/backtop':
+ specifier: workspace:*
+ version: link:components/Backtop
'@ikun-ui/badge':
specifier: workspace:*
version: link:components/Badge
@@ -233,6 +236,34 @@ importers:
specifier: ^5.1.6
version: 5.1.6
+ components/Backtop:
+ dependencies:
+ '@ikun-ui/icon':
+ specifier: workspace:*
+ version: link:../Icon
+ '@ikun-ui/utils':
+ specifier: workspace:*
+ version: link:../../utils
+ baiwusanyu-utils:
+ specifier: ^1.0.14
+ version: 1.0.14(ansi-colors@4.1.3)(hash-sum@2.0.0)(moment@2.29.4)
+ smoke-distance:
+ specifier: 1.0.3
+ version: 1.0.3
+ devDependencies:
+ '@tsconfig/svelte':
+ specifier: ^5.0.0
+ version: 5.0.0
+ svelte-strip:
+ specifier: ^2.0.0
+ version: 2.0.0(postcss@8.4.27)(svelte@3.59.2)
+ tslib:
+ specifier: ^2.6.1
+ version: 2.6.1
+ typescript:
+ specifier: ^5.1.6
+ version: 5.1.6
+
components/Badge:
dependencies:
'@ikun-ui/utils':
@@ -272,7 +303,7 @@ importers:
version: 5.0.0
svelte-strip:
specifier: ^2.0.0
- version: 2.0.0(postcss@8.4.27)(svelte@4.0.0-next.3)
+ version: 2.0.0(postcss@8.4.27)(svelte@3.59.2)
tslib:
specifier: ^2.6.1
version: 2.6.1
@@ -297,7 +328,7 @@ importers:
version: 5.0.0
svelte-strip:
specifier: ^2.0.0
- version: 2.0.0(postcss@8.4.27)(svelte@4.0.0-next.3)
+ version: 2.0.0(postcss@8.4.27)(svelte@3.59.2)
tslib:
specifier: ^2.6.1
version: 2.6.1
@@ -5560,6 +5591,10 @@ packages:
engines: {node: '>=12'}
dev: true
+ /smoke-distance@1.0.3:
+ resolution: {integrity: sha512-wup6+TpdGHNDjxmqrS1zh514iV/Tof51lvKe9hwJxvCJTLKUNYYVFaOqnT5j/Y8PJYewxLfzX1m6kKvnqxefaA==}
+ dev: false
+
/sorcery@0.11.0:
resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==}
hasBin: true
diff --git a/preset/src/shortcuts/avatar.ts b/preset/src/shortcuts/avatar.ts
index 66bcdc41..ab292a7b 100644
--- a/preset/src/shortcuts/avatar.ts
+++ b/preset/src/shortcuts/avatar.ts
@@ -1,8 +1,8 @@
export const avatarShortcuts: Record = {
// avatar
'k-avatar':
- 'infcc v-mid box-border text-ikun-white text-14px text-center bg-#c0c4cc overflow-hidden [&>img]:(block b-none max-w-full w-full h-full)',
+ 'infcc v-mid box-border text-ikun-tx-base text-14px text-center bg-ikun-light-700 overflow-hidden [&>img]:(block b-none max-w-full w-full h-full)',
// dark
- 'k-avatar__dark': 'dark:bg-#6C6E72'
+ 'k-avatar__dark': 'dark:bg-ikun-light-700'
};
diff --git a/preset/src/shortcuts/backtop.ts b/preset/src/shortcuts/backtop.ts
new file mode 100644
index 00000000..1196656f
--- /dev/null
+++ b/preset/src/shortcuts/backtop.ts
@@ -0,0 +1,8 @@
+export const backtopShortcuts: Record = {
+ // backtop
+ 'k-backtop--base':
+ 'fcc shadow-lg shadow-ikun-main pf cursor-pointer bg-ikun-white z-100 rounded-full w-12 h-12',
+
+ // dark
+ 'k-backtop__dark': 'dark:bg-ikun-dark-300'
+};
diff --git a/preset/src/shortcuts/index.ts b/preset/src/shortcuts/index.ts
index 3af0b0fe..ad1daafe 100644
--- a/preset/src/shortcuts/index.ts
+++ b/preset/src/shortcuts/index.ts
@@ -24,7 +24,7 @@ import { switchShortcuts } from './swtich';
import { selectShortcuts } from './select';
import { msgBoxShortcuts } from './message-box';
import { spinShortcuts } from './spin';
-
+import { backtopShortcuts } from './backtop';
export default [
baseShortcuts,
commonShortcuts,
@@ -71,7 +71,9 @@ export default [
// message box
msgBoxShortcuts,
// spin
- spinShortcuts
+ spinShortcuts,
+ // backtop
+ backtopShortcuts
] as UserShortcuts;
export function getSafeList() {
@@ -97,6 +99,7 @@ export function getSafeList() {
const selectList = Object.keys(selectShortcuts);
const msgBoxList = Object.keys(msgBoxShortcuts);
const spinList = Object.keys(spinShortcuts);
+ const backtopList = Object.keys(backtopShortcuts);
return iconList
.concat(msgBoxList)
.concat(selectList)
@@ -118,7 +121,8 @@ export function getSafeList() {
.concat(buttonGroupList)
.concat(collapseList)
.concat(checkboxList)
- .concat(spinList);
+ .concat(spinList)
+ .concat(backtopList);
}
export { baseShortcuts } from './base';
@@ -145,3 +149,4 @@ export { switchShortcuts } from './swtich';
export { selectShortcuts } from './select';
export { msgBoxShortcuts } from './message-box';
export { spinShortcuts } from './spin';
+export { backtopShortcuts } from './backtop';