!27 导出并安装组件

Merge pull request !27 from Sagi/feature/input-group
This commit is contained in:
Sagi 2022-09-30 07:28:01 +00:00 committed by Gitee
commit 97724f266b
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
19 changed files with 426 additions and 441 deletions

View File

@ -5,7 +5,7 @@
"printWidth": 140,
"semi": true,
"useTabs": false,
"trailingComma": "es5",
"trailingComma": "none",
"singleQuote": true,
"tabWidth": 4,
"endOfLine": "auto",

View File

@ -1,110 +1,112 @@
const types = ['config', 'feature', 'fix', 'docs', 'style', 'refactor', 'performance', 'test', 'build', 'release', 'chore', 'revert'];
module.exports = {
parserPreset: { parserOpts: { headerPattern: /^(\w*)(?:\((.*)\))?!?: (.*)$/ } },
extends: ['@commitlint/config-conventional'],
rules: {
'type-empty': [2, 'never'],
'type-enum': [2, 'always', types],
'scope-case': [0, 'always'],
'subject-empty': [2, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [2, 'always', 88],
},
prompt: {
questions: {
type: {
description: "Select the type of change that you're committing",
enum: {
config: {
description: 'Changes that affect the tools, such as eslint, npm, vscode.',
title: 'Config',
emoji: '🛠',
},
feature: {
description: 'A new feature',
title: 'Features',
emoji: '✨',
},
fix: {
description: 'A bug fix',
title: 'Bug Fixes',
emoji: '🐛',
},
docs: {
description: 'Documentation only changes',
title: 'Documentation',
emoji: '📚',
},
style: {
description: 'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
title: 'Styles',
emoji: '💎',
},
refactor: {
description: 'A code change that neither fixes a bug nor adds a feature',
title: 'Code Refactoring',
emoji: '📦',
},
performance: {
description: 'A code change that improves performance',
title: 'Performance Improvements',
emoji: '🚀',
},
test: {
description: 'Adding missing tests or correcting existing tests',
title: 'Tests',
emoji: '🚨',
},
build: {
description: 'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)',
title: 'Builds',
emoji: '🛠',
},
ci: {
description: 'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)',
title: 'Continuous Integrations',
emoji: '⚙️',
},
chore: {
description: "Other changes that don't modify src or test files",
title: 'Chores',
emoji: '♻️',
},
revert: {
description: 'Reverts a previous commit',
title: 'Reverts',
emoji: '🗑',
},
},
},
scope: {
description: 'What is the scope of this change (e.g. component or file name)',
},
subject: {
description: 'Write a short, imperative tense description of the change',
},
body: {
description: 'Provide a longer description of the change',
},
isBreaking: {
description: 'Are there any breaking changes?',
},
breakingBody: {
description: 'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself',
},
breaking: {
description: 'Describe the breaking changes',
},
isIssueAffected: {
description: 'Does this change affect any open issues?',
},
issuesBody: {
description: 'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself',
},
issues: {
description: 'Add issue references (e.g. "fix #123", "re #123".)',
},
parserPreset: { parserOpts: { headerPattern: /^(\w*)(?:\((.*)\))?!?: (.*)$/ } },
extends: ['@commitlint/config-conventional'],
rules: {
'type-empty': [2, 'never'],
'type-enum': [2, 'always', types],
'scope-case': [0, 'always'],
'subject-empty': [2, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [2, 'always', 88],
},
prompt: {
questions: {
type: {
description: "Select the type of change that you're committing",
enum: {
config: {
description: 'Changes that affect the tools, such as eslint, npm, vscode.',
title: 'Config',
emoji: '🛠',
},
feature: {
description: 'A new feature',
title: 'Features',
emoji: '✨',
},
fix: {
description: 'A bug fix',
title: 'Bug Fixes',
emoji: '🐛',
},
docs: {
description: 'Documentation only changes',
title: 'Documentation',
emoji: '📚',
},
style: {
description:
'Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)',
title: 'Styles',
emoji: '💎',
},
refactor: {
description: 'A code change that neither fixes a bug nor adds a feature',
title: 'Code Refactoring',
emoji: '📦',
},
performance: {
description: 'A code change that improves performance',
title: 'Performance Improvements',
emoji: '🚀',
},
test: {
description: 'Adding missing tests or correcting existing tests',
title: 'Tests',
emoji: '🚨',
},
build: {
description: 'Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)',
title: 'Builds',
emoji: '🛠',
},
ci: {
description:
'Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)',
title: 'Continuous Integrations',
emoji: '⚙️',
},
chore: {
description: "Other changes that don't modify src or test files",
title: 'Chores',
emoji: '♻️',
},
revert: {
description: 'Reverts a previous commit',
title: 'Reverts',
emoji: '🗑',
},
},
},
scope: {
description: 'What is the scope of this change (e.g. component or file name)',
},
subject: {
description: 'Write a short, imperative tense description of the change',
},
body: {
description: 'Provide a longer description of the change',
},
isBreaking: {
description: 'Are there any breaking changes?',
},
breakingBody: {
description: 'A BREAKING CHANGE commit requires a body. Please enter a longer description of the commit itself',
},
breaking: {
description: 'Describe the breaking changes',
},
isIssueAffected: {
description: 'Does this change affect any open issues?',
},
issuesBody: {
description: 'If issues are closed, the commit requires a body. Please enter a longer description of the commit itself',
},
issues: {
description: 'Add issue references (e.g. "fix #123", "re #123".)',
},
},
},
}
};

View File

@ -0,0 +1,15 @@
import type { App } from 'vue';
import According from './src/according.component';
import AccordingItem from './src/components/according-item.component';
export * from './src/according.props';
export * from './src/components/according-item.props';
export { According, AccordingItem };
export default {
install(app: App): void {
app.component(According.name, According);
app.component(AccordingItem.name, AccordingItem);
}
};

View File

@ -0,0 +1,12 @@
import type { App } from 'vue';
import Avatar from './src/avatar.component';
export * from './src/avatar.props';
export { Avatar };
export default {
install(app: App): void {
app.component(Avatar.name, Avatar);
}
};

View File

@ -1,308 +0,0 @@
import { Component, OnInit, ViewChildren, ElementRef, Input, Output, EventEmitter, HostListener, ViewChild, forwardRef } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { NotifyService } from '@farris/ui-notify';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { LocaleService } from '@farris/ui-locale';
export interface upImageFile {
size: number;
name: string;
type: string;
lastModified?: string;
lastModifiedDate?: Date;
state?: string;
base64?: string;
}
@Component({
selector: 'farris-avatar',
templateUrl: './avatar.component.html',
styleUrls: ['./avatar.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => AvatarComponent),
multi: true
}
]
})
export class AvatarComponent implements ControlValueAccessor, OnInit {
private defaultImgSrc = 'data:image/jpeg;base64,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'
private errorImgSrc = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QBARXhpZgAATU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAZKADAAQAAAABAAAAZAAAAAD/7QA4UGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAAA4QklNBCUAAAAAABDUHYzZjwCyBOmACZjs+EJ+/8AAEQgAZABkAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/bAEMAAQEBAQEBAgEBAgMCAgIDBAMDAwMEBQQEBAQEBQYFBQUFBQUGBgYGBgYGBgcHBwcHBwgICAgICQkJCQkJCQkJCf/bAEMBAQEBAgICBAICBAkGBQYJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCf/dAAQAB//aAAwDAQACEQMRAD8A/swooooAKKKKACiiigAooooAKKKKACiiigAooooA/9D+zCiiigAort/h7bWl34kSG8jWVdjEBhkZA9DXbX/jiz0vVJdKs9KV3jkMYwQu45wMAIetAHieDjdjikr6D8c64NP8OCxuUUXN4m3ywchR/Efw6A+vNeUeEfDM3iPUNjZW3iwZW9v7o9z+lAHJ0V7ZqfxC0vSro6Vp1mk9vANgIYKMjqF+U8D17/zz/wDhYPh6f/j70lDnr9xv5qKAPI6K9c/4Sv4fzf6/Siv+7HH/AEYVdutM8G6x4Xu9Z0m1MRhDBScqQygHpkjHNAHi1FFFABRRRQB//9H+zCiiigDs/h9J5fiy1HZt4/8AHGq/q1/HoPxBm1CWLzVjk3Ff95RyPcZyKwvB0nleJ7JvWQD8xitP4iR7PFc7f31Q/wDjoH9KAOx8TaBF4ytx4k8PTec4UK0RPYdh6H27/wA+R8G+Jm8NX72WoKRbynbICOUYcZx/MVzmia7qOgXYu7B8f3lP3WHoRXpPjKHTNY8MQ+KxD5FzKVH+9kkYPrwMg9cUAc7418KLpEg1XTPnsp+RjkIT2+h7H8PrheFtDXxDrCafI+xMFmI64Hp716h4RaW08HTzeJSDYkHy0Yc7D/Qn7orxyw1G50q+W/05jG6E7e/B7H14oA9B8a+CLHQtPXUtNd9oYKyuQevQg4H5Vc0z/R/hddyf33P6sq1xOu+LNY8QxpDfsojQ5CoMDPqeTmu3m/cfCiNe8rf+1Sf5CgDyKiiigAooooA//9L+zCiiigDX8PyeVr1lJ6Tx/wDoQrrvifHs8SK39+FT+rD+lcHZSeVeRS/3XU/ka9r8d+FNX17U4bnTUVlWLYxZgMEMT9e9AHhgBJwOpr6Rv/DIv7XTdIuOLW0UNL2yUUKB+OTn2ryyLwZqWj6zp41XZ5c86r8pzyCDg9Otd5471y5aeLwpph2zXe0O54AVjgDPv39uKAOB8ceJxrN0NPsDiztzhcdGI43fQdB/9euCr0iX4XeIk5jkgf6MR/NazJfh94ri5FsHH+y6/wBSKAOKr1zxB/o/w20+L++yfqGauFl8JeJYfv2Up/3V3fyzXeeOka18I6TZSAqyhMg8EFY8HP50AeQ0UUUAFFFFAH//0/7MKKKKACvffG8viWSOyk8PGYiRWL+SD/skZI6dTXgVd3D8RfEkFsltG0eI1ChiuTgcc84oAoX+n+MYVXVdUS4IgIYPIS205GDyTjmvRfFehXfjCysdc0ZVMjR/MCQODyBk+hyK831Lxn4i1a1ayvJ8xP8AeVVUZx7gZrMste1rToxBY3UsaDooY7R+HSgDrP7A+Itj/qvtCgf3Jgf0DUv2/wCJNl1F1x3MZcfmQay4vHniyH7t2T/vKh/mK0oviZ4mj++YpP8AeT/AigB//CdeNbP/AI+ucf8APSID+QFbvxUlcw6dG/3iHY/XC1Ri+KurL/r7aFv93cv8ya5XxT4om8T3EU0sQiESkAA569TnigDlqKKKACiiigD/1P7MKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/V/swooooAKKKKACiiigAooooAKKKKACiiigAooooA/9k=';
public imgSrc;
// public fileBinary: string;
@ViewChild('file') file: ElementRef;
// @Input() cover = '';
tReadOnly: boolean = false;
@Input()
set readonly(value: boolean) {
if (value !== this.tReadOnly) {
let localeTitle = this.localeService.getValue('avatar.imgtitle');
this.imgtitle = value ? '' : (this.imgTitle ? this.imgTitle : localeTitle);
this.tReadOnly = value;
}
};
get readonly(): boolean {
return this.tReadOnly;
}
// @Input() type;
@Input() size: number = 1;
@Input() imgTitle: string;
@Input() avatarWidth: number = 100;
@Input() avatarHeight: number = 100;
@Input() imgShape: string = 'circle';
imgtitle: string = '点击修改';
// @Input() isBase64:boolean = true;
@Output('imgChange') imgChange = new EventEmitter();
_type;
@Input()
set type(val) {
if (val && val.length) {
let types = val;
if (typeof val === 'string') {
types = val.split(',');
}
if (types && types.length) {
this.currentImgType = [];
types.forEach(t => {
if ((typeof t == 'string') && t.constructor == String) {
let tImgtype = 'image/' + t;
if (t === 'jpg') {
let jpgType = 'image/jpeg';
this.currentImgType.push(jpgType);
}
this.currentImgType.push(tImgtype);
}
});
if (this.currentImgType.length > 0) {
this.imgType = this.currentImgType.join(',')
}
}
}
}
get type() {
return this._type;
}
_cover;
@Input()
set cover(val) {
if (val) {
this._cover = val;
this.imgsrcInit(this.cover);
}
else {
this.imgSrc = this.defaultImgSrc;
}
}
get cover() {
return this._cover;
}
private onChangeCallback: Function = () => { }
private onTouchedCallback: Function = () => { }
//是否加载中
loadingImg: boolean;
imgType = 'image/*';
imgFileObj: upImageFile;
currentImgType = ['image/image', 'image/webp', 'image/png', 'image/svg', 'image/gif', 'image/jpg', 'image/jpeg', 'image/bmp'];
constructor(private notifyService: NotifyService, public localeService: LocaleService) {
this.notifyService.config.position = 'top-center';
}
ngOnInit() {
// if(this.cover){
// this.imgsrcInit(this.cover);
// }
// else{
// this.imgSrc = this.defaultImgSrc;
// }
if (this.readonly) {
this.imgtitle = '';
}
else if (this.imgTitle) {
this.imgtitle = this.imgTitle;
}
else {
this.imgtitle = this.localeService.getValue('avatar.imgtitle');
}
}
/*coverimgSrc
*/
imgsrcInit(val) {
let isImg = this.isSrc(val);
if (isImg) {
this.imgSrc = val;
}
else {
let isFullBase64 = this.isBaseSrc(val);
if (isFullBase64) {
this.imgSrc = val
}
else {
this.imgSrc = this.addBase64(val);
}
}
}
@HostListener('click')
onClick(): void {
if (this.readonly) {
return;
}
(this.file.nativeElement as HTMLInputElement).click();
}
getfiledata(event) {
if (this.readonly) {
return;
}
const filetarget = event.target as HTMLInputElement;
let getfile = filetarget.files;
if (!getfile[0]) {
return;
}
let fileType = getfile[0].type;
const isLtSize = getfile[0].size / 1024 / 1024 < this.size;
if (this.currentImgType.indexOf(fileType) < 0) {
let typeerrorText = this.localeService.getValue('avatar.typeError');
this.notifyService.error({
type: 'error',
title: '',
msg: typeerrorText
});
filetarget.value = '';
// this.notifyService.error('上传图片类型不正确');
return;
}
if (!isLtSize) {
let sizeerrorText = this.localeService.getValue('avatar.sizeError');
let errormes: string = sizeerrorText + this.size + "M!";
this.notifyService.error({
type: 'error',
title: '',
msg: errormes
});
filetarget.value = '';
// this.notifyService.error(`上传图片不能大于${this.size}M!`);
return;
}
this.transformFile(getfile[0]);
filetarget.value = '';
}
public getImgFileObj() {
return this.imgFileObj;
}
transformFile(getfile: any) {
// const subject = new Subject();
this.imgFileObj = {
size: getfile.size,
name: getfile.name,
type: getfile.type,
lastModified: getfile.lastModified,
lastModifiedDate: getfile.lastModifiedDate
}
this.do(getfile).subscribe(res => {
this.loadingImg = false;
if (res['state'] === 'done') {
this.imgSrc = res['result'];
//this.onChangeCallback(this.imgSrc);
this.onChangeCallback(this.removeBase64(this.imgSrc));
this.onTouchedCallback();
}
else if (res['state'] === 'error') {
let uploaderrorText = this.localeService.getValue('avatar.uploadError');
this.notifyService.error({
type: 'error',
title: '',
msg: uploaderrorText
})
// this.notifyService.error('图片上传失败,请重试!');
}
this.imgFileObj.state = res['state'];
this.imgFileObj.base64 = res['result'];
this.imgChange.emit(this.imgFileObj);
});
}
read(file: File): Observable<string> {
return Observable.create(observer => {
const reader = new FileReader();
reader.readAsDataURL(file);
//this.loadingImg = true;
// reader.onloadstart=function(){}
reader.onload = () => {
//console.log(reader.result);
observer.next({ state: 'done', 'result': reader.result });
observer.complete();
};
reader.onerror = function () {
observer.next({ state: 'error', 'result': reader.result });
observer.complete();
}
});
}
do(file: any): Observable<string> {
return this.read(file as File);
}
writeValue(val: any): void {
if (val && val.length) {
// if(this.isBase64){
// this.imgSrc = this.addBase64(val);
// }
// else{
// this.imgSrc = val;
// }
this.imgsrcInit(val);
}
else if (this.cover) {
this.imgsrcInit(this.cover);
}
else {
this.imgSrc = this.defaultImgSrc;
}
}
registerOnChange(fn: any): void {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any): void {
this.onTouchedCallback = fn;
}
// setDisabledState?(isDisabled: boolean): void {
// this.disabled = isDisabled;
// }
addBase64(val) {
if (!val) return;
return 'data:image/jpeg;base64,' + val;
}
removeBase64(val) {
if (!val) return;
let img_arr = val.split(',');
if (img_arr.length) {
return img_arr[1];
}
}
//判断是否是图片路径
isSrc(url) {
return (url.match(/\.(jpeg|jpg|gif|png|svg|bmp|webp)$/) != null)
}
//判断是否是完成base64
isBaseSrc(url) {
return (url.indexOf('data:image/') > -1 ? true : false)
}
errorSrc() {
this.imgSrc = this.errorImgSrc;
this.imgtitle = this.localeService.getValue('avatar.loadError');
}
}

View File

@ -6,7 +6,7 @@ export * from './src/button-edit.props';
export { ButtonEdit };
export default {
install(app: App): void {
app.component(ButtonEdit.name, ButtonEdit);
},
install(app: App): void {
app.component(ButtonEdit.name, ButtonEdit);
}
};

View File

@ -0,0 +1,15 @@
import type { App } from 'vue';
import Notify from './src/notify.component';
import Toast from './src/components/toast.component';
export * from './src/notify.props';
export * from './src/components/toast.props';
export { Notify, Toast };
export default {
install(app: App): void {
app.component(Notify.name, Notify);
app.component(Toast.name, Toast);
}
};

View File

@ -1 +1,12 @@
import type { App } from 'vue';
import Popover from './src/popover.component';
export * from './src/popover.props';
export { Popover };
export default {
install(app: App): void {
app.component(Popover.name, Popover);
}
};

View File

@ -0,0 +1,11 @@
import type { App } from 'vue';
import Section from './src/section.component';
export * from './src/section.props';
export { Section };
export default {
install(app: App): void {
app.component(Section.name, Section);
}
};

View File

@ -0,0 +1,10 @@
import type { App } from 'vue';
import Switch from './src/switch.component';
export * from './src/switch.props';
export default {
install(app: App): void {
app.component(Switch.name, Switch);
}
};

View File

@ -0,0 +1,15 @@
import type { App } from 'vue';
import Tabs from './src/tabs.component';
import TabPage from './src/components/tab-page.component';
export * from './src/tabs.props';
export * from './src/components/tab-page.props';
export { Tabs, TabPage };
export default {
install(app: App): void {
app.component(Tabs.name, Tabs);
app.component(TabPage.name, TabPage);
}
};

View File

@ -0,0 +1,13 @@
import { defineComponent, SetupContext } from 'vue';
import { TabPageProps, tabPageProps } from './tab-page.props';
export default defineComponent({
name: 'FTabPage',
props: tabPageProps,
emits: [],
setup(props: TabPageProps, context: SetupContext) {
return () => {
return context.slots.default && context.slots.default();
};
}
});

View File

@ -0,0 +1,13 @@
import { ExtractPropTypes } from 'vue';
export const tabPageProps = {
tabWidth: { type: Number, default: -1 },
id: { type: String, default: '' },
customTitleClass: { type: String, default: '' },
titleOverflow: { type: Boolean, default: false },
title: { type: String, default: '' },
selected: { type: Boolean, default: false },
disabled: { type: Boolean, default: false },
removeable: { type: Boolean, default: false }
};
export type TabPageProps = ExtractPropTypes<typeof tabPageProps>;

View File

@ -0,0 +1,131 @@
import { computed, defineComponent, ref, SetupContext } from 'vue';
import { TabsProps, tabsProps } from './tabs.props';
export default defineComponent({
name: 'FTabs',
props: tabsProps,
emits: [],
setup(props: TabsProps, context: SetupContext) {
const hideButtons = ref(false);
const hideDropDown = ref(false);
const hasInHeadClass = computed(() => {
return false;
});
const fill = ref('');
const tabType = ref('');
const position = ref(props.position);
const tabs = ref([]);
const shouldShowNavFill = computed(() => {
fill.value || tabType.value === 'fill';
});
const shouldShowNavPills = computed(() => {});
const tabsHeaderClass = computed(() => ({
'farris-tabs-header': true,
'farris-tabs-inHead': hasInHeadClass.value,
'farris-tabs-inContent': !hasInHeadClass.value,
'farris-tabs-nav-fill': shouldShowNavFill.value,
'farris-tabs-nav-pills': shouldShowNavPills.value,
}));
const tabsTitleStyle = computed(() => ({
width: hasInHeadClass.value ? (props.titleWidth ? `${props.titleWidth}%` : '') : '',
}));
const tabsTitleButtonClass = computed(() => ({
btn: true,
'sc-nav-btn': true,
'px-1': true,
'sc-nav-lr': true,
'd-none': hideButtons.value,
}));
const tabParentClass = computed(() => ({
spacer: true,
'f-utils-fill': true,
'spacer-sides': !hideButtons.value && hideDropDown.value,
'spacer-sides-dropdown': !hideButtons.value && !hideDropDown.value,
}));
const tabContainerClass = computed(() => ({
nav: true,
'farris-nav-tabs': true,
'flex-nowrap': true,
'nav-fill': fill.value || tabType.value === 'fill',
'nav-pills': tabType.value === 'pills',
'flex-row': position.value === 'top' || position.value === 'bottom',
'flex-column': position.value === 'left' || 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,
};
}
function getTabStyle(tab: any) {
return { width: `${tab.tabWidth}px` };
}
function getTabNavLinkClass(tab: any) {
return {
'nav-link': true,
'tabs-text-truncate': true,
active: tab.id === activeId,
disabled: tab.disabled,
};
}
function selectTabByIndex($event: Event, targetTabId: string) {}
function getTabTextClass(tab: any) {
return {
'st-tab-text': true,
'farris-title-auto': props.autoTitleWidth,
'farris-title-text-custom': tab.titleOverflow,
};
}
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>
</div>
</div>
{context.slots.default && context.slots.default()}
</>
);
};
},
});

View File

@ -0,0 +1,24 @@
import { ExtractPropTypes, PropType } from 'vue';
export type TabType = 'fill' | 'pills' | 'default';
export type TabPosition = 'left' | 'right' | 'top' | 'bottom';
export const tabsProps = {
tabTab: { type: String as PropType<TabType>, default: 'default' },
autoTitleWidth: { type: Boolean, default: false },
titleLength: { type: Number, default: 7 },
position: { type: String as PropType<TabPosition>, default: 'top' },
showDropDwon: { type: Boolean, default: false },
showTooltips: { type: Boolean, default: false },
scrollStep: { type: Number, default: 1 },
autoResize: { type: Boolean, default: false },
closeable: { type: Boolean, default: false },
selectedTab: { type: String, default: '' },
width: { type: Number },
height: { type: Number },
searchBoxVisible: { type: Boolean, default: true },
titleWidth: { type: Number, default: 0 },
customClass: { type: String, default: '' },
};
export type TabsProps = ExtractPropTypes<typeof tabsProps>;

View File

@ -0,0 +1,11 @@
import type { App } from 'vue';
import Text from './src/text.component';
export * from './src/text.props';
export { Text };
export default {
install(app: App): void {
app.component(Text.name, Text);
}
};

View File

@ -0,0 +1,12 @@
import type { App } from 'vue';
import Tooltip from './src/tooltip.component';
export * from './src/tooltip.props';
export { Tooltip };
export default {
install(app: App): void {
app.component(Tooltip.name, Tooltip);
}
};

View File

@ -1,7 +1,7 @@
{
"name": "@farris/ui-vue",
"private": true,
"version": "0.0.0",
"version": "0.0.1",
"scripts": {
"dev": "vite",
"build": "vue-tsc --noEmit && vite build",

View File

@ -1,38 +1,36 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ref } from 'vue';
defineProps<{ msg: string }>()
defineProps<{ msg: string }>();
const count = ref(0)
const count = ref(0);
</script>
<template>
<h1>{{ msg }}</h1>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank">create-vue</a>, the official Vue + Vite starter
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Install
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
in your IDE for a better DX
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
<p>
Install
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
in your IDE for a better DX
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
color: #888;
}
</style>