vunor 0.0.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 +33 -0
- package/dist/theme.d.ts +133 -0
- package/dist/theme.mjs +1149 -0
- package/dist/vite.d.ts +5 -0
- package/dist/vite.mjs +13 -0
- package/package.json +83 -0
- package/src/components/AppLayout/AppLayout.vue +114 -0
- package/src/components/Button/Button.vue +49 -0
- package/src/components/Button/ButtonBase.vue +43 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/Button/shortcuts.ts +29 -0
- package/src/components/Card/Card.vue +47 -0
- package/src/components/Card/CardHeader.vue +26 -0
- package/src/components/Card/CardInner.vue +5 -0
- package/src/components/Card/index.ts +3 -0
- package/src/components/Card/pi.ts +46 -0
- package/src/components/Card/shortcuts.ts +19 -0
- package/src/components/Checkbox/Checkbox.vue +59 -0
- package/src/components/Checkbox/index.ts +1 -0
- package/src/components/Checkbox/shortcuts.ts +27 -0
- package/src/components/Combobox/Combobox.vue +502 -0
- package/src/components/Combobox/index.ts +2 -0
- package/src/components/Combobox/shortcuts.ts +12 -0
- package/src/components/Combobox/types.ts +33 -0
- package/src/components/Icon/Icon.vue +9 -0
- package/src/components/Icon/index.ts +1 -0
- package/src/components/Input/Input.vue +109 -0
- package/src/components/Input/InputShell.vue +133 -0
- package/src/components/Input/index.ts +4 -0
- package/src/components/Input/pi.ts +18 -0
- package/src/components/Input/types.ts +52 -0
- package/src/components/Input/utils.ts +108 -0
- package/src/components/Label/Label.vue +6 -0
- package/src/components/Label/index.ts +1 -0
- package/src/components/Loading/LoadingIndicator.vue +23 -0
- package/src/components/Loading/index.ts +1 -0
- package/src/components/Loading/shortcuts.ts +9 -0
- package/src/components/Menu/Menu.vue +100 -0
- package/src/components/Menu/MenuItem.vue +20 -0
- package/src/components/Menu/index.ts +2 -0
- package/src/components/Menu/shortcuts.ts +6 -0
- package/src/components/OverflowContainer/OverflowContainer.vue +120 -0
- package/src/components/OverflowContainer/index.ts +1 -0
- package/src/components/Pagination/Pagination.vue +71 -0
- package/src/components/Popover/Popover.vue +58 -0
- package/src/components/Popover/index.ts +1 -0
- package/src/components/RadioGroup/RadioGroup.vue +83 -0
- package/src/components/RadioGroup/index.ts +1 -0
- package/src/components/RadioGroup/shortcuts.ts +34 -0
- package/src/components/Select/Select.vue +93 -0
- package/src/components/Select/SelectBase.vue +148 -0
- package/src/components/Select/index.ts +3 -0
- package/src/components/Select/shortcuts.ts +30 -0
- package/src/components/Select/types.ts +30 -0
- package/src/components/Slider/Slider.vue +73 -0
- package/src/components/Slider/index.ts +1 -0
- package/src/components/Slider/shortcuts.ts +23 -0
- package/src/components/shortcuts.ts +21 -0
- package/src/components/utils/index.ts +1 -0
- package/src/components/utils/provide-inject.ts +39 -0
package/dist/vite.d.ts
ADDED
package/dist/vite.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "vunor",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "vite",
|
|
7
|
+
"build-with-checks": "run-p type-check \"build {@}\" --",
|
|
8
|
+
"preview": "vite preview",
|
|
9
|
+
"build": "vite build",
|
|
10
|
+
"pub": "npm publish --access public",
|
|
11
|
+
"type-check": "vue-tsc --build --force"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@prostojs/palitra": "^0.0.3",
|
|
15
|
+
"@unocss/preset-mini": "^0.60.4",
|
|
16
|
+
"defu": "^6.1.4",
|
|
17
|
+
"radix-vue": "^1.8.3",
|
|
18
|
+
"unocss": "^0.60.4",
|
|
19
|
+
"vue": "^3.4.27",
|
|
20
|
+
"vue-router": "^4.3.2"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"src/components"
|
|
25
|
+
],
|
|
26
|
+
"exports": {
|
|
27
|
+
"./package.json": "./package.json",
|
|
28
|
+
"./theme": {
|
|
29
|
+
"import": "./dist/theme.mjs",
|
|
30
|
+
"types": "./dist/theme.d.ts"
|
|
31
|
+
},
|
|
32
|
+
"./vite": {
|
|
33
|
+
"import": "./dist/vite.mjs",
|
|
34
|
+
"types": "./dist/vite.d.ts"
|
|
35
|
+
},
|
|
36
|
+
"./Input.vue": "./src/components/Input/Input.vue",
|
|
37
|
+
"./InputBase.vue": "./src/components/Input/InputBase.vue",
|
|
38
|
+
"./Button.vue": "./src/components/Button/Button.vue",
|
|
39
|
+
"./ButtonBase.vue": "./src/components/Button/ButtonBase.vue",
|
|
40
|
+
"./AppLayout.vue": "./src/components/AppLayout/AppLayout.vue",
|
|
41
|
+
"./Card.vue": "./src/components/Card/Card.vue",
|
|
42
|
+
"./CardHeader.vue": "./src/components/Card/CardHeader.vue",
|
|
43
|
+
"./CardInner.vue": "./src/components/Card/CardInner.vue",
|
|
44
|
+
"./Checkbox.vue": "./src/components/Checkbox/Checkbox.vue",
|
|
45
|
+
"./Combobox.vue": "./src/components/Combobox/Combobox.vue",
|
|
46
|
+
"./Icon.vue": "./src/components/Icon/Icon.vue",
|
|
47
|
+
"./InputShell.vue": "./src/components/Input/InputShell.vue",
|
|
48
|
+
"./Label.vue": "./src/components/Label/Label.vue",
|
|
49
|
+
"./LoadingIndicator.vue": "./src/components/Loading/LoadingIndicator.vue",
|
|
50
|
+
"./Menu.vue": "./src/components/Menu/Menu.vue",
|
|
51
|
+
"./MenuItem.vue": "./src/components/Menu/MenuItem.vue",
|
|
52
|
+
"./OverflowContainer.vue": "./src/components/OverflowContainer/OverflowContainer.vue",
|
|
53
|
+
"./Pagination.vue": "./src/components/Pagination/Pagination.vue",
|
|
54
|
+
"./Popover.vue": "./src/components/Popover/Popover.vue",
|
|
55
|
+
"./RadioGroup.vue": "./src/components/RadioGroup/RadioGroup.vue",
|
|
56
|
+
"./Select.vue": "./src/components/Select/Select.vue",
|
|
57
|
+
"./SelectBase.vue": "./src/components/Select/SelectBase.vue",
|
|
58
|
+
"./Slider.vue": "./src/components/Slider/Slider.vue",
|
|
59
|
+
"./utils": "./src/components/utils/index.ts"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@iconify/utils": "^2.1.23",
|
|
63
|
+
"@prostojs/palitra": "^0.0.3",
|
|
64
|
+
"@tsconfig/node20": "^20.1.4",
|
|
65
|
+
"@types/node": "^20.12.5",
|
|
66
|
+
"@unocss/preset-icons": "^0.59.4",
|
|
67
|
+
"@unocss/preset-mini": "^0.59.4",
|
|
68
|
+
"@unocss/preset-wind": "^0.59.4",
|
|
69
|
+
"@unocss/reset": "^0.59.4",
|
|
70
|
+
"@vitejs/plugin-vue": "^5.0.4",
|
|
71
|
+
"@vue/tsconfig": "^0.5.1",
|
|
72
|
+
"@vueuse/core": "^10.10.0",
|
|
73
|
+
"typescript": "~5.4.5",
|
|
74
|
+
"unocss": "^0.60.4",
|
|
75
|
+
"unocss-preset-scrollbar": "^0.3.1",
|
|
76
|
+
"unplugin-auto-import": "^0.17.6",
|
|
77
|
+
"unplugin-vue-components": "^0.27.0",
|
|
78
|
+
"vite": "^5.2.8",
|
|
79
|
+
"vite-plugin-dts": "^3.9.1",
|
|
80
|
+
"vitest": "^1.6.0",
|
|
81
|
+
"vue-tsc": "^2.0.11"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const props = withDefaults(
|
|
3
|
+
defineProps<{
|
|
4
|
+
maxW?: string
|
|
5
|
+
headerH?: string
|
|
6
|
+
footerH?: string
|
|
7
|
+
leftW?: string
|
|
8
|
+
rightW?: string
|
|
9
|
+
footer?: boolean
|
|
10
|
+
header?: boolean
|
|
11
|
+
left?: boolean
|
|
12
|
+
right?: boolean
|
|
13
|
+
headerClass?: string | Record<string, boolean>
|
|
14
|
+
footerClass?: string | Record<string, boolean>
|
|
15
|
+
leftClass?: string | Record<string, boolean>
|
|
16
|
+
rightClass?: string | Record<string, boolean>
|
|
17
|
+
mainClass?: string | Record<string, boolean>
|
|
18
|
+
scrollTopOnChangeView?: boolean
|
|
19
|
+
}>(),
|
|
20
|
+
{
|
|
21
|
+
maxW: '90rem',
|
|
22
|
+
headerH: '3rem',
|
|
23
|
+
footerH: '3rem',
|
|
24
|
+
leftW: '14rem',
|
|
25
|
+
rightW: '14rem',
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const vars = computed(() =>
|
|
30
|
+
[
|
|
31
|
+
`--app-max-w: ${props.maxW}`,
|
|
32
|
+
`--app-header-h: ${props.header ? props.headerH : '0rem'}`,
|
|
33
|
+
`--app-footer-h: ${props.footer ? props.footerH : '0rem'}`,
|
|
34
|
+
`--app-left-w: ${props.left ? props.leftW : '0rem'}`,
|
|
35
|
+
`--app-right-w: ${props.right ? props.rightW : '0rem'}`,
|
|
36
|
+
].join(';')
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
const mainScroll = ref<HTMLDivElement>()
|
|
40
|
+
const main = ref<HTMLDivElement>()
|
|
41
|
+
|
|
42
|
+
let observer: MutationObserver
|
|
43
|
+
|
|
44
|
+
const autoScroll: MutationCallback = (changes: MutationRecord[]) => {
|
|
45
|
+
if (changes.length && changes.some(c => c.type === 'childList') && mainScroll.value) {
|
|
46
|
+
mainScroll.value.scroll({ top: 0, left: 0 })
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
onMounted(() => {
|
|
51
|
+
if (props.scrollTopOnChangeView && main.value) {
|
|
52
|
+
observer = new MutationObserver(autoScroll)
|
|
53
|
+
observer.observe(main.value, {
|
|
54
|
+
childList: true,
|
|
55
|
+
subtree: false,
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
onBeforeUnmount(() => {
|
|
61
|
+
if (observer) {
|
|
62
|
+
observer.disconnect()
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<div class="h-screen w-full flex flex-col items-center" :style="vars">
|
|
69
|
+
<div ref="mainScroll" class="flex-1 overflow-y-scroll overflow-x-auto w-full thin-scrollbar">
|
|
70
|
+
<header
|
|
71
|
+
v-if="header"
|
|
72
|
+
class="sticky top-0 flex-shrink-0 h-[var(--app-header-h)] w-full flex"
|
|
73
|
+
:class="headerClass"
|
|
74
|
+
>
|
|
75
|
+
<div class="mx-auto max-w-[var(--app-max-w)] flex items-center justify-between w-full">
|
|
76
|
+
<slot name="header"></slot>
|
|
77
|
+
</div>
|
|
78
|
+
</header>
|
|
79
|
+
|
|
80
|
+
<div class="max-w-[var(--app-max-w)] w-full mx-auto flex">
|
|
81
|
+
<aside
|
|
82
|
+
class="hidden lg:block w-[var(--app-left-w)] top-[var(--app-header-h)] overflow-auto fixed"
|
|
83
|
+
:style="'height: calc(100vh - var(--app-header-h) - var(--app-footer-h))'"
|
|
84
|
+
>
|
|
85
|
+
<div class="min-h-full" :class="leftClass">
|
|
86
|
+
<slot name="left"></slot>
|
|
87
|
+
</div>
|
|
88
|
+
</aside>
|
|
89
|
+
|
|
90
|
+
<main
|
|
91
|
+
class="flex-1 overflow-auto lg:pl-[var(--app-left-w)] lg:pr-[var(--app-right-w)]"
|
|
92
|
+
:class="mainClass"
|
|
93
|
+
ref="main"
|
|
94
|
+
>
|
|
95
|
+
<slot></slot>
|
|
96
|
+
</main>
|
|
97
|
+
|
|
98
|
+
<aside
|
|
99
|
+
class="hidden xl:block w-[var(--app-right-w)] top-[var(--app-header-h)] overflow-auto fixed"
|
|
100
|
+
:class="rightClass"
|
|
101
|
+
:style="'height: calc(100vh - var(--app-header-h) - var(--app-footer-h)); left: calc(50% - var(--app-right-w) + min(var(--app-max-w), 100vw) / 2);'"
|
|
102
|
+
>
|
|
103
|
+
<slot name="right"></slot>
|
|
104
|
+
</aside>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<footer v-if="footer" class="flex-shrink-0 h-[var(--app-footer-h)] px-4 w-full flex">
|
|
109
|
+
<div class="mx-auto max-w-[var(--app-max-w)] flex items-center justify-between w-full">
|
|
110
|
+
footer
|
|
111
|
+
</div>
|
|
112
|
+
</footer>
|
|
113
|
+
</div>
|
|
114
|
+
</template>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { RouterLink, type RouteLocationRaw } from 'vue-router'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
label?: string
|
|
6
|
+
icon?: string
|
|
7
|
+
iconSide?: 'left' | 'right'
|
|
8
|
+
loading?: boolean
|
|
9
|
+
disabled?: boolean
|
|
10
|
+
active?: boolean
|
|
11
|
+
pressed?: boolean
|
|
12
|
+
selected?: boolean
|
|
13
|
+
to?: RouteLocationRaw
|
|
14
|
+
class?: string | Record<string, boolean>
|
|
15
|
+
style?: string | Record<string, string>
|
|
16
|
+
asLink?: boolean
|
|
17
|
+
}>()
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<RouterLink v-if="!!to" custom :to v-slot="{ isActive, href }">
|
|
22
|
+
<VuButtonBase as="a" :href :aria-selected="isActive" v-bind="props">
|
|
23
|
+
<template #icon-left v-if="$slots['icon-left']">
|
|
24
|
+
<slot name="icon-left"></slot>
|
|
25
|
+
</template>
|
|
26
|
+
<slot></slot>
|
|
27
|
+
<template #icon-right v-if="$slots['icon-right']">
|
|
28
|
+
<slot name="icon-right"></slot>
|
|
29
|
+
</template>
|
|
30
|
+
</VuButtonBase>
|
|
31
|
+
</RouterLink>
|
|
32
|
+
|
|
33
|
+
<VuButtonBase
|
|
34
|
+
v-else
|
|
35
|
+
:as="asLink ? 'a' : 'button'"
|
|
36
|
+
v-bind="props"
|
|
37
|
+
:data-active="active ? '' : undefined"
|
|
38
|
+
:aria-pressed="typeof pressed === 'boolean' ? pressed : undefined"
|
|
39
|
+
:aria-selected="typeof selected === 'boolean' ? selected : undefined"
|
|
40
|
+
>
|
|
41
|
+
<template #icon-left v-if="$slots['icon-left']">
|
|
42
|
+
<slot name="icon-left"></slot>
|
|
43
|
+
</template>
|
|
44
|
+
<slot></slot>
|
|
45
|
+
<template #icon-right v-if="$slots['icon-right']">
|
|
46
|
+
<slot name="icon-right"></slot>
|
|
47
|
+
</template>
|
|
48
|
+
</VuButtonBase>
|
|
49
|
+
</template>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
withDefaults(
|
|
3
|
+
defineProps<{
|
|
4
|
+
label?: string
|
|
5
|
+
icon?: string
|
|
6
|
+
iconSide?: 'left' | 'right'
|
|
7
|
+
loading?: boolean
|
|
8
|
+
disabled?: boolean
|
|
9
|
+
as?: string
|
|
10
|
+
href?: string
|
|
11
|
+
}>(),
|
|
12
|
+
{
|
|
13
|
+
iconSide: 'left',
|
|
14
|
+
as: 'button',
|
|
15
|
+
}
|
|
16
|
+
)
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>
|
|
20
|
+
<Primitive
|
|
21
|
+
class="btn group/btn"
|
|
22
|
+
:as
|
|
23
|
+
:href
|
|
24
|
+
:data-has-label="!!label || !!$slots.default"
|
|
25
|
+
:data-has-icon="!!icon"
|
|
26
|
+
:data-loading="loading ? '' : undefined"
|
|
27
|
+
:disabled="loading || disabled || undefined"
|
|
28
|
+
>
|
|
29
|
+
<div class="loading-indicator-wrapper" v-if="loading">
|
|
30
|
+
<VuLoadingIndicator />
|
|
31
|
+
</div>
|
|
32
|
+
<slot name="icon-left">
|
|
33
|
+
<VuIcon v-if="icon && iconSide === 'left'" :name="icon" class="btn-icon btn-icon-left" />
|
|
34
|
+
</slot>
|
|
35
|
+
<slot>
|
|
36
|
+
<span class="btn-label">{{ label }}</span>
|
|
37
|
+
</slot>
|
|
38
|
+
|
|
39
|
+
<slot name="icon-right">
|
|
40
|
+
<VuIcon v-if="icon && iconSide === 'right'" :name="icon" class="btn-icon btn-icon-right" />
|
|
41
|
+
</slot>
|
|
42
|
+
</Primitive>
|
|
43
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as VuButton } from './Button.vue'
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { scFromObject } from '../../theme/utils/shortcut-obj'
|
|
2
|
+
|
|
3
|
+
export const buttonShortcuts = {
|
|
4
|
+
'btn': scFromObject({
|
|
5
|
+
'': 'h-fingertip flex items-center justify-center px-$m gap-$xs select-none fw-bold tracking-wide relative',
|
|
6
|
+
'[&.btn-round]:': 'px-fingertip-half rounded-fingertip-half',
|
|
7
|
+
'[&.btn-square]:': 'size-fingertip px-0',
|
|
8
|
+
'[&.btn-round.btn-square]:': 'px-0',
|
|
9
|
+
'disabled:': 'opacity-80 cursor-not-allowed',
|
|
10
|
+
'[&>span]:data-[loading]:': 'opacity-0 pointer-events-none',
|
|
11
|
+
'[&>div:not(.loading-indicator-wrapper)]:data-[loading]:': 'opacity-0 pointer-events-none',
|
|
12
|
+
'[&>.loading-indicator-wrapper]:':
|
|
13
|
+
'absolute left-0 top-0 right-0 bottom-0 flex items-center justify-center cursor-wait',
|
|
14
|
+
}),
|
|
15
|
+
'btn-square': scFromObject({
|
|
16
|
+
'': '',
|
|
17
|
+
}),
|
|
18
|
+
'btn-label': scFromObject({
|
|
19
|
+
'': 'lh-1em ellipsis whitespace-nowrap overflow-x-clip overflow-y-visible',
|
|
20
|
+
'group-[.btn-square]/btn:': 'hidden',
|
|
21
|
+
}),
|
|
22
|
+
'btn-icon': scFromObject({
|
|
23
|
+
'': 'size-1em font-size-1.25em',
|
|
24
|
+
'group-[.btn-round]/btn:[&.btn-icon-left]:': 'ml-[-0.5em]',
|
|
25
|
+
'group-[.btn-round]/btn:[&.btn-icon-right]:': 'mr-[-0.5em]',
|
|
26
|
+
'group-[.btn-square]/btn:': 'font-size-1.5em m-0!',
|
|
27
|
+
'group-[.btn-round.btn-square]/btn:': 'm-0!',
|
|
28
|
+
}),
|
|
29
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useCardPI } from './pi'
|
|
3
|
+
|
|
4
|
+
const props = withDefaults(
|
|
5
|
+
defineProps<{
|
|
6
|
+
as?: string
|
|
7
|
+
asChild?: boolean
|
|
8
|
+
noPadding?: boolean
|
|
9
|
+
level?:
|
|
10
|
+
| 'h1'
|
|
11
|
+
| 'h2'
|
|
12
|
+
| 'h3'
|
|
13
|
+
| 'h4'
|
|
14
|
+
| 'h5'
|
|
15
|
+
| 'h6'
|
|
16
|
+
| 'subheading'
|
|
17
|
+
| 'body-l'
|
|
18
|
+
| 'body'
|
|
19
|
+
| 'body-s'
|
|
20
|
+
| 'callout'
|
|
21
|
+
dense?: boolean
|
|
22
|
+
rounded?: boolean
|
|
23
|
+
}>(),
|
|
24
|
+
{
|
|
25
|
+
as: 'div',
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
const { headerLevel } = useCardPI().provide()
|
|
30
|
+
|
|
31
|
+
const _level = computed(() => props.level || headerLevel.value || 'h6')
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<Primitive
|
|
36
|
+
:as
|
|
37
|
+
:asChild
|
|
38
|
+
:data-rounded="rounded"
|
|
39
|
+
:data-dense="dense"
|
|
40
|
+
:data-level="_level"
|
|
41
|
+
:style="noPadding ? 'padding: 0' : ''"
|
|
42
|
+
class="card"
|
|
43
|
+
>
|
|
44
|
+
<slot />
|
|
45
|
+
</Primitive>
|
|
46
|
+
</template>
|
|
47
|
+
./pi
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useCardPI } from './pi'
|
|
3
|
+
|
|
4
|
+
const props = defineProps<{
|
|
5
|
+
as?: string
|
|
6
|
+
asChild?: boolean
|
|
7
|
+
level?: string
|
|
8
|
+
}>()
|
|
9
|
+
|
|
10
|
+
const _as = computed(() =>
|
|
11
|
+
props.as
|
|
12
|
+
? props.as
|
|
13
|
+
: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(props.level || '')
|
|
14
|
+
? props.level
|
|
15
|
+
: 'h6'
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
useCardPI().inject()
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<template>
|
|
22
|
+
<Primitive :as="_as" :asChild class="text-card-header text-mt-0">
|
|
23
|
+
<slot></slot>
|
|
24
|
+
</Primitive>
|
|
25
|
+
</template>
|
|
26
|
+
./pi
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/* eslint-disable sonarjs/cognitive-complexity */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
4
|
+
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
5
|
+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
6
|
+
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
|
|
7
|
+
|
|
8
|
+
import { useProvideInject } from '../utils'
|
|
9
|
+
|
|
10
|
+
const safeTag = (t?: string) => (t && /^h[1-6]$/.test(t) ? t : '')
|
|
11
|
+
|
|
12
|
+
export const useCardPI = () =>
|
|
13
|
+
useProvideInject('__vunor_card_PI', () => {
|
|
14
|
+
const headerLevel = ref('')
|
|
15
|
+
|
|
16
|
+
function updateCardLevel(v: string) {
|
|
17
|
+
if (v) {
|
|
18
|
+
headerLevel.value = v
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
_provide: () => ({ headerLevel }),
|
|
24
|
+
_inject: () => {
|
|
25
|
+
const instance = getCurrentInstance()
|
|
26
|
+
if (instance) {
|
|
27
|
+
const v2 = (instance.props.level || safeTag(instance.props.as as string)) as string
|
|
28
|
+
if (v2) {
|
|
29
|
+
updateCardLevel(v2)
|
|
30
|
+
} else {
|
|
31
|
+
onMounted(() => {
|
|
32
|
+
const v = (instance.props.level || safeTag(instance.props.as as string)) as string
|
|
33
|
+
const tag = instance.vnode.el?.tagName.toLowerCase()
|
|
34
|
+
updateCardLevel(v || safeTag(tag) ? tag : '')
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
watch(
|
|
38
|
+
() => [instance.props.level, instance.props.as],
|
|
39
|
+
() => {
|
|
40
|
+
updateCardLevel((instance.props.level || instance.props.as) as string)
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const headers = [
|
|
2
|
+
'h1',
|
|
3
|
+
'h2',
|
|
4
|
+
'h3',
|
|
5
|
+
'h4',
|
|
6
|
+
'h5',
|
|
7
|
+
'h6',
|
|
8
|
+
'subheading',
|
|
9
|
+
'body-l',
|
|
10
|
+
'body',
|
|
11
|
+
'body-s',
|
|
12
|
+
'callout',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
export const cardShortcuts = {
|
|
16
|
+
card: `data-[rounded=true]:rounded-$card-spacing data-[dense=true]:card-dense! ${headers
|
|
17
|
+
.map(h => `data-[level=${h}]:card-${h}`)
|
|
18
|
+
.join(' ')}`,
|
|
19
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
const modelValue = defineModel<boolean | undefined | 'indeterminate'>()
|
|
3
|
+
defineProps<{
|
|
4
|
+
label?: string
|
|
5
|
+
disabled?: boolean
|
|
6
|
+
error?: string | boolean
|
|
7
|
+
required?: boolean
|
|
8
|
+
verticalMiddle?: boolean
|
|
9
|
+
reverse?: boolean
|
|
10
|
+
readonly?: boolean
|
|
11
|
+
}>()
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<!-- [&>.checkbox]:hover:bg-neutral-100 -->
|
|
16
|
+
<div>
|
|
17
|
+
<label
|
|
18
|
+
:style="{
|
|
19
|
+
'pointer-events': readonly ? 'none' : undefined,
|
|
20
|
+
}"
|
|
21
|
+
:aria-disabled="disabled"
|
|
22
|
+
class="checkbox-root group/cb"
|
|
23
|
+
:aria-readonly="readonly || undefined"
|
|
24
|
+
:data-error="!!error"
|
|
25
|
+
:class="{
|
|
26
|
+
'items-center': verticalMiddle,
|
|
27
|
+
'items-start': !verticalMiddle,
|
|
28
|
+
'flex-row-reverse': reverse,
|
|
29
|
+
}"
|
|
30
|
+
>
|
|
31
|
+
<CheckboxRoot
|
|
32
|
+
:disabled
|
|
33
|
+
:required="true"
|
|
34
|
+
:aria-required="required"
|
|
35
|
+
v-model:checked="modelValue"
|
|
36
|
+
:tabindex="readonly ? '-1' : undefined"
|
|
37
|
+
class="checkbox"
|
|
38
|
+
:aria-readonly="readonly || undefined"
|
|
39
|
+
>
|
|
40
|
+
<CheckboxIndicator class="checkbox-indicator">
|
|
41
|
+
<VuIcon v-if="modelValue === 'indeterminate'" name="i--dash" class="checkbox-icon" />
|
|
42
|
+
<VuIcon v-if="modelValue === true" name="i--checkmark" class="checkbox-icon" />
|
|
43
|
+
</CheckboxIndicator>
|
|
44
|
+
</CheckboxRoot>
|
|
45
|
+
<span class="checkbox-label">
|
|
46
|
+
<slot :label="label">
|
|
47
|
+
{{ label }}
|
|
48
|
+
</slot>
|
|
49
|
+
</span>
|
|
50
|
+
</label>
|
|
51
|
+
<div
|
|
52
|
+
v-if="!!error && typeof error === 'string'"
|
|
53
|
+
class="text-caption text-error-500 text-mt-$s"
|
|
54
|
+
:class="{ 'text-right': reverse }"
|
|
55
|
+
>
|
|
56
|
+
{{ error }}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as VuCheckbox } from './Checkbox.vue'
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { scFromObject } from '../../theme/utils/shortcut-obj'
|
|
2
|
+
|
|
3
|
+
export const checkboxShortcuts = {
|
|
4
|
+
'checkbox-root': scFromObject({
|
|
5
|
+
'': 'text-body select-none flex gap-$m cursor-default current-bg-scope-color-500 current-border-scope-color-500',
|
|
6
|
+
'data-[error=true]:': 'current-border-error-500',
|
|
7
|
+
'aria-[disabled=true]:': 'scope-grey opacity-50 cursor-not-allowed',
|
|
8
|
+
}),
|
|
9
|
+
'checkbox': scFromObject({
|
|
10
|
+
'': 'cursor-default shrink-0 select-none rounded-[0.28em] transition-all transition-duration-100 flex size-1.5em appearance-none items-center justify-center bg-current/0 backdrop-blur-sm border-current border-[0.16em] current-icon-white',
|
|
11
|
+
'group-active/cb:enabled:':
|
|
12
|
+
'current-bg-scope-color-500 bg-current/20 current-icon-scope-color-500',
|
|
13
|
+
// 'group-hover/cb:enabled:': 'border-current',
|
|
14
|
+
'disabled:': 'cursor-not-allowed border-1px backdrop-blur-sm',
|
|
15
|
+
'group-[[data-error=true]]/cb:enabled:': 'current-border-error-500 border-current',
|
|
16
|
+
'data-[state=unchecked]': 'current-border-grey-500 border-current/40',
|
|
17
|
+
}),
|
|
18
|
+
'checkbox-indicator': scFromObject({
|
|
19
|
+
'': 'bg-current icon-current h-full w-full flex items-center justify-center',
|
|
20
|
+
}),
|
|
21
|
+
'checkbox-icon': scFromObject({
|
|
22
|
+
'': 'size-0.9em animate-cb-appear animate-duration-200 animate-ease',
|
|
23
|
+
}),
|
|
24
|
+
'checkbox-label': scFromObject({
|
|
25
|
+
'': 'select-none text-body lh-1.5em',
|
|
26
|
+
}),
|
|
27
|
+
}
|