@brickflow/ui 0.0.41 → 0.0.43
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/dist/module.json +1 -1
- package/dist/runtime/components/Button/icons.demo.vue +9 -8
- package/dist/runtime/components/Button/index.vue +83 -51
- package/dist/runtime/components/Button/size.demo.vue +8 -7
- package/dist/runtime/components/Button/slots.demo.vue +10 -8
- package/dist/runtime/components/Button/state.demo.vue +10 -8
- package/dist/runtime/components/Button/variants.demo.vue +10 -8
- package/dist/runtime/components/Icon/basic.demo.vue +13 -10
- package/dist/runtime/components/Icon/gallery.demo.vue +48 -38
- package/dist/runtime/components/Icon/index.vue +15 -9
- package/dist/runtime/components/Link/basic.demo.vue +7 -7
- package/dist/runtime/components/Link/index.vue +81 -50
- package/dist/runtime/pages/ui.vue +513 -346
- package/package.json +1 -1
- package/dist/runtime/components/Button/icons.demo.d.vue.ts +0 -8
- package/dist/runtime/components/Button/icons.demo.vue.d.ts +0 -8
- package/dist/runtime/components/Button/index.d.vue.ts +0 -53
- package/dist/runtime/components/Button/index.vue.d.ts +0 -53
- package/dist/runtime/components/Button/size.demo.d.vue.ts +0 -7
- package/dist/runtime/components/Button/size.demo.vue.d.ts +0 -7
- package/dist/runtime/components/Button/slots.demo.d.vue.ts +0 -7
- package/dist/runtime/components/Button/slots.demo.vue.d.ts +0 -7
- package/dist/runtime/components/Button/state.demo.d.vue.ts +0 -7
- package/dist/runtime/components/Button/state.demo.vue.d.ts +0 -7
- package/dist/runtime/components/Button/variants.demo.d.vue.ts +0 -7
- package/dist/runtime/components/Button/variants.demo.vue.d.ts +0 -7
- package/dist/runtime/components/Icon/basic.demo.d.vue.ts +0 -8
- package/dist/runtime/components/Icon/basic.demo.vue.d.ts +0 -8
- package/dist/runtime/components/Icon/gallery.demo.d.vue.ts +0 -8
- package/dist/runtime/components/Icon/gallery.demo.vue.d.ts +0 -8
- package/dist/runtime/components/Icon/index.d.vue.ts +0 -7
- package/dist/runtime/components/Icon/index.vue.d.ts +0 -7
- package/dist/runtime/components/Link/basic.demo.d.vue.ts +0 -8
- package/dist/runtime/components/Link/basic.demo.vue.d.ts +0 -8
- package/dist/runtime/components/Link/index.d.vue.ts +0 -51
- package/dist/runtime/components/Link/index.vue.d.ts +0 -51
- package/dist/runtime/pages/ui.d.vue.ts +0 -4
- package/dist/runtime/pages/ui.vue.d.ts +0 -4
package/dist/module.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
description: 'Set leadingIcon and trailingIcon to an icon name. Slots take precedence when both are provided.',
|
|
4
|
+
title: 'Icons',
|
|
5
|
+
}
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
|
-
<script setup>
|
|
9
|
-
import { firstIconName } from
|
|
10
|
-
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import { firstIconName } from '#brickflow-ui-icons'
|
|
10
|
+
|
|
11
|
+
import Button from './index.vue'
|
|
11
12
|
</script>
|
|
12
13
|
|
|
13
14
|
<template>
|
|
@@ -1,47 +1,79 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
const UI_CONFIG = defineUiConfig
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
const UI_CONFIG = defineUiConfig<{
|
|
3
|
+
colorClasses: Record<string, Record<string, string>>
|
|
4
|
+
colorDefault: string
|
|
5
|
+
loadingIconName: string
|
|
6
|
+
sizeClasses: Record<string, string>
|
|
7
|
+
sizeDefault: string
|
|
8
|
+
sizeIconClasses: Record<string, string>
|
|
9
|
+
variantDefault: string
|
|
10
|
+
}>()
|
|
11
|
+
|
|
12
|
+
export type ButtonConfig = typeof UI_CONFIG
|
|
3
13
|
</script>
|
|
4
14
|
|
|
5
|
-
<script setup>
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
15
|
+
<script setup lang="ts">
|
|
16
|
+
import type { RouteLocationRaw } from 'vue-router'
|
|
17
|
+
|
|
18
|
+
import { computed, shallowRef } from 'vue'
|
|
19
|
+
|
|
20
|
+
import Icon from '../Icon/index.vue'
|
|
21
|
+
import BaseLink from '../Link/index.vue'
|
|
22
|
+
const props = withDefaults(
|
|
23
|
+
defineProps<{
|
|
24
|
+
block?: boolean
|
|
25
|
+
color?: ButtonColor
|
|
26
|
+
disabled?: boolean
|
|
27
|
+
icon?: string
|
|
28
|
+
loading?: boolean
|
|
29
|
+
rounded?: boolean
|
|
30
|
+
size?: ButtonSize
|
|
31
|
+
square?: boolean
|
|
32
|
+
to?: RouteLocationRaw
|
|
33
|
+
trailingIcon?: string
|
|
34
|
+
type?: 'button' | 'reset' | 'submit'
|
|
35
|
+
variant?: ButtonVariant
|
|
36
|
+
}>(),
|
|
37
|
+
{
|
|
38
|
+
color: UI_CONFIG.colorDefault,
|
|
39
|
+
icon: undefined,
|
|
40
|
+
rounded: false,
|
|
41
|
+
size: UI_CONFIG.sizeDefault,
|
|
42
|
+
to: undefined,
|
|
43
|
+
trailingIcon: undefined,
|
|
44
|
+
type: 'button',
|
|
45
|
+
variant: UI_CONFIG.variantDefault,
|
|
46
|
+
},
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
const colorClasses = UI_CONFIG.colorClasses
|
|
50
|
+
const sizeClasses = UI_CONFIG.sizeClasses
|
|
51
|
+
const sizeIconClasses = UI_CONFIG.sizeIconClasses
|
|
52
|
+
type ButtonColor = Extract<keyof typeof colorClasses, string>
|
|
53
|
+
type ButtonSize = Extract<keyof typeof sizeClasses, string>
|
|
54
|
+
type ButtonVariant = Extract<keyof (typeof colorClasses)[ButtonColor], string>
|
|
55
|
+
|
|
56
|
+
const component = computed(() => (props.to === undefined ? 'button' : BaseLink))
|
|
57
|
+
const disabled = computed(() => props.disabled || props.loading)
|
|
58
|
+
const isButton = computed(() => props.to === undefined)
|
|
59
|
+
const classes = computed(() => [
|
|
60
|
+
UI_STYLE.base,
|
|
61
|
+
sizeClasses[props.size],
|
|
62
|
+
colorClasses[props.color][props.variant],
|
|
63
|
+
props.block && UI_STYLE.state.block,
|
|
64
|
+
props.square && UI_STYLE.state.square,
|
|
65
|
+
disabled.value && UI_STYLE.state.disabled,
|
|
66
|
+
])
|
|
67
|
+
|
|
68
|
+
const isAnimating = shallowRef(false)
|
|
69
|
+
const animationTapClass = UI_STYLE.animationTap
|
|
70
|
+
function handleTap(): void {
|
|
71
|
+
isAnimating.value = false
|
|
72
|
+
|
|
73
|
+
requestAnimationFrame(() => {
|
|
74
|
+
isAnimating.value = true
|
|
75
|
+
})
|
|
76
|
+
}
|
|
45
77
|
</script>
|
|
46
78
|
|
|
47
79
|
<template>
|
|
@@ -49,16 +81,16 @@ function handleTap() {
|
|
|
49
81
|
:is="component"
|
|
50
82
|
v-bind="animationTapClass ? { onPointerupPassive: handleTap } : {}"
|
|
51
83
|
:to="props.to"
|
|
52
|
-
:type="isButton ? props.type :
|
|
53
|
-
:disabled="isButton ? disabled :
|
|
54
|
-
:aria-busy="props.loading ||
|
|
55
|
-
:aria-disabled="disabled ||
|
|
56
|
-
:tabindex="disabled && !isButton ? -1 :
|
|
84
|
+
:type="isButton ? props.type : undefined"
|
|
85
|
+
:disabled="isButton ? disabled : undefined"
|
|
86
|
+
:aria-busy="props.loading || undefined"
|
|
87
|
+
:aria-disabled="disabled || undefined"
|
|
88
|
+
:tabindex="disabled && !isButton ? -1 : undefined"
|
|
57
89
|
:class="[classes, isAnimating && animationTapClass]"
|
|
58
90
|
data-testid="ui-button"
|
|
59
91
|
:style="{
|
|
60
|
-
|
|
61
|
-
}"
|
|
92
|
+
borderRadius: props.rounded && '99999px',
|
|
93
|
+
}"
|
|
62
94
|
@contextmenu.prevent
|
|
63
95
|
>
|
|
64
96
|
<span
|
|
@@ -74,7 +106,7 @@ function handleTap() {
|
|
|
74
106
|
/>
|
|
75
107
|
<Icon
|
|
76
108
|
v-else
|
|
77
|
-
:name="props.icon"
|
|
109
|
+
:name="props.icon!"
|
|
78
110
|
:class="sizeIconClasses[props.size]"
|
|
79
111
|
aria-hidden="true"
|
|
80
112
|
/>
|
|
@@ -94,7 +126,7 @@ function handleTap() {
|
|
|
94
126
|
>
|
|
95
127
|
<slot name="trailing">
|
|
96
128
|
<Icon
|
|
97
|
-
:name="props.trailingIcon"
|
|
129
|
+
:name="props.trailingIcon!"
|
|
98
130
|
:class="sizeIconClasses[props.size]"
|
|
99
131
|
aria-hidden="true"
|
|
100
132
|
/>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
title: 'Size & Rounded',
|
|
4
|
+
}
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
|
-
<script setup>
|
|
8
|
-
import { buttonConfig, firstIconName } from
|
|
9
|
-
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { buttonConfig, firstIconName } from '#brickflow-ui-icons'
|
|
9
|
+
|
|
10
|
+
import Button from './index.vue'
|
|
10
11
|
</script>
|
|
11
12
|
|
|
12
13
|
<template>
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
title: 'Slots',
|
|
4
|
+
}
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
|
-
<script setup>
|
|
8
|
-
import { ref } from
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { ref } from 'vue'
|
|
9
|
+
|
|
10
|
+
import Button from './index.vue'
|
|
11
|
+
|
|
12
|
+
const clicks = ref(0)
|
|
11
13
|
</script>
|
|
12
14
|
|
|
13
15
|
<template>
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
title: 'State',
|
|
4
|
+
}
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
|
-
<script setup>
|
|
8
|
-
import { buttonConfig } from
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { buttonConfig } from '#brickflow-ui-icons'
|
|
9
|
+
|
|
10
|
+
import Button from './index.vue'
|
|
11
|
+
|
|
12
|
+
const firstColorClasses = Object.values(buttonConfig.colorClasses)[0] ?? {}
|
|
11
13
|
</script>
|
|
12
14
|
|
|
13
15
|
<template>
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
title: 'Color & Variants',
|
|
4
|
+
}
|
|
5
5
|
</script>
|
|
6
6
|
|
|
7
|
-
<script setup>
|
|
8
|
-
import { buttonConfig } from
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
<script lang="ts" setup>
|
|
8
|
+
import { buttonConfig } from '#brickflow-ui-icons'
|
|
9
|
+
|
|
10
|
+
import Button from './index.vue'
|
|
11
|
+
|
|
12
|
+
const firstColorClasses = Object.values(buttonConfig.colorClasses)[0] ?? {}
|
|
11
13
|
</script>
|
|
12
14
|
|
|
13
15
|
<template>
|
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
description: 'The name matches the SVG filename without its extension.',
|
|
4
|
+
title: 'Basic usage',
|
|
5
|
+
}
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
|
-
<script setup>
|
|
9
|
-
import { ref } from
|
|
10
|
-
|
|
11
|
-
import
|
|
12
|
-
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import { ref } from 'vue'
|
|
10
|
+
|
|
11
|
+
import { firstIconName } from '#brickflow-ui-icons'
|
|
12
|
+
|
|
13
|
+
import Icon from './index.vue'
|
|
14
|
+
|
|
15
|
+
const iconName = ref(firstIconName)
|
|
13
16
|
</script>
|
|
14
17
|
|
|
15
18
|
<template>
|
|
@@ -1,36 +1,44 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
description: 'Browse every icon available in the project, filter by name, and click to copy its name.',
|
|
4
|
+
title: 'Icon gallery',
|
|
5
|
+
}
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
|
-
<script setup>
|
|
9
|
-
import { computed, onBeforeUnmount, ref } from
|
|
10
|
-
|
|
11
|
-
import
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import { computed, onBeforeUnmount, ref } from 'vue'
|
|
10
|
+
|
|
11
|
+
import { iconNames } from '#brickflow-ui-icons'
|
|
12
|
+
|
|
13
|
+
import Icon from './index.vue'
|
|
14
|
+
|
|
15
|
+
const search = ref('')
|
|
16
|
+
const copiedIconName = ref('')
|
|
17
|
+
const copyError = ref('')
|
|
18
|
+
let copiedTimeout: ReturnType<typeof setTimeout> | undefined
|
|
19
|
+
|
|
20
|
+
const filteredIconNames = computed(() => {
|
|
21
|
+
const query = search.value.trim().toLocaleLowerCase()
|
|
22
|
+
|
|
23
|
+
return query ? iconNames.filter((name) => name.toLocaleLowerCase().includes(query)) : iconNames
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const copyIconName = async (name: string): Promise<void> => {
|
|
27
|
+
copyError.value = ''
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
await navigator.clipboard.writeText(name)
|
|
31
|
+
clearTimeout(copiedTimeout)
|
|
32
|
+
copiedIconName.value = name
|
|
33
|
+
copiedTimeout = setTimeout(() => {
|
|
34
|
+
copiedIconName.value = ''
|
|
35
|
+
}, 2000)
|
|
36
|
+
} catch {
|
|
37
|
+
copyError.value = 'Could not copy the icon name. Please try again.'
|
|
38
|
+
}
|
|
31
39
|
}
|
|
32
|
-
|
|
33
|
-
onBeforeUnmount(() => clearTimeout(copiedTimeout))
|
|
40
|
+
|
|
41
|
+
onBeforeUnmount(() => clearTimeout(copiedTimeout))
|
|
34
42
|
</script>
|
|
35
43
|
|
|
36
44
|
<template>
|
|
@@ -75,7 +83,7 @@ onBeforeUnmount(() => clearTimeout(copiedTimeout));
|
|
|
75
83
|
class="sr-only"
|
|
76
84
|
role="status"
|
|
77
85
|
>
|
|
78
|
-
{{ copiedIconName ? `Copied ${copiedIconName}` :
|
|
86
|
+
{{ copiedIconName ? `Copied ${copiedIconName}` : '' }}
|
|
79
87
|
</p>
|
|
80
88
|
<p
|
|
81
89
|
v-if="copyError"
|
|
@@ -98,9 +106,11 @@ onBeforeUnmount(() => clearTimeout(copiedTimeout));
|
|
|
98
106
|
type="button"
|
|
99
107
|
:aria-label="`Copy ${name}`"
|
|
100
108
|
:class="[
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
109
|
+
'group flex w-full cursor-pointer flex-col items-center gap-3 rounded-xl border px-3 py-5 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-400',
|
|
110
|
+
copiedIconName === name
|
|
111
|
+
? 'border-green-500/50 bg-green-500/10'
|
|
112
|
+
: 'border-zinc-900 bg-zinc-950/50 hover:border-zinc-700 hover:bg-zinc-900/70',
|
|
113
|
+
]"
|
|
104
114
|
:title="`Copy ${name}`"
|
|
105
115
|
@click="copyIconName(name)"
|
|
106
116
|
>
|
|
@@ -111,11 +121,11 @@ onBeforeUnmount(() => clearTimeout(copiedTimeout));
|
|
|
111
121
|
/>
|
|
112
122
|
<span
|
|
113
123
|
:class="[
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
]"
|
|
124
|
+
'w-full truncate text-center font-mono text-xs transition-colors',
|
|
125
|
+
copiedIconName === name ? 'text-green-400' : 'text-zinc-400 group-hover:text-zinc-100',
|
|
126
|
+
]"
|
|
117
127
|
>
|
|
118
|
-
{{ copiedIconName === name ?
|
|
128
|
+
{{ copiedIconName === name ? 'Copied' : name }}
|
|
119
129
|
</span>
|
|
120
130
|
</button>
|
|
121
131
|
</li>
|
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { computed } from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
|
|
4
|
+
defineOptions({
|
|
5
|
+
inheritAttrs: false,
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
const props = withDefaults(
|
|
9
|
+
defineProps<{
|
|
10
|
+
name: string
|
|
11
|
+
}>(),
|
|
12
|
+
{},
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
const classes = computed(() => `icon-${props.name}`)
|
|
10
16
|
</script>
|
|
11
17
|
|
|
12
18
|
<template>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
export const uiDemo = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
export const uiDemo = {
|
|
3
|
+
description: 'Internal navigation keeps the current locale.',
|
|
4
|
+
title: 'Basic usage',
|
|
5
|
+
}
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
|
-
<script setup>
|
|
9
|
-
import Link from
|
|
8
|
+
<script lang="ts" setup>
|
|
9
|
+
import Link from './index.vue'
|
|
10
10
|
</script>
|
|
11
11
|
|
|
12
12
|
<template>
|
|
@@ -8,55 +8,86 @@
|
|
|
8
8
|
</NuxtLink>
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
|
-
<script setup>
|
|
12
|
-
import { computed, ref } from
|
|
13
|
-
import { useRouter } from
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
11
|
+
<script lang="ts" setup>
|
|
12
|
+
import { type ComponentPublicInstance, computed, ref } from 'vue'
|
|
13
|
+
import { type RouteLocationPathRaw, type RouteLocationRaw, useRouter } from 'vue-router'
|
|
14
|
+
|
|
15
|
+
import { useTranslate } from '../../composables/useTranslate'
|
|
16
|
+
|
|
17
|
+
defineOptions({ inheritAttrs: false })
|
|
18
|
+
|
|
19
|
+
const props = withDefaults(
|
|
20
|
+
defineProps<{
|
|
21
|
+
activeClass?: string
|
|
22
|
+
class?: (false | string)[] | string
|
|
23
|
+
custom?: boolean
|
|
24
|
+
exactActiveClass?: string
|
|
25
|
+
external?: boolean
|
|
26
|
+
faster?: boolean
|
|
27
|
+
href?: RouteLocationRaw
|
|
28
|
+
onClick?: () => void
|
|
29
|
+
onPointerdown?: () => void
|
|
30
|
+
prefetch?: boolean
|
|
31
|
+
rel?: null | string
|
|
32
|
+
replace?: boolean
|
|
33
|
+
style?: Record<string, string>
|
|
34
|
+
target?: '_blank' | '_parent' | '_self' | '_top' | null | (Record<string, never> & string)
|
|
35
|
+
to?: RouteLocationRaw
|
|
36
|
+
}>(),
|
|
37
|
+
{
|
|
38
|
+
activeClass: undefined,
|
|
39
|
+
class: undefined,
|
|
40
|
+
custom: false,
|
|
41
|
+
exactActiveClass: undefined,
|
|
42
|
+
external: false,
|
|
43
|
+
faster: false,
|
|
44
|
+
href: undefined,
|
|
45
|
+
onClick: undefined,
|
|
46
|
+
onPointerdown: undefined,
|
|
47
|
+
prefetch: false,
|
|
48
|
+
rel: undefined,
|
|
49
|
+
replace: false,
|
|
50
|
+
style: undefined,
|
|
51
|
+
target: undefined,
|
|
52
|
+
to: undefined,
|
|
53
|
+
},
|
|
54
|
+
)
|
|
55
|
+
const { localePath } = useTranslate()
|
|
56
|
+
|
|
57
|
+
const prepareProps = computed(() => {
|
|
58
|
+
const { faster: _faster, onPointerdown: _onPointerdown, ...linkProps } = props
|
|
59
|
+
const refineDrops = { ...linkProps, onPointerdown: props.faster ? handlePointerDown : undefined }
|
|
60
|
+
|
|
61
|
+
if (typeof props.to === 'string') {
|
|
62
|
+
return { ...refineDrops, to: localePath(props.to) }
|
|
63
|
+
} else if ((props.to as RouteLocationPathRaw)?.path) {
|
|
64
|
+
return { ...refineDrops, to: { ...props.to, path: localePath((props.to as RouteLocationPathRaw).path) } }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return refineDrops
|
|
68
|
+
})
|
|
69
|
+
const linkRef = ref<ComponentPublicInstance>()
|
|
70
|
+
|
|
71
|
+
function handlePointerDown(e: PointerEvent): void {
|
|
72
|
+
const router = useRouter()
|
|
73
|
+
props.onPointerdown?.()
|
|
74
|
+
if (e.button !== 0) {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
e.preventDefault()
|
|
82
|
+
|
|
83
|
+
const to = prepareProps.value.to
|
|
84
|
+
|
|
85
|
+
if (!to) {
|
|
86
|
+
return
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
props.replace ? router.replace(to) : router.push(to)
|
|
58
90
|
}
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
defineExpose({ linkRef });
|
|
91
|
+
|
|
92
|
+
defineExpose({ linkRef })
|
|
62
93
|
</script>
|