chore: merge code

This commit is contained in:
Sagi 2022-10-02 21:22:49 +08:00
commit c5d4ebdc29
14 changed files with 439 additions and 34 deletions

11
.vscode/settings.json vendored
View File

@ -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"
}
}

View File

@ -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);
}
};

View File

@ -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
};
}

View File

@ -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;
}

View File

@ -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>
);
};
},
});

View File

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

View File

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

View File

@ -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
};
}

View File

@ -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()}
</>
);
};

View File

@ -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;
}

View File

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

View File

@ -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>

View File

@ -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>

View File

@ -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>