@globalbrain/sefirot 3.29.2 → 3.31.0
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/lib/components/SInputTextarea.vue +112 -52
- package/lib/composables/Markdown.ts +1 -0
- package/lib/composables/Url.ts +100 -87
- package/lib/styles/bootstrap.css +4 -4
- package/package.json +15 -15
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { type IconifyIcon } from '@iconify/vue/dist/offline'
|
|
3
|
-
import { computed } from 'vue'
|
|
3
|
+
import { computed, ref } from 'vue'
|
|
4
4
|
import { type Validatable } from '../composables/V'
|
|
5
5
|
import SInputBase from './SInputBase.vue'
|
|
6
|
+
import SInputSegments from './SInputSegments.vue'
|
|
6
7
|
|
|
7
8
|
export type Size = 'mini' | 'small' | 'medium'
|
|
8
9
|
export type Color = 'neutral' | 'mute' | 'info' | 'success' | 'warning' | 'danger'
|
|
@@ -24,6 +25,9 @@ const props = defineProps<{
|
|
|
24
25
|
modelValue?: string | null
|
|
25
26
|
hideError?: boolean
|
|
26
27
|
validation?: Validatable
|
|
28
|
+
preview?: (value: string | null) => string
|
|
29
|
+
previewLabel?: string
|
|
30
|
+
writeLabel?: string
|
|
27
31
|
}>()
|
|
28
32
|
|
|
29
33
|
const emit = defineEmits<{
|
|
@@ -57,6 +61,8 @@ function emitBlur(e: FocusEvent): void {
|
|
|
57
61
|
emit('update:model-value', v)
|
|
58
62
|
emit('blur', v)
|
|
59
63
|
}
|
|
64
|
+
|
|
65
|
+
const isPreview = ref(false)
|
|
60
66
|
</script>
|
|
61
67
|
|
|
62
68
|
<template>
|
|
@@ -74,24 +80,96 @@ function emitBlur(e: FocusEvent): void {
|
|
|
74
80
|
:hide-error="hideError"
|
|
75
81
|
:validation="validation"
|
|
76
82
|
>
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
<div class="box">
|
|
84
|
+
<div v-if="preview !== undefined" class="control">
|
|
85
|
+
<SInputSegments
|
|
86
|
+
:options="[
|
|
87
|
+
{ label: writeLabel ?? 'Write', value: false },
|
|
88
|
+
{ label: previewLabel ?? 'Preview', value: true }
|
|
89
|
+
]"
|
|
90
|
+
v-model="isPreview"
|
|
91
|
+
size="mini"
|
|
92
|
+
/>
|
|
93
|
+
</div>
|
|
94
|
+
<textarea
|
|
95
|
+
v-show="!isPreview"
|
|
96
|
+
:id="name"
|
|
97
|
+
class="input"
|
|
98
|
+
:placeholder="placeholder"
|
|
99
|
+
:rows="rows ?? 3"
|
|
100
|
+
:disabled="disabled"
|
|
101
|
+
:value="_value ?? undefined"
|
|
102
|
+
@input="emitInput"
|
|
103
|
+
@blur="emitBlur"
|
|
104
|
+
/>
|
|
105
|
+
<div
|
|
106
|
+
v-if="preview !== undefined && isPreview"
|
|
107
|
+
class="prose"
|
|
108
|
+
:class="!_value && 'empty'"
|
|
109
|
+
v-html="preview(_value)"
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
88
112
|
<template v-if="$slots.info" #info><slot name="info" /></template>
|
|
89
113
|
</SInputBase>
|
|
90
114
|
</template>
|
|
91
115
|
|
|
92
116
|
<style scoped lang="postcss">
|
|
117
|
+
.box {
|
|
118
|
+
display: flex;
|
|
119
|
+
flex-direction: column;
|
|
120
|
+
gap: 1px;
|
|
121
|
+
flex-grow: 1;
|
|
122
|
+
border: 1px solid var(--input-border-color);
|
|
123
|
+
border-radius: 6px;
|
|
124
|
+
width: 100%;
|
|
125
|
+
background-color: var(--c-gutter);
|
|
126
|
+
overflow: hidden;
|
|
127
|
+
transition: border-color 0.25s;
|
|
128
|
+
|
|
129
|
+
&:has(.input:hover) {
|
|
130
|
+
border-color: var(--input-hover-border-color);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
&:has(.input:focus) {
|
|
134
|
+
border-color: var(--input-focus-border-color);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.control {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
padding: 0 8px;
|
|
142
|
+
height: 48px;
|
|
143
|
+
background-color: var(--c-bg-elv-3);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.input,
|
|
147
|
+
.prose {
|
|
148
|
+
display: block;
|
|
149
|
+
flex-grow: 1;
|
|
150
|
+
width: 100%;
|
|
151
|
+
font-family: var(--input-value-font-family);
|
|
152
|
+
font-weight: 400;
|
|
153
|
+
background-color: var(--input-bg-color);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.input {
|
|
157
|
+
&::placeholder {
|
|
158
|
+
color: var(--input-placeholder-color);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.prose {
|
|
163
|
+
background-color: var(--c-bg-elv-3);
|
|
164
|
+
|
|
165
|
+
&.empty {
|
|
166
|
+
color: var(--input-placeholder-color);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
93
170
|
.SInputTextarea.mini {
|
|
94
|
-
.input
|
|
171
|
+
.input,
|
|
172
|
+
.prose {
|
|
95
173
|
padding: 6px 10px;
|
|
96
174
|
width: 100%;
|
|
97
175
|
min-height: 80px;
|
|
@@ -101,7 +179,8 @@ function emitBlur(e: FocusEvent): void {
|
|
|
101
179
|
}
|
|
102
180
|
|
|
103
181
|
.SInputTextarea.small {
|
|
104
|
-
.input
|
|
182
|
+
.input,
|
|
183
|
+
.prose {
|
|
105
184
|
padding: 7px 12px;
|
|
106
185
|
width: 100%;
|
|
107
186
|
min-height: 96px;
|
|
@@ -111,7 +190,8 @@ function emitBlur(e: FocusEvent): void {
|
|
|
111
190
|
}
|
|
112
191
|
|
|
113
192
|
.SInputTextarea.medium {
|
|
114
|
-
.input
|
|
193
|
+
.input,
|
|
194
|
+
.prose {
|
|
115
195
|
padding: 11px 16px;
|
|
116
196
|
width: 100%;
|
|
117
197
|
min-height: 96px;
|
|
@@ -120,10 +200,24 @@ function emitBlur(e: FocusEvent): void {
|
|
|
120
200
|
}
|
|
121
201
|
}
|
|
122
202
|
|
|
123
|
-
.SInputTextarea.
|
|
203
|
+
.SInputTextarea.fill {
|
|
204
|
+
display: flex;
|
|
205
|
+
flex-direction: column;
|
|
206
|
+
flex-grow: 1;
|
|
207
|
+
height: 100%;
|
|
208
|
+
|
|
124
209
|
.input,
|
|
125
|
-
.
|
|
210
|
+
.prose {
|
|
211
|
+
height: 100%;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.SInputTextarea.disabled {
|
|
216
|
+
.box {
|
|
126
217
|
border-color: var(--input-disabled-border-color);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.input {
|
|
127
221
|
color: var(--input-disabled-value-color);
|
|
128
222
|
background-color: var(--input-disabled-bg-color);
|
|
129
223
|
cursor: not-allowed;
|
|
@@ -131,42 +225,8 @@ function emitBlur(e: FocusEvent): void {
|
|
|
131
225
|
}
|
|
132
226
|
|
|
133
227
|
.SInputTextarea.has-error {
|
|
134
|
-
.
|
|
228
|
+
.box {
|
|
135
229
|
border-color: var(--input-error-border-color);
|
|
136
|
-
|
|
137
|
-
&:hover,
|
|
138
|
-
&:focus {
|
|
139
|
-
border-color: var(--input-error-border-color);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
.input {
|
|
145
|
-
display: block;
|
|
146
|
-
flex-grow: 1;
|
|
147
|
-
border: 1px solid var(--input-border-color);
|
|
148
|
-
border-radius: 6px;
|
|
149
|
-
width: 100%;
|
|
150
|
-
font-family: var(--input-value-font-family);
|
|
151
|
-
font-weight: 400;
|
|
152
|
-
background-color: var(--input-bg-color);
|
|
153
|
-
transition: border-color 0.25s, background-color 0.25s;
|
|
154
|
-
|
|
155
|
-
&::placeholder {
|
|
156
|
-
color: var(--input-placeholder-color);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
&:hover {
|
|
160
|
-
border-color: var(--input-hover-border-color);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
&:focus,
|
|
164
|
-
&:hover:focus {
|
|
165
|
-
border-color: var(--input-focus-border-color);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
&.fill {
|
|
169
|
-
height: 100%;
|
|
170
230
|
}
|
|
171
231
|
}
|
|
172
232
|
</style>
|
package/lib/composables/Url.ts
CHANGED
|
@@ -1,128 +1,141 @@
|
|
|
1
1
|
import isEqual from 'lodash-es/isEqual'
|
|
2
|
-
import
|
|
3
|
-
import { type
|
|
4
|
-
import { useRoute, useRouter } from 'vue-router'
|
|
2
|
+
import { type MaybeRef, nextTick, unref, watch } from 'vue'
|
|
3
|
+
import { type LocationQuery, useRoute, useRouter } from 'vue-router'
|
|
5
4
|
|
|
6
5
|
export interface UseUrlQuerySyncOptions {
|
|
7
6
|
casts?: Record<string, (value: any) => any>
|
|
8
7
|
exclude?: string[]
|
|
9
8
|
}
|
|
10
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Sync between the given state and the URL query params.
|
|
12
|
+
*
|
|
13
|
+
* Caveats:
|
|
14
|
+
* - Vulnerable to prototype pollution.
|
|
15
|
+
* - Does not support objects inside arrays.
|
|
16
|
+
*/
|
|
11
17
|
export function useUrlQuerySync(
|
|
12
18
|
state: MaybeRef<Record<string, any>>,
|
|
13
|
-
{ casts = {}, exclude }: UseUrlQuerySyncOptions = {}
|
|
19
|
+
{ casts = {}, exclude = [] }: UseUrlQuerySyncOptions = {}
|
|
14
20
|
): void {
|
|
15
|
-
const router = useRouter()
|
|
16
21
|
const route = useRoute()
|
|
22
|
+
const router = useRouter()
|
|
17
23
|
|
|
18
|
-
const
|
|
19
|
-
JSON.parse(JSON.stringify(unref(state)))
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
setStateFromQuery()
|
|
23
|
-
|
|
24
|
-
watch(() => unref(state), setQueryFromState, {
|
|
25
|
-
deep: true,
|
|
26
|
-
immediate: true
|
|
27
|
-
})
|
|
24
|
+
const flattenedDefaultState = flattenObject(unref(state))
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
const flattenState = flattenObject(unref(state))
|
|
31
|
-
const flattenQuery = flattenObject(route.query)
|
|
26
|
+
let isSyncing = false
|
|
32
27
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
28
|
+
watch(
|
|
29
|
+
() => route.query,
|
|
30
|
+
async () => {
|
|
31
|
+
if (!isSyncing) {
|
|
32
|
+
isSyncing = true
|
|
33
|
+
await setState()
|
|
34
|
+
isSyncing = false
|
|
36
35
|
}
|
|
36
|
+
},
|
|
37
|
+
{ deep: true, immediate: true }
|
|
38
|
+
)
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
watch(
|
|
41
|
+
() => unref(state),
|
|
42
|
+
async () => {
|
|
43
|
+
if (!isSyncing) {
|
|
44
|
+
isSyncing = true
|
|
45
|
+
await setQuery()
|
|
46
|
+
isSyncing = false
|
|
41
47
|
}
|
|
48
|
+
},
|
|
49
|
+
{ deep: true }
|
|
50
|
+
)
|
|
42
51
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
52
|
+
async function setState() {
|
|
53
|
+
const newState = unflattenObject({ ...flattenedDefaultState, ...normalizeQuery(route.query) })
|
|
54
|
+
deepAssign(unref(state), newState)
|
|
46
55
|
|
|
47
|
-
|
|
56
|
+
await nextTick()
|
|
57
|
+
await setQuery()
|
|
48
58
|
}
|
|
49
59
|
|
|
50
|
-
async function
|
|
51
|
-
const
|
|
52
|
-
const
|
|
60
|
+
async function setQuery() {
|
|
61
|
+
const flattenedState = flattenObject(unref(state))
|
|
62
|
+
const newQuery: Record<string, any> = {}
|
|
53
63
|
|
|
54
|
-
|
|
55
|
-
if (exclude
|
|
56
|
-
|
|
64
|
+
for (const key in flattenedState) {
|
|
65
|
+
if (!exclude.includes(key) && flattenedDefaultState[key] !== flattenedState[key]) {
|
|
66
|
+
newQuery[key] = flattenedState[key]
|
|
57
67
|
}
|
|
68
|
+
}
|
|
58
69
|
|
|
59
|
-
|
|
60
|
-
const initialValue = flattenInitialState[key]
|
|
70
|
+
const currentQuery = normalizeQuery(route.query)
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
72
|
+
if (!isEqual(newQuery, currentQuery)) {
|
|
73
|
+
await router.replace({ query: unflattenObject(newQuery) })
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function normalizeQuery(query: LocationQuery): Record<string, any> {
|
|
78
|
+
const flattenedQuery = flattenObject(query)
|
|
79
|
+
const result: Record<string, any> = {}
|
|
67
80
|
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
for (const key in flattenedQuery) {
|
|
82
|
+
if (!exclude.includes(key)) {
|
|
83
|
+
result[key] = casts[key] ? casts[key](flattenedQuery[key]) : flattenedQuery[key]
|
|
70
84
|
}
|
|
71
|
-
}
|
|
85
|
+
}
|
|
72
86
|
|
|
73
|
-
|
|
87
|
+
return result
|
|
74
88
|
}
|
|
75
89
|
}
|
|
76
90
|
|
|
77
|
-
function flattenObject(obj: Record<string, any>,
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
function flattenObject(obj: Record<string, any>, path: string[] = []): Record<string, any> {
|
|
92
|
+
const result: Record<string, any> = {}
|
|
93
|
+
|
|
94
|
+
for (const key in obj) {
|
|
95
|
+
const value = obj[key]
|
|
96
|
+
|
|
97
|
+
if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
98
|
+
Object.assign(result, flattenObject(value, [...path, key]))
|
|
82
99
|
} else {
|
|
83
|
-
|
|
100
|
+
result[path.concat(key).join('.')] = value
|
|
84
101
|
}
|
|
85
|
-
|
|
86
|
-
}, {} as Record<string, any>)
|
|
87
|
-
}
|
|
102
|
+
}
|
|
88
103
|
|
|
89
|
-
|
|
90
|
-
return Object.keys(obj).reduce((acc, k) => {
|
|
91
|
-
const keys = k.split('.')
|
|
92
|
-
keys.reduce((a, c, i) => {
|
|
93
|
-
if (i === keys.length - 1) {
|
|
94
|
-
a[c] = obj[k]
|
|
95
|
-
} else {
|
|
96
|
-
a[c] = a[c] || {}
|
|
97
|
-
}
|
|
98
|
-
return a[c]
|
|
99
|
-
}, acc)
|
|
100
|
-
return acc
|
|
101
|
-
}, {} as Record<string, any>)
|
|
104
|
+
return result
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
function
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
107
|
+
function unflattenObject(obj: Record<string, any>): Record<string, any> {
|
|
108
|
+
const result: Record<string, any> = {}
|
|
109
|
+
|
|
110
|
+
for (const key in obj) {
|
|
111
|
+
const value = obj[key]
|
|
112
|
+
|
|
113
|
+
let target = result
|
|
114
|
+
const keys = key.split('.')
|
|
115
|
+
|
|
116
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
117
|
+
const k = keys[i]
|
|
118
|
+
target = target[k] = target[k] || {}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
target[keys[keys.length - 1]] = value
|
|
115
122
|
}
|
|
123
|
+
|
|
124
|
+
return result
|
|
116
125
|
}
|
|
117
126
|
|
|
118
|
-
function
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
function deepAssign(target: Record<string, any>, source: Record<string, any>) {
|
|
128
|
+
for (const key in source) {
|
|
129
|
+
const value = source[key]
|
|
130
|
+
|
|
131
|
+
if (Array.isArray(value)) {
|
|
132
|
+
target[key].splice(0, target[key].length, ...value)
|
|
133
|
+
} else if (value && typeof value === 'object') {
|
|
134
|
+
target[key] = deepAssign(target[key] || {}, value)
|
|
135
|
+
} else {
|
|
136
|
+
target[key] = value
|
|
137
|
+
}
|
|
127
138
|
}
|
|
139
|
+
|
|
140
|
+
return target
|
|
128
141
|
}
|
package/lib/styles/bootstrap.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@import "normalize.css";
|
|
2
2
|
@import "v-calendar/dist/style.css";
|
|
3
|
-
@import "./variables-deprecated";
|
|
4
|
-
@import "./variables";
|
|
5
|
-
@import "./base";
|
|
6
|
-
@import "./utilities";
|
|
3
|
+
@import "./variables-deprecated.css";
|
|
4
|
+
@import "./variables.css";
|
|
5
|
+
@import "./base.css";
|
|
6
|
+
@import "./utilities.css";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@globalbrain/sefirot",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"packageManager": "pnpm@8.15.
|
|
3
|
+
"version": "3.31.0",
|
|
4
|
+
"packageManager": "pnpm@8.15.3",
|
|
5
5
|
"description": "Vue Components for Global Brain Design System.",
|
|
6
6
|
"author": "Kia Ishii <ka.ishii@globalbrains.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -53,10 +53,10 @@
|
|
|
53
53
|
"markdown-it": "^14.0.0",
|
|
54
54
|
"normalize.css": "^8.0.1",
|
|
55
55
|
"pinia": "^2.1.7",
|
|
56
|
-
"postcss": "^8.4.
|
|
56
|
+
"postcss": "^8.4.35",
|
|
57
57
|
"postcss-nested": "^6.0.1",
|
|
58
58
|
"v-calendar": "^3.1.2",
|
|
59
|
-
"vue": "^3.4.
|
|
59
|
+
"vue": "^3.4.19",
|
|
60
60
|
"vue-router": "^4.2.5"
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
74
|
"@globalbrain/eslint-config": "^1.5.2",
|
|
75
|
-
"@histoire/plugin-vue": "
|
|
75
|
+
"@histoire/plugin-vue": "0.17.9",
|
|
76
76
|
"@iconify-icons/ph": "^1.2.5",
|
|
77
77
|
"@iconify-icons/ri": "^1.2.10",
|
|
78
78
|
"@iconify/vue": "^4.1.1",
|
|
@@ -80,9 +80,9 @@
|
|
|
80
80
|
"@types/body-scroll-lock": "^3.1.2",
|
|
81
81
|
"@types/lodash-es": "^4.17.12",
|
|
82
82
|
"@types/markdown-it": "^13.0.7",
|
|
83
|
-
"@types/node": "^20.11.
|
|
84
|
-
"@vitejs/plugin-vue": "^5.0.
|
|
85
|
-
"@vitest/coverage-v8": "^1.
|
|
83
|
+
"@types/node": "^20.11.19",
|
|
84
|
+
"@vitejs/plugin-vue": "^5.0.4",
|
|
85
|
+
"@vitest/coverage-v8": "^1.3.0",
|
|
86
86
|
"@vue/test-utils": "^2.4.4",
|
|
87
87
|
"@vuelidate/core": "^2.0.3",
|
|
88
88
|
"@vuelidate/validators": "^2.0.4",
|
|
@@ -91,21 +91,21 @@
|
|
|
91
91
|
"eslint": "^8.56.0",
|
|
92
92
|
"fuse.js": "^7.0.0",
|
|
93
93
|
"happy-dom": "^13.3.8",
|
|
94
|
-
"histoire": "
|
|
94
|
+
"histoire": "0.17.9",
|
|
95
95
|
"lodash-es": "^4.17.21",
|
|
96
96
|
"markdown-it": "^14.0.0",
|
|
97
97
|
"normalize.css": "^8.0.1",
|
|
98
98
|
"pinia": "^2.1.7",
|
|
99
|
-
"postcss": "^8.4.
|
|
99
|
+
"postcss": "^8.4.35",
|
|
100
100
|
"postcss-nested": "^6.0.1",
|
|
101
101
|
"punycode": "^2.3.1",
|
|
102
|
-
"release-it": "^17.
|
|
102
|
+
"release-it": "^17.1.1",
|
|
103
103
|
"typescript": "~5.3.3",
|
|
104
104
|
"v-calendar": "^3.1.2",
|
|
105
|
-
"vite": "^5.
|
|
106
|
-
"vitepress": "1.0.0-rc.
|
|
107
|
-
"vitest": "^1.
|
|
108
|
-
"vue": "^3.4.
|
|
105
|
+
"vite": "^5.1.3",
|
|
106
|
+
"vitepress": "1.0.0-rc.44",
|
|
107
|
+
"vitest": "^1.3.0",
|
|
108
|
+
"vue": "^3.4.19",
|
|
109
109
|
"vue-router": "^4.2.5",
|
|
110
110
|
"vue-tsc": "^1.8.27"
|
|
111
111
|
}
|