chore: merge code
This commit is contained in:
commit
c5d4ebdc29
|
@ -1,3 +1,12 @@
|
|||
{
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
},
|
||||
"[vue]": {
|
||||
"editor.defaultFormatter": "Wscats.vue"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import type { App } from 'vue';
|
||||
import RadioGroup from './src/radio-group.component';
|
||||
|
||||
export * from './src/radio-group.props';
|
||||
|
||||
export { RadioGroup };
|
||||
|
||||
export default {
|
||||
install(app: App): void {
|
||||
app.component(RadioGroup.name, RadioGroup);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,38 @@
|
|||
import { ChangeRadio, Radio } from './types';
|
||||
import { computed, Ref, SetupContext } from 'vue';
|
||||
import { RadioGroupProps } from '../radio-group.props';
|
||||
|
||||
export function changeRadio(props: RadioGroupProps, context: SetupContext, modelValue: Ref<string>): ChangeRadio {
|
||||
|
||||
const canChangeRadioButton = computed(() => !props.disabled);
|
||||
const enumData = computed(() => props.enumData || []);
|
||||
|
||||
function getValue(item: Radio): any {
|
||||
return item[props.valueField];
|
||||
};
|
||||
|
||||
function getText(item: Radio): any {
|
||||
return item[props.textField];
|
||||
};
|
||||
|
||||
function onClickRadio(item, $event: Event) {
|
||||
if (canChangeRadioButton.value) {
|
||||
const newValue = getValue(item);
|
||||
if (modelValue.value !== item) {
|
||||
modelValue.value = newValue;
|
||||
|
||||
context.emit('changeValue', newValue);
|
||||
|
||||
context.emit('update:modelValue', newValue);
|
||||
}
|
||||
}
|
||||
$event.stopPropagation();
|
||||
}
|
||||
|
||||
return {
|
||||
enumData,
|
||||
getValue,
|
||||
getText,
|
||||
onClickRadio
|
||||
};
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import { ComputedRef, Ref } from 'vue';
|
||||
|
||||
export interface Radio {
|
||||
/**
|
||||
* 枚举值
|
||||
*/
|
||||
value: ComputedRef<any>;
|
||||
/**
|
||||
* 枚举展示文本
|
||||
*/
|
||||
name: ComputedRef<any>;
|
||||
}
|
||||
|
||||
export interface ChangeRadio {
|
||||
|
||||
enumData: ComputedRef<Array<Radio>>;
|
||||
|
||||
/**
|
||||
* 获取枚举值
|
||||
*/
|
||||
getValue(item: Radio): any;
|
||||
/**
|
||||
* 获取枚举文本
|
||||
*/
|
||||
getText(item: Radio): any;
|
||||
|
||||
/**
|
||||
* 切换单选按钮事件
|
||||
*/
|
||||
onClickRadio: (item: Radio, $event: Event) => void;
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import { defineComponent, computed, ref } from 'vue';
|
||||
import type { SetupContext } from 'vue';
|
||||
import { radioGroupProps, RadioGroupProps } from './radio-group.props';
|
||||
import { changeRadio } from './composition/change-radio';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FRadioGroup',
|
||||
props: radioGroupProps,
|
||||
emits: [
|
||||
'changeValue',
|
||||
'update:modelValue',
|
||||
],
|
||||
setup(props: RadioGroupProps, context: SetupContext) {
|
||||
const modelValue = ref(props.modelValue);
|
||||
const { enumData, onClickRadio, getValue, getText } = changeRadio(props, context, modelValue);
|
||||
|
||||
|
||||
const horizontalClass = computed(() => ({
|
||||
'farris-checkradio-hor': props.horizontal
|
||||
}));
|
||||
|
||||
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<div class={['farris-input-wrap', horizontalClass.value]}>
|
||||
{
|
||||
enumData.value.map((item, index) => {
|
||||
const id = 'radio_' + props.name + index;
|
||||
|
||||
return (
|
||||
<div class="custom-control custom-radio" >
|
||||
<input
|
||||
type="radio"
|
||||
class="custom-control-input"
|
||||
name={props.name}
|
||||
id={id}
|
||||
value={getValue(item)}
|
||||
checked={getValue(item) === modelValue.value}
|
||||
disabled={props.disabled}
|
||||
tabindex={props.tabIndex}
|
||||
onClick={(event: MouseEvent) => onClickRadio(item, event)}
|
||||
/>
|
||||
<label class="custom-control-label" for={id}>
|
||||
{ getText(item) }
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
|
@ -0,0 +1,45 @@
|
|||
import { ExtractPropTypes, PropType } from 'vue';
|
||||
import { Radio } from './composition/types';
|
||||
|
||||
export const radioGroupProps = {
|
||||
/**
|
||||
* 组件标识
|
||||
*/
|
||||
id: String,
|
||||
/**
|
||||
* 组件名称
|
||||
*/
|
||||
name: { type: String, default: '' },
|
||||
/**
|
||||
* 单选组枚举数组
|
||||
*/
|
||||
enumData: Array<Radio>,
|
||||
/**
|
||||
* 枚举数组中展示文本的key值。
|
||||
*/
|
||||
textField: { type: String, default: 'name' },
|
||||
/**
|
||||
* 枚举数组中枚举值的key值。
|
||||
*/
|
||||
valueField: { type: String, default: 'value' },
|
||||
/**
|
||||
* 组件是否水平排列
|
||||
*/
|
||||
horizontal: { type: Boolean, default: false },
|
||||
/**
|
||||
* 禁用组件,不允许切换单选值
|
||||
*/
|
||||
disabled: { type: Boolean, default: false },
|
||||
|
||||
/**
|
||||
* 组件值
|
||||
*/
|
||||
modelValue: { type: String, default: '' },
|
||||
|
||||
/**
|
||||
* 输入框Tab键索引
|
||||
*/
|
||||
tabIndex: Number,
|
||||
};
|
||||
|
||||
export type RadioGroupProps = ExtractPropTypes<typeof radioGroupProps>;
|
|
@ -8,6 +8,7 @@ export const tabPageProps = {
|
|||
title: { type: String, default: '' },
|
||||
selected: { type: Boolean, default: false },
|
||||
disabled: { type: Boolean, default: false },
|
||||
removeable: { type: Boolean, default: false }
|
||||
removeable: { type: Boolean, default: false },
|
||||
show: { type: Boolean, default: true }
|
||||
};
|
||||
export type TabPageProps = ExtractPropTypes<typeof tabPageProps>;
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import { computed, ComputedRef, Ref, ref, SetupContext, watch } from 'vue';
|
||||
import { TabsProps } from '../tabs.props';
|
||||
|
||||
export function useTabs(
|
||||
props: TabsProps,
|
||||
context: SetupContext
|
||||
): any {
|
||||
|
||||
function setActiveId(tabs: Ref<any[]>, activeId: Ref) {
|
||||
const index = tabs.value.findIndex(tab => tab.show !== false && !activeId.value && !tab.disabled)
|
||||
if (!activeId.value && index !== -1) {
|
||||
activeId.value = tabs.value[index].id
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
setActiveId
|
||||
};
|
||||
}
|
|
@ -1,12 +1,14 @@
|
|||
import { computed, defineComponent, ref, SetupContext } from 'vue';
|
||||
import { TabsProps, tabsProps } from './tabs.props';
|
||||
import './tabs.css'
|
||||
import { useTabs } from './composition/use-tabs';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FTabs',
|
||||
props: tabsProps,
|
||||
emits: [],
|
||||
setup(props: TabsProps, context: SetupContext) {
|
||||
const hideButtons = ref(false);
|
||||
const hideButtons = ref(true);
|
||||
|
||||
const hideDropDown = ref(false);
|
||||
|
||||
|
@ -20,13 +22,17 @@ export default defineComponent({
|
|||
|
||||
const position = ref(props.position);
|
||||
|
||||
const tabs = ref([]);
|
||||
const tabs = ref([] as any[]);
|
||||
|
||||
const activeId = ref(props.activeId);
|
||||
|
||||
const shouldShowNavFill = computed(() => {
|
||||
fill.value || tabType.value === 'fill';
|
||||
});
|
||||
|
||||
const shouldShowNavPills = computed(() => {});
|
||||
const shouldShowNavPills = computed(() => { });
|
||||
|
||||
const { setActiveId } = useTabs(props, context)
|
||||
|
||||
const tabsHeaderClass = computed(() => ({
|
||||
'farris-tabs-header': true,
|
||||
|
@ -65,15 +71,38 @@ export default defineComponent({
|
|||
'flex-column': position.value === 'left' || position.value === 'right'
|
||||
}));
|
||||
|
||||
let tabPages = context.slots.default && context.slots.default()
|
||||
|
||||
tabPages?.forEach((tabPage: any) => {
|
||||
tabs.value.push(tabPage.props)
|
||||
})
|
||||
|
||||
setActiveId(tabs, activeId)
|
||||
|
||||
const tabsContainerClass = computed(() => ({
|
||||
'farris-tabs': true,
|
||||
'farris-tabs-top': position.value === 'top',
|
||||
'farris-tabs-bottom': position.value === 'bottom',
|
||||
'farris-tabs-left': position.value === 'left',
|
||||
'farris-tabs-right': position.value === 'right'
|
||||
}))
|
||||
|
||||
function getTabClass(tab: any) {
|
||||
return {
|
||||
'nav-item': true,
|
||||
'd-none': !tab.show,
|
||||
'f-state-active': tab.id === activeId,
|
||||
'f-state-disable': tab.disabled
|
||||
'd-none': tab.show !== undefined ? !tab.show : false,
|
||||
'f-state-active': tab.id === activeId.value,
|
||||
'f-state-disable': tab.disabled,
|
||||
};
|
||||
}
|
||||
|
||||
function getTabPageStyle(tabPage) {
|
||||
const props: any = tabPage.props
|
||||
return {
|
||||
display: props.id === activeId.value ? '' : 'none'
|
||||
}
|
||||
}
|
||||
|
||||
function getTabStyle(tab: any) {
|
||||
return { width: `${tab.tabWidth}px` };
|
||||
}
|
||||
|
@ -81,13 +110,17 @@ export default defineComponent({
|
|||
function getTabNavLinkClass(tab: any) {
|
||||
return {
|
||||
'nav-link': true,
|
||||
'tabs-text-truncate': true,
|
||||
active: tab.id === activeId,
|
||||
disabled: tab.disabled
|
||||
// 'tabs-text-truncate': true,
|
||||
active: tab.id === activeId.value,
|
||||
disabled: tab.disabled,
|
||||
};
|
||||
}
|
||||
|
||||
function selectTabByIndex($event: Event, targetTabId: string) {}
|
||||
function selectTabByIndex($event: Event, targetTabId: string) {
|
||||
activeId.value = targetTabId
|
||||
$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
}
|
||||
|
||||
function getTabTextClass(tab: any) {
|
||||
return {
|
||||
|
@ -97,33 +130,52 @@ export default defineComponent({
|
|||
};
|
||||
}
|
||||
|
||||
function removeTab($event: Event, targetTabId: string) {
|
||||
tabs.value = tabs.value.filter(tab => tab.id !== targetTabId)
|
||||
tabPages = tabPages?.filter(tabPage => (tabPage.props as any).id !== targetTabId)
|
||||
if (activeId.value === targetTabId) {
|
||||
activeId.value = ''
|
||||
setActiveId(tabs, activeId)
|
||||
}
|
||||
$event.preventDefault();
|
||||
$event.stopPropagation();
|
||||
}
|
||||
|
||||
return () => {
|
||||
return (
|
||||
<>
|
||||
<div class={tabsHeaderClass.value}>
|
||||
<div class="farris-tabs-title scroll-tabs" style={tabsTitleStyle.value}>
|
||||
<button type="button" class={tabsTitleButtonClass.value}></button>
|
||||
<div class={tabParentClass.value} style="width:100%">
|
||||
<ul class={tabContainerClass.value}>
|
||||
{tabs.value.forEach((tab: any, tabIndex) => {
|
||||
return (
|
||||
<li class={getTabClass(tab)} style={getTabStyle(tab)}>
|
||||
<a class={getTabNavLinkClass(tab)} onClick={($event) => selectTabByIndex($event, tab.id)}>
|
||||
<span class={getTabTextClass(tab)}>{tab.title}</span>
|
||||
{tab.removeable && (
|
||||
<span class="st-drop-close">
|
||||
<i class="f-icon f-icon-close"></i>
|
||||
</span>
|
||||
)}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<div class={tabsContainerClass.value}>
|
||||
<div class={tabsHeaderClass.value}>
|
||||
<div class="farris-tabs-title scroll-tabs" style={tabsTitleStyle.value}>
|
||||
<button type="button" class={tabsTitleButtonClass.value}></button>
|
||||
<div class={tabParentClass.value} style="width:100%">
|
||||
<ul class={tabContainerClass.value}>
|
||||
{tabs.value.map((tab: any) => {
|
||||
return (
|
||||
<li class={getTabClass(tab)} style={getTabStyle(tab)}>
|
||||
<a class={getTabNavLinkClass(tab)} onClick={($event) => selectTabByIndex($event, tab.id)}>
|
||||
<span class={getTabTextClass(tab)}>{tab.title}</span>
|
||||
{tab.removeable && (
|
||||
<span class="st-drop-close" onClick={($event) => removeTab($event, tab.id)}>
|
||||
<i class="f-icon f-icon-close"></i>
|
||||
</span>
|
||||
)}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="farris-tabs-content">
|
||||
{
|
||||
tabPages?.map(tabPage => {
|
||||
return <div class="farris-tab-page" style={getTabPageStyle(tabPage)}>{tabPage}</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
{context.slots.default && context.slots.default()}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
.farris-tabs {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #000000d9;
|
||||
font-size: 14px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1.5715;
|
||||
list-style: none;
|
||||
font-feature-settings: "tnum";
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.farris-tabs.farris-tabs-top {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.farris-tabs.farris-tabs-top .farris-tabs-header{
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.farris-tabs.farris-tabs-bottom {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
.farris-tabs.farris-tabs-left {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.farris-tabs.farris-tabs-right {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.farris-tabs-header {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.farris-tabs-header .nav-item {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
background: transparent;
|
||||
border: 1px solid #ddd;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
margin-right: 30px;
|
||||
line-height: 20px;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.farris-tabs-header .nav-item.f-state-active {
|
||||
border-bottom: 1px solid #1890ff;
|
||||
}
|
||||
|
||||
.farris-tabs-header .nav-item .nav-link {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.farris-tabs-header .nav-item.f-state-active .nav-link {
|
||||
color: #1890ff;
|
||||
text-shadow: 0 0 .25px #f1f1f1;
|
||||
}
|
||||
|
||||
.farris-tabs-header .nav-item.f-state-disable {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.farris-tabs-content {
|
||||
flex: auto;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.farris-tabs-content .farris-tab-page {
|
||||
flex: none;
|
||||
width: 100%;
|
||||
outline: none;
|
||||
}
|
||||
|
|
@ -18,7 +18,8 @@ export const tabsProps = {
|
|||
height: { type: Number },
|
||||
searchBoxVisible: { type: Boolean, default: true },
|
||||
titleWidth: { type: Number, default: 0 },
|
||||
customClass: { type: String, default: '' }
|
||||
customClass: { type: String, default: '' },
|
||||
activeId: { type: String }
|
||||
};
|
||||
|
||||
export type TabsProps = ExtractPropTypes<typeof tabsProps>;
|
||||
|
|
|
@ -4,9 +4,11 @@
|
|||
import { ref } from 'vue';
|
||||
import HelloWorld from './components/hello-world.vue';
|
||||
import Avatar from './components/avatar.vue';
|
||||
import Tabs from './components/tabs.vue'
|
||||
import ButtonEdit from './components/button-edit.vue';
|
||||
import FButton from '../components/button/src/button.component';
|
||||
import Switch from './components/switch.vue';
|
||||
import RadioGroup from './components/radio-group.vue';
|
||||
import Section from './components/section.vue';
|
||||
import Notify from './components/notify.vue';
|
||||
import Accordion from './components/accordion.vue';
|
||||
|
@ -37,9 +39,11 @@ const canAutoComplete = ref(false);
|
|||
<label for="checkbox">disable:{{ disable }}</label>
|
||||
<FButton :disable="disable"></FButton>
|
||||
<Switch></Switch>
|
||||
<RadioGroup></RadioGroup>
|
||||
<Section></Section>
|
||||
<Notify></Notify>
|
||||
<Accordion></Accordion>
|
||||
<Tabs />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
|
||||
import RadioGroup from "../../components/radio-group/src/radio-group.component";
|
||||
|
||||
const radioDisabled = ref(false);
|
||||
const radioEnumData = ref([
|
||||
{ value: "aa", name: "标签一" },
|
||||
{ value: "bb", name: "标签二" },
|
||||
{ value: "cc", name: "标签三" },
|
||||
]);
|
||||
const radioHorizontal = ref(false);
|
||||
|
||||
const value = ref("aa");
|
||||
|
||||
function testConsole(value) {
|
||||
// console.log("change radio value to", value);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<p></p>
|
||||
<label for="radio_disabled" class="mr-1">是否禁用单选组</label>
|
||||
<input type="checkbox" id="radio_disabled" v-model="radioDisabled" />
|
||||
|
||||
<label for="radio_horizontaol" class="mr-1 ml-3">是否水平排列</label>
|
||||
<input type="checkbox" id="radio_horizontaol" v-model="radioHorizontal" />
|
||||
<br />
|
||||
<RadioGroup
|
||||
:disabled="radioDisabled"
|
||||
:enum-data="radioEnumData"
|
||||
:horizontal="radioHorizontal"
|
||||
v-model="value"
|
||||
@change-value="testConsole"
|
||||
>
|
||||
</RadioGroup>
|
||||
<br />
|
||||
当前选中值: {{ value }}
|
||||
</template>
|
|
@ -0,0 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import FTab from '../../components/tabs/src/tabs.component'
|
||||
import FTabPage from '../../components/tabs/src/components/tab-page.component'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<FTab>
|
||||
<FTabPage id="Tab0" title="Tab0" :show="false">Content of Tab Page 0</FTabPage>
|
||||
<FTabPage id="Tab1" title="Tab1" :removeable="true">Content of Tab Page 1</FTabPage>
|
||||
<FTabPage id="Tab2" title="Tab2" :disabled="true" :removeable="true">Content of Tab Page 2</FTabPage>
|
||||
<FTabPage id="Tab3" title="Tab3" :removeable="true">Content of Tab Page 3</FTabPage>
|
||||
</FTab>
|
||||
</template>
|
Loading…
Reference in New Issue