big update
This commit is contained in:
parent
f58a5106eb
commit
56c40021ba
14
index.html
Normal file
14
index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Vite + Vue + TS</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
40
package.json
40
package.json
@ -1,23 +1,25 @@
|
||||
{
|
||||
"name": "axp-ui",
|
||||
"descriiption": "My helper ui lib",
|
||||
"version": "1.6.3",
|
||||
"version": "1.7.0",
|
||||
"homepage": "https://antoxahub.ru/antoxa/axp-ui",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://antoxahub.ru/antoxa/axp-ui.git"
|
||||
},
|
||||
"module": "./dist/index.js",
|
||||
"module": "./dist/index.mjs",
|
||||
"main": "./dist/index.umd.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js"
|
||||
"import": "./dist/index.mjs",
|
||||
"requier": "./dist/index.umd.js"
|
||||
},
|
||||
"./styles/": [
|
||||
"./src/css/"
|
||||
],
|
||||
"./tailwind.config": "./tailwind.config.ts"
|
||||
"./tailwind.config": "./tailwind.config.ts",
|
||||
"./style.css": "./dist/style.css",
|
||||
"./style/*": "./src/style/*",
|
||||
"./tsconfig.json": "./tsconfig.json"
|
||||
},
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist",
|
||||
"tsconfig.json",
|
||||
@ -25,23 +27,23 @@
|
||||
"src/css"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rollup -c --configPlugin rollup-plugin-typescript2",
|
||||
"build": "vite build",
|
||||
"dev": "vite",
|
||||
"prepare": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"axp-ts": "^1.9.6",
|
||||
"peerDependencies": {
|
||||
"axp-ts": "^1.9.10",
|
||||
"vue": "^3.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.14",
|
||||
"postcss": "^8.4.27",
|
||||
"@vitejs/plugin-vue": "^4.3.4",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"postcss": "^8.4.29",
|
||||
"prettier": "^2.8.8",
|
||||
"rollup": "^3.27.0",
|
||||
"rollup-plugin-sass": "^1.12.20",
|
||||
"rollup-plugin-typescript2": "^0.35.0",
|
||||
"rollup-plugin-vue": "^6.0.0",
|
||||
"sass": "^1.64.2",
|
||||
"sass": "^1.66.1",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"tslib": "^2.6.1"
|
||||
"typescript": "^5.2.2",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-dts": "^3.5.3"
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
import { defineConfig } from 'rollup'
|
||||
import typescript from 'rollup-plugin-typescript2'
|
||||
import vue from 'rollup-plugin-vue'
|
||||
import sass from 'rollup-plugin-sass'
|
||||
|
||||
export default defineConfig({
|
||||
input: 'src/index.ts',
|
||||
output: {
|
||||
format: 'esm',
|
||||
dir: 'dist'
|
||||
},
|
||||
plugins: [typescript(), vue(), sass()],
|
||||
external: ['vue', 'axp-ts'],
|
||||
})
|
342
src/App.vue
Normal file
342
src/App.vue
Normal file
@ -0,0 +1,342 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { cFieldsSchema } from 'axp-ts'
|
||||
import { colors, icons } from '.'
|
||||
import {
|
||||
UiBtn,
|
||||
UiIcon,
|
||||
UiIconVisibility,
|
||||
UiAlert,
|
||||
UiForm,
|
||||
UiFieldText,
|
||||
UiFieldNumber,
|
||||
UiFieldPassword,
|
||||
UiFieldPhone,
|
||||
UiFieldDate,
|
||||
UiFieldTextArea,
|
||||
UiFieldSelect,
|
||||
UiFieldSelectGender,
|
||||
UiFieldCheckbox,
|
||||
UiFieldFile,
|
||||
UiTable,
|
||||
UiCard,
|
||||
UiPickerDays
|
||||
} from './components'
|
||||
|
||||
// Test fields.
|
||||
const fieldTextValue = ref('Text field')
|
||||
const fieldTextError = ref('Error message')
|
||||
const fieldNumberValue = ref(new Date().getDay())
|
||||
|
||||
// Test phone number.
|
||||
const testPhoneNumber = ref(996919353)
|
||||
const testPhoneNumberError = ref('')
|
||||
const testPhoneNumberSchema = cFieldsSchema.shape.phone
|
||||
|
||||
const testHandler = () => {
|
||||
try {
|
||||
testPhoneNumberError.value = ''
|
||||
testPhoneNumberSchema.parse(testPhoneNumber.value)
|
||||
} catch (e: any) {
|
||||
testPhoneNumberError.value = 'Number phone not valid'
|
||||
}
|
||||
}
|
||||
|
||||
// Test checkbox.
|
||||
const testCheckboxValue = ref(true)
|
||||
const testCheckboxError = ref('Error checkbox')
|
||||
|
||||
// Days.
|
||||
const days = ref([1, 3, 5])
|
||||
|
||||
// File.
|
||||
const testFileValue = ref<FileList | undefined>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="layout">
|
||||
<header class="header">
|
||||
<div class="container">
|
||||
<h1 class="page-title">AXP-UI My helper ui lib</h1>
|
||||
</div>
|
||||
</header>
|
||||
<main class="main">
|
||||
<div class="container">
|
||||
<div class="components">
|
||||
<h2 class="title">Components UI:</h2>
|
||||
|
||||
<div class="item btns">
|
||||
<div class="item-title">Buttons</div>
|
||||
<div class="item-content flex">
|
||||
<ui-btn
|
||||
v-for="item in colors"
|
||||
class="mr-2 mb-2"
|
||||
:color="item"
|
||||
:label="item"
|
||||
/>
|
||||
<ui-btn label="Disabled" class="mr-2 mb-2" disabled />
|
||||
<ui-btn label="Icon" icon="edit" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item fields">
|
||||
<div class="item-title">Input fields</div>
|
||||
<div class="item-content">
|
||||
<ui-field-text
|
||||
label="Text"
|
||||
v-model="fieldTextValue"
|
||||
:description="'Description field: ' + fieldTextValue"
|
||||
/>
|
||||
<ui-field-text label="Placeholder" placeholder="Search..." />
|
||||
<ui-field-text
|
||||
model-value="Disabled text field"
|
||||
disabled
|
||||
/>
|
||||
<ui-field-text label="Error" v-model:error="fieldTextError" />
|
||||
|
||||
<ui-field-number
|
||||
label="Номер"
|
||||
v-model="fieldNumberValue"
|
||||
:description="'Value field: ' + fieldNumberValue"
|
||||
v-model:error="fieldTextError"
|
||||
/>
|
||||
|
||||
<ui-field-password label="Пароль" v-model:error="fieldTextError" />
|
||||
|
||||
<ui-field-phone
|
||||
label="Телефон"
|
||||
v-model="testPhoneNumber"
|
||||
v-model:error="testPhoneNumberError"
|
||||
:description="'Value phone number ' + testPhoneNumber"
|
||||
/>
|
||||
<ui-btn
|
||||
label="Valid phone"
|
||||
color="primary"
|
||||
@click="testHandler"
|
||||
class="mb-4"
|
||||
/>
|
||||
|
||||
<ui-field-date
|
||||
label="Дата"
|
||||
:modelValue="new Date()"
|
||||
v-model:error="fieldTextError"
|
||||
/>
|
||||
|
||||
<ui-field-text-area
|
||||
label="Текстовая область"
|
||||
v-model="fieldTextValue"
|
||||
:description="'Text area value: ' + fieldTextValue"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item fields">
|
||||
<div class="item-title">Выподающие списки</div>
|
||||
<div class="item-content">
|
||||
<ui-field-select-gender label="Выбор пола" />
|
||||
<ui-field-select
|
||||
label="Заблокирован"
|
||||
:modelValue="1"
|
||||
:options="[
|
||||
{ text: 'Выбор 1', value: 1 },
|
||||
{ text: 'Выбор 2', value: 2 }
|
||||
]"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item checkbox">
|
||||
<div class="item-title">Чекбоксы</div>
|
||||
<div class="item-content">
|
||||
<ui-field-checkbox
|
||||
label="Выбрать 1"
|
||||
v-model="testCheckboxValue"
|
||||
:description="'Value checkbox: ' + testCheckboxValue"
|
||||
/>
|
||||
<ui-field-checkbox
|
||||
label="Выбрать 2"
|
||||
:modelValue="true"
|
||||
v-model:error="testCheckboxError"
|
||||
/>
|
||||
<ui-field-checkbox label="Выбрать 3" disabled />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item icons">
|
||||
<div class="item-title">Иконки</div>
|
||||
<div class="item-content">
|
||||
<div class="grid grid-cols-4 lg:grid-cols-8 gap-4">
|
||||
<div
|
||||
class="flex flex-col items-center"
|
||||
v-for="item of Object.keys(icons)"
|
||||
>
|
||||
<ui-icon :name="item" class="mb-2" />
|
||||
<div class="mb-4">{{ item }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item alerts">
|
||||
<div class="item-title">Уведомления</div>
|
||||
<div class="item-content">
|
||||
<ui-alert
|
||||
v-for="item in colors"
|
||||
:color="item"
|
||||
:value="'Текстовое уведомление - ' + item"
|
||||
close
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item tables">
|
||||
<div class="item-title">Таблицы</div>
|
||||
<div class="item-content">
|
||||
<ui-table>
|
||||
<thead>
|
||||
<th class="w-0"></th>
|
||||
<th class="w-0">Видимость</th>
|
||||
<th>Название столбца</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<ui-btn icon="edit" />
|
||||
</td>
|
||||
<td>
|
||||
<ui-icon-visibility
|
||||
class="m-auto"
|
||||
:modelValue="false"
|
||||
color
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Quis delectus magnam hic! Corporis blanditiis sequi quae
|
||||
autem quaerat soluta cupiditate ipsa ducimus quidem ipsum
|
||||
dicta, reiciendis excepturi vero tempora in.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ui-btn icon="edit" />
|
||||
</td>
|
||||
<td>
|
||||
<ui-icon-visibility
|
||||
class="m-auto"
|
||||
:modelValue="true"
|
||||
color
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Recusandae asperiores pariatur quasi ad a sunt minus quia
|
||||
omnis! Doloremque sapiente repellat, ea voluptatibus
|
||||
dolor inventore itaque quidem temporibus a asperiores.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ui-btn icon="edit" />
|
||||
</td>
|
||||
<td>
|
||||
<ui-icon-visibility
|
||||
class="m-auto"
|
||||
:modelValue="false"
|
||||
color
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Rem facere ratione commodi odit accusantium iusto, harum
|
||||
asperiores explicabo veniam ipsam placeat recusandae quod
|
||||
quisquam! Pariatur est veniam possimus. Mollitia, culpa.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<ui-btn icon="edit" />
|
||||
</td>
|
||||
<td>
|
||||
<ui-icon-visibility
|
||||
class="m-auto"
|
||||
:modelValue="true"
|
||||
color
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
Lorem ipsum dolor sit, amet consectetur adipisicing elit.
|
||||
Necessitatibus esse autem natus, cum consequuntur
|
||||
aspernatur rerum aliquam voluptatum laboriosam harum
|
||||
fuga, deserunt ad corporis ipsum quod nulla atque.
|
||||
Laborum, beatae.
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</ui-table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item complex">
|
||||
<div class="item-title">Сложные элементы</div>
|
||||
<div class="item-content">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<ui-card title="Карточка">
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
Similique incidunt sunt fugiat, ratione eveniet consequatur
|
||||
soluta cum sit voluptatem expedita adipisci qui,
|
||||
dignissimos quae? Sed, atque omnis! Dolor, iure molestias!
|
||||
</p>
|
||||
<ui-picker-days v-model="days" />
|
||||
<code class="block mt-4">Дни недели: {{ days }}</code>
|
||||
<template v-slot:actions>
|
||||
<ui-btn label="Отмена" />
|
||||
<ui-btn label="Кнопка" color="accent" />
|
||||
</template>
|
||||
</ui-card>
|
||||
<ui-card title="Картачка с формой">
|
||||
<ui-form>
|
||||
<ui-field-text label="Текстовое поле" />
|
||||
<ui-field-date label="Дата" />
|
||||
<ui-field-file
|
||||
v-model="testFileValue"
|
||||
:description="'Count files: ' + testFileValue?.length"
|
||||
multiple
|
||||
/>
|
||||
</ui-form>
|
||||
</ui-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="sass">
|
||||
@import './style/tailwind.sass'
|
||||
@import './style/common.sass'
|
||||
@import './style/theme.sass'
|
||||
|
||||
.header
|
||||
@apply py-8 border-b
|
||||
.page-title
|
||||
@apply text-primary
|
||||
|
||||
.main
|
||||
@apply py-4
|
||||
.components
|
||||
.title
|
||||
@apply mb-6
|
||||
.item
|
||||
@apply mb-8
|
||||
&-title
|
||||
@apply text-lg font-bold mb-4
|
||||
@apply text-primary
|
||||
&.fields
|
||||
.ui-field:not(:last-child)
|
||||
@apply mb-4
|
||||
</style>
|
@ -1,14 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
<script lang="ts">
|
||||
import type { TColor } from '../colors'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{
|
||||
export type TUiAlertProps = {
|
||||
color?: TColor
|
||||
value?: string
|
||||
close?: boolean
|
||||
}>()
|
||||
}
|
||||
|
||||
const emit = defineEmits<{ (e: 'close'): void }>()
|
||||
export type TUiAlertEmits = {
|
||||
(e: 'close'): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiIcon from './Icon.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiAlertProps>()
|
||||
|
||||
// Emit.
|
||||
const emit = defineEmits<TUiAlertEmits>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,26 +1,52 @@
|
||||
<script setup lang="ts">
|
||||
<script lang="ts">
|
||||
import type { TColor } from '../colors'
|
||||
import type { TUiIcon } from '../icons'
|
||||
|
||||
import UiIcon from './Icon.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{
|
||||
export type TUiBtnProps = {
|
||||
label?: string
|
||||
type?: 'button' | 'submit'
|
||||
color?: TColor
|
||||
icon?: TUiIcon
|
||||
to?: string
|
||||
}>()
|
||||
}
|
||||
|
||||
export type TUiBtnEmits = {
|
||||
(e: 'click', v: PointerEvent): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiIcon from './Icon.vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiBtnProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<TUiBtnEmits>()
|
||||
|
||||
// Handlers.
|
||||
const clickHandler = (e: PointerEvent) => emit('click', e)
|
||||
|
||||
// Computed.
|
||||
const cssClass = computed(() => {
|
||||
let obj: any = {
|
||||
'ui-btn': true,
|
||||
'ui-btn-icon': props.icon
|
||||
}
|
||||
|
||||
if (props.color) obj[props.color] = true
|
||||
return obj
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
class="ui-btn"
|
||||
:is="props.to ? 'router-link' : 'button'"
|
||||
:to="props.to"
|
||||
:class="props.color"
|
||||
:type="props.type"
|
||||
@click="clickHandler"
|
||||
:class="cssClass"
|
||||
>
|
||||
<ui-icon v-if="props.icon" :name="props.icon" />
|
||||
<div v-if="props.label" class="label">{{ props.label }}</div>
|
||||
|
@ -1,7 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
<script lang="ts">
|
||||
export type TUiCardProps = {
|
||||
title?: string
|
||||
}>()
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<TUiCardProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,32 +1,43 @@
|
||||
<script lang="ts">
|
||||
export type TUiDialogProps = {
|
||||
title?: string
|
||||
open?: boolean
|
||||
close?: boolean
|
||||
}
|
||||
|
||||
export type TUiDialogEmits = {
|
||||
(e: 'update:open', v: boolean): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import UiIcon from './Icon.vue'
|
||||
|
||||
const props = defineProps({
|
||||
open: { type: Boolean, default: false },
|
||||
close: { type: Boolean, default: false },
|
||||
title: { type: String }
|
||||
})
|
||||
// Props.
|
||||
const props = defineProps<TUiDialogProps>()
|
||||
|
||||
const emit = defineEmits(['update:open'])
|
||||
// Emits.
|
||||
const emit = defineEmits<TUiDialogEmits>()
|
||||
|
||||
// Init data.
|
||||
const dialogState = ref(props.open)
|
||||
|
||||
// Methods.
|
||||
const closeDialog = () => {
|
||||
dialogState.value = false
|
||||
emit('update:open', false)
|
||||
}
|
||||
|
||||
// Handlers.
|
||||
const clickWrapperHandler = (e: MouseEvent) => {
|
||||
if (e.target instanceof Element) {
|
||||
if (e.target.classList.contains('ui-dialog')) closeDialog()
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.open,
|
||||
val => (dialogState.value = val)
|
||||
)
|
||||
// Etc.
|
||||
watch(() => props.open, val => (dialogState.value = val))
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -34,7 +45,7 @@ watch(
|
||||
<div class="ui-dialog-window">
|
||||
<div class="ui-dialog-window-header" v-if="props.title">
|
||||
<h4>{{ title }}</h4>
|
||||
<ui-icon name="close" @click="closeDialog" />
|
||||
<ui-icon name="close" @click="closeDialog" class="ui-icon-close" />
|
||||
</div>
|
||||
<div v-if="$slots.default" class="ui-dialog-window-content">
|
||||
<slot name="default" />
|
||||
|
@ -1,95 +0,0 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
modelValue?: any
|
||||
label?: string
|
||||
type?: 'text' | 'number' | 'date' | 'password' | 'checkbox'
|
||||
error?: string
|
||||
readonly?: boolean
|
||||
disabled?: boolean
|
||||
placeholder?: string
|
||||
tag?: 'input' | 'textarea' | 'select'
|
||||
checked?: boolean
|
||||
options?: { text: string, value: any }[]
|
||||
multiple?: boolean
|
||||
}>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<{
|
||||
(e: 'input', v: any): void
|
||||
(e: 'update:modelValue', v: any): void
|
||||
(e: 'update:error'): void
|
||||
}>()
|
||||
|
||||
// Handlers.
|
||||
const inputHandler = (val: any) => {
|
||||
emit('input', val)
|
||||
emit('update:error')
|
||||
|
||||
if (val?.target?.value) {
|
||||
let value: any = val.target.value
|
||||
|
||||
try {
|
||||
switch (props.type) {
|
||||
case 'number':
|
||||
value = Number(value)
|
||||
break
|
||||
case 'date':
|
||||
value = new Date(value)
|
||||
break
|
||||
case 'text':
|
||||
case 'password':
|
||||
case 'checkbox':
|
||||
value = String(value)
|
||||
break
|
||||
}
|
||||
} catch (ex) {}
|
||||
|
||||
emit('update:modelValue', value)
|
||||
} else {
|
||||
emit('update:modelValue', undefined)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="{ 'ui-field': true, error: props.error, disabled: props.disabled }"
|
||||
>
|
||||
<div v-if="props.label" class="label">{{ props.label }}</div>
|
||||
<input
|
||||
v-if="!tag || tag === 'input'"
|
||||
class="input"
|
||||
:type="props.type"
|
||||
:value="props.modelValue"
|
||||
:readonly="props.readonly"
|
||||
:disabled="props.disabled"
|
||||
:checked="checked"
|
||||
:placeholder="props.placeholder"
|
||||
@input="inputHandler"
|
||||
/>
|
||||
<textarea
|
||||
v-if="tag === 'textarea'"
|
||||
class="input"
|
||||
:value="props.modelValue"
|
||||
:readonly="props.readonly"
|
||||
:disabled="props.disabled"
|
||||
:placeholder="props.placeholder"
|
||||
@input="inputHandler"
|
||||
/>
|
||||
<select
|
||||
v-if="tag === 'select'"
|
||||
class="input"
|
||||
:value="props.modelValue"
|
||||
:readonly="props.readonly"
|
||||
:disabled="props.disabled"
|
||||
:placeholder="props.placeholder"
|
||||
:multiple="props.multiple"
|
||||
@input="inputHandler"
|
||||
>
|
||||
<option v-for="item in props.options" :value="item.value">
|
||||
{{ item.text }}
|
||||
</option>
|
||||
</select>
|
||||
<div v-if="props.error" class="message">{{ props.error }}</div>
|
||||
</div>
|
||||
</template>
|
@ -1,31 +1,51 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFiledWrapperProps } from './FieldWrapper.vue'
|
||||
|
||||
export type TUiFieldCheckboxProps = TUiFiledWrapperProps & {
|
||||
modelValue?: boolean
|
||||
}
|
||||
|
||||
export type TUiFieldCheckboxEmits = {
|
||||
(e: 'input', v: Event): void
|
||||
(e: 'update:model-value', v?: boolean): void
|
||||
(e: 'update:error', v?: string): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiField from './Field.vue'
|
||||
import { computed } from 'vue'
|
||||
import UiFieldWrapper from './FieldWrapper.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{
|
||||
modelValue?: boolean
|
||||
disabled?: boolean
|
||||
readonly?: boolean
|
||||
}>()
|
||||
const props = defineProps<TUiFieldCheckboxProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', v?: boolean): void }>()
|
||||
|
||||
// Value.
|
||||
const value = computed(() => props.modelValue)
|
||||
const emit = defineEmits<TUiFieldCheckboxEmits>()
|
||||
|
||||
// Handlers.
|
||||
const updateHandler = () => emit('update:modelValue', !props.modelValue)
|
||||
const inputHandler = (val: Event) => {
|
||||
emit('input', val)
|
||||
emit('update:error')
|
||||
|
||||
if (val.target instanceof HTMLInputElement) {
|
||||
emit('update:model-value', !props.modelValue)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field
|
||||
type="checkbox"
|
||||
class="ui-field-checkbox"
|
||||
:checked="value"
|
||||
<ui-field-wrapper
|
||||
:label="props.label"
|
||||
:error="props.error"
|
||||
:disabled="props.disabled"
|
||||
:readonly="props.readonly"
|
||||
@input="updateHandler"
|
||||
:description="props.description"
|
||||
class="ui-field-checkbox"
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="props.modelValue"
|
||||
:disabled="props.disabled || props.readonly"
|
||||
@input="inputHandler"
|
||||
/>
|
||||
</ui-field-wrapper>
|
||||
</template>
|
||||
|
@ -1,32 +1,39 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFieldInputProps, TUiFieldInputEmits } from './FieldInput.vue'
|
||||
|
||||
export type TUiFieldDateProps = TUiFieldInputProps<Date>
|
||||
export type TUiFieldDateEmits = TUiFieldInputEmits
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { cFieldsSchema, getDateCommonFormat } from 'axp-ts'
|
||||
import UiFieldInput from './FieldInput.vue'
|
||||
|
||||
import UiField from './Field.vue'
|
||||
// Props.
|
||||
const props = defineProps<TUiFieldDateProps>()
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: Date
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', v?: Date): void }>()
|
||||
// Emits.
|
||||
const emit = defineEmits<TUiFieldDateEmits>()
|
||||
|
||||
// Etc.
|
||||
const valueStr = computed({
|
||||
get: () => {
|
||||
try {
|
||||
const value = cFieldsSchema.shape.date.parse(props.modelValue)
|
||||
const format = getDateCommonFormat(value)
|
||||
return format
|
||||
return getDateCommonFormat(value)
|
||||
} catch (e) { }
|
||||
},
|
||||
set: (val) => {
|
||||
set: val => {
|
||||
emit('update:error')
|
||||
try {
|
||||
const value = cFieldsSchema.shape.date.parse(val)
|
||||
emit('update:modelValue', value)
|
||||
emit('update:model-value', value)
|
||||
} catch (e) { }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field type="date" class="ui-field-date" v-model="valueStr" />
|
||||
<ui-field-input :="{ ...props, ...$attrs }" v-model="valueStr" type="date" />
|
||||
</template>
|
||||
|
57
src/components/FieldFile.vue
Normal file
57
src/components/FieldFile.vue
Normal file
@ -0,0 +1,57 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFiledWrapperProps } from './FieldWrapper.vue'
|
||||
|
||||
type TModelValue = FileList
|
||||
|
||||
export type TUiFieldFileProps = TUiFiledWrapperProps & {
|
||||
modelValue?: TModelValue
|
||||
multiple?: boolean
|
||||
accept?: string
|
||||
}
|
||||
|
||||
export type TUiFieldFileEmits = {
|
||||
(e: 'input', v?: Event): void
|
||||
(e: 'update:model-value', v?: TModelValue): void
|
||||
(e: 'update:error', v?: string): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiFieldWrapper from './FieldWrapper.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiFieldFileProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<TUiFieldFileEmits>()
|
||||
|
||||
// Handlers.
|
||||
const inputHandler = (e: Event) => {
|
||||
emit('input', e)
|
||||
emit('update:error')
|
||||
|
||||
if (e.target instanceof HTMLInputElement && e.target.files) {
|
||||
emit('update:model-value', e.target.files)
|
||||
} else {
|
||||
emit('update:model-value')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field-wrapper
|
||||
:label="props.label"
|
||||
:error="props.error"
|
||||
:disabled="props.disabled"
|
||||
:readonly="props.readonly"
|
||||
:description="props.description"
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
:multiple="props.multiple"
|
||||
:disabled="props.disabled || props.readonly"
|
||||
:accept="props.accept"
|
||||
@input="inputHandler"
|
||||
/>
|
||||
</ui-field-wrapper>
|
||||
</template>
|
64
src/components/FieldInput.vue
Normal file
64
src/components/FieldInput.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFiledWrapperProps } from './FieldWrapper.vue'
|
||||
|
||||
export type TUiFieldInputProps<T extends string | number | Date> =
|
||||
TUiFiledWrapperProps & {
|
||||
type?: 'text' | 'number' | 'password' | 'date' | 'checkbox'
|
||||
modelValue?: T
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
export type TUiFieldInputEmits = {
|
||||
(e: 'input', v: Event): void
|
||||
(e: 'update:model-value', v?: string | number | Date): void
|
||||
(e: 'update:error', v?: string): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiFieldWrapper from './FieldWrapper.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiFieldInputProps<any>>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<TUiFieldInputEmits>()
|
||||
|
||||
// Handlers.
|
||||
const inputHandler = (val: Event) => {
|
||||
emit('input', val)
|
||||
emit('update:error')
|
||||
|
||||
if (val.target instanceof HTMLInputElement) {
|
||||
const { value } = val.target
|
||||
switch (props.type) {
|
||||
case 'number':
|
||||
emit('update:model-value', Number(value))
|
||||
break
|
||||
default:
|
||||
emit('update:model-value', String(value))
|
||||
}
|
||||
} else {
|
||||
emit('update:model-value', undefined)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field-wrapper
|
||||
:label="props.label"
|
||||
:error="props.error"
|
||||
:disabled="props.disabled"
|
||||
:readonly="props.readonly"
|
||||
:description="props.description"
|
||||
>
|
||||
<input
|
||||
:type="props.type"
|
||||
:value="props.modelValue"
|
||||
:placeholder="props.placeholder"
|
||||
:disabled="props.disabled"
|
||||
:readonly="props.readonly"
|
||||
@input="inputHandler"
|
||||
/>
|
||||
</ui-field-wrapper>
|
||||
</template>
|
@ -1,7 +1,16 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFieldInputProps } from './FieldInput.vue'
|
||||
|
||||
export type TUiFieldNumberProps = TUiFieldInputProps<number>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiField from './Field.vue'
|
||||
import UiFieldInput from './FieldInput.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiFieldNumberProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field type="number" class="ui-field-number" />
|
||||
<ui-field-input :="{ ...props, ...$attrs }" type="number" />
|
||||
</template>
|
||||
|
@ -1,7 +1,16 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFieldInputProps } from './FieldInput.vue'
|
||||
|
||||
export type TFieldPasswordProps = TUiFieldInputProps<string>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiField from './Field.vue'
|
||||
import UiFieldInput from './FieldInput.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TFieldPasswordProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field type="password" class="ui-field-password" />
|
||||
<ui-field-input :="{ ...props, ...$attrs }" type="password" />
|
||||
</template>
|
||||
|
@ -1,22 +1,32 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFieldInputProps, TUiFieldInputEmits } from './FieldInput.vue'
|
||||
|
||||
export type TUiFieldPhoneProps = TUiFieldInputProps<number>
|
||||
export type TUiFieldPhoneEmits = TUiFieldInputEmits
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { getPhoneNumberFormat, getPhoneNumberValue } from 'axp-ts'
|
||||
|
||||
import UiField from './Field.vue'
|
||||
import UiFieldInput from './FieldInput.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{ modelValue?: number }>()
|
||||
const props = defineProps<TUiFieldPhoneProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', v?: number): void }>()
|
||||
const emit = defineEmits<TUiFieldPhoneEmits>()
|
||||
|
||||
// Value string.
|
||||
const valueStr = computed({
|
||||
get: () => getPhoneNumberFormat(props.modelValue),
|
||||
set: val => emit('update:modelValue', getPhoneNumberValue(val))
|
||||
set: val => {
|
||||
emit('update:error')
|
||||
emit('update:model-value', getPhoneNumberValue(val))
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field v-model="valueStr" class="ui-field-phone" />
|
||||
<ui-field-input :="{ ...props, ...$attrs }" v-model="valueStr" />
|
||||
</template>
|
||||
|
@ -1,27 +1,59 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import UiField from './Field.vue'
|
||||
<script lang="ts">
|
||||
import type { TUiFiledWrapperProps } from './FieldWrapper.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue?: string | string[] | number | number[],
|
||||
export type TUiFieldSelectProps = TUiFiledWrapperProps & {
|
||||
modelValue?: string | string[] | number | number[]
|
||||
options?: { text: string; value: string | number }[]
|
||||
multiple?: boolean
|
||||
options: { text: string, value: any }[]
|
||||
}>()
|
||||
}
|
||||
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', v?: any): void }>()
|
||||
export type TUiFieldSelectEmits = {
|
||||
(e: 'input', v: Event): void
|
||||
(e: 'update:model-value', v?: string | string[] | number | number[]): void
|
||||
(e: 'update:error', v?: string): void
|
||||
}
|
||||
</script>
|
||||
|
||||
const displayValue = computed({
|
||||
get: () => props.modelValue,
|
||||
set: (val) => emit('update:modelValue', val)
|
||||
})
|
||||
<script setup lang="ts">
|
||||
import UiFieldWrapper from './FieldWrapper.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiFieldSelectProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<TUiFieldSelectEmits>()
|
||||
|
||||
// Handlers.
|
||||
const inputHandler = (val: Event) => {
|
||||
emit('input', val)
|
||||
emit('update:error')
|
||||
|
||||
if (val.target instanceof HTMLSelectElement) {
|
||||
emit('update:model-value', val.target.value)
|
||||
} else {
|
||||
emit('update:model-value')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field
|
||||
tag="select"
|
||||
<ui-field-wrapper
|
||||
:label="props.label"
|
||||
:error="props.error"
|
||||
:disabled="props.disabled"
|
||||
:readonly="props.readonly"
|
||||
:description="props.description"
|
||||
class="ui-field-select"
|
||||
:options="props.options"
|
||||
>
|
||||
<select
|
||||
:value="props.modelValue"
|
||||
:multiple="props.multiple"
|
||||
v-model="displayValue"
|
||||
/>
|
||||
:disabled="props.disabled || props.readonly"
|
||||
@input="inputHandler"
|
||||
>
|
||||
<option v-for="item in props.options" :value="item.value">
|
||||
{{ item.text }}
|
||||
</option>
|
||||
</select>
|
||||
</ui-field-wrapper>
|
||||
</template>
|
||||
|
@ -15,5 +15,5 @@ const options: { text: string, value: TGender }[] = [
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field-select class="ui-field-select-gender" :options="options" />
|
||||
<ui-field-select :options="options" />
|
||||
</template>
|
||||
|
@ -1,7 +1,16 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFieldInputProps } from './FieldInput.vue'
|
||||
|
||||
export type TUiFieldText = TUiFieldInputProps<string>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiField from './Field.vue'
|
||||
import UiFieldInput from './FieldInput.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiFieldText>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field class="ui-field-text" />
|
||||
<ui-field-input :="{ ...props, ...$attrs }" type="text" />
|
||||
</template>
|
||||
|
@ -1,7 +1,50 @@
|
||||
<script lang="ts">
|
||||
import type { TUiFiledWrapperProps } from './FieldWrapper.vue'
|
||||
|
||||
export type TUiFieldTextAreaProps = TUiFiledWrapperProps & {
|
||||
modelValue?: string
|
||||
}
|
||||
|
||||
export type TUiFieldTextAreaEmits = {
|
||||
(e: 'input', v: Event): void
|
||||
(e: 'update:model-value', v?: string | number | Date): void
|
||||
(e: 'update:error', v?: string): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiField from './Field.vue'
|
||||
import UiFieldWrapper from './FieldWrapper.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiFieldTextAreaProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<TUiFieldTextAreaEmits>()
|
||||
|
||||
// Handlers.
|
||||
const inputHandler = (val: Event) => {
|
||||
emit('input', val)
|
||||
emit('update:error')
|
||||
|
||||
if (val.target instanceof HTMLTextAreaElement) {
|
||||
emit('update:model-value', val.target.value)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ui-field tag="textarea" class="ui-field-textarea" />
|
||||
<ui-field-wrapper
|
||||
:label="props.label"
|
||||
:error="props.error"
|
||||
:disabled="props.disabled"
|
||||
:readonly="props.readonly"
|
||||
:description="props.description"
|
||||
class="ui-field-textarea"
|
||||
>
|
||||
<textarea
|
||||
:value="props.modelValue"
|
||||
:disabled="props.disabled || props.readonly"
|
||||
@input="inputHandler"
|
||||
/>
|
||||
</ui-field-wrapper>
|
||||
</template>
|
||||
|
36
src/components/FieldWrapper.vue
Normal file
36
src/components/FieldWrapper.vue
Normal file
@ -0,0 +1,36 @@
|
||||
<script lang="ts">
|
||||
export type TUiFiledWrapperProps = {
|
||||
label?: string
|
||||
error?: string
|
||||
disabled?: boolean
|
||||
readonly?: boolean
|
||||
description?: string
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
// Props.
|
||||
const props = defineProps<TUiFiledWrapperProps>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
:class="{
|
||||
'ui-field': true,
|
||||
error: props.error,
|
||||
disabled: props.disabled,
|
||||
readonly: props.readonly
|
||||
}"
|
||||
>
|
||||
<div class="ui-field-wrap">
|
||||
<div v-if="props.label" class="label">{{ props.label }}</div>
|
||||
<div class="input">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="props.description" class="description">
|
||||
{{ props.description }}
|
||||
</div>
|
||||
<div v-if="props.error" class="message">{{ props.error }}</div>
|
||||
</div>
|
||||
</template>
|
@ -1,16 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import type { Ref } from 'vue'
|
||||
import type { TNotificationItem, BaseFormModel } from 'axp-ts'
|
||||
<script lang="ts">
|
||||
import type { TNotificationItem, IFormModel } from 'axp-ts'
|
||||
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { colors } from '../colors'
|
||||
|
||||
import UiBtn from './Btn.vue'
|
||||
import UiAlert from './Alert.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{
|
||||
modelValue?: BaseFormModel<any>
|
||||
export type TUiFormProps<T = any> = {
|
||||
modelValue?: IFormModel<T>
|
||||
title?: string
|
||||
noTitle?: boolean
|
||||
messages?: TNotificationItem[]
|
||||
@ -18,16 +10,30 @@ const props = defineProps<{
|
||||
disabled?: boolean
|
||||
load?: boolean
|
||||
showAll?: boolean
|
||||
fn?: (obj?: any) => Promise<any>
|
||||
}>()
|
||||
fn?: (obj?: T) => Promise<T>
|
||||
}
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<{
|
||||
(e: 'submit', v?: BaseFormModel<any>): void
|
||||
(e: 'failedValid', v?: BaseFormModel<any>): void
|
||||
export type TUiFormEmits<T = any> = {
|
||||
(e: 'submit', v?: IFormModel<T>): void
|
||||
(e: 'failedValid', v?: IFormModel<T>): void
|
||||
(e: 'update:load', v: boolean): void
|
||||
(e: 'fnCompleted', v?: any): void
|
||||
}>()
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import UiBtn from './Btn.vue'
|
||||
import UiAlert from './Alert.vue'
|
||||
|
||||
import { colors } from '../colors'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiFormProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<TUiFormEmits>()
|
||||
|
||||
// Controls.
|
||||
const ctrls = computed(() => {
|
||||
@ -35,7 +41,6 @@ const ctrls = computed(() => {
|
||||
if (props.showAll) {
|
||||
return props.modelValue.ctrls
|
||||
} else {
|
||||
// @ts-ignore
|
||||
return props.modelValue.ctrls.filter(e => !e.hidden)
|
||||
}
|
||||
}
|
||||
@ -76,7 +81,6 @@ const submitHandler = async () => {
|
||||
if (err.code && err.text)
|
||||
if (
|
||||
props.modelValue &&
|
||||
// @ts-ignore
|
||||
props.modelValue.ctrls.find(e => e.key === err.code)
|
||||
) {
|
||||
props.modelValue.setValidError(err.code, err.text)
|
||||
@ -118,6 +122,9 @@ const getColorMessage = (item: TNotificationItem) => {
|
||||
/>
|
||||
</div>
|
||||
<div class="ui-form-body">
|
||||
<slot v-if="$slots.pre" name="pre" />
|
||||
<slot v-if="$slots.default" name="default" />
|
||||
<template v-else>
|
||||
<component
|
||||
v-if="props.modelValue"
|
||||
v-for="ctrl in ctrls"
|
||||
@ -127,9 +134,11 @@ const getColorMessage = (item: TNotificationItem) => {
|
||||
v-model:error="props.modelValue._errors[ctrl.key]"
|
||||
:readonly="ctrl.readonly"
|
||||
:disabled="load || props.load || props.disabled || ctrl.disabled"
|
||||
:class="'ui-field-' + ctrl.key"
|
||||
:description="ctrl.description"
|
||||
:class="'ui-field-key-' + ctrl.key"
|
||||
/>
|
||||
<slot v-if="$slots.default" name="default" />
|
||||
</template>
|
||||
<slot v-if="$slots.post" name="post" />
|
||||
</div>
|
||||
<div v-if="!props.noActions" class="ui-form-actions">
|
||||
<slot v-if="$slots.actions" name="actions" />
|
||||
|
@ -1,19 +1,21 @@
|
||||
<script setup lang="ts">
|
||||
<script lang="ts">
|
||||
import type { TUiIcon } from '../icons'
|
||||
|
||||
export type TUiIconProps = {
|
||||
name: TUiIcon
|
||||
fill?: boolean
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import { icons } from '../icons'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{
|
||||
name: TUiIcon
|
||||
fill?: boolean
|
||||
}>()
|
||||
const props = defineProps<TUiIconProps>()
|
||||
|
||||
const iconName = computed(() => {
|
||||
// @ts-ignore
|
||||
return icons[props.name]
|
||||
})
|
||||
// Etc.
|
||||
const icon = computed(() => icons[props.name])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -23,7 +25,7 @@ const iconName = computed(() => {
|
||||
:fill="fill ? 'currentColor' : 'none'"
|
||||
stroke="currentColor"
|
||||
stroke-width="1.2"
|
||||
v-html="iconName"
|
||||
v-html="icon"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
|
@ -1,15 +1,23 @@
|
||||
<script lang="ts">
|
||||
export type TUiIconVisibilityProps = {
|
||||
modelValue?: boolean,
|
||||
color?: boolean,
|
||||
cursor?: boolean
|
||||
}
|
||||
|
||||
export type TUiIconVisibilityEmits = {
|
||||
(e: 'update:modelValue', v: boolean): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiIcon from './Icon.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{
|
||||
modelValue?: boolean,
|
||||
color?: boolean,
|
||||
cursor?: boolean
|
||||
}>()
|
||||
const props = defineProps<TUiIconVisibilityProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', v: boolean): void }>()
|
||||
const emit = defineEmits<TUiIconVisibilityEmits>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -1,17 +1,25 @@
|
||||
<script setup lang="ts">
|
||||
import UiFieldCheckbox from './FieldCheckbox.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{
|
||||
<script lang="ts">
|
||||
export type TUiPickerDaysProps = {
|
||||
modelValue?: number[]
|
||||
label?: string
|
||||
error?: string
|
||||
readonly?: boolean
|
||||
disabled?: boolean
|
||||
}>()
|
||||
}
|
||||
|
||||
export type TUiPickerDaysEmits = {
|
||||
(e: 'update:modelValue', v: number[]): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiFieldCheckbox from './FieldCheckbox.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<TUiPickerDaysProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', v: number[]): void }>()
|
||||
const emit = defineEmits<TUiPickerDaysEmits>()
|
||||
|
||||
// Init data.
|
||||
const days = ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс']
|
||||
|
@ -1,17 +1,23 @@
|
||||
<script lang="ts">
|
||||
export type TTheme = 'light' | 'dark'
|
||||
export type TUiThemeName = 'light' | 'dark'
|
||||
|
||||
export type TUiToggleThemeProps = {
|
||||
modelValue?: TUiThemeName
|
||||
}
|
||||
|
||||
export type TUiToggleThemeEmits = {
|
||||
(e: 'update:modelValue', v: TUiThemeName): void
|
||||
}
|
||||
</script>
|
||||
|
||||
<script setup lang="ts">
|
||||
import UiIcon from './Icon.vue'
|
||||
|
||||
// Props.
|
||||
const props = defineProps<{
|
||||
modelValue?: TTheme
|
||||
}>()
|
||||
const props = defineProps<TUiToggleThemeProps>()
|
||||
|
||||
// Emits.
|
||||
const emit = defineEmits<{ (e: 'update:modelValue', v: TTheme): void }>()
|
||||
const emit = defineEmits<TUiToggleThemeEmits>()
|
||||
|
||||
// Handlers.
|
||||
const clickHandler = ({}: PointerEvent) =>
|
||||
|
@ -1,20 +1,65 @@
|
||||
export { default as UiBtn } from './Btn.vue'
|
||||
export { default as UiAlert } from './Alert.vue'
|
||||
export { default as UiField } from './Field.vue'
|
||||
export { default as UiFieldText } from './FieldText.vue'
|
||||
export { default as UiFieldTextArea } from './FieldTextArea.vue'
|
||||
export { default as UiFieldPassword } from './FieldPassword.vue'
|
||||
export { default as UiFieldNumber } from './FieldNumber.vue'
|
||||
export { default as UiFieldPhone } from './FieldPhone.vue'
|
||||
export { default as UiFieldDate } from './FieldDate.vue'
|
||||
export { default as UiFieldCheckbox } from './FieldCheckbox.vue'
|
||||
export { default as UiFieldSelect } from './FieldSelect.vue'
|
||||
export { default as UiFieldSelectGender } from './FieldSelectGender.vue'
|
||||
export { default as UiPickerDays } from './PickerDays.vue'
|
||||
export { default as UiIcon } from './Icon.vue'
|
||||
export { default as UiIconVisibility } from './IconVisibility.vue'
|
||||
export { default as UiForm } from './Form.vue'
|
||||
export * from './Alert.vue'
|
||||
|
||||
export { default as UiBtn } from './Btn.vue'
|
||||
export * from './Btn.vue'
|
||||
|
||||
export { default as UiCard } from './Card.vue'
|
||||
export { default as UiTable } from './Table.vue'
|
||||
export * from './Card.vue'
|
||||
|
||||
export { default as UiDialog } from './Dialog.vue'
|
||||
export * from './Dialog.vue'
|
||||
|
||||
export { default as UiIcon } from './Icon.vue'
|
||||
export * from './Icon.vue'
|
||||
|
||||
export { default as UiIconVisibility } from './IconVisibility.vue'
|
||||
export * from './IconVisibility.vue'
|
||||
|
||||
export { default as UiTable } from './Table.vue'
|
||||
export * from './Table.vue'
|
||||
|
||||
export { default as UiToggleTheme } from './ToggleTheme.vue'
|
||||
export * from './ToggleTheme.vue'
|
||||
|
||||
export { default as UiFieldWrapper } from './FieldWrapper.vue'
|
||||
export * from './FieldWrapper.vue'
|
||||
|
||||
export { default as UiFieldInput } from './FieldInput.vue'
|
||||
export * from './FieldInput.vue'
|
||||
|
||||
export { default as UiFieldText } from './FieldText.vue'
|
||||
export * from './FieldText.vue'
|
||||
|
||||
export { default as UiFieldNumber } from './FieldNumber.vue'
|
||||
export * from './FieldNumber.vue'
|
||||
|
||||
export { default as UiFieldPassword } from './FieldPassword.vue'
|
||||
export * from './FieldPassword.vue'
|
||||
|
||||
export { default as UiFieldPhone } from './FieldPhone.vue'
|
||||
export * from './FieldPhone.vue'
|
||||
|
||||
export { default as UiFieldDate } from './FieldDate.vue'
|
||||
export * from './FieldDate.vue'
|
||||
|
||||
export { default as UiFieldTextArea } from './FieldTextArea.vue'
|
||||
export * from './FieldTextArea.vue'
|
||||
|
||||
export { default as UiFieldFile } from './FieldFile.vue'
|
||||
export * from './FieldFile.vue'
|
||||
|
||||
export { default as UiFieldCheckbox } from './FieldCheckbox.vue'
|
||||
export * from './FieldCheckbox.vue'
|
||||
|
||||
export { default as UiFieldSelect } from './FieldSelect.vue'
|
||||
export * from './FieldSelect.vue'
|
||||
|
||||
export { default as UiFieldSelectGender } from './FieldSelectGender.vue'
|
||||
export * from './FieldSelectGender.vue'
|
||||
|
||||
export { default as UiPickerDays } from './PickerDays.vue'
|
||||
export * from './PickerDays.vue'
|
||||
|
||||
export { default as UiForm } from './Form.vue'
|
||||
export * from './Form.vue'
|
||||
|
@ -83,4 +83,4 @@ export const icons = {
|
||||
`
|
||||
}
|
||||
|
||||
export type TUiIcon = keyof typeof icons
|
||||
export type TIcon = keyof typeof icons
|
||||
|
@ -1,3 +1,7 @@
|
||||
export * from './components'
|
||||
export * from './icons'
|
||||
export * from './colors'
|
||||
|
||||
import './style/tailwind.sass'
|
||||
import './style/common.sass'
|
||||
import './style/theme.sass'
|
||||
|
3
src/main.ts
Normal file
3
src/main.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
createApp(App).mount('#app')
|
@ -27,28 +27,31 @@
|
||||
|
||||
// Ui.
|
||||
.ui
|
||||
&-btn,
|
||||
&-field .input
|
||||
@apply outline-none
|
||||
@apply h-[38px] text-base
|
||||
|
||||
&-btn
|
||||
@apply px-4 border
|
||||
@apply h-[38px] text-base
|
||||
@apply flex justify-center items-center
|
||||
@apply px-2 border
|
||||
> *:not(:last-child)
|
||||
@apply mr-1
|
||||
> .ui-icon:first-child
|
||||
@apply ml-[-5px]
|
||||
@apply mr-2
|
||||
.label
|
||||
@apply text-base font-normal
|
||||
|
||||
&-field
|
||||
&-wrap
|
||||
.label
|
||||
@apply mb-1
|
||||
.input
|
||||
@apply block w-full border px-2 py-2
|
||||
@apply h-[38px] text-base
|
||||
@apply block w-full border
|
||||
> *
|
||||
@apply w-full h-full px-2 py-2 outline-none
|
||||
.description,
|
||||
.message
|
||||
@apply mt-1 text-sm
|
||||
@apply w-full pl-1 mt-1 text-sm
|
||||
|
||||
&-checkbox
|
||||
@apply mb-4
|
||||
.ui-field-wrap
|
||||
@apply flex items-center justify-start
|
||||
.label
|
||||
@apply mb-0
|
||||
@ -59,7 +62,10 @@
|
||||
|
||||
&-textarea
|
||||
.input
|
||||
@apply min-h-[80px]
|
||||
@apply h-auto
|
||||
> *
|
||||
@apply min-h-[94px]
|
||||
@apply leading-5
|
||||
|
||||
&-alert
|
||||
@apply relative border
|
||||
@ -134,8 +140,8 @@
|
||||
@apply flex items-center justify-between py-2 px-3
|
||||
> .title
|
||||
@apply text-lg font-normal
|
||||
.ui-icon
|
||||
@apply w-[30px] h-[30px] p-0 border-0
|
||||
.ui-icon-close
|
||||
@apply w-[30px] h-[30px] p-0 border-0 cursor-pointer
|
||||
&:hover
|
||||
@apply text-dark
|
||||
&-content
|
3
src/style/tailwind.sass
Normal file
3
src/style/tailwind.sass
Normal file
@ -0,0 +1,3 @@
|
||||
@tailwind base
|
||||
@tailwind components
|
||||
@tailwind utilities
|
@ -33,16 +33,19 @@
|
||||
@apply text-white bg-light border-light
|
||||
|
||||
&-field
|
||||
.input
|
||||
.input > *
|
||||
@apply bg-white dark:bg-white/10 text-dark dark:text-white
|
||||
.description
|
||||
@apply text-dark/50
|
||||
&.error
|
||||
.label,
|
||||
.input,
|
||||
.message
|
||||
@apply text-error border-error
|
||||
&:disabled
|
||||
&.disabled
|
||||
@apply text-dark/60
|
||||
.input
|
||||
@apply bg-light/10 text-dark/60
|
||||
@apply bg-light/10
|
||||
&-btn
|
||||
@apply outline-none
|
||||
&:hover:not(:active)
|
||||
@ -51,5 +54,6 @@
|
||||
&-btn,
|
||||
&-alert,
|
||||
&-field .input,
|
||||
&-field .input > *,
|
||||
&-card
|
||||
@apply rounded
|
@ -1,7 +1,7 @@
|
||||
import type { Config } from 'tailwindcss'
|
||||
|
||||
const config: Config = {
|
||||
content: ['./src/components/**/*.vue'],
|
||||
content: ['./src/App.vue', './src/components/**/*.vue'],
|
||||
darkMode: 'class',
|
||||
theme: {
|
||||
extend: {
|
||||
@ -12,7 +12,7 @@ const config: Config = {
|
||||
dark: '#363636',
|
||||
light: '#f1f1f1',
|
||||
|
||||
info: '#2196f3',
|
||||
info: '#00b8ff',
|
||||
warning: '#ff9800',
|
||||
success: '#2dd633',
|
||||
error: '#f00000'
|
||||
|
30
vite.config.ts
Normal file
30
vite.config.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import dts from 'vite-plugin-dts'
|
||||
|
||||
import postcss from 'postcss'
|
||||
|
||||
import autoprefixer from 'autoprefixer'
|
||||
import tailwindcss from 'tailwindcss'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [vue(), dts()],
|
||||
css: {
|
||||
postcss: postcss([autoprefixer(), tailwindcss()])
|
||||
},
|
||||
build: {
|
||||
lib: {
|
||||
entry: 'src/index.ts',
|
||||
name: 'axp-ui',
|
||||
fileName: 'index'
|
||||
},
|
||||
rollupOptions: {
|
||||
external: ['vue'],
|
||||
output: {
|
||||
globals: {
|
||||
vue: 'Vue'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue
Block a user