@wishbone-media/spark 0.38.0 → 0.40.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 (66) hide show
  1. package/dist/index.css +1 -1
  2. package/dist/index.js +818 -845
  3. package/formkit.theme.mjs +3415 -3415
  4. package/package.json +31 -1
  5. package/src/assets/css/spark-table.css +1 -1
  6. package/src/assets/css/spark-tooltip.css +9 -3
  7. package/src/components/SparkAddressInput.vue +20 -3
  8. package/src/components/SparkAppSelector.vue +7 -7
  9. package/src/components/SparkBrandSelector.vue +2 -2
  10. package/src/components/SparkButton.vue +4 -4
  11. package/src/components/SparkButtonGroup.vue +2 -2
  12. package/src/components/SparkCard.vue +5 -3
  13. package/src/components/SparkEntityBadge.vue +3 -9
  14. package/src/components/SparkFileDragUpload.vue +13 -9
  15. package/src/components/SparkImageUpload.vue +4 -1
  16. package/src/components/SparkModalContainer.vue +23 -19
  17. package/src/components/SparkModalDialog.vue +36 -17
  18. package/src/components/SparkNotificationOutlet.vue +1 -1
  19. package/src/components/SparkOverlay.vue +20 -24
  20. package/src/components/SparkSubNav.vue +7 -14
  21. package/src/components/SparkTable.vue +72 -73
  22. package/src/components/SparkTablePaginationPaging.vue +2 -2
  23. package/src/components/SparkTableToolbar.vue +1 -1
  24. package/src/components/SparkToastContainer.vue +25 -41
  25. package/src/components/SparkTooltip.vue +14 -22
  26. package/src/components/plugins/SparkTableFilterButtons.vue +5 -1
  27. package/src/components/plugins/SparkTableFilterSelect.vue +1 -4
  28. package/src/components/plugins/SparkTableReset.vue +21 -19
  29. package/src/components/plugins/SparkTableSearch.vue +3 -2
  30. package/src/composables/index.js +1 -1
  31. package/src/composables/sparkModalService.js +64 -64
  32. package/src/composables/sparkNotificationService.js +10 -8
  33. package/src/composables/sparkOverlayService.js +36 -36
  34. package/src/composables/useCrudResource.js +1 -7
  35. package/src/composables/useFormSubmission.js +1 -3
  36. package/src/composables/useSparkOverlay.js +1 -1
  37. package/src/composables/useSparkTableRouteSync.js +4 -6
  38. package/src/composables/useSubNavigation.js +18 -15
  39. package/src/containers/SparkDefaultContainer.vue +8 -8
  40. package/src/containers/SparkPublicContainer.vue +1 -2
  41. package/src/directives/sparkTooltip.js +4 -11
  42. package/src/index.js +1 -1
  43. package/src/plugins/app-bootstrap.js +1 -1
  44. package/src/plugins/axios.js +1 -1
  45. package/src/plugins/fontawesome.js +3 -3
  46. package/src/plugins/index.js +17 -3
  47. package/src/plugins/router.js +8 -12
  48. package/src/stores/auth.js +1 -1
  49. package/src/stores/brand-filter.js +40 -40
  50. package/src/stores/index.js +1 -1
  51. package/src/stores/navigation.js +1 -1
  52. package/src/utils/formatTemporal.js +4 -4
  53. package/src/utils/sparkTable/renderers/badge.js +1 -1
  54. package/src/utils/sparkTable/renderers/boolean.js +3 -3
  55. package/src/utils/sparkTable/renderers/currency.js +1 -1
  56. package/src/utils/sparkTable/renderers/date.js +14 -6
  57. package/src/utils/sparkTable/renderers/datetime.js +1 -1
  58. package/src/utils/sparkTable/renderers/image.js +1 -1
  59. package/src/utils/sparkTable/renderers/link.js +1 -1
  60. package/src/views/SparkError403View.vue +3 -7
  61. package/src/views/SparkError404View.vue +3 -9
  62. package/src/views/SparkErrorGeneralView.vue +1 -3
  63. package/src/views/SparkForgotPasswordView.vue +7 -4
  64. package/src/views/SparkLoginView.vue +8 -7
  65. package/src/views/SparkLogoutView.vue +2 -1
  66. package/src/views/SparkResetPasswordView.vue +4 -6
