@globalbrain/sefirot 2.2.1 → 2.4.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.
Files changed (50) hide show
  1. package/lib/components/SButton.vue +0 -1
  2. package/lib/components/SButtonGroup.vue +17 -17
  3. package/lib/components/SDropdownSectionFilter.vue +5 -5
  4. package/lib/components/SIcon.vue +2 -2
  5. package/lib/components/SInputBase.vue +4 -5
  6. package/lib/components/SInputCheckbox.vue +23 -23
  7. package/lib/components/SInputCheckboxes.vue +23 -23
  8. package/lib/components/SInputDate.vue +55 -132
  9. package/lib/components/SInputDropdown.vue +3 -3
  10. package/lib/components/SInputFile.vue +1 -1
  11. package/lib/components/SInputSelect.vue +48 -48
  12. package/lib/components/SInputSwitch.vue +68 -142
  13. package/lib/components/SInputSwitches.vue +51 -58
  14. package/lib/components/SInputText.vue +1 -1
  15. package/lib/components/SInputTextarea.vue +24 -24
  16. package/lib/components/SLink.vue +14 -14
  17. package/lib/components/SMarkdown.vue +3 -3
  18. package/lib/components/SMount.vue +1 -1
  19. package/lib/components/SSheetFooterAction.vue +1 -1
  20. package/lib/components/SSpinner.vue +28 -12
  21. package/lib/components/SStep.vue +15 -15
  22. package/lib/components/SSteps.vue +16 -16
  23. package/lib/components/STable.vue +2 -2
  24. package/lib/components/STableCellAvatar.vue +1 -1
  25. package/lib/components/STableCellAvatars.vue +1 -1
  26. package/lib/components/STableCellDay.vue +1 -1
  27. package/lib/components/STableColumn.vue +4 -4
  28. package/lib/components/STooltip.vue +17 -17
  29. package/lib/composables/Data.ts +108 -0
  30. package/lib/composables/Form.ts +12 -12
  31. package/lib/composables/Grid.ts +3 -3
  32. package/lib/composables/Markdown.ts +2 -2
  33. package/lib/composables/Tooltip.ts +2 -1
  34. package/lib/composables/Validation.ts +2 -2
  35. package/lib/support/Day.ts +1 -1
  36. package/lib/support/Utils.ts +4 -0
  37. package/lib/validation/rules/email.ts +1 -1
  38. package/lib/validation/rules/hms.ts +1 -1
  39. package/lib/validation/rules/maxLength.ts +1 -1
  40. package/lib/validation/rules/maxValue.ts +1 -1
  41. package/lib/validation/rules/minLength.ts +1 -1
  42. package/lib/validation/rules/minValue.ts +1 -1
  43. package/lib/validation/rules/required.ts +1 -1
  44. package/lib/validation/rules/requiredHms.ts +1 -1
  45. package/lib/validation/rules/requiredIf.ts +1 -1
  46. package/lib/validation/rules/requiredYmd.ts +1 -1
  47. package/lib/validation/rules/url.ts +1 -1
  48. package/lib/validation/rules/ymd.ts +1 -1
  49. package/lib/validation/validators/requiredYmd.ts +1 -1
  50. package/package.json +12 -15
@@ -1,20 +1,6 @@
1
- <template>
2
- <div class="SSteps">
3
- <SStep
4
- v-for="(step, index) in steps"
5
- :key="index"
6
- class="item"
7
- :style="{ width }"
8
- :bar-left="getBarLeftMode(index)"
9
- :bar-right="getBarRightMode(index)"
10
- v-bind="step"
11
- />
12
- </div>
13
- </template>
14
-
15
1
  <script setup lang="ts">
16
- import { computed, PropType } from 'vue'
17
- import { Step, BarMode } from '../composables/Step'
2
+ import { PropType, computed } from 'vue'
3
+ import { BarMode, Step } from '../composables/Step'
18
4
  import SStep from './SStep.vue'
19
5
 
