diff --git a/packages/core/components.d.ts b/packages/core/components.d.ts index 829d2fd7..232d1a4f 100644 --- a/packages/core/components.d.ts +++ b/packages/core/components.d.ts @@ -47,6 +47,12 @@ declare module 'vue' { ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem'] ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElUpload: typeof import('element-plus/es')['ElUpload'] + ELXButton: typeof import('./src/components/ELXButton/index.vue')['default'] + ELXClearButton: typeof import('./src/components/ELXButton/components/ELXClearButton.vue')['default'] + ELXLoadingButton: typeof import('./src/components/ELXButton/components/ELXLoadingButton.vue')['default'] + ELXSendButton: typeof import('./src/components/ELXButton/components/ELXSendButton.vue')['default'] + ELXSpeechButton: typeof import('./src/components/ELXButton/components/ELXSpeechButton.vue')['default'] + ELXSpeechLoadingButton: typeof import('./src/components/ELXButton/components/ELXSpeechLoadingButton.vue')['default'] Excel: typeof import('./src/components/FilesCard/fileSvg/excel.vue')['default'] File: typeof import('./src/components/FilesCard/fileSvg/file.vue')['default'] FilesCard: typeof import('./src/components/FilesCard/index.vue')['default'] diff --git a/packages/core/src/components.ts b/packages/core/src/components.ts index 0c93aa1e..2b42e742 100644 --- a/packages/core/src/components.ts +++ b/packages/core/src/components.ts @@ -5,6 +5,7 @@ export { default as BubbleList } from './components/BubbleList/index.vue'; export { default as ConfigProvider } from './components/ConfigProvider/index.vue'; export { default as Conversations } from './components/Conversations/index.vue'; export { default as EditorSender } from './components/EditorSender/index.vue'; +export { default as ELXButton } from './components/ELXButton/index.vue'; export { default as FilesCard } from './components/FilesCard/index.vue'; export { default as MentionSender } from './components/MentionSender/index.vue'; export { default as Prompts } from './components/Prompts/index.vue'; diff --git a/packages/core/src/components/ELXButton/components/ELXClearButton.vue b/packages/core/src/components/ELXButton/components/ELXClearButton.vue new file mode 100644 index 00000000..8ffbe2ec --- /dev/null +++ b/packages/core/src/components/ELXButton/components/ELXClearButton.vue @@ -0,0 +1,10 @@ + + + + + diff --git a/packages/core/src/components/ELXButton/components/ELXLoadingButton.vue b/packages/core/src/components/ELXButton/components/ELXLoadingButton.vue new file mode 100644 index 00000000..764c827a --- /dev/null +++ b/packages/core/src/components/ELXButton/components/ELXLoadingButton.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/packages/core/src/components/ELXButton/components/ELXSendButton.vue b/packages/core/src/components/ELXButton/components/ELXSendButton.vue new file mode 100644 index 00000000..367aa115 --- /dev/null +++ b/packages/core/src/components/ELXButton/components/ELXSendButton.vue @@ -0,0 +1,10 @@ + + + + + diff --git a/packages/core/src/components/ELXButton/components/ELXSpeechButton.vue b/packages/core/src/components/ELXButton/components/ELXSpeechButton.vue new file mode 100644 index 00000000..92510fd8 --- /dev/null +++ b/packages/core/src/components/ELXButton/components/ELXSpeechButton.vue @@ -0,0 +1,10 @@ + + + + + diff --git a/packages/core/src/components/ELXButton/components/ELXSpeechLoadingButton.vue b/packages/core/src/components/ELXButton/components/ELXSpeechLoadingButton.vue new file mode 100644 index 00000000..d885a4c3 --- /dev/null +++ b/packages/core/src/components/ELXButton/components/ELXSpeechLoadingButton.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/packages/core/src/components/ELXButton/index.ts b/packages/core/src/components/ELXButton/index.ts new file mode 100644 index 00000000..c2c0b1db --- /dev/null +++ b/packages/core/src/components/ELXButton/index.ts @@ -0,0 +1,60 @@ +import type { SetupContext } from 'vue'; +import { buttonEmits, buttonProps } from 'element-plus'; + +export const elxButtonTypes = [ + 'clear', + 'loading', + 'send', + 'speech', + 'speechLoading', + '' +] as const; + +export const elxButtonProps = { + /** + * @description xButton type + */ + elxButtonType: { + type: String, + values: elxButtonTypes, + default: '' + }, + ...buttonProps +}; + +export const elxButtonEmits = { + clear: (evt: MouseEvent) => evt instanceof MouseEvent, + cancel: (evt: MouseEvent) => evt instanceof MouseEvent, + submit: (evt: MouseEvent) => evt instanceof MouseEvent, + ...buttonEmits +}; + +export type ELXButtonProps = Partial>; +export type ELXButtonEmits = typeof elxButtonEmits; +export type ELXButtonType = ELXButtonProps['elxButtonType']; + +export function useButton( + props: ELXButtonProps, + emit: SetupContext['emit'] +) { + const handleClick = (evt: MouseEvent) => { + if (props.disabled || props.loading) { + evt.stopPropagation(); + return; + } + if (props.elxButtonType?.trim()?.length) { + if (props.elxButtonType === 'clear') { + return emit('clear', evt); + } else if (['loading', 'speechLoading'].includes(props.elxButtonType)) { + return emit('cancel', evt); + } else if (props.elxButtonType === 'send') { + return emit('submit', evt); + } + } + emit('click', evt); + }; + + return { + handleClick + }; +} diff --git a/packages/core/src/components/ELXButton/index.vue b/packages/core/src/components/ELXButton/index.vue new file mode 100644 index 00000000..b1133d82 --- /dev/null +++ b/packages/core/src/components/ELXButton/index.vue @@ -0,0 +1,79 @@ + + + + + + diff --git a/packages/core/src/components/ELXButton/style.scss b/packages/core/src/components/ELXButton/style.scss new file mode 100644 index 00000000..af286fb9 --- /dev/null +++ b/packages/core/src/components/ELXButton/style.scss @@ -0,0 +1,32 @@ +.elx-button { + &.elx-button-type-clear { + .el-icon { + // 旋转180 + transform: rotate(180deg); + } + } + + &.elx-button-type-loading { + padding: 0; + + .loading-svg { + color: var(--el-color-primary); + width: 100%; + } + } + + &.elx-button-type-send { + } + + &.elx-button-type-speech { + } + + &.elx-button-type-speechLoading { + padding: 0; + + .loading-svg { + color: var(--el-color-primary); + width: 16px; + } + } +} diff --git a/packages/core/src/stories/ELXButton/ELXButton.stories.ts b/packages/core/src/stories/ELXButton/ELXButton.stories.ts new file mode 100644 index 00000000..3bc2e06b --- /dev/null +++ b/packages/core/src/stories/ELXButton/ELXButton.stories.ts @@ -0,0 +1,75 @@ +import type ELXButtonSource from '@components/ELXButton/index.vue'; +import type { Meta, StoryObj } from '@storybook/vue3'; +import ELXButtonSlot from './ELXButtonSlot.vue'; +import ELXButton from './index.vue'; + +const meta: Meta = { + title: 'Example/ELXButton', + component: ELXButton, + argTypes: { + size: { + control: { type: 'select' }, + options: ['large', 'default', 'small'] + }, + disabled: { + control: 'boolean' + } + }, + args: {} +} satisfies Meta; + +export default meta; + +type Story = StoryObj; + +export const ELXButtonDemo: Story = { + render: _args => ({ + setup() { + return { + attrs: _args + }; + }, + components: { ELXButton }, + template: ` + + ` + }) +}; + +export const ELXButtonSlotDemo: Story = { + argTypes: { + type: { + control: { type: 'select' }, + options: ['primary', 'success', 'warning', 'danger', 'info'] + }, + loading: { + control: 'boolean' + }, + circle: { + control: 'boolean' + }, + round: { + control: 'boolean' + }, + color: { + control: 'text' + }, + icon: { + control: 'text' + } + }, + args: { + type: 'primary' + }, + render: _args => ({ + setup() { + return { + attrs: _args + }; + }, + components: { ELXButtonSlot }, + template: ` + + ` + }) +}; diff --git a/packages/core/src/stories/ELXButton/ELXButtonSlot.vue b/packages/core/src/stories/ELXButton/ELXButtonSlot.vue new file mode 100644 index 00000000..28d9e482 --- /dev/null +++ b/packages/core/src/stories/ELXButton/ELXButtonSlot.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/packages/core/src/stories/ELXButton/index.vue b/packages/core/src/stories/ELXButton/index.vue new file mode 100644 index 00000000..590ecd26 --- /dev/null +++ b/packages/core/src/stories/ELXButton/index.vue @@ -0,0 +1,69 @@ + + + + +