@@ -1,5 +1,9 @@
1
1
  import { useSparkAuthStore } from '../stores/auth.js'
2
- import { hasAnyDirtyForm, getDirtyFormMessage, clearAllDirtyForms } from '../composables/useFormDirtyGuard.js'
2
+ import {
3
+ hasAnyDirtyForm,
4
+ getDirtyFormMessage,
5
+ clearAllDirtyForms,
6
+ } from '../composables/useFormDirtyGuard.js'
3
7
  import { sparkModalService } from '../composables/sparkModalService.js'
4
8
  import {
5
9
  SparkLoginView,
@@ -8,7 +12,6 @@ import {
8
12
  SparkResetPasswordView,
9
13
  SparkError403View,
10
14
  SparkError404View,
11
- SparkErrorGeneralView,
12
15
  } from '../views/index.js'
13
16
 
14
17
  export function createAuthRoutes(options = {}) {
@@ -108,7 +111,7 @@ function processNavigation(to, next, authStore, defaultAuthenticatedRoute) {
108
111
 
109
112
  next({
110
113
  path: authStore.state.routes.auth,
111
- query: { redirect }
114
+ query: { redirect },
112
115
  })
113
116
  return
114
117
  }
@@ -143,11 +146,7 @@ function processNavigation(to, next, authStore, defaultAuthenticatedRoute) {
143
146
  * @returns {Object} Route configuration for 403 error page
144
147
  */
145
148
  export function create403Route(options = {}) {
146
- const {
147
- forbiddenPath = '/error/403',
148
- logo = '',
149
- homeRoute = '/dashboard',
150
- } = options
149
+ const { forbiddenPath = '/error/403', logo = '', homeRoute = '/dashboard' } = options
151
150
 
152
151
  return {
153
152
  path: forbiddenPath,
@@ -167,10 +166,7 @@ export function create403Route(options = {}) {
167
166
  * @returns {Object} Route configuration for 404 catch-all
168
167
  */
169
168
  export function create404Route(options = {}) {
170
- const {
171
- logo = '',
172
- homeRoute = '/dashboard',
173
- } = options
169
+ const { logo = '', homeRoute = '/dashboard' } = options
174
170
 
175
171
  return {
176
172
  path: '/:pathMatch(.*)*',
@@ -145,7 +145,7 @@ export const useSparkAuthStore = defineStore('auth', () => {
145
145
  if (!state.overrideToken) {
146
146
  state.token = token
147
147
  }
148
- } catch (error) {
148
+ } catch {
149
149
  // Only clear cookie if not using override token
150
150
  if (!state.overrideToken) {
151
151
  clearTokenCookie()
@@ -8,55 +8,55 @@ export const useSparkBrandFilterStore = defineStore(
8
8
  brands: [],
9
9
  })
10
10
 
11
- const initialize = (config = {}) => {
12
- if (!config.brands || !Array.isArray(config.brands)) {
13
- console.warn('useSparkBrandFilterStore: No brands provided to initialize()')
14
- state.brands = []
15
- return
16
- }
17
-
18
- // Validate brand structure
19
- const validBrands = config.brands.filter((brand) => {
20
- const isValid = brand.name && brand.logo
21
- if (!isValid) {
22
- console.warn('useSparkBrandFilterStore: Invalid brand object', brand)
11
+ const initialize = (config = {}) => {
12
+ if (!config.brands || !Array.isArray(config.brands)) {
13
+ console.warn('useSparkBrandFilterStore: No brands provided to initialize()')
14
+ state.brands = []
15
+ return
23
16
  }
24
- return isValid
25
- })
26
17
 
27
- // Ensure exactly one brand is marked as current
28
- const currentBrands = validBrands.filter((b) => b.current)
29
- if (currentBrands.length === 0 && validBrands.length > 0) {
30
- validBrands[0].current = true
31
- } else if (currentBrands.length > 1) {
32
- // Only the first current brand stays current
33
- validBrands.forEach((brand) => {
34
- brand.current = brand === currentBrands[0]
18
+ // Validate brand structure
19
+ const validBrands = config.brands.filter((brand) => {
20
+ const isValid = brand.name && brand.logo
21
+ if (!isValid) {
22
+ console.warn('useSparkBrandFilterStore: Invalid brand object', brand)
23
+ }
24
+ return isValid
35
25
  })
26
+
27
+ // Ensure exactly one brand is marked as current
28
+ const currentBrands = validBrands.filter((b) => b.current)
29
+ if (currentBrands.length === 0 && validBrands.length > 0) {
30
+ validBrands[0].current = true
31
+ } else if (currentBrands.length > 1) {
32
+ // Only the first current brand stays current
33
+ validBrands.forEach((brand) => {
34
+ brand.current = brand === currentBrands[0]
35
+ })
36
+ }
37
+
38
+ state.brands = validBrands.map((brand) => ({
39
+ id: brand.id,
40
+ name: brand.name,
41
+ logo: brand.logo,
42
+ current: brand.current || false,
43
+ }))
36
44
  }
37
45
 
38
- state.brands = validBrands.map((brand) => ({
39
- id: brand.id,
40
- name: brand.name,
41
- logo: brand.logo,
42
- current: brand.current || false,
43
- }))
44
- }
46
+ const currentBrand = computed(() => state.brands.find((item) => item.current) || null)
47
+ const allBrands = computed(() => state.brands)
45
48
 
46
- const currentBrand = computed(() => state.brands.find((item) => item.current) || null)
47
- const allBrands = computed(() => state.brands)
49
+ const toggleBrand = (brand) => {
50
+ if (!brand || !state.brands.includes(brand)) {
51
+ console.warn('useSparkBrandFilterStore: Invalid brand provided to toggleBrand()')
52
+ return
53
+ }
48
54
 
49
- const toggleBrand = (brand) => {
50
- if (!brand || !state.brands.includes(brand)) {
51
- console.warn('useSparkBrandFilterStore: Invalid brand provided to toggleBrand()')
52
- return
55
+ state.brands.forEach((item) => {
56
+ item.current = item === brand
57
+ })
53
58
  }
54
59
 
55
- state.brands.forEach((item) => {
56
- item.current = item === brand
57
- })
58
- }
59
-
60
60
  return {
61
61
  state,
62
62
  initialize,
@@ -2,4 +2,4 @@ export * from './app.js'
2
2
  export * from './app-selector.js'
3
3
  export * from './auth.js'
4
4
  export * from './brand-filter.js'
5
- export * from './navigation.js'
5
+ export * from './navigation.js'
@@ -72,7 +72,7 @@ export const useSparkNavStore = defineStore('sparkNav', () => {
72
72
  () => {
73
73
  syncWithRoute()
74
74
  },
75
- { immediate: true }
75
+ { immediate: true },
76
76
  )
77
77
 
78
78
  return {
@@ -95,7 +95,7 @@ const getFormatter = (locale, options) => {
95
95
  const getFormattedPart = (date, locale, options, type) => {
96
96
  const formatter = getFormatter(locale, options)
97
97
  const parts = formatter.formatToParts(date)
98
- const part = parts.find(p => p.type === type)
98
+ const part = parts.find((p) => p.type === type)
99
99
  return part ? part.value : ''
100
100
  }
101
101
 
@@ -117,7 +117,7 @@ const temporalToDate = (temporal) => {
117
117
  temporal.hour || 0,
118
118
  temporal.minute || 0,
119
119
  temporal.second || 0,
120
- temporal.millisecond || 0
120
+ temporal.millisecond || 0,
121
121
  )
122
122
  }
123
123
 
@@ -223,8 +223,8 @@ const createTokens = (temporal, locale) => {
223
223
  ['SSS', () => pad(comp.millisecond, 3)],
224
224
 
225
225
  // AM/PM
226
- ['A', () => comp.isPM ? 'PM' : 'AM'],
227
- ['a', () => comp.isPM ? 'pm' : 'am'],
226
+ ['A', () => (comp.isPM ? 'PM' : 'AM')],
227
+ ['a', () => (comp.isPM ? 'pm' : 'am')],
228
228
 
229
229
  // Timezone offset
230
230
  ['ZZ', () => getTimezoneOffset(temporal, false)],
@@ -29,7 +29,7 @@ const colorClasses = {
29
29
  indigo: 'bg-indigo-100 text-indigo-800',
30
30
  }
31
31
 
32
- export const badgeRenderer = (sparkTable) => {
32
+ export const badgeRenderer = (_sparkTable) => {
33
33
  return (instance, td, row, col, prop, value, cellProperties) => {
34
34
  // Clear cell
35
35
  td.innerHTML = ''
@@ -54,7 +54,7 @@ const isTruthy = (value) => {
54
54
  return false
55
55
  }
56
56
 
57
- export const booleanRenderer = (sparkTable) => {
57
+ export const booleanRenderer = (_sparkTable) => {
58
58
  return (instance, td, row, col, prop, value, cellProperties) => {
59
59
  // Clear cell
60
60
  td.innerHTML = ''
@@ -63,8 +63,8 @@ export const booleanRenderer = (sparkTable) => {
63
63
  const config = cellProperties.rendererConfig || {}
64
64
 
65
65
  const truthy = isTruthy(value)
66
- const iconName = truthy ? (config.trueIcon || 'check') : (config.falseIcon || 'xmark')
67
- const colorName = truthy ? (config.trueColor || 'green') : (config.falseColor || 'red')
66
+ const iconName = truthy ? config.trueIcon || 'check' : config.falseIcon || 'xmark'
67
+ const colorName = truthy ? config.trueColor || 'green' : config.falseColor || 'red'
68
68
  const size = config.size || 32
69
69
  const iconPrefix = config.iconPrefix || 'far'
70
70
 
@@ -43,7 +43,7 @@ const formatCurrency = (value, decimals = 2) => {
43
43
  return isNegative ? `-$${formatted}` : `$${formatted}`
44
44
  }
45
45
 
46
- export const currencyRenderer = (sparkTable) => {
46
+ export const currencyRenderer = (_sparkTable) => {
47
47
  return (instance, td, row, col, prop, value, cellProperties) => {
48
48
  td.innerHTML = ''
49
49
  td.classList.add('spark-table-cell-currency')
@@ -14,7 +14,7 @@
14
14
  * }
15
15
  */
16
16
 
17
- export const dateRenderer = (sparkTable) => {
17
+ export const dateRenderer = (_sparkTable) => {
18
18
  return (instance, td, row, col, prop, value, cellProperties) => {
19
19
  // Clear cell
20
20
  td.innerHTML = ''
@@ -28,7 +28,7 @@ export const dateRenderer = (sparkTable) => {
28
28
  const format = config.format || 'short'
29
29
  const locale = config.locale || 'en-US'
30
30
 
31
- let formattedDate = value
31
+ let formattedDate
32
32
 
33
33
  try {
34
34
  const date = new Date(value)
@@ -89,14 +89,22 @@ function getRelativeTime(date) {
89
89
  if (seconds < 60) {
90
90
  return isPast ? 'just now' : 'in a moment'
91
91
  } else if (minutes < 60) {
92
- return isPast ? `${minutes} minute${minutes > 1 ? 's' : ''} ago` : `in ${minutes} minute${minutes > 1 ? 's' : ''}`
92
+ return isPast
93
+ ? `${minutes} minute${minutes > 1 ? 's' : ''} ago`
94
+ : `in ${minutes} minute${minutes > 1 ? 's' : ''}`
93
95
  } else if (hours < 24) {
94
- return isPast ? `${hours} hour${hours > 1 ? 's' : ''} ago` : `in ${hours} hour${hours > 1 ? 's' : ''}`
96
+ return isPast
97
+ ? `${hours} hour${hours > 1 ? 's' : ''} ago`
98
+ : `in ${hours} hour${hours > 1 ? 's' : ''}`
95
99
  } else if (days < 30) {
96
100
  return isPast ? `${days} day${days > 1 ? 's' : ''} ago` : `in ${days} day${days > 1 ? 's' : ''}`
97
101
  } else if (months < 12) {
98
- return isPast ? `${months} month${months > 1 ? 's' : ''} ago` : `in ${months} month${months > 1 ? 's' : ''}`
102
+ return isPast
103
+ ? `${months} month${months > 1 ? 's' : ''} ago`
104
+ : `in ${months} month${months > 1 ? 's' : ''}`
99
105
  } else {
100
- return isPast ? `${years} year${years > 1 ? 's' : ''} ago` : `in ${years} year${years > 1 ? 's' : ''}`
106
+ return isPast
107
+ ? `${years} year${years > 1 ? 's' : ''} ago`
108
+ : `in ${years} year${years > 1 ? 's' : ''}`
101
109
  }
102
110
  }
@@ -61,7 +61,7 @@ import { formatTemporal, parseDatetime } from '@/utils/formatTemporal.js'
61
61
  * - 'DD/MM/YY [at] h:mma' → "03/12/25 at 11:36am"
62
62
  */
63
63
 
64
- export const datetimeRenderer = (sparkTable) => {
64
+ export const datetimeRenderer = (_sparkTable) => {
65
65
  return (instance, td, row, col, prop, value, cellProperties) => {
66
66
  // Clear cell
67
67
  td.innerHTML = ''
@@ -23,7 +23,7 @@ const sizes = {
23
23
  lg: 'h-12 w-12',
24
24
  }
25
25
 
26
- export const imageRenderer = (sparkTable) => {
26
+ export const imageRenderer = (_sparkTable) => {
27
27
  return (instance, td, row, col, prop, value, cellProperties) => {
28
28
  // Clear cell
29
29
  td.innerHTML = ''
@@ -17,7 +17,7 @@
17
17
  * }
18
18
  */
19
19
 
20
- export const linkRenderer = (sparkTable) => {
20
+ export const linkRenderer = (_sparkTable) => {
21
21
  return (instance, td, row, col, prop, value, cellProperties) => {
22
22
  // Clear cell
23
23
  td.innerHTML = ''
@@ -29,19 +29,15 @@
29
29
  <div class="max-w-lg grid gap-y-6 text-center -mt-8">
30
30
  <div>
31
31
  <div class="text-primary-600 text-7xl font-bold mb-4">403</div>
32
- <h1 class="text-3xl text-gray-900 font-semibold tracking-tight mb-3">
33
- Access Forbidden
34
- </h1>
32
+ <h1 class="text-3xl text-gray-900 font-semibold tracking-tight mb-3">Access Forbidden</h1>
35
33
  <p class="text-gray-600">
36
- You don't have permission to access this resource.<br>
34
+ You don't have permission to access this resource.<br />
37
35
  If you believe this is an error, please contact your administrator.
38
36
  </p>
39
37
  </div>
40
38
 
41
39
  <div class="flex gap-4 justify-center">
42
- <spark-button @click="goHome" size="lg">
43
- Go to Home
44
- </spark-button>
40
+ <SparkButton size="lg" @click="goHome"> Go to Home </SparkButton>
45
41
  </div>
46
42
  </div>
47
43
  </div>
@@ -29,18 +29,12 @@
29
29
  <div class="max-w-lg grid gap-y-6 text-center -mt-8">
30
30
  <div>
31
31
  <div class="text-primary-600 text-7xl font-bold mb-4">404</div>
32
- <h1 class="text-3xl text-gray-900 font-semibold tracking-tight mb-3">
33
- Page Not Found
34
- </h1>
35
- <p class="text-gray-600">
36
- The page you're looking for doesn't exist or has been moved.
37
- </p>
32
+ <h1 class="text-3xl text-gray-900 font-semibold tracking-tight mb-3">Page Not Found</h1>
33
+ <p class="text-gray-600">The page you're looking for doesn't exist or has been moved.</p>
38
34
  </div>
39
35
 
40
36
  <div class="flex gap-4 justify-center">
41
- <spark-button @click="goHome" size="lg">
42
- Go to Home
43
- </spark-button>
37
+ <SparkButton size="lg" @click="goHome"> Go to Home </SparkButton>
44
38
  </div>
45
39
  </div>
46
40
  </div>
@@ -40,9 +40,7 @@
40
40
  </div>
41
41
 
42
42
  <div class="flex gap-4 justify-center">
43
- <spark-button @click="goHome" size="lg">
44
- Go to Home
45
- </spark-button>
43
+ <SparkButton size="lg" @click="goHome"> Go to Home </SparkButton>
46
44
  </div>
47
45
  </div>
48
46
  </div>
@@ -35,7 +35,7 @@
35
35
  </p>
36
36
  </div>
37
37
 
38
- <FormKit type="form" @submit="handleSubmit" :actions="false">
38
+ <FormKit type="form" :actions="false" @submit="handleSubmit">
39
39
  <FormKit
40
40
  label="Email"
41
41
  name="email"
@@ -53,12 +53,15 @@
53
53
  {{ successMessage }}
54
54
  </div>
55
55
 
56
- <spark-button type="submit" size="xl" :disabled="isLoading" button-class="w-full mb-2">
56
+ <SparkButton type="submit" size="xl" :disabled="isLoading" button-class="w-full mb-2">
57
57
  <span v-if="!isLoading">Send reset link</span>
58
58
  <span v-else>Sending...</span>
59
- </spark-button>
59
+ </SparkButton>
60
60
 
61
- <router-link :to="props.loginRoute" class="text-sm text-center text-primary-600 font-semibold block">
61
+ <router-link
62
+ :to="props.loginRoute"
63
+ class="text-sm text-center text-primary-600 font-semibold block"
64
+ >
62
65
  Back to login
63
66
  </router-link>
64
67
  </FormKit>
@@ -31,12 +31,12 @@
31
31
  <h1 class="text-4xl text-gray-900 semibold tracking-tight mb-3">Log in</h1>
32
32
 
33
33
  <p class="text-gray-600">
34
- Welcome back{{ appStore.state.app ? ` to ${appStore.state.app}` : '' }}! Please enter
35
- your details.
34
+ Welcome back{{ appStore.state.app ? ` to ${appStore.state.app}` : '' }}! Please enter your
35
+ details.
36
36
  </p>
37
37
  </div>
38
38
 
39
- <FormKit type="form" @submit="handleLogin" :actions="false">
39
+ <FormKit type="form" :actions="false" @submit="handleLogin">
40
40
  <FormKit
41
41
  label="Email"
42
42
  name="email"
@@ -58,7 +58,7 @@
58
58
  />
59
59
 
60
60
  <div class="grid grid-flow-col justify-between mt-1 mb-4">
61
- <span></span>
61
+ <span />
62
62
 
63
63
  <router-link
64
64
  :to="props.forgotPasswordRoute"
@@ -72,10 +72,10 @@
72
72
  {{ errorMessage }}
73
73
  </div>
74
74
 
75
- <spark-button type="submit" size="xl" :disabled="isLoading" button-class="w-full mb-2">
75
+ <SparkButton type="submit" size="xl" :disabled="isLoading" button-class="w-full mb-2">
76
76
  <span v-if="!isLoading">Sign in</span>
77
77
  <span v-else>Signing in...</span>
78
- </spark-button>
78
+ </SparkButton>
79
79
  </FormKit>
80
80
  </div>
81
81
  </div>
@@ -130,7 +130,8 @@ const handleLogin = async (credentials) => {
130
130
  await router.push(props.defaultRedirect)
131
131
  }
132
132
  } catch (error) {
133
- errorMessage.value = error.response?.data?.message || error.message || 'Login failed. Please try again.'
133
+ errorMessage.value =
134
+ error.response?.data?.message || error.message || 'Login failed. Please try again.'
134
135
  } finally {
135
136
  isLoading.value = false
136
137
  }
@@ -1,4 +1,5 @@
1
- <template></template>
1
+ <!-- eslint-disable vue/valid-template-root -- Renderless component, runs logout logic only -->
2
+ <template><span /></template>
2
3
 
3
4
  <script setup>
4
5
  import { onMounted } from 'vue'
@@ -30,12 +30,10 @@
30
30
  <div class="mb-7">
31
31
  <h1 class="text-4xl text-gray-900 semibold tracking-tight mb-3">Set new password</h1>
32
32
 
33
- <p class="text-gray-600">
34
- Enter your new password below.
35
- </p>
33
+ <p class="text-gray-600">Enter your new password below.</p>
36
34
  </div>
37
35
 
38
- <FormKit type="form" @submit="handleSubmit" :actions="false">
36
+ <FormKit type="form" :actions="false" @submit="handleSubmit">
39
37
  <FormKit
40
38
  label="New Password"
41
39
  name="password"
@@ -58,10 +56,10 @@
58
56
  {{ errorMessage }}
59
57
  </div>
60
58
 
61
- <spark-button type="submit" size="xl" :disabled="isLoading" button-class="w-full mb-2">
59
+ <SparkButton type="submit" size="xl" :disabled="isLoading" button-class="w-full mb-2">
62
60
  <span v-if="!isLoading">Reset password</span>
63
61
  <span v-else>Resetting...</span>
64
- </spark-button>
62
+ </SparkButton>
65
63
  </FormKit>
66
64
  </div>
67
65
  </div>