20
6
  const props = defineProps({
@@ -52,6 +38,20 @@ function isActive(step: Step): boolean {
52
38
  }
53
39
  </script>
54
40
 
41
+ <template>
42
+ <div class="SSteps">
43
+ <SStep
44
+ v-for="(step, index) in steps"
45
+ :key="index"
46
+ class="item"
47
+ :style="{ width }"
48
+ :bar-left="getBarLeftMode(index)"
49
+ :bar-right="getBarRightMode(index)"
50
+ v-bind="step"
51
+ />
52
+ </div>
53
+ </template>
54
+
55
55
  <style lang="postcss" scoped>
56
56
  .SSteps {
57
57
  display: flex;
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import { reactive, ref, computed, watch, toRefs } from 'vue'
2
+ import { computed, reactive, ref, toRefs, watch } from 'vue'
3
3
  import { Table } from '../composables/Table'
4
4
  import SSpinner from './SSpinner.vue'
5
5
  import STableCell from './STableCell.vue'
@@ -24,7 +24,7 @@ const {
24
24
  loading,
25
25
  onPrev,
26
26
  onNext,
27
- onReset,
27
+ onReset
28
28
  } = toRefs(props.options)
29
29
 
30
30
  const head = ref<HTMLElement | null>(null)
@@ -17,7 +17,7 @@ const _name = computed(() => props.name?.(props.value, props.record))
17
17
  </script>
18
18
 
19
19
  <template>
20
- <div class="STableCellAvatar" :class="[{ link}, color]">
20
+ <div class="STableCellAvatar" :class="[{ link }, color]">
21
21
  <SLink class="container" :href="link?.(value, record)">
22
22
  <div v-if="_image" class="avatar">
23
23
  <SAvatar size="mini" :avatar="_image" :name="_name" />
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { computed } from 'vue'
3
- import type { TableCellAvatarsOption } from '../composables/Table'
3
+ import { TableCellAvatarsOption } from '../composables/Table'
4
4
  import SAvatar from './SAvatar.vue'
5
5
 
6
6
  const props = defineProps<{
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- import type { Day } from '../support/Day'
2
+ import { Day } from '../support/Day'
3
3
 
4
4
  defineProps<{
5
5
  value?: Day | null
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import IconDotsThree from '@iconify-icons/ph/dots-three'
3
- import { ref, computed, unref, watch, nextTick } from 'vue'
3
+ import { computed, nextTick, ref, unref, watch } from 'vue'
4
4
  import { DropdownSection } from '../composables/Dropdown'
5
5
  import { useFlyout } from '../composables/Flyout'
6
6
  import { isArray } from '../support/Utils'
@@ -93,11 +93,11 @@ async function adjustDialogPosition() {
93
93
  const position = (window.innerWidth - rect.right) > dialogWidth ? 'right' : 'left'
94
94
 
95
95
  top.value = `${rect.top + rect.height - 8}px`
96
- left.value =
97
- Math.max(
96
+ left.value
97
+ = `${Math.max(
98
98
  16,
99
99
  position === 'right' ? rect.left - 4 : rect.right - dialogWidth - 4
100
- ) + 'px'
100
+ )}px`
101
101
  }
102
102
 
103
103
  function startDialogPositionListener() {
@@ -1,3 +1,20 @@
1
+ <script setup lang="ts">
2
+ import { PropType, computed, ref } from 'vue'
3
+ import { Position, useTooltip } from '../composables/Tooltip'
4
+ import SMarkdown from './SMarkdown.vue'
5
+
6
+ const props = defineProps({
7
+ tag: { type: String, default: 'span' },
8
+ text: { type: String, default: null },
9
+ position: { type: String as PropType<Position>, default: 'top' }
10
+ })
11
+
12
+ const tip = ref<HTMLElement | null>(null)
13
+ const content = ref<HTMLElement | null>(null)
14
+ const classes = computed(() => [props.position])
15
+ const { on, show, hide } = useTooltip(content, tip, props.position)
16
+ </script>
17
+
1
18
  <template>
2
19
  <component :is="tag" class="STooltip" @mouseenter="show" @mouseleave="hide">
3
20
  <template v-if="text">
@@ -20,23 +37,6 @@
20
37
  </component>
21
38
  </template>
22
39
 
23
- <script setup lang="ts">
24
- import { computed, PropType, ref } from 'vue'
25
- import { Position, useTooltip } from '../composables/Tooltip'
26
- import SMarkdown from './SMarkdown.vue'
27
-
28
- const props = defineProps({
29
- tag: { type: String, default: 'span' },
30
- text: { type: String, default: null },
31
- position: { type: String as PropType<Position>, default: 'top' }
32
- })
33
-
34
- const tip = ref<HTMLElement | null>(null)
35
- const content = ref<HTMLElement | null>(null)
36
- const classes = computed(() => [props.position])
37
- const { on, show, hide } = useTooltip(content, tip, props.position)
38
- </script>
39
-
40
40
  <style lang="postcss" scoped>
41
41
  .STooltip {
42
42
  position: relative;
@@ -0,0 +1,108 @@
1
+ import { watchOnce } from '@vueuse/core'
2
+ import cloneDeep from 'lodash-es/cloneDeep'
3
+ import { WatchSource, reactive } from 'vue'
4
+ import { isObject } from '../support/Utils'
5
+
6
+ export interface Data<T extends Record<string, any>> {
7
+ state: T
8
+ init(): void
9
+ }
10
+
11
+ export type DataWithDef = Record<string, any>
12
+
13
+ export interface Def<T = any> {
14
+ __isDef: true
15
+ value: any
16
+ source: WatchSource<T>
17
+ cb: (value: Exclude<T, undefined>) => void
18
+ }
19
+
20
+ export type UseDataInput<
21
+ T extends Record<string, any>
22
+ > = T | ((utils: UseDataInputUtils) => DataWithDef)
23
+
24
+ export interface UseDataInputUtils {
25
+ def<T>(
26
+ value: any,
27
+ source: WatchSource<T>,
28
+ cb: (value: Exclude<T, undefined>) => void
29
+ ): Def<T>
30
+ }
31
+
32
+ export function useData<T extends Record<string, any>>(
33
+ data: UseDataInput<T>
34
+ ): Data<T> {
35
+ const { state, defs } = createState(data)
36
+
37
+ const initialState = cloneDeep(state)
38
+ const reactiveState = reactive(state)
39
+
40
+ handleDefs(defs, reactiveState)
41
+
42
+ function init(): void {
43
+ Object.assign(reactiveState, initialState)
44
+ }
45
+
46
+ return {
47
+ state: reactiveState,
48
+ init
49
+ }
50
+ }
51
+
52
+ function createState<T extends Record<string, any>>(
53
+ data: UseDataInput<T>
54
+ ): { state: T; defs: [string, Def][] } {
55
+ if (typeof data !== 'function') {
56
+ return { state: data, defs: [] }
57
+ }
58
+
59
+ const dataWithDef = data({ def })
60
+
61
+ const state = {} as T
62
+ const defs = [] as [string, Def][]
63
+
64
+ for (const key in dataWithDef) {
65
+ const maybeDef = dataWithDef[key]
66
+
67
+ if (!isDef(maybeDef)) {
68
+ (state as any)[key] = maybeDef
69
+ continue
70
+ }
71
+
72
+ (state as any)[key] = maybeDef.value
73
+
74
+ defs.push([key, maybeDef])
75
+ }
76
+
77
+ return {
78
+ state,
79
+ defs
80
+ }
81
+ }
82
+
83
+ function handleDefs<T extends Record<string, any>>(
84
+ defs: [string, Def][], state: T
85
+ ): void {
86
+ defs.forEach(([key, def]) => {
87
+ watchOnce(def.source, (value: any) => {
88
+ (state as any)[key] = def.cb(value)
89
+ })
90
+ })
91
+ }
92
+
93
+ function def<T>(
94
+ value: any,
95
+ source: WatchSource<T>,
96
+ cb: (value: Exclude<T, undefined>) => void
97
+ ): Def {
98
+ return {
99
+ __isDef: true,
100
+ value,
101
+ source,
102
+ cb
103
+ }
104
+ }
105
+
106
+ function isDef(value: any): boolean {
107
+ return isObject(value) ? !!value.__isDef : false
108
+ }
@@ -1,6 +1,6 @@
1
- import cloneDeep from 'lodash-es/cloneDeep'
2
- import { Ref, reactive } from 'vue'
1
+ import { Ref, computed } from 'vue'
3
2
  import { useSnackbars } from '../stores/Snackbars'
3
+ import { UseDataInput, useData } from './Data'
4
4
  import { Validation, useValidation } from './Validation'
5
5
 
6
6
  export interface Form<T extends Record<string, any>> {
@@ -13,7 +13,7 @@ export interface Form<T extends Record<string, any>> {
13
13
  }
14
14
 
15
15
  export interface UseFormOptions<T extends Record<string, any>> {
16
- data: T,
16
+ data: UseDataInput<T>
17
17
  rules?: Record<string, any> | ((state: T) => Record<string, any>)
18
18
  }
19
19
 
@@ -22,18 +22,18 @@ export function useForm<
22
22
  >(options: UseFormOptions<T>): Form<T> {
23
23
  const snackbars = useSnackbars()
24
24
 
25
- const initialData = cloneDeep(options.data)
25
+ const data = useData(options.data)
26
26
 
27
- const data = reactive(options.data)
27
+ const rules = computed(() => {
28
+ return options.rules
29
+ ? typeof options.rules === 'function' ? options.rules(data.state) : options.rules
30
+ : {}
31
+ })
28
32
 
29
- const rules = options.rules
30
- ? typeof options.rules === 'function' ? options.rules(data) : options.rules
31
- : {}
32
-
33
- const validation = useValidation(data, rules)
33
+ const validation = useValidation(data.state, rules)
34
34
 
35
35
  function init(): void {
36
- Object.assign(data, initialData)
36
+ data.init()
37
37
  reset()
38
38
  }
39
39
 
@@ -59,7 +59,7 @@ export function useForm<
59
59
  }
60
60
 
61
61
  return {
62
- data,
62
+ data: data.state,
63
63
  init,
64
64
  reset,
65
65
  validation,
@@ -1,4 +1,4 @@
1
- import { Ref, ref, watchEffect, onMounted, onUnmounted } from 'vue'
1
+ import { Ref, onMounted, onUnmounted, ref, watchEffect } from 'vue'
2
2
 
3
3
  export interface Grid {
4
4
  container: Ref<HTMLElement | null>
@@ -69,7 +69,7 @@ export function useGrid(options: UseGridOptions): Grid {
69
69
  }
70
70
 
71
71
  function toClassSelector(name: string) {
72
- return name.startsWith('.') ? name : '.' + name
72
+ return name.startsWith('.') ? name : `.${name}`
73
73
  }
74
74
 
75
75
  function toClassName(name: string) {
@@ -84,7 +84,7 @@ function createSpacers(size: number, tag: string, classes: string, type: 'fill'
84
84
  }
85
85
 
86
86
  if (type === 'fill') {
87
- const spacer = createSpacer(tag, classes, { gridColumn: `span ${size}`})
87
+ const spacer = createSpacer(tag, classes, { gridColumn: `span ${size}` })
88
88
 
89
89
  fragment.appendChild(spacer)
90
90
 
@@ -1,7 +1,7 @@
1
1
  import MarkdownIt from 'markdown-it'
2
- import { onUnmounted, Ref } from 'vue'
2
+ import { Ref, onUnmounted } from 'vue'
3
3
  import { useRouter } from 'vue-router'
4
- import { isCallbackUrl, isExternalUrl, LinkAttrs, linkPlugin } from './markdown/LinkPlugin'
4
+ import { LinkAttrs, isCallbackUrl, isExternalUrl, linkPlugin } from './markdown/LinkPlugin'
5
5
 
6
6
  export type UseMarkdown = (source: string, inline: boolean) => string
7
7
 
@@ -46,7 +46,8 @@ export function useTooltip(
46
46
 
47
47
  if (tipRect.x < 0) {
48
48
  adjustLeftPosition(contentRect.x)
49
- } else if (tipRightX > window.outerWidth) {
49
+ }
50
+ else if (tipRightX > window.outerWidth) {
50
51
  adjustRightPosition(contentRightX)
51
52
  }
52
53
 
@@ -1,8 +1,8 @@
1
1
  import {
2
+ ErrorObject,
3
+ GlobalConfig,
2
4
  Validation,
3
5
  ValidationArgs,
4
- GlobalConfig,
5
- ErrorObject,
6
6
  useVuelidate
7
7
  } from '@vuelidate/core'
8
8
  import { Ref, ToRefs } from 'vue'
@@ -1,4 +1,4 @@
1
- import dayjs, { Dayjs, ConfigType } from 'dayjs'
1
+ import dayjs, { ConfigType, Dayjs } from 'dayjs'
2
2
 
3
3
  export type Day = Dayjs
4
4
  export type Input = ConfigType
@@ -13,3 +13,7 @@ export function isNumber(value: unknown): value is number {
13
13
  export function isArray(value: unknown): value is unknown[] {
14
14
  return Array.isArray(value)
15
15
  }
16
+
17
+ export function isObject(value: unknown): value is Record<string, any> {
18
+ return typeof value === 'object' && value !== null && !isArray(value)
19
+ }
@@ -1,4 +1,4 @@
1
- import { helpers, email as baseEmail } from '@vuelidate/validators'
1
+ import { email as baseEmail, helpers } from '@vuelidate/validators'
2
2
 
3
3
  export function email(msg?: string) {
4
4
  return helpers.withMessage(
@@ -1,5 +1,5 @@
1
1
  import { helpers } from '@vuelidate/validators'
2
- import { hms as baseHms, Hms, HmsType } from '../validators/hms'
2
+ import { Hms, HmsType, hms as baseHms } from '../validators/hms'
3
3
 
4
4
  export function hms(required?: HmsType[], msg?: string) {
5
5
  return helpers.withMessage(
@@ -1,4 +1,4 @@
1
- import { helpers, maxLength as baseMaxLength } from '@vuelidate/validators'
1
+ import { maxLength as baseMaxLength, helpers } from '@vuelidate/validators'
2
2
 
3
3
  export function maxLength(length: number, msg?: string) {
4
4
  return helpers.withMessage(
@@ -1,4 +1,4 @@
1
- import { helpers, maxValue as baseMaxValue } from '@vuelidate/validators'
1
+ import { maxValue as baseMaxValue, helpers } from '@vuelidate/validators'
2
2
 
3
3
  export function maxValue(value: number, msg?: string) {
4
4
  return helpers.withMessage(
@@ -1,4 +1,4 @@
1
- import { helpers, minLength as baseMinLength } from '@vuelidate/validators'
1
+ import { minLength as baseMinLength, helpers } from '@vuelidate/validators'
2
2
 
3
3
  export function minLength(length: number, msg?: string) {
4
4
  return helpers.withMessage(
@@ -1,4 +1,4 @@
1
- import { helpers, minValue as baseMinValue } from '@vuelidate/validators'
1
+ import { minValue as baseMinValue, helpers } from '@vuelidate/validators'
2
2
 
3
3
  export function minValue(value: number, msg?: string) {
4
4
  return helpers.withMessage(
@@ -1,4 +1,4 @@
1
- import { helpers, required as baseRequired } from '@vuelidate/validators'
1
+ import { required as baseRequired, helpers } from '@vuelidate/validators'
2
2
 
3
3
  export function required(msg?: string) {
4
4
  return helpers.withMessage(
@@ -1,5 +1,5 @@
1
1
  import { helpers } from '@vuelidate/validators'
2
- import { requiredHms as baseRequiredHms, Hms, HmsType } from '../validators/requiredHms'
2
+ import { Hms, HmsType, requiredHms as baseRequiredHms } from '../validators/requiredHms'
3
3
 
4
4
  export function requiredHms(required?: HmsType[], msg?: string) {
5
5
  return helpers.withMessage(
@@ -1,4 +1,4 @@
1
- import { helpers, requiredIf as baseRequiredIf } from '@vuelidate/validators'
1
+ import { requiredIf as baseRequiredIf, helpers } from '@vuelidate/validators'
2
2
 
3
3
  export function requiredIf(
4
4
  prop: boolean | string | (() => boolean | Promise<boolean>),
@@ -1,5 +1,5 @@
1
1
  import { helpers } from '@vuelidate/validators'
2
- import { requiredYmd as baseRequiredYmd, Ymd, YmdType } from '../validators/requiredYmd'
2
+ import { Ymd, YmdType, requiredYmd as baseRequiredYmd } from '../validators/requiredYmd'
3
3
 
4
4
  export function requiredYmd(required?: YmdType[], msg?: string) {
5
5
  return helpers.withMessage(
@@ -1,4 +1,4 @@
1
- import { helpers, url as baseUrl } from '@vuelidate/validators'
1
+ import { url as baseUrl, helpers } from '@vuelidate/validators'
2
2
 
3
3
  export function url(msg?: string) {
4
4
  return helpers.withMessage(
@@ -1,5 +1,5 @@
1
1
  import { helpers } from '@vuelidate/validators'
2
- import { ymd as baseYmd, Ymd, YmdType } from '../validators/ymd'
2
+ import { Ymd, YmdType, ymd as baseYmd } from '../validators/ymd'
3
3
 
4
4
  export function ymd(required?: YmdType[], msg?: string) {
5
5
  return helpers.withMessage(
@@ -1,4 +1,4 @@
1
- import { Ymd, YmdType, YmdMap } from './ymd'
1
+ import { Ymd, YmdMap, YmdType } from './ymd'
2
2
 
3
3
  export type { Ymd, YmdType, YmdMap }
4
4
 
package/package.json CHANGED
@@ -1,24 +1,24 @@
1
1
  {
2
2
  "name": "@globalbrain/sefirot",
3
- "version": "2.2.1",
3
+ "version": "2.4.0",
4
4
  "description": "Vue Components for Global Brain Design System.",
5
- "files": [
6
- "lib"
7
- ],
5
+ "author": "Kia Ishii <ka.ishii@globalbrains.com>",
6
+ "license": "MIT",
8
7
  "repository": {
9
8
  "type": "git",
10
9
  "url": "git@github.com:globalbrain/sefirot.git"
11
10
  },
11
+ "bugs": {
12
+ "url": "https://github.com/globalbrain/sefirot/issues"
13
+ },
12
14
  "keywords": [
13
15
  "sefirot",
14
16
  "vue",
15
17
  "vue component"
16
18
  ],
17
- "author": "Kia Ishii <ka.ishii@globalbrains.com>",
18
- "license": "MIT",
19
- "bugs": {
20
- "url": "https://github.com/globalbrain/sefirot/issues"
21
- },
19
+ "files": [
20
+ "lib"
21
+ ],
22
22
  "peerDependencies": {
23
23
  "@iconify-icons/ph": "^1.2.2",
24
24
  "@iconify/vue": "^4.0.0",
@@ -43,6 +43,7 @@
43
43
  "vue-router": "^4.1.5"
44
44
  },
45
45
  "devDependencies": {
46
+ "@globalbrain/eslint-config": "^0.1.0",
46
47
  "@histoire/plugin-vue": "^0.10.7",
47
48
  "@iconify-icons/ph": "^1.2.2",
48
49
  "@iconify/vue": "^4.0.0",
@@ -50,8 +51,6 @@
50
51
  "@types/lodash-es": "^4.17.6",
51
52
  "@types/markdown-it": "^12.2.3",
52
53
  "@types/node": "^18.8.0",
53
- "@typescript-eslint/eslint-plugin": "^5.38.0",
54
- "@typescript-eslint/parser": "^5.38.0",
55
54
  "@vitejs/plugin-vue": "^3.1.2",
56
55
  "@vitest/coverage-c8": "^0.23.4",
57
56
  "@vue/test-utils": "^2.1.0",
@@ -64,8 +63,6 @@
64
63
  "dayjs": "^1.11.5",
65
64
  "enquirer": "^2.3.6",
66
65
  "eslint": "^8.23.1",
67
- "eslint-plugin-import": "^2.26.0",
68
- "eslint-plugin-vue": "^9.5.1",
69
66
  "execa": "^5.1.1",
70
67
  "fuse.js": "^6.6.2",
71
68
  "happy-dom": "^6.0.4",
@@ -94,8 +91,8 @@
94
91
  "story:build": "histoire build",
95
92
  "story:preview": "histoire preview --port 3000",
96
93
  "type": "vue-tsc --noEmit",
97
- "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix './{lib,tests}/**/*.{ts,vue}'",
98
- "lint:fail": "eslint --ext .js,.vue --ignore-path .gitignore './{lib,tests}/**/*.{ts,vue}'",
94
+ "lint": "eslint --fix .",
95
+ "lint:fail": "eslint .",
99
96
  "vitest": "vitest",
100
97
  "coverage": "vitest run --coverage",
101
98
  "test": "pnpm run type && pnpm run lint && pnpm run coverage",