From 84a46c38625245bf291885680470acd137a3d6ea Mon Sep 17 00:00:00 2001 From: webfansplz <308241863@qq.com> Date: Tue, 6 Sep 2022 21:35:00 +0800 Subject: [PATCH] feat: loading component --- packages/core/package.json | 1 + packages/core/src/components/Loading.ts | 46 +++++++++++++++++++ packages/core/src/components/Text.ts | 14 ++---- packages/core/src/components/TextTransform.ts | 8 ++-- packages/core/src/components/index.ts | 1 + .../core/src/composables/scheduleUpdate.ts | 9 ++++ packages/core/src/index.ts | 1 + packages/playground/components.d.ts | 2 + packages/playground/src/LoadingDemo.vue | 8 ++++ packages/playground/src/main.ts | 3 +- packages/playground/vite.config.cjs | 1 + packages/vite-plugin-vue-termui/src/index.ts | 4 ++ pnpm-lock.yaml | 7 +++ 13 files changed, 90 insertions(+), 15 deletions(-) create mode 100644 packages/core/src/components/Loading.ts create mode 100644 packages/core/src/composables/scheduleUpdate.ts create mode 100644 packages/playground/src/LoadingDemo.vue diff --git a/packages/core/package.json b/packages/core/package.json index 77b0f60..50ffc17 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -44,6 +44,7 @@ "chalk": "^5.0.1", "cli-boxes": "^3.0.0", "cli-cursor": "^4.0.0", + "cli-spinners": "^2.7.0", "cli-truncate": "^3.1.0", "indent-string": "^5.0.0", "slice-ansi": "^5.0.0", diff --git a/packages/core/src/components/Loading.ts b/packages/core/src/components/Loading.ts new file mode 100644 index 0000000..ee7a8b2 --- /dev/null +++ b/packages/core/src/components/Loading.ts @@ -0,0 +1,46 @@ +import { + computed, + defineComponent, + h, + onMounted, + onUnmounted, + onUpdated, + ref, +} from '@vue/runtime-core' +import spinners from 'cli-spinners' +import type { PropType } from '@vue/runtime-core' +import { useScheduleUpdate } from '../composables/scheduleUpdate' +import type { SpinnerName } from 'cli-spinners' + +export const TuiLoading = defineComponent({ + props: { + /** + * Type of a loading. + * See [cli-spinners](https://github.com/sindresorhus/cli-spinners) for available spinners. + * + * @default dots + */ + type: String as PropType, + }, + setup(props) { + const spinner = computed(() => spinners[props.type ?? 'dots']) + const frame = ref(0) + let timer: NodeJS.Timer | null = null + const { update } = useScheduleUpdate() + onUpdated(() => { + update() + }) + onMounted(() => { + timer = setInterval(() => { + frame.value = (frame.value + 1) % spinner.value?.frames?.length + }, spinner.value.interval) + }) + onUnmounted(() => { + clearInterval(timer!) + }) + + return () => { + return h('tui:text', spinner.value?.frames[frame.value]) + } + }, +}) diff --git a/packages/core/src/components/Text.ts b/packages/core/src/components/Text.ts index 1f412d9..ab57d63 100644 --- a/packages/core/src/components/Text.ts +++ b/packages/core/src/components/Text.ts @@ -1,13 +1,7 @@ import chalk, { ForegroundColor } from 'chalk' -import { - PropType, - h, - inject, - defineComponent, - onUpdated, -} from '@vue/runtime-core' +import { PropType, h, defineComponent, onUpdated } from '@vue/runtime-core' import type { Styles } from '../renderer/styles' -import { scheduleUpdateSymbol } from '../injectionSymbols' +import { useScheduleUpdate } from '../composables/scheduleUpdate' import { colorize } from '../renderer/textColor' export const defaultStyle: Styles = { @@ -44,9 +38,9 @@ export const TuiText = defineComponent({ }, setup(props, { slots }) { - const scheduleUpdate = inject(scheduleUpdateSymbol)! + const { update } = useScheduleUpdate() onUpdated(() => { - scheduleUpdate() + update() }) function transform(text: string): string { diff --git a/packages/core/src/components/TextTransform.ts b/packages/core/src/components/TextTransform.ts index 796828c..4f3949c 100644 --- a/packages/core/src/components/TextTransform.ts +++ b/packages/core/src/components/TextTransform.ts @@ -1,9 +1,9 @@ import chalk, { ForegroundColor } from 'chalk' -import { h, inject, FunctionalComponent } from '@vue/runtime-core' -import { scheduleUpdateSymbol } from '../injectionSymbols' +import { h, FunctionalComponent } from '@vue/runtime-core' import type { OutputTransformer } from '../renderer/Output' import { defaultStyle, TuiTextProps } from './Text' import { colorize } from '../renderer/textColor' +import { useScheduleUpdate } from '../composables/scheduleUpdate' /** * A Text Transforms allows modifying the text before it is written to the stdout while accounting for line breaks and @@ -14,8 +14,8 @@ export const TuiTextTransform: FunctionalComponent< transform?: OutputTransformer } & TuiTextProps > = (props, { slots }) => { - const scheduleUpdate = inject(scheduleUpdateSymbol)! - scheduleUpdate() + const { update } = useScheduleUpdate() + update() // onUpdated(() => { // scheduleUpdate() // }) diff --git a/packages/core/src/components/index.ts b/packages/core/src/components/index.ts index 392921c..13664b2 100644 --- a/packages/core/src/components/index.ts +++ b/packages/core/src/components/index.ts @@ -5,4 +5,5 @@ export { TuiApp } from './App' export { TuiBox } from './Box' export { TuiLink } from './Link' +export { TuiLoading } from './Loading' // export { default as TuiInput } from './Input.vue' diff --git a/packages/core/src/composables/scheduleUpdate.ts b/packages/core/src/composables/scheduleUpdate.ts new file mode 100644 index 0000000..092dbbe --- /dev/null +++ b/packages/core/src/composables/scheduleUpdate.ts @@ -0,0 +1,9 @@ +import { inject } from '@vue/runtime-core' +import { scheduleUpdateSymbol } from '../injectionSymbols' + +export function useScheduleUpdate() { + const scheduleUpdate = inject(scheduleUpdateSymbol)! + return { + update: scheduleUpdate, + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index bc9dee5..d0964a6 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -31,6 +31,7 @@ export { onInputData } from './composables/input' export { useInterval, useTimeout } from './composables/utils' export { onResize, useStdoutDimensions, useTitle } from './composables/screen' export { useStdout } from './composables/writeStreams' +export { useScheduleUpdate } from './composables/scheduleUpdate' export type { UseStdoutReturn } from './composables/writeStreams' export { useDebugLog } from './utils' diff --git a/packages/playground/components.d.ts b/packages/playground/components.d.ts index c44c4ad..bfb1e24 100644 --- a/packages/playground/components.d.ts +++ b/packages/playground/components.d.ts @@ -7,8 +7,10 @@ export {} declare module '@vue/runtime-core' { export interface GlobalComponents { + Box: typeof import('vue-termui')['TuiBox'] Div: typeof import('vue-termui')['TuiBox'] Link: typeof import('vue-termui')['TuiLink'] + Loading: typeof import('vue-termui')['TuiLoading'] Text: typeof import('vue-termui')['TuiText'] } } diff --git a/packages/playground/src/LoadingDemo.vue b/packages/playground/src/LoadingDemo.vue new file mode 100644 index 0000000..71bdec7 --- /dev/null +++ b/packages/playground/src/LoadingDemo.vue @@ -0,0 +1,8 @@ + diff --git a/packages/playground/src/main.ts b/packages/playground/src/main.ts index bbaa6b2..8520259 100644 --- a/packages/playground/src/main.ts +++ b/packages/playground/src/main.ts @@ -1,7 +1,8 @@ // import devtools from '@vue/devtools' // import devtools from '@vue/devtools/node' import { createApp } from 'vue-termui' -import App from './Focusables.vue' +// import App from './Focusables.vue' +import App from './LoadingDemo.vue' // import App from './Fragments.vue' // import App from './CenteredDemo.vue' // import App from './App.vue' diff --git a/packages/playground/vite.config.cjs b/packages/playground/vite.config.cjs index 46f9e7c..4b6434d 100644 --- a/packages/playground/vite.config.cjs +++ b/packages/playground/vite.config.cjs @@ -27,6 +27,7 @@ export default defineConfig({ 'yoga-layout-prebuilt', 'is-fullwidth-code-point', 'terminal-link', + 'cli-spinners', 'restore-cursor', ], }, diff --git a/packages/vite-plugin-vue-termui/src/index.ts b/packages/vite-plugin-vue-termui/src/index.ts index 35dce1b..d0c5a2d 100644 --- a/packages/vite-plugin-vue-termui/src/index.ts +++ b/packages/vite-plugin-vue-termui/src/index.ts @@ -116,6 +116,8 @@ export default function VueTermui({ 'wrap-ansi', 'yoga-layout', 'yoga-layout-prebuilt', + 'terminal-link', + 'cli-spinners', ], output: { @@ -169,6 +171,8 @@ export const VueTuiComponents = new Map([ ['a', 'TuiLink'], ['link', 'TuiLink'], + ['loading', 'TuiLoading'], + ['div', 'TuiBox'], ['box', 'TuiBox'], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a181d6..775a62c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -108,6 +108,7 @@ importers: chalk: ^5.0.1 cli-boxes: ^3.0.0 cli-cursor: ^4.0.0 + cli-spinners: ^2.7.0 cli-truncate: ^3.1.0 indent-string: ^5.0.0 slice-ansi: ^5.0.0 @@ -123,6 +124,7 @@ importers: chalk: 5.0.1 cli-boxes: 3.0.0 cli-cursor: 4.0.0 + cli-spinners: 2.7.0 cli-truncate: 3.1.0 indent-string: 5.0.0 slice-ansi: 5.0.0 @@ -1249,6 +1251,11 @@ packages: restore-cursor: 4.0.0 dev: false + /cli-spinners/2.7.0: + resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==} + engines: {node: '>=6'} + dev: false + /cli-truncate/3.1.0: resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}