better-auth-ui-svelte 0.12.4 → 0.12.6
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/components/admin/admin-dashboard.svelte +3 -3
- package/dist/components/auth/forms/email-otp-form.svelte +8 -6
- package/dist/components/auth/forms/forgot-password-form.svelte +7 -5
- package/dist/components/auth/forms/magic-link-form.svelte +3 -2
- package/dist/components/auth/forms/recover-account-form.svelte +5 -5
- package/dist/components/auth/forms/reset-password-form.svelte +6 -4
- package/dist/components/auth/forms/sign-in-form.svelte +5 -5
- package/dist/components/auth/forms/sign-up-form.svelte +4 -4
- package/dist/components/auth/forms/two-factor-form.svelte +5 -5
- package/dist/components/auth/magic-link-sent.svelte +4 -3
- package/dist/components/auth/passkey-button.svelte +13 -3
- package/dist/components/auth/provider-button.svelte +17 -8
- package/dist/components/auth/verify-email.svelte +5 -4
- package/dist/components/chart-area-interactive.svelte +3 -3
- package/dist/components/ui/chart/chart-tooltip.svelte +24 -16
- package/dist/components/ui/chart/chart-utils.d.ts +8 -4
- package/dist/components/ui/chart/chart-utils.js +2 -10
- package/package.json +3 -3
|
@@ -516,15 +516,15 @@
|
|
|
516
516
|
yAxis: { format: () => '' }
|
|
517
517
|
}}
|
|
518
518
|
>
|
|
519
|
-
{#snippet marks({
|
|
519
|
+
{#snippet marks({ context })}
|
|
520
520
|
<defs>
|
|
521
521
|
<linearGradient id="fillUsers" x1="0" y1="0" x2="0" y2="1">
|
|
522
522
|
<stop offset="5%" stop-color="var(--color-users)" stop-opacity={1.0} />
|
|
523
523
|
<stop offset="95%" stop-color="var(--color-users)" stop-opacity={0.1} />
|
|
524
524
|
</linearGradient>
|
|
525
525
|
</defs>
|
|
526
|
-
{#each series as s
|
|
527
|
-
<Area {
|
|
526
|
+
{#each context.series.visibleSeries as s (s.key)}
|
|
527
|
+
<Area seriesKey={s.key} fill="url(#fillUsers)" />
|
|
528
528
|
{/each}
|
|
529
529
|
{/snippet}
|
|
530
530
|
{#snippet tooltip()}
|
|
@@ -45,9 +45,8 @@
|
|
|
45
45
|
let verifiedEmail = $state<string | undefined>(undefined);
|
|
46
46
|
|
|
47
47
|
// Transition for OTP verification success
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
});
|
|
48
|
+
const transition = useOnSuccessTransition({ redirectTo });
|
|
49
|
+
const { onSuccess } = transition;
|
|
51
50
|
|
|
52
51
|
// Reactive validation schemas
|
|
53
52
|
const emailFormSchema = $derived(
|
|
@@ -106,10 +105,13 @@
|
|
|
106
105
|
}
|
|
107
106
|
}));
|
|
108
107
|
|
|
108
|
+
const emailFormIsSubmitting = emailForm.useStore((s) => s.isSubmitting);
|
|
109
|
+
const otpFormIsSubmitting = otpForm.useStore((s) => s.isSubmitting);
|
|
110
|
+
|
|
109
111
|
// Computed submitting states
|
|
110
|
-
const emailFormSubmitting = $derived(isSubmittingProp ||
|
|
112
|
+
const emailFormSubmitting = $derived(isSubmittingProp || emailFormIsSubmitting.current);
|
|
111
113
|
const otpFormSubmitting = $derived(
|
|
112
|
-
isSubmittingProp ||
|
|
114
|
+
isSubmittingProp || otpFormIsSubmitting.current || transition.isPending
|
|
113
115
|
);
|
|
114
116
|
|
|
115
117
|
// Handle email form submission with error handling
|
|
@@ -137,7 +139,7 @@
|
|
|
137
139
|
// Update parent isSubmitting state
|
|
138
140
|
$effect(() => {
|
|
139
141
|
setIsSubmitting?.(
|
|
140
|
-
|
|
142
|
+
emailFormIsSubmitting.current || otpFormIsSubmitting.current || transition.isPending
|
|
141
143
|
);
|
|
142
144
|
});
|
|
143
145
|
|
|
@@ -103,10 +103,12 @@
|
|
|
103
103
|
}
|
|
104
104
|
}));
|
|
105
105
|
|
|
106
|
+
const formIsSubmitting = form.useStore((s) => s.isSubmitting);
|
|
107
|
+
|
|
106
108
|
// Sync isSubmitting state
|
|
107
109
|
$effect(() => {
|
|
108
|
-
isSubmitting =
|
|
109
|
-
setIsSubmitting?.(
|
|
110
|
+
isSubmitting = formIsSubmitting.current;
|
|
111
|
+
setIsSubmitting?.(formIsSubmitting.current);
|
|
110
112
|
});
|
|
111
113
|
</script>
|
|
112
114
|
|
|
@@ -130,7 +132,7 @@
|
|
|
130
132
|
value={field.state.value}
|
|
131
133
|
oninput={(e) => field.handleChange(e.currentTarget.value)}
|
|
132
134
|
onblur={field.handleBlur}
|
|
133
|
-
disabled={
|
|
135
|
+
disabled={formIsSubmitting.current}
|
|
134
136
|
class={classNames?.input}
|
|
135
137
|
/>
|
|
136
138
|
|
|
@@ -147,10 +149,10 @@
|
|
|
147
149
|
|
|
148
150
|
<Button
|
|
149
151
|
type="submit"
|
|
150
|
-
disabled={
|
|
152
|
+
disabled={formIsSubmitting.current}
|
|
151
153
|
class={cn('w-full', classNames?.button, classNames?.primaryButton)}
|
|
152
154
|
>
|
|
153
|
-
{#if
|
|
155
|
+
{#if formIsSubmitting.current}
|
|
154
156
|
<Loader2 class="animate-spin" />
|
|
155
157
|
{:else}
|
|
156
158
|
{localization.FORGOT_PASSWORD_ACTION}
|
|
@@ -129,11 +129,12 @@
|
|
|
129
129
|
}
|
|
130
130
|
}));
|
|
131
131
|
|
|
132
|
-
const
|
|
132
|
+
const formIsSubmitting = form.useStore((s) => s.isSubmitting);
|
|
133
|
+
const isSubmitting = $derived(isSubmittingProp || formIsSubmitting.current);
|
|
133
134
|
|
|
134
135
|
// Update parent isSubmitting state
|
|
135
136
|
$effect(() => {
|
|
136
|
-
setIsSubmitting?.(
|
|
137
|
+
setIsSubmitting?.(formIsSubmitting.current);
|
|
137
138
|
});
|
|
138
139
|
</script>
|
|
139
140
|
|
|
@@ -41,9 +41,8 @@
|
|
|
41
41
|
// Merge localization from context and props
|
|
42
42
|
const localization = { ...contextLocalization, ...localizationProp };
|
|
43
43
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
});
|
|
44
|
+
const transition = useOnSuccessTransition({ redirectTo });
|
|
45
|
+
const { onSuccess } = transition;
|
|
47
46
|
|
|
48
47
|
const schema = z.object({
|
|
49
48
|
code: z.string().min(1, { message: localization.BACKUP_CODE_REQUIRED })
|
|
@@ -71,11 +70,12 @@
|
|
|
71
70
|
}));
|
|
72
71
|
|
|
73
72
|
// Compute final isSubmitting state
|
|
74
|
-
const
|
|
73
|
+
const formIsSubmitting = form.useStore((s) => s.isSubmitting);
|
|
74
|
+
const isSubmitting = $derived(isSubmittingProp ?? (formIsSubmitting.current || transition.isPending));
|
|
75
75
|
|
|
76
76
|
// Sync isSubmitting state
|
|
77
77
|
$effect(() => {
|
|
78
|
-
setIsSubmitting?.(
|
|
78
|
+
setIsSubmitting?.(formIsSubmitting.current || transition.isPending);
|
|
79
79
|
});
|
|
80
80
|
</script>
|
|
81
81
|
|
|
@@ -125,6 +125,8 @@
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
}));
|
|
128
|
+
|
|
129
|
+
const formIsSubmitting = form.useStore((s) => s.isSubmitting);
|
|
128
130
|
</script>
|
|
129
131
|
|
|
130
132
|
<form
|
|
@@ -147,7 +149,7 @@
|
|
|
147
149
|
value={field.state.value}
|
|
148
150
|
oninput={(e) => field.handleChange(e.currentTarget.value)}
|
|
149
151
|
onblur={field.handleBlur}
|
|
150
|
-
disabled={
|
|
152
|
+
disabled={formIsSubmitting.current}
|
|
151
153
|
class={classNames?.input}
|
|
152
154
|
/>
|
|
153
155
|
{#if field.state.meta.errors.length > 0}
|
|
@@ -183,7 +185,7 @@
|
|
|
183
185
|
value={field.state.value}
|
|
184
186
|
oninput={(e) => field.handleChange(e.currentTarget.value)}
|
|
185
187
|
onblur={field.handleBlur}
|
|
186
|
-
disabled={
|
|
188
|
+
disabled={formIsSubmitting.current}
|
|
187
189
|
class={classNames?.input}
|
|
188
190
|
/>
|
|
189
191
|
{#if field.state.meta.errors.length > 0}
|
|
@@ -198,10 +200,10 @@
|
|
|
198
200
|
|
|
199
201
|
<Button
|
|
200
202
|
type="submit"
|
|
201
|
-
disabled={
|
|
203
|
+
disabled={formIsSubmitting.current}
|
|
202
204
|
class={cn('w-full', classNames?.button, classNames?.primaryButton)}
|
|
203
205
|
>
|
|
204
|
-
{#if
|
|
206
|
+
{#if formIsSubmitting.current}
|
|
205
207
|
<Loader2 class="animate-spin" />
|
|
206
208
|
{:else}
|
|
207
209
|
{loc.RESET_PASSWORD_ACTION}
|
|
@@ -79,9 +79,8 @@
|
|
|
79
79
|
captchaHook.captchaRef = captchaRef;
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
});
|
|
82
|
+
const transition = useOnSuccessTransition({ redirectTo });
|
|
83
|
+
const { onSuccess } = transition;
|
|
85
84
|
|
|
86
85
|
// Form schema
|
|
87
86
|
const formSchema = $derived(
|
|
@@ -162,11 +161,12 @@
|
|
|
162
161
|
}
|
|
163
162
|
}));
|
|
164
163
|
|
|
165
|
-
const
|
|
164
|
+
const formIsSubmitting = form.useStore((s) => s.isSubmitting);
|
|
165
|
+
const isSubmitting = $derived(isSubmittingProp || formIsSubmitting.current || transition.isPending);
|
|
166
166
|
|
|
167
167
|
// Update parent isSubmitting state
|
|
168
168
|
$effect(() => {
|
|
169
|
-
setIsSubmitting?.(
|
|
169
|
+
setIsSubmitting?.(formIsSubmitting.current || transition.isPending);
|
|
170
170
|
});
|
|
171
171
|
</script>
|
|
172
172
|
|
|
@@ -98,9 +98,8 @@
|
|
|
98
98
|
});
|
|
99
99
|
|
|
100
100
|
// Success transition for navigation
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
});
|
|
101
|
+
const transition = useOnSuccessTransition({ redirectTo });
|
|
102
|
+
const { onSuccess } = transition;
|
|
104
103
|
|
|
105
104
|
// Helper functions
|
|
106
105
|
function getRedirectTo() {
|
|
@@ -391,7 +390,8 @@
|
|
|
391
390
|
}
|
|
392
391
|
|
|
393
392
|
// Combine isSubmitting states
|
|
394
|
-
const
|
|
393
|
+
const formIsSubmitting = form.useStore((s) => s.isSubmitting);
|
|
394
|
+
const isSubmitting = $derived(formIsSubmitting.current || transition.isPending);
|
|
395
395
|
|
|
396
396
|
// Sync external isSubmitting
|
|
397
397
|
$effect(() => {
|
|
@@ -56,9 +56,8 @@
|
|
|
56
56
|
|
|
57
57
|
const localization = $derived({ ...contextLocalization, ...localizationProp });
|
|
58
58
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
});
|
|
59
|
+
const transition = useOnSuccessTransition({ redirectTo });
|
|
60
|
+
const { onSuccess } = transition;
|
|
62
61
|
|
|
63
62
|
// Get session data to check if 2FA is being enabled
|
|
64
63
|
const sessionQuery = hooks?.useSession?.();
|
|
@@ -128,12 +127,13 @@
|
|
|
128
127
|
}
|
|
129
128
|
}));
|
|
130
129
|
|
|
131
|
-
const
|
|
130
|
+
const formIsSubmitting = form.useStore((s) => s.isSubmitting);
|
|
131
|
+
const isSubmitting = $derived(isSubmittingProp || formIsSubmitting.current || transition.isPending);
|
|
132
132
|
|
|
133
133
|
// Update parent isSubmitting state
|
|
134
134
|
$effect(() => {
|
|
135
135
|
if (setIsSubmitting) {
|
|
136
|
-
setIsSubmitting(
|
|
136
|
+
setIsSubmitting(formIsSubmitting.current || transition.isPending);
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
139
|
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as Card from '../ui/card/index.js';
|
|
6
6
|
import { Button } from '../ui/button/index.js';
|
|
7
7
|
import type { AuthLocalization } from '../../localization/auth-localization.js';
|
|
8
|
+
import Loader2 from '@lucide/svelte/icons/loader-2';
|
|
8
9
|
import MailOpen from '@lucide/svelte/icons/mail-open';
|
|
9
10
|
|
|
10
11
|
interface Props {
|
|
@@ -186,10 +187,10 @@
|
|
|
186
187
|
onclick={handleResendMagicLink}
|
|
187
188
|
class="w-full"
|
|
188
189
|
>
|
|
189
|
-
{#if
|
|
190
|
+
{#if isResending}
|
|
191
|
+
<Loader2 class="animate-spin" />
|
|
192
|
+
{:else if countdown > 0}
|
|
190
193
|
{localization.RESEND_MAGIC_LINK} ({countdown}s)
|
|
191
|
-
{:else if isResending}
|
|
192
|
-
{localization.RESEND_MAGIC_LINK}...
|
|
193
194
|
{:else}
|
|
194
195
|
{localization.RESEND_MAGIC_LINK}
|
|
195
196
|
{/if}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import Fingerprint from '@lucide/svelte/icons/fingerprint';
|
|
3
|
+
import Loader2 from '@lucide/svelte/icons/loader-2';
|
|
3
4
|
import {
|
|
4
5
|
getAuthClient,
|
|
5
6
|
getAuthUIConfig,
|
|
@@ -31,8 +32,11 @@
|
|
|
31
32
|
|
|
32
33
|
const { onSuccess } = useOnSuccessTransition({ redirectTo });
|
|
33
34
|
|
|
35
|
+
let isPending = $state(false);
|
|
36
|
+
|
|
34
37
|
async function signInPasskey() {
|
|
35
38
|
setIsSubmitting?.(true);
|
|
39
|
+
isPending = true;
|
|
36
40
|
|
|
37
41
|
try {
|
|
38
42
|
const response = await authClient.signIn.passkey({
|
|
@@ -48,6 +52,7 @@
|
|
|
48
52
|
);
|
|
49
53
|
|
|
50
54
|
setIsSubmitting?.(false);
|
|
55
|
+
isPending = false;
|
|
51
56
|
} else {
|
|
52
57
|
await onSuccess();
|
|
53
58
|
}
|
|
@@ -55,6 +60,7 @@
|
|
|
55
60
|
config.toast.error(getLocalizedError({ error, localization: loc }));
|
|
56
61
|
|
|
57
62
|
setIsSubmitting?.(false);
|
|
63
|
+
isPending = false;
|
|
58
64
|
}
|
|
59
65
|
}
|
|
60
66
|
</script>
|
|
@@ -67,7 +73,11 @@
|
|
|
67
73
|
variant="secondary"
|
|
68
74
|
onclick={signInPasskey}
|
|
69
75
|
>
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
{
|
|
76
|
+
{#if isPending}
|
|
77
|
+
<Loader2 class="animate-spin" />
|
|
78
|
+
{:else}
|
|
79
|
+
<Fingerprint class={classNames?.form?.icon} />
|
|
80
|
+
{loc.SIGN_IN_WITH}
|
|
81
|
+
{loc.PASSKEY}
|
|
82
|
+
{/if}
|
|
73
83
|
</Button>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import Loader2 from '@lucide/svelte/icons/loader-2';
|
|
2
3
|
import { Button } from '../ui/button/index.js';
|
|
3
4
|
import { getAuthClient, getAuthUIConfig } from '../../context/auth-ui-config.svelte';
|
|
4
5
|
import { cn } from '../../utils/ui.js';
|
|
@@ -37,6 +38,8 @@
|
|
|
37
38
|
const authClient = getAuthClient();
|
|
38
39
|
const config = getAuthUIConfig();
|
|
39
40
|
|
|
41
|
+
let isPending = $state(false);
|
|
42
|
+
|
|
40
43
|
function getRedirectTo() {
|
|
41
44
|
return redirectToProp || getSearchParam('redirectTo') || config.redirectTo;
|
|
42
45
|
}
|
|
@@ -53,6 +56,7 @@
|
|
|
53
56
|
|
|
54
57
|
async function doSignInSocial() {
|
|
55
58
|
setIsSubmitting(true);
|
|
59
|
+
isPending = true;
|
|
56
60
|
|
|
57
61
|
try {
|
|
58
62
|
if (other) {
|
|
@@ -94,6 +98,7 @@
|
|
|
94
98
|
config.toast.error(getLocalizedError({ error, localization }));
|
|
95
99
|
|
|
96
100
|
setIsSubmitting(false);
|
|
101
|
+
isPending = false;
|
|
97
102
|
}
|
|
98
103
|
}
|
|
99
104
|
</script>
|
|
@@ -110,14 +115,18 @@
|
|
|
110
115
|
variant="outline"
|
|
111
116
|
onclick={doSignInSocial}
|
|
112
117
|
>
|
|
113
|
-
{#if
|
|
114
|
-
<
|
|
115
|
-
{
|
|
118
|
+
{#if isPending}
|
|
119
|
+
<Loader2 class="animate-spin" />
|
|
120
|
+
{:else}
|
|
121
|
+
{#if provider.icon}
|
|
122
|
+
<provider.icon class={classNames?.form?.icon} />
|
|
123
|
+
{/if}
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
{#if socialLayout === 'grid'}
|
|
126
|
+
{provider.name}
|
|
127
|
+
{/if}
|
|
128
|
+
{#if socialLayout === 'vertical'}
|
|
129
|
+
{localization.SIGN_IN_WITH} {provider.name}
|
|
130
|
+
{/if}
|
|
122
131
|
{/if}
|
|
123
132
|
</Button>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as Card from '../ui/card/index.js';
|
|
6
6
|
import { Button } from '../ui/button/index.js';
|
|
7
7
|
import type { AuthLocalization } from '../../localization/auth-localization.js';
|
|
8
|
+
import Loader2 from '@lucide/svelte/icons/loader-2';
|
|
8
9
|
import MailOpen from '@lucide/svelte/icons/mail-open';
|
|
9
10
|
import CheckCircle from '@lucide/svelte/icons/check-circle';
|
|
10
11
|
|
|
@@ -274,7 +275,7 @@
|
|
|
274
275
|
|
|
275
276
|
<Button onclick={handleVerifyEmail} disabled={isVerifying} class="w-full">
|
|
276
277
|
{#if isVerifying}
|
|
277
|
-
|
|
278
|
+
<Loader2 class="animate-spin" />
|
|
278
279
|
{:else}
|
|
279
280
|
{localization.VERIFY_EMAIL_BUTTON || 'Verify Email'}
|
|
280
281
|
{/if}
|
|
@@ -299,10 +300,10 @@
|
|
|
299
300
|
onclick={handleResendEmail}
|
|
300
301
|
class="w-full"
|
|
301
302
|
>
|
|
302
|
-
{#if
|
|
303
|
+
{#if isResending}
|
|
304
|
+
<Loader2 class="animate-spin" />
|
|
305
|
+
{:else if countdown > 0}
|
|
303
306
|
{localization.RESEND_VERIFICATION_EMAIL} ({countdown}s)
|
|
304
|
-
{:else if isResending}
|
|
305
|
-
{localization.RESEND_VERIFICATION_EMAIL}...
|
|
306
307
|
{:else}
|
|
307
308
|
{localization.RESEND_VERIFICATION_EMAIL}
|
|
308
309
|
{/if}
|
|
@@ -214,7 +214,7 @@
|
|
|
214
214
|
yAxis: { format: () => '' }
|
|
215
215
|
}}
|
|
216
216
|
>
|
|
217
|
-
{#snippet marks({
|
|
217
|
+
{#snippet marks({ context })}
|
|
218
218
|
<defs>
|
|
219
219
|
<linearGradient id="fillDesktop" x1="0" y1="0" x2="0" y2="1">
|
|
220
220
|
<stop offset="5%" stop-color="var(--color-desktop)" stop-opacity={1.0} />
|
|
@@ -225,9 +225,9 @@
|
|
|
225
225
|
<stop offset="95%" stop-color="var(--color-mobile)" stop-opacity={0.1} />
|
|
226
226
|
</linearGradient>
|
|
227
227
|
</defs>
|
|
228
|
-
{#each series as s
|
|
228
|
+
{#each context.series.visibleSeries as s (s.key)}
|
|
229
229
|
<Area
|
|
230
|
-
{
|
|
230
|
+
seriesKey={s.key}
|
|
231
231
|
fill={s.key === 'desktop' ? 'url(#fillDesktop)' : 'url(#fillMobile)'}
|
|
232
232
|
/>
|
|
233
233
|
{/each}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { cn, type WithElementRef, type WithoutChildren } from '../../../utils/ui.js';
|
|
3
3
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
4
|
import { getPayloadConfigFromPayload, useChart, type TooltipPayload } from './chart-utils.js';
|
|
5
|
-
import {
|
|
5
|
+
import { getChartContext, Tooltip as TooltipPrimitive } from 'layerchart';
|
|
6
6
|
import type { Snippet } from 'svelte';
|
|
7
7
|
|
|
8
8
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -48,27 +48,33 @@
|
|
|
48
48
|
} = $props();
|
|
49
49
|
|
|
50
50
|
const chart = useChart();
|
|
51
|
-
const
|
|
51
|
+
const ctx = getChartContext();
|
|
52
|
+
|
|
53
|
+
const payload = $derived(ctx.tooltip.series.filter((s) => s.visible));
|
|
54
|
+
|
|
55
|
+
const headerLabel = $derived(
|
|
56
|
+
ctx.tooltip.data ? ctx.x(ctx.tooltip.data) : undefined
|
|
57
|
+
);
|
|
52
58
|
|
|
53
59
|
const formattedLabel = $derived.by(() => {
|
|
54
|
-
if (hideLabel || !
|
|
60
|
+
if (hideLabel || !payload.length) return null;
|
|
55
61
|
|
|
56
|
-
const [item] =
|
|
57
|
-
const key = labelKey ?? item?.label ?? item?.
|
|
62
|
+
const [item] = payload;
|
|
63
|
+
const key = labelKey ?? item?.label ?? item?.key ?? 'value';
|
|
58
64
|
|
|
59
65
|
const itemConfig = getPayloadConfigFromPayload(chart.config, item, key);
|
|
60
66
|
|
|
61
67
|
const value =
|
|
62
68
|
!labelKey && typeof label === 'string'
|
|
63
69
|
? (chart.config[label as keyof typeof chart.config]?.label ?? label)
|
|
64
|
-
: (itemConfig?.label ??
|
|
70
|
+
: (itemConfig?.label ?? (headerLabel != null ? String(headerLabel) : undefined));
|
|
65
71
|
|
|
66
72
|
if (value === undefined) return null;
|
|
67
73
|
if (!labelFormatter) return value;
|
|
68
|
-
return labelFormatter(value,
|
|
74
|
+
return labelFormatter(value, payload);
|
|
69
75
|
});
|
|
70
76
|
|
|
71
|
-
const nestLabel = $derived(
|
|
77
|
+
const nestLabel = $derived(payload.length === 1 && indicator !== 'dot');
|
|
72
78
|
</script>
|
|
73
79
|
|
|
74
80
|
{#snippet TooltipLabel()}
|
|
@@ -95,23 +101,23 @@
|
|
|
95
101
|
{@render TooltipLabel()}
|
|
96
102
|
{/if}
|
|
97
103
|
<div class="grid gap-1.5">
|
|
98
|
-
{#each
|
|
99
|
-
{@const key = `${nameKey || item.key ||
|
|
104
|
+
{#each payload as item, i (item.key + i)}
|
|
105
|
+
{@const key = `${nameKey || item.key || 'value'}`}
|
|
100
106
|
{@const itemConfig = getPayloadConfigFromPayload(chart.config, item, key)}
|
|
101
|
-
{@const indicatorColor = color || item.
|
|
107
|
+
{@const indicatorColor = color || item.color}
|
|
102
108
|
<div
|
|
103
109
|
class={cn(
|
|
104
110
|
'flex w-full flex-wrap items-stretch gap-2 [&>svg]:size-2.5 [&>svg]:text-muted-foreground',
|
|
105
111
|
indicator === 'dot' && 'items-center'
|
|
106
112
|
)}
|
|
107
113
|
>
|
|
108
|
-
{#if formatter && item.value !== undefined && item.
|
|
114
|
+
{#if formatter && item.value !== undefined && item.label}
|
|
109
115
|
{@render formatter({
|
|
110
116
|
value: item.value,
|
|
111
|
-
name: item.
|
|
117
|
+
name: item.label,
|
|
112
118
|
item,
|
|
113
119
|
index: i,
|
|
114
|
-
payload
|
|
120
|
+
payload
|
|
115
121
|
})}
|
|
116
122
|
{:else}
|
|
117
123
|
{#if itemConfig?.icon}
|
|
@@ -138,12 +144,14 @@
|
|
|
138
144
|
{@render TooltipLabel()}
|
|
139
145
|
{/if}
|
|
140
146
|
<span class="text-muted-foreground">
|
|
141
|
-
{itemConfig?.label || item.
|
|
147
|
+
{itemConfig?.label || item.label}
|
|
142
148
|
</span>
|
|
143
149
|
</div>
|
|
144
150
|
{#if item.value !== undefined}
|
|
145
151
|
<span class="font-mono font-medium text-foreground tabular-nums">
|
|
146
|
-
{item.value
|
|
152
|
+
{typeof item.value === 'number'
|
|
153
|
+
? item.value.toLocaleString()
|
|
154
|
+
: item.value}
|
|
147
155
|
</span>
|
|
148
156
|
{/if}
|
|
149
157
|
</div>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { type Component, type ComponentProps, type Snippet } from 'svelte';
|
|
1
|
+
import { type Component } from 'svelte';
|
|
3
2
|
export declare const THEMES: {
|
|
4
3
|
readonly light: "";
|
|
5
4
|
readonly dark: ".dark";
|
|
@@ -16,8 +15,13 @@ export type ChartConfig = {
|
|
|
16
15
|
theme: Record<keyof typeof THEMES, string>;
|
|
17
16
|
});
|
|
18
17
|
};
|
|
19
|
-
export type
|
|
20
|
-
|
|
18
|
+
export type TooltipPayload = {
|
|
19
|
+
key: string;
|
|
20
|
+
label: string;
|
|
21
|
+
value: any;
|
|
22
|
+
color?: string;
|
|
23
|
+
visible: boolean;
|
|
24
|
+
};
|
|
21
25
|
export declare function getPayloadConfigFromPayload(config: ChartConfig, payload: TooltipPayload, key: string): ({
|
|
22
26
|
label?: string;
|
|
23
27
|
icon?: Component;
|
|
@@ -4,24 +4,16 @@ export const THEMES = { light: '', dark: '.dark' };
|
|
|
4
4
|
export function getPayloadConfigFromPayload(config, payload, key) {
|
|
5
5
|
if (typeof payload !== 'object' || payload === null)
|
|
6
6
|
return undefined;
|
|
7
|
-
const payloadPayload = 'payload' in payload && typeof payload.payload === 'object' && payload.payload !== null
|
|
8
|
-
? payload.payload
|
|
9
|
-
: undefined;
|
|
10
7
|
let configLabelKey = key;
|
|
11
8
|
if (payload.key === key) {
|
|
12
9
|
configLabelKey = payload.key;
|
|
13
10
|
}
|
|
14
|
-
else if (payload.
|
|
15
|
-
configLabelKey = payload.
|
|
11
|
+
else if (payload.label === key) {
|
|
12
|
+
configLabelKey = payload.label;
|
|
16
13
|
}
|
|
17
14
|
else if (key in payload && typeof payload[key] === 'string') {
|
|
18
15
|
configLabelKey = payload[key];
|
|
19
16
|
}
|
|
20
|
-
else if (payloadPayload !== undefined &&
|
|
21
|
-
key in payloadPayload &&
|
|
22
|
-
typeof payloadPayload[key] === 'string') {
|
|
23
|
-
configLabelKey = payloadPayload[key];
|
|
24
|
-
}
|
|
25
17
|
return configLabelKey in config ? config[configLabelKey] : config[key];
|
|
26
18
|
}
|
|
27
19
|
const chartContextKey = Symbol('chart-context');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "better-auth-ui-svelte",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.6",
|
|
4
4
|
"description": "Pre-built authentication UI components for Better Auth in Svelte 5",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "vite dev",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"bits-ui": "^2.14.4",
|
|
56
56
|
"d3-scale": "^4.0.2",
|
|
57
57
|
"d3-shape": "^3.2.0",
|
|
58
|
-
"layerchart": "2.0.0-next.
|
|
58
|
+
"layerchart": "2.0.0-next.48",
|
|
59
59
|
"svelte": "^5.0.0",
|
|
60
60
|
"tailwindcss": "^4.0.0",
|
|
61
61
|
"zod": "^4.0.0"
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"eslint-plugin-svelte": "^3.13.1",
|
|
101
101
|
"formsnap": "^2.0.1",
|
|
102
102
|
"globals": "^16.5.0",
|
|
103
|
-
"layerchart": "2.0.0-next.
|
|
103
|
+
"layerchart": "2.0.0-next.48",
|
|
104
104
|
"mode-watcher": "^1.1.0",
|
|
105
105
|
"paneforge": "^1.0.2",
|
|
106
106
|
"playwright": "^1.57.0",
|