@indielayer/ui 1.0.0-alpha.0 → 1.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -10
- package/lib/components/avatar/Avatar.vue.d.ts +2 -2
- package/lib/components/badge/Badge.vue.d.ts +2 -2
- package/lib/components/button/Button.vue.d.ts +2 -2
- package/lib/components/button/ButtonGroup.vue.d.ts +2 -2
- package/lib/components/checkbox/Checkbox.vue.d.ts +5 -4
- package/lib/components/drawer/Drawer.vue.d.ts +1 -1
- package/lib/components/icon/Icon.vue.d.ts +2 -2
- package/lib/components/index.d.ts +2 -2
- package/lib/components/input/Input.vue.d.ts +4 -3
- package/lib/components/menu/Menu.vue.d.ts +2 -2
- package/lib/components/menu/MenuItem.vue.d.ts +3 -3
- package/lib/components/notifications/Notifications.vue.d.ts +2 -2
- package/lib/components/pagination/Pagination.vue.d.ts +3 -2
- package/lib/components/pagination/PaginationItem.vue.d.ts +2 -2
- package/lib/components/radio/Radio.vue.d.ts +3 -3
- package/lib/components/select/Select.vue.d.ts +4 -3
- package/lib/components/slider/Slider.vue.d.ts +3 -3
- package/lib/components/spacer/Spacer.vue.d.ts +1 -1
- package/lib/components/spinner/Spinner.vue.d.ts +2 -2
- package/lib/components/{tabs → tab}/Tab.vue.d.ts +2 -2
- package/lib/components/{tabs/Tabs.vue.d.ts → tab/TabGroup.vue.d.ts} +0 -0
- package/lib/components/table/TableBody.vue.d.ts +1 -1
- package/lib/components/table/TableHead.vue.d.ts +1 -1
- package/lib/components/tag/Tag.vue.d.ts +2 -2
- package/lib/components/textarea/Textarea.vue.d.ts +4 -12
- package/lib/components/toggle/Toggle.vue.d.ts +3 -3
- package/lib/composables/colors.d.ts +1 -1
- package/lib/composables/css.d.ts +4 -4
- package/lib/composables/keys.d.ts +1 -0
- package/lib/create.d.ts +11 -0
- package/lib/index.cjs.js +2 -2
- package/lib/index.d.ts +2 -0
- package/lib/index.es.js +183 -107
- package/lib/install.d.ts +4 -6
- package/lib/nuxt.js +15 -16
- package/lib/nuxt.plugin.js +8 -0
- package/lib/style.css +1 -1
- package/lib/version.d.ts +1 -1
- package/package.json +19 -15
- package/src/components/alert/Alert.vue +164 -0
- package/src/components/avatar/Avatar.vue +137 -0
- package/src/components/badge/Badge.vue +107 -0
- package/src/components/breadcrumbs/Breadcrumbs.vue +60 -0
- package/src/components/button/Button.vue +433 -0
- package/src/components/button/ButtonGroup.vue +73 -0
- package/src/components/card/Card.vue +25 -0
- package/src/components/checkbox/Checkbox.vue +205 -0
- package/src/components/collapse/Collapse.vue +181 -0
- package/src/components/container/Container.vue +23 -0
- package/src/components/divider/Divider.vue +52 -0
- package/src/components/drawer/Drawer.vue +244 -0
- package/src/components/form/Form.vue +111 -0
- package/src/components/icon/Icon.vue +56 -0
- package/src/components/image/Image.vue +36 -0
- package/src/components/index.ts +45 -0
- package/src/components/input/Input.vue +198 -0
- package/src/components/link/Link.vue +110 -0
- package/src/components/menu/Menu.vue +118 -0
- package/src/components/menu/MenuItem.vue +277 -0
- package/src/components/modal/Modal.vue +175 -0
- package/src/components/notifications/Notifications.vue +318 -0
- package/src/components/pagination/Pagination.vue +181 -0
- package/src/components/pagination/PaginationItem.vue +58 -0
- package/src/components/popover/Popover.vue +194 -0
- package/src/components/popover/PopoverContainer.vue +23 -0
- package/src/components/progress/Progress.vue +86 -0
- package/src/components/radio/Radio.vue +220 -0
- package/src/components/scroll/Scroll.vue +143 -0
- package/src/components/select/Select.vue +408 -0
- package/src/components/skeleton/Skeleton.vue +23 -0
- package/src/components/slider/Slider.vue +240 -0
- package/src/components/spacer/Spacer.vue +11 -0
- package/src/components/spinner/Spinner.vue +45 -0
- package/src/components/tab/Tab.vue +100 -0
- package/src/components/tab/TabGroup.vue +151 -0
- package/src/components/table/Table.vue +172 -0
- package/src/components/table/TableBody.vue +13 -0
- package/src/components/table/TableCell.vue +78 -0
- package/src/components/table/TableHead.vue +15 -0
- package/src/components/table/TableHeader.vue +94 -0
- package/src/components/table/TableRow.vue +43 -0
- package/src/components/tag/Tag.vue +98 -0
- package/src/components/textarea/Textarea.vue +156 -0
- package/src/components/toggle/Toggle.vue +144 -0
- package/src/components/tooltip/Tooltip.vue +26 -0
- package/src/composables/colors-utils.ts +378 -0
- package/src/composables/colors.ts +82 -0
- package/src/composables/common.ts +20 -0
- package/src/composables/css.ts +45 -0
- package/src/composables/index.ts +7 -0
- package/src/composables/inputtable.ts +128 -0
- package/src/composables/interactive.ts +16 -0
- package/src/composables/keys.ts +8 -0
- package/src/composables/notification.ts +10 -0
- package/src/create.ts +36 -0
- package/src/exports/nuxt.js +32 -0
- package/src/exports/nuxt.plugin.js +8 -0
- package/src/exports/tailwind.preset.js +55 -0
- package/src/index.ts +8 -0
- package/src/install.ts +8 -0
- package/src/shims-vue.d.ts +6 -0
- package/src/version.ts +1 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { defineComponent, provide, onMounted, watch, nextTick } from 'vue'
|
|
3
|
+
import { injectFormKey } from '../../composables/keys'
|
|
4
|
+
|
|
5
|
+
export type Form = {
|
|
6
|
+
name: string,
|
|
7
|
+
focus: ()=> void,
|
|
8
|
+
validate: ()=> boolean,
|
|
9
|
+
setError: (val: string)=> void,
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default defineComponent({
|
|
13
|
+
name: 'XForm',
|
|
14
|
+
|
|
15
|
+
inheritAttrs: false,
|
|
16
|
+
|
|
17
|
+
props: {
|
|
18
|
+
autoValidate: {
|
|
19
|
+
type: Boolean,
|
|
20
|
+
default: true,
|
|
21
|
+
},
|
|
22
|
+
autoFocus: {
|
|
23
|
+
type: Boolean,
|
|
24
|
+
default: true,
|
|
25
|
+
},
|
|
26
|
+
disabled: Boolean,
|
|
27
|
+
errors: {
|
|
28
|
+
type: Array,
|
|
29
|
+
default: () => [],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
emits: ['submit'],
|
|
34
|
+
|
|
35
|
+
setup(props, { emit }) {
|
|
36
|
+
const inputs: Form[] = []
|
|
37
|
+
|
|
38
|
+
provide(injectFormKey, {
|
|
39
|
+
registerInput: (name: string, focus: ()=> void, validate: ()=> boolean, setError: (val: string)=> void) => {
|
|
40
|
+
const exists = inputs.find((i) => i.name === name)
|
|
41
|
+
|
|
42
|
+
if (exists) {
|
|
43
|
+
exists.focus = focus
|
|
44
|
+
exists.validate = validate
|
|
45
|
+
exists.setError = setError
|
|
46
|
+
}
|
|
47
|
+
else inputs.push({ name, focus, validate, setError })
|
|
48
|
+
},
|
|
49
|
+
unregisterInput: (name: string) => {
|
|
50
|
+
const index = inputs.findIndex((i) => i.name === name)
|
|
51
|
+
|
|
52
|
+
inputs.splice(index, 1)
|
|
53
|
+
},
|
|
54
|
+
isInsideForm: true,
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
onMounted(() => {
|
|
58
|
+
if (props.autoFocus && inputs && inputs.length > 0) inputs[0].focus()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
watch(() => props.errors, (errors) => {
|
|
62
|
+
nextTick(() => {
|
|
63
|
+
errors.forEach((error: any) => {
|
|
64
|
+
const input = inputs.find((i) => i.name === error.field)
|
|
65
|
+
|
|
66
|
+
if (input) input.setError(error.msg)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const validate = () => {
|
|
72
|
+
let isFormValid = true
|
|
73
|
+
|
|
74
|
+
inputs.forEach((input) => {
|
|
75
|
+
const isInputValid = input.validate()
|
|
76
|
+
|
|
77
|
+
if (!isInputValid && isFormValid) {
|
|
78
|
+
isFormValid = false
|
|
79
|
+
|
|
80
|
+
// focus on input error
|
|
81
|
+
if (input.focus) input.focus()
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
return isFormValid
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const submit = (e: Event) => {
|
|
89
|
+
e.preventDefault()
|
|
90
|
+
e.stopPropagation()
|
|
91
|
+
|
|
92
|
+
const isFormValid = props.autoValidate ? validate() : true
|
|
93
|
+
|
|
94
|
+
emit('submit', isFormValid)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
validate,
|
|
99
|
+
submit,
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
</script>
|
|
104
|
+
|
|
105
|
+
<template>
|
|
106
|
+
<form @submit="submit">
|
|
107
|
+
<fieldset :disabled="disabled">
|
|
108
|
+
<slot></slot>
|
|
109
|
+
</fieldset>
|
|
110
|
+
</form>
|
|
111
|
+
</template>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { computed, defineComponent, inject } from 'vue'
|
|
3
|
+
import { useCommon } from '../../composables/common'
|
|
4
|
+
import { injectIconsKey } from '../../composables/keys'
|
|
5
|
+
|
|
6
|
+
export default defineComponent({
|
|
7
|
+
name: 'XIcon',
|
|
8
|
+
|
|
9
|
+
validators: {
|
|
10
|
+
...useCommon.validators(),
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
props: {
|
|
14
|
+
...useCommon.props(),
|
|
15
|
+
icon: {
|
|
16
|
+
type: String,
|
|
17
|
+
required: true,
|
|
18
|
+
},
|
|
19
|
+
filled: Boolean,
|
|
20
|
+
viewBox: {
|
|
21
|
+
type: String,
|
|
22
|
+
default: '0 0 24 24',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
setup(props) {
|
|
27
|
+
const icons: any = inject(injectIconsKey, {})
|
|
28
|
+
const sizeClasses = computed(() => {
|
|
29
|
+
if (props.size === 'xs') return 'h-3 w-3'
|
|
30
|
+
else if (props.size === 'sm') return 'h-4 w-4'
|
|
31
|
+
else if (props.size === 'lg') return 'h-6 w-6'
|
|
32
|
+
else if (props.size === 'xl') return 'h-9 w-9'
|
|
33
|
+
|
|
34
|
+
return 'h-5 w-5'
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
icons,
|
|
39
|
+
sizeClasses,
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<template>
|
|
46
|
+
<svg
|
|
47
|
+
:class="[sizeClasses, { 'stroke-2': !filled}]"
|
|
48
|
+
:fill="filled ? 'currentColor' : 'none'"
|
|
49
|
+
:stroke="filled ? undefined : 'currentColor'"
|
|
50
|
+
:viewBox="viewBox"
|
|
51
|
+
:stroke-linecap="filled ? undefined : 'round'"
|
|
52
|
+
:stroke-linejoin="filled ? undefined : 'round'"
|
|
53
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
54
|
+
v-html="icons[icon] ? icons[icon] : icon"
|
|
55
|
+
/>
|
|
56
|
+
</template>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { defineComponent, watch, ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
const fallback = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
|
|
5
|
+
|
|
6
|
+
export default defineComponent({
|
|
7
|
+
name: 'XImage',
|
|
8
|
+
|
|
9
|
+
props: {
|
|
10
|
+
src: String,
|
|
11
|
+
},
|
|
12
|
+
|
|
13
|
+
setup(props) {
|
|
14
|
+
const source = ref<string | undefined>(fallback)
|
|
15
|
+
|
|
16
|
+
watch(() => props.src, (src) => {
|
|
17
|
+
if (!src) return
|
|
18
|
+
const img = new Image()
|
|
19
|
+
|
|
20
|
+
img.onload = () => { source.value = props.src }
|
|
21
|
+
img.onerror = () => { }
|
|
22
|
+
img.src = src
|
|
23
|
+
}, {
|
|
24
|
+
immediate: true,
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
source,
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
})
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<img :src="source" />
|
|
36
|
+
</template>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export { default as XAlert } from './alert/Alert.vue'
|
|
2
|
+
export { default as XAvatar } from './avatar/Avatar.vue'
|
|
3
|
+
export { default as XBadge } from './badge/Badge.vue'
|
|
4
|
+
export { default as XBreadcrumbs } from './breadcrumbs/Breadcrumbs.vue'
|
|
5
|
+
export { default as XButton } from './button/Button.vue'
|
|
6
|
+
export { default as XButtonGroup } from './button/ButtonGroup.vue'
|
|
7
|
+
export { default as XCard } from './card/Card.vue'
|
|
8
|
+
export { default as XCheckbox } from './checkbox/Checkbox.vue'
|
|
9
|
+
export { default as XCollapse } from './collapse/Collapse.vue'
|
|
10
|
+
export { default as XContainer } from './container/Container.vue'
|
|
11
|
+
export { default as XDivider } from './divider/Divider.vue'
|
|
12
|
+
export { default as XDrawer } from './drawer/Drawer.vue'
|
|
13
|
+
export { default as XForm } from './form/Form.vue'
|
|
14
|
+
export { default as XIcon } from './icon/Icon.vue'
|
|
15
|
+
export { default as XImage } from './image/Image.vue'
|
|
16
|
+
export { default as XInput } from './input/Input.vue'
|
|
17
|
+
export { default as XLink } from './link/Link.vue'
|
|
18
|
+
export { default as XMenu } from './menu/Menu.vue'
|
|
19
|
+
export { default as XMenuItem } from './menu/MenuItem.vue'
|
|
20
|
+
export { default as XModal } from './modal/Modal.vue'
|
|
21
|
+
export { default as XNotifications } from './notifications/Notifications.vue'
|
|
22
|
+
export { default as XPagination } from './pagination/Pagination.vue'
|
|
23
|
+
export { default as XPaginationItem } from './pagination/PaginationItem.vue'
|
|
24
|
+
export { default as XPopover } from './popover/Popover.vue'
|
|
25
|
+
export { default as XPopoverContainer } from './popover/PopoverContainer.vue'
|
|
26
|
+
export { default as XProgress } from './progress/Progress.vue'
|
|
27
|
+
export { default as XRadio } from './radio/Radio.vue'
|
|
28
|
+
export { default as XScroll } from './scroll/Scroll.vue'
|
|
29
|
+
export { default as XSelect } from './select/Select.vue'
|
|
30
|
+
export { default as XSkeleton } from './skeleton/Skeleton.vue'
|
|
31
|
+
export { default as XSlider } from './slider/Slider.vue'
|
|
32
|
+
export { default as XSpacer } from './spacer/Spacer.vue'
|
|
33
|
+
export { default as XSpinner } from './spinner/Spinner.vue'
|
|
34
|
+
export { default as XTable } from './table/Table.vue'
|
|
35
|
+
export { default as XTableBody } from './table/TableBody.vue'
|
|
36
|
+
export { default as XTableCell } from './table/TableCell.vue'
|
|
37
|
+
export { default as XTableHead } from './table/TableHead.vue'
|
|
38
|
+
export { default as XTableHeader } from './table/TableHeader.vue'
|
|
39
|
+
export { default as XTableRow } from './table/TableRow.vue'
|
|
40
|
+
export { default as XTab } from './tab/Tab.vue'
|
|
41
|
+
export { default as XTabGroup } from './tab/TabGroup.vue'
|
|
42
|
+
export { default as XTag } from './tag/Tag.vue'
|
|
43
|
+
export { default as XTextarea } from './textarea/Textarea.vue'
|
|
44
|
+
export { default as XToggle } from './toggle/Toggle.vue'
|
|
45
|
+
export { default as XTooltip } from './tooltip/Tooltip.vue'
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { defineComponent, ref, computed } from 'vue'
|
|
3
|
+
import { useCSS } from '../../composables/css'
|
|
4
|
+
import { useColors } from '../../composables/colors'
|
|
5
|
+
import { useCommon } from '../../composables/common'
|
|
6
|
+
import { useInputtable } from '../../composables/inputtable'
|
|
7
|
+
import { useInteractive } from '../../composables/interactive'
|
|
8
|
+
|
|
9
|
+
export default defineComponent({
|
|
10
|
+
name: 'XInput',
|
|
11
|
+
|
|
12
|
+
validators: {
|
|
13
|
+
...useCommon.validators(),
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
props: {
|
|
17
|
+
...useCommon.props(),
|
|
18
|
+
...useInteractive.props(),
|
|
19
|
+
...useInputtable.props(),
|
|
20
|
+
showPasswordToggle: {
|
|
21
|
+
type: Boolean,
|
|
22
|
+
default: true,
|
|
23
|
+
},
|
|
24
|
+
helper: String,
|
|
25
|
+
label: String,
|
|
26
|
+
dir: {
|
|
27
|
+
type: String,
|
|
28
|
+
default: 'ltr',
|
|
29
|
+
},
|
|
30
|
+
icon: String,
|
|
31
|
+
iconRight: String,
|
|
32
|
+
max: Number,
|
|
33
|
+
maxlength: Number,
|
|
34
|
+
min: Number,
|
|
35
|
+
minlength: Number,
|
|
36
|
+
placeholder: String,
|
|
37
|
+
type: {
|
|
38
|
+
type: String,
|
|
39
|
+
default: 'text',
|
|
40
|
+
},
|
|
41
|
+
inputClass: String,
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
emits: useInputtable.emits(),
|
|
45
|
+
|
|
46
|
+
setup(props, { emit }) {
|
|
47
|
+
const elRef = ref<HTMLInputElement>()
|
|
48
|
+
const currentType = ref(props.type)
|
|
49
|
+
|
|
50
|
+
const labelClasses = computed(() => {
|
|
51
|
+
if (props.size === 'xs') return 'text-xs'
|
|
52
|
+
else if (props.size === 'sm') return 'text-sm'
|
|
53
|
+
else if (props.size === 'lg') return 'text-lg'
|
|
54
|
+
else if (props.size === 'xl') return 'text-xl'
|
|
55
|
+
|
|
56
|
+
return ''
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
const sizeClasses = computed(() => {
|
|
60
|
+
if (props.size === 'xs') return 'px-2 py-1 text-xs'
|
|
61
|
+
else if (props.size === 'sm') return 'px-2 py-2 text-sm'
|
|
62
|
+
else if (props.size === 'lg') return 'px-4 py-3 text-lg'
|
|
63
|
+
else if (props.size === 'xl') return 'px-5 py-4 text-xl'
|
|
64
|
+
|
|
65
|
+
return 'px-3 py-2'
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
const css = useCSS('input')
|
|
69
|
+
const colors = useColors()
|
|
70
|
+
const color = colors.getPalette('primary')
|
|
71
|
+
const style = css.get('border', color[500])
|
|
72
|
+
|
|
73
|
+
function onChange(e: Event) {
|
|
74
|
+
if (!e.target) return
|
|
75
|
+
|
|
76
|
+
const target = (e.target as HTMLInputElement)
|
|
77
|
+
const value = Number(target.value)
|
|
78
|
+
|
|
79
|
+
if (props.type === 'number') {
|
|
80
|
+
if (typeof props.min !== 'undefined') {
|
|
81
|
+
if (value < props.min) target.value = props.min.toString()
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof props.max !== 'undefined') {
|
|
85
|
+
if (value > props.max) target.value = props.max.toString()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function togglePasswordVisibility() {
|
|
91
|
+
currentType.value = currentType.value === 'password' ? 'text' : 'password'
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const interactive = useInteractive(elRef)
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
...interactive,
|
|
98
|
+
...useInputtable(props, { focus: interactive.focus, emit }),
|
|
99
|
+
currentType,
|
|
100
|
+
labelClasses,
|
|
101
|
+
sizeClasses,
|
|
102
|
+
style,
|
|
103
|
+
elRef,
|
|
104
|
+
onChange,
|
|
105
|
+
togglePasswordVisibility,
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
</script>
|
|
110
|
+
|
|
111
|
+
<template>
|
|
112
|
+
<label
|
|
113
|
+
class="inline-block relative align-bottom text-left"
|
|
114
|
+
:class="{ 'mb-3': isInsideForm }"
|
|
115
|
+
>
|
|
116
|
+
<p
|
|
117
|
+
v-if="label"
|
|
118
|
+
class="font-medium text-gray-800 dark:text-gray-200 mb-1"
|
|
119
|
+
:class="labelClasses"
|
|
120
|
+
v-text="label"
|
|
121
|
+
></p>
|
|
122
|
+
|
|
123
|
+
<div class="relative">
|
|
124
|
+
<x-icon
|
|
125
|
+
v-if="icon"
|
|
126
|
+
:size="size"
|
|
127
|
+
:icon="icon"
|
|
128
|
+
class="text-gray-600 dark:text-gray-300 absolute ml-2 left-0 my-auto inset-y-0"
|
|
129
|
+
/>
|
|
130
|
+
|
|
131
|
+
<input
|
|
132
|
+
ref="elRef"
|
|
133
|
+
class="appearance-none block w-full placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none transition-colors duration-150 ease-in-out border-gray-300 hover:border-gray-400 dark:border-gray-700 border shadow-sm rounded-md
|
|
134
|
+
focus:border-[color:var(--x-input-border)]
|
|
135
|
+
"
|
|
136
|
+
:style="style"
|
|
137
|
+
:class="[
|
|
138
|
+
sizeClasses,
|
|
139
|
+
disabled ? 'bg-gray-100 dark:bg-gray-700 text-gray-500 cursor-not-allowed' : 'bg-white dark:bg-gray-800 text-gray-700 dark:text-gray-200',
|
|
140
|
+
type === 'password' ? 'pr-9' : '',
|
|
141
|
+
{
|
|
142
|
+
'!pl-9': icon,
|
|
143
|
+
'!pr-9': iconRight,
|
|
144
|
+
// error
|
|
145
|
+
'border-red-500 focus:border-red-500 dark:focus:border-red-500': errorInternal,
|
|
146
|
+
},
|
|
147
|
+
inputClass,
|
|
148
|
+
]"
|
|
149
|
+
:disabled="disabled"
|
|
150
|
+
:min="min"
|
|
151
|
+
:max="max"
|
|
152
|
+
:minlength="minlength"
|
|
153
|
+
:maxlength="maxlength"
|
|
154
|
+
:dir="dir"
|
|
155
|
+
:name="name"
|
|
156
|
+
:placeholder="placeholder"
|
|
157
|
+
:readonly="readonly"
|
|
158
|
+
:type="currentType"
|
|
159
|
+
:value="modelValue"
|
|
160
|
+
v-bind="$attrs"
|
|
161
|
+
v-on="inputListeners"
|
|
162
|
+
@change="onChange"
|
|
163
|
+
/>
|
|
164
|
+
|
|
165
|
+
<x-icon
|
|
166
|
+
v-if="iconRight"
|
|
167
|
+
:size="size"
|
|
168
|
+
:icon="iconRight"
|
|
169
|
+
class="text-gray-600 dark:text-gray-300 absolute mr-2 right-0 my-auto inset-y-0"
|
|
170
|
+
/>
|
|
171
|
+
|
|
172
|
+
<svg
|
|
173
|
+
v-else-if="type === 'password' && showPasswordToggle"
|
|
174
|
+
width="24"
|
|
175
|
+
height="24"
|
|
176
|
+
viewBox="0 0 24 24"
|
|
177
|
+
stroke="currentColor"
|
|
178
|
+
stroke-linejoin="round"
|
|
179
|
+
stroke-linecap="round"
|
|
180
|
+
fill="none"
|
|
181
|
+
class="text-gray-600 dark:text-gray-300 stroke-2 w-5 h-5 absolute my-auto mr-2 inset-y-0 right-1 cursor-pointer"
|
|
182
|
+
@click="togglePasswordVisibility()"
|
|
183
|
+
>
|
|
184
|
+
<template v-if="currentType === 'password'">
|
|
185
|
+
<path d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
186
|
+
<path d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z" />
|
|
187
|
+
</template>
|
|
188
|
+
|
|
189
|
+
<template v-else>
|
|
190
|
+
<path d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21" />
|
|
191
|
+
</template>
|
|
192
|
+
</svg>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
195
|
+
<p v-if="errorInternal" class="text-sm text-red-500 mt-1" v-text="errorInternal"></p>
|
|
196
|
+
<p v-else-if="helper" class="text-sm text-gray-500 mt-1" v-text="helper"></p>
|
|
197
|
+
</label>
|
|
198
|
+
</template>
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { defineComponent, computed } from 'vue'
|
|
3
|
+
import { useColors } from '../../composables/colors'
|
|
4
|
+
import { useCSS } from '../../composables/css'
|
|
5
|
+
|
|
6
|
+
export default defineComponent({
|
|
7
|
+
name: 'XLink',
|
|
8
|
+
|
|
9
|
+
props: {
|
|
10
|
+
...useColors.props(),
|
|
11
|
+
tag: {
|
|
12
|
+
type: String,
|
|
13
|
+
default: 'a',
|
|
14
|
+
},
|
|
15
|
+
to: [String, Object],
|
|
16
|
+
shadow: Boolean,
|
|
17
|
+
external: Boolean,
|
|
18
|
+
underline: Boolean,
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
setup(props) {
|
|
22
|
+
const css = useCSS()
|
|
23
|
+
const colors = useColors()
|
|
24
|
+
const styles = computed(() => {
|
|
25
|
+
const color = colors.getPalette(props.color || 'gray')
|
|
26
|
+
|
|
27
|
+
return css.variables({
|
|
28
|
+
text: props.color ? color[500] : '',
|
|
29
|
+
hover: {
|
|
30
|
+
text: !props.shadow ? color[600] : '',
|
|
31
|
+
},
|
|
32
|
+
shadow: color[100],
|
|
33
|
+
dark: {
|
|
34
|
+
text: props.color ? color[400] : '',
|
|
35
|
+
hover: {
|
|
36
|
+
text: color[300],
|
|
37
|
+
},
|
|
38
|
+
shadow: color[900],
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
styles,
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<template>
|
|
51
|
+
<component
|
|
52
|
+
:is="to ? 'router-link' : tag"
|
|
53
|
+
:to="to"
|
|
54
|
+
class="transition duration-300 ease-in-out cursor-pointer
|
|
55
|
+
text-[color:var(--x-text)]
|
|
56
|
+
dark:text-[color:var(--x-dark-text)]
|
|
57
|
+
"
|
|
58
|
+
:style="styles"
|
|
59
|
+
:class="[
|
|
60
|
+
[shadow ? $style['link--shadow'] : ''],
|
|
61
|
+
{
|
|
62
|
+
'underline': underline
|
|
63
|
+
},
|
|
64
|
+
]"
|
|
65
|
+
>
|
|
66
|
+
<span
|
|
67
|
+
v-if="external"
|
|
68
|
+
class="inline-flex items-center"
|
|
69
|
+
>
|
|
70
|
+
<slot></slot>
|
|
71
|
+
<svg
|
|
72
|
+
width="24"
|
|
73
|
+
height="24"
|
|
74
|
+
viewBox="0 0 24 24"
|
|
75
|
+
stroke="currentColor"
|
|
76
|
+
stroke-linejoin="round"
|
|
77
|
+
stroke-linecap="round"
|
|
78
|
+
fill="none"
|
|
79
|
+
role="presentation"
|
|
80
|
+
class="stroke-2 w-4 h-4 ml"
|
|
81
|
+
>
|
|
82
|
+
<line x1="7" y1="17" x2="17" y2="7" />
|
|
83
|
+
<polyline points="7 7 17 7 17 17" />
|
|
84
|
+
</svg>
|
|
85
|
+
</span>
|
|
86
|
+
<template v-else>
|
|
87
|
+
<slot></slot>
|
|
88
|
+
</template>
|
|
89
|
+
</component>
|
|
90
|
+
</template>
|
|
91
|
+
|
|
92
|
+
<style lang="postcss" module scoped>
|
|
93
|
+
.link {
|
|
94
|
+
&--shadow {
|
|
95
|
+
box-shadow: inset 0 -0.315em 0 0 var(--x-shadow);
|
|
96
|
+
&:hover {
|
|
97
|
+
box-shadow: inset 0 -1.125em 0 0 var(--x-shadow);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
:global(.dark) & {
|
|
102
|
+
&--shadow {
|
|
103
|
+
box-shadow: inset 0 -0.315em 0 0 var(--x-dark-shadow);
|
|
104
|
+
&:hover {
|
|
105
|
+
box-shadow: inset 0 -1.125em 0 0 var(--x-dark-shadow);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</style>
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { defineComponent, type PropType } from 'vue'
|
|
3
|
+
import { useCommon } from '../../composables/common'
|
|
4
|
+
import { useColors } from '../../composables/colors'
|
|
5
|
+
|
|
6
|
+
import XMenuItem from './MenuItem.vue'
|
|
7
|
+
import XCollapse from '../../components/collapse/Collapse.vue'
|
|
8
|
+
import XDivider from '../../components/divider/Divider.vue'
|
|
9
|
+
|
|
10
|
+
export default defineComponent({
|
|
11
|
+
name: 'XMenu',
|
|
12
|
+
|
|
13
|
+
components: {
|
|
14
|
+
XDivider,
|
|
15
|
+
XCollapse,
|
|
16
|
+
XMenuItem,
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
props: {
|
|
20
|
+
...useCommon.props(),
|
|
21
|
+
...useColors.props('primary'),
|
|
22
|
+
items: Array as PropType<Array<any>>,
|
|
23
|
+
collapsible: {
|
|
24
|
+
type: Boolean,
|
|
25
|
+
default: true,
|
|
26
|
+
},
|
|
27
|
+
collapseIcon: String,
|
|
28
|
+
expanded: Boolean,
|
|
29
|
+
disabled: Boolean,
|
|
30
|
+
rounded: Boolean,
|
|
31
|
+
filled: Boolean,
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
emits: ['expand'],
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<div v-if="items">
|
|
40
|
+
<template v-for="(item, index) in items" :key="index">
|
|
41
|
+
<template v-if="item.items">
|
|
42
|
+
<x-collapse
|
|
43
|
+
v-if="item.collapsible !== false"
|
|
44
|
+
:icon="item.collapseIcon || collapseIcon"
|
|
45
|
+
:expanded="item.expanded || expanded"
|
|
46
|
+
:disabled="disabled || item.disabled"
|
|
47
|
+
class="x-menu-inner"
|
|
48
|
+
@expand="$emit('expand')"
|
|
49
|
+
>
|
|
50
|
+
<template #default="{ }">
|
|
51
|
+
<x-menu-item
|
|
52
|
+
:item="item"
|
|
53
|
+
:color="item.color || color"
|
|
54
|
+
:size="item.size || size"
|
|
55
|
+
:rounded="rounded"
|
|
56
|
+
:filled="filled"
|
|
57
|
+
:disabled="disabled || item.disabled"
|
|
58
|
+
class="pr-10 font-medium"
|
|
59
|
+
/>
|
|
60
|
+
</template>
|
|
61
|
+
<template #content="{ expand }">
|
|
62
|
+
<x-menu
|
|
63
|
+
class="border-l ml-4 border-gray-100 dark:border-gray-700 mt-2 mb-1"
|
|
64
|
+
:class="{ 'pl-1': filled }"
|
|
65
|
+
:items="item.items"
|
|
66
|
+
:color="item.color || color"
|
|
67
|
+
:size="item.size || size"
|
|
68
|
+
:collapsible="collapsible"
|
|
69
|
+
:collapse-icon="item.collapseIcon || collapseIcon"
|
|
70
|
+
:expanded="item.expanded || expanded"
|
|
71
|
+
:disabled="disabled || item.disabled"
|
|
72
|
+
:rounded="rounded"
|
|
73
|
+
:filled="filled"
|
|
74
|
+
@expand="expand(false)"
|
|
75
|
+
/>
|
|
76
|
+
</template>
|
|
77
|
+
</x-collapse>
|
|
78
|
+
<template v-else>
|
|
79
|
+
<x-menu-item
|
|
80
|
+
:item="item"
|
|
81
|
+
:rounded="rounded"
|
|
82
|
+
:color="item.color || color"
|
|
83
|
+
:size="item.size || size"
|
|
84
|
+
:disabled="disabled || item.disabled"
|
|
85
|
+
class="font-medium"
|
|
86
|
+
inactive
|
|
87
|
+
/>
|
|
88
|
+
<x-menu
|
|
89
|
+
class="x-menu-inner ml-4 border-l border-gray-100 dark:border-gray-700"
|
|
90
|
+
:class="{ 'pl-1': filled }"
|
|
91
|
+
:items="item.items"
|
|
92
|
+
:color="item.color || color"
|
|
93
|
+
:size="item.size || size"
|
|
94
|
+
:collapsible="collapsible"
|
|
95
|
+
:collapse-icon="item.collapseIcon || collapseIcon"
|
|
96
|
+
:expanded="item.expanded || expanded"
|
|
97
|
+
:disabled="disabled || item.disabled"
|
|
98
|
+
:rounded="rounded"
|
|
99
|
+
:filled="filled"
|
|
100
|
+
@expand="$emit('expand')"
|
|
101
|
+
/>
|
|
102
|
+
</template>
|
|
103
|
+
</template>
|
|
104
|
+
<component
|
|
105
|
+
:is="item.divider ? 'x-divider' : 'x-menu-item'"
|
|
106
|
+
v-else
|
|
107
|
+
:color="item.color || color"
|
|
108
|
+
:size="item.size || size"
|
|
109
|
+
:item="item"
|
|
110
|
+
:disabled="disabled || item.disabled"
|
|
111
|
+
:filled="filled"
|
|
112
|
+
:rounded="rounded"
|
|
113
|
+
:class="{ 'my-2': item.divider }"
|
|
114
|
+
@active="$emit('expand')"
|
|
115
|
+
/>
|
|
116
|
+
</template>
|
|
117
|
+
</div>
|
|
118
|
+
</template>
|