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';