@nymphjs/tilmeld-components 1.0.0-beta.135 → 1.0.0-beta.136
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/CHANGELOG.md +6 -0
- package/dist/Account.svelte +144 -142
- package/dist/ChangePassword.svelte +63 -61
- package/dist/Login.svelte +13 -2
- package/dist/Recover.svelte +153 -137
- package/dist/RevokeTokens.svelte +31 -29
- package/dist/TwoFactor.svelte +194 -180
- package/package.json +3 -3
- package/src/Account.svelte +144 -142
- package/src/ChangePassword.svelte +63 -61
- package/src/Login.svelte +13 -2
- package/src/Recover.svelte +153 -137
- package/src/RevokeTokens.svelte +31 -29
- package/src/TwoFactor.svelte +194 -180
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.0.0-beta.136](https://forge.sciactive.com/sciactive/nymphjs/compare/v1.0.0-beta.135...v1.0.0-beta.136) (2026-10-31)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
- wrap all tilmeld components in form with submit handler ([1b03774](https://forge.sciactive.com/sciactive/nymphjs/commits/1b0377498596bac957f83ec43b178347489d7a7a))
|
|
11
|
+
|
|
6
12
|
# [1.0.0-beta.135](https://forge.sciactive.com/sciactive/nymphjs/compare/v1.0.0-beta.134...v1.0.0-beta.135) (2026-10-31)
|
|
7
13
|
|
|
8
14
|
**Note:** Version bump only for package @nymphjs/tilmeld-components
|
package/dist/Account.svelte
CHANGED
|
@@ -27,167 +27,169 @@
|
|
|
27
27
|
<!-- Title cannot contain leading whitespace due to mdc-typography-baseline-top() -->
|
|
28
28
|
<Title id="tilmeld-account-title">{title}</Title>
|
|
29
29
|
<Content id="tilmeld-account-content">
|
|
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
|
-
{#if $clientConfig.emailUsernames || $clientConfig.userFields.includes('email')}
|
|
55
|
-
<div>
|
|
56
|
-
<Textfield
|
|
57
|
-
bind:value={$user.email}
|
|
58
|
-
label="Email"
|
|
59
|
-
type="email"
|
|
60
|
-
style="width: 100%;"
|
|
61
|
-
helperLine$style="width: 100%;"
|
|
62
|
-
invalid={emailVerified === false}
|
|
63
|
-
input$autocomplete="email"
|
|
64
|
-
input$autocapitalize="off"
|
|
65
|
-
input$spellcheck="false"
|
|
66
|
-
input$emptyValueUndefined
|
|
67
|
-
{...prefixFilter(restProps, 'email$')}
|
|
68
|
-
>
|
|
69
|
-
{#snippet helper()}
|
|
70
|
-
<HelperText persistent>
|
|
71
|
-
{emailVerifiedMessage || ''}
|
|
72
|
-
</HelperText>
|
|
73
|
-
{/snippet}
|
|
74
|
-
</Textfield>
|
|
75
|
-
</div>
|
|
76
|
-
{/if}
|
|
77
|
-
|
|
78
|
-
{#if $clientConfig.userFields.includes('name')}
|
|
79
|
-
<div>
|
|
80
|
-
<Textfield
|
|
81
|
-
bind:value={$user.nameFirst}
|
|
82
|
-
label="First Name"
|
|
83
|
-
type="text"
|
|
84
|
-
style="width: 100%;"
|
|
85
|
-
input$autocomplete="given-name"
|
|
86
|
-
input$emptyValueUndefined
|
|
87
|
-
{...prefixFilter(restProps, 'nameFirst$')}
|
|
88
|
-
/>
|
|
89
|
-
</div>
|
|
30
|
+
<form onsubmit={preventDefault(stopPropagation(save))}>
|
|
31
|
+
{#if !$clientConfig.emailUsernames && $clientConfig.allowUsernameChange}
|
|
32
|
+
<div>
|
|
33
|
+
<Textfield
|
|
34
|
+
bind:value={$user.username}
|
|
35
|
+
label="Username"
|
|
36
|
+
type="text"
|
|
37
|
+
style="width: 100%;"
|
|
38
|
+
helperLine$style="width: 100%;"
|
|
39
|
+
invalid={usernameVerified === false}
|
|
40
|
+
input$autocomplete="username"
|
|
41
|
+
input$autocapitalize="off"
|
|
42
|
+
input$spellcheck="false"
|
|
43
|
+
input$emptyValueUndefined
|
|
44
|
+
{...prefixFilter(restProps, 'username$')}
|
|
45
|
+
>
|
|
46
|
+
{#snippet helper()}
|
|
47
|
+
<HelperText persistent>
|
|
48
|
+
{usernameVerifiedMessage || ''}
|
|
49
|
+
</HelperText>
|
|
50
|
+
{/snippet}
|
|
51
|
+
</Textfield>
|
|
52
|
+
</div>
|
|
53
|
+
{/if}
|
|
90
54
|
|
|
91
|
-
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
55
|
+
{#if $clientConfig.emailUsernames || $clientConfig.userFields.includes('email')}
|
|
56
|
+
<div>
|
|
57
|
+
<Textfield
|
|
58
|
+
bind:value={$user.email}
|
|
59
|
+
label="Email"
|
|
60
|
+
type="email"
|
|
61
|
+
style="width: 100%;"
|
|
62
|
+
helperLine$style="width: 100%;"
|
|
63
|
+
invalid={emailVerified === false}
|
|
64
|
+
input$autocomplete="email"
|
|
65
|
+
input$autocapitalize="off"
|
|
66
|
+
input$spellcheck="false"
|
|
67
|
+
input$emptyValueUndefined
|
|
68
|
+
{...prefixFilter(restProps, 'email$')}
|
|
69
|
+
>
|
|
70
|
+
{#snippet helper()}
|
|
71
|
+
<HelperText persistent>
|
|
72
|
+
{emailVerifiedMessage || ''}
|
|
73
|
+
</HelperText>
|
|
74
|
+
{/snippet}
|
|
75
|
+
</Textfield>
|
|
76
|
+
</div>
|
|
77
|
+
{/if}
|
|
102
78
|
|
|
103
|
-
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
79
|
+
{#if $clientConfig.userFields.includes('name')}
|
|
80
|
+
<div>
|
|
81
|
+
<Textfield
|
|
82
|
+
bind:value={$user.nameFirst}
|
|
83
|
+
label="First Name"
|
|
84
|
+
type="text"
|
|
85
|
+
style="width: 100%;"
|
|
86
|
+
input$autocomplete="given-name"
|
|
87
|
+
input$emptyValueUndefined
|
|
88
|
+
{...prefixFilter(restProps, 'nameFirst$')}
|
|
89
|
+
/>
|
|
90
|
+
</div>
|
|
115
91
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
/>
|
|
128
|
-
</div>
|
|
129
|
-
{/if}
|
|
92
|
+
<div>
|
|
93
|
+
<Textfield
|
|
94
|
+
bind:value={$user.nameMiddle}
|
|
95
|
+
label="Middle Name"
|
|
96
|
+
type="text"
|
|
97
|
+
style="width: 100%;"
|
|
98
|
+
input$autocomplete="additional-name"
|
|
99
|
+
input$emptyValueUndefined
|
|
100
|
+
{...prefixFilter(restProps, 'nameMiddle$')}
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
130
103
|
|
|
131
|
-
|
|
104
|
+
<div>
|
|
105
|
+
<Textfield
|
|
106
|
+
bind:value={$user.nameLast}
|
|
107
|
+
label="Last Name"
|
|
108
|
+
type="text"
|
|
109
|
+
style="width: 100%;"
|
|
110
|
+
input$autocomplete="family-name"
|
|
111
|
+
input$emptyValueUndefined
|
|
112
|
+
{...prefixFilter(restProps, 'nameLast$')}
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
{/if}
|
|
132
116
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
117
|
+
{#if $clientConfig.userFields.includes('phone')}
|
|
118
|
+
<div>
|
|
119
|
+
<Textfield
|
|
120
|
+
bind:value={$user.phone}
|
|
121
|
+
label="Phone Number"
|
|
122
|
+
type="tel"
|
|
123
|
+
style="width: 100%;"
|
|
124
|
+
input$autocomplete="tel"
|
|
125
|
+
input$name="phone"
|
|
126
|
+
input$emptyValueUndefined
|
|
127
|
+
{...prefixFilter(restProps, 'phone$')}
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
{/if}
|
|
145
131
|
|
|
146
|
-
|
|
147
|
-
<a
|
|
148
|
-
href={'javascript:void(0);'}
|
|
149
|
-
onclick={() => {
|
|
150
|
-
open = false;
|
|
151
|
-
revokeTokensOpen = true;
|
|
152
|
-
}}
|
|
153
|
-
{...prefixFilter(restProps, 'revokeTokensLink$')}
|
|
154
|
-
>
|
|
155
|
-
Log out of other sessions.
|
|
156
|
-
</a>
|
|
132
|
+
{@render additional?.()}
|
|
157
133
|
|
|
158
134
|
<div class="tilmeld-account-action">
|
|
159
135
|
<a
|
|
160
136
|
href={'javascript:void(0);'}
|
|
161
137
|
onclick={() => {
|
|
162
138
|
open = false;
|
|
163
|
-
|
|
139
|
+
changePasswordOpen = true;
|
|
164
140
|
}}
|
|
165
|
-
{...prefixFilter(restProps, '
|
|
141
|
+
{...prefixFilter(restProps, 'changePasswordLink$')}
|
|
166
142
|
>
|
|
167
|
-
|
|
168
|
-
Enable two factor authentication (2FA).
|
|
169
|
-
{:else}
|
|
170
|
-
Manage two factor authentication (2FA).
|
|
171
|
-
{/if}
|
|
143
|
+
Change your password.
|
|
172
144
|
</a>
|
|
173
145
|
</div>
|
|
174
146
|
|
|
175
|
-
|
|
176
|
-
<
|
|
177
|
-
{
|
|
178
|
-
|
|
179
|
-
|
|
147
|
+
<div class="tilmeld-account-action">
|
|
148
|
+
<a
|
|
149
|
+
href={'javascript:void(0);'}
|
|
150
|
+
onclick={() => {
|
|
151
|
+
open = false;
|
|
152
|
+
revokeTokensOpen = true;
|
|
153
|
+
}}
|
|
154
|
+
{...prefixFilter(restProps, 'revokeTokensLink$')}
|
|
155
|
+
>
|
|
156
|
+
Log out of other sessions.
|
|
157
|
+
</a>
|
|
180
158
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
159
|
+
<div class="tilmeld-account-action">
|
|
160
|
+
<a
|
|
161
|
+
href={'javascript:void(0);'}
|
|
162
|
+
onclick={() => {
|
|
163
|
+
open = false;
|
|
164
|
+
twoFactorOpen = true;
|
|
165
|
+
}}
|
|
166
|
+
{...prefixFilter(restProps, 'twoFactor$')}
|
|
167
|
+
>
|
|
168
|
+
{#if hasTOTPSecret === false}
|
|
169
|
+
Enable two factor authentication (2FA).
|
|
170
|
+
{:else}
|
|
171
|
+
Manage two factor authentication (2FA).
|
|
172
|
+
{/if}
|
|
173
|
+
</a>
|
|
188
174
|
</div>
|
|
189
|
-
|
|
190
|
-
|
|
175
|
+
|
|
176
|
+
{#if failureMessage}
|
|
177
|
+
<div class="tilmeld-account-failure">
|
|
178
|
+
{failureMessage}
|
|
179
|
+
</div>
|
|
180
|
+
{/if}
|
|
181
|
+
|
|
182
|
+
{#if loading}
|
|
183
|
+
<div class="tilmeld-account-loading">
|
|
184
|
+
<CircularProgress
|
|
185
|
+
style="height: 24px; width: 24px;"
|
|
186
|
+
indeterminate
|
|
187
|
+
{...prefixFilter(restProps, 'progress$')}
|
|
188
|
+
/>
|
|
189
|
+
</div>
|
|
190
|
+
{/if}
|
|
191
|
+
</div>
|
|
192
|
+
</form>
|
|
191
193
|
</Content>
|
|
192
194
|
<Actions>
|
|
193
195
|
<Button disabled={loading} {...prefixFilter(restProps, 'closeButton$')}>
|
|
@@ -20,73 +20,75 @@
|
|
|
20
20
|
<!-- Title cannot contain leading whitespace due to mdc-typography-baseline-top() -->
|
|
21
21
|
<Title id="tilmeld-password-title">{title}</Title>
|
|
22
22
|
<Content id="tilmeld-password-content">
|
|
23
|
-
<
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
</div>
|
|
33
|
-
|
|
34
|
-
<div>
|
|
35
|
-
<Textfield
|
|
36
|
-
bind:value={newPassword}
|
|
37
|
-
label="New Password"
|
|
38
|
-
type="password"
|
|
39
|
-
style="width: 100%;"
|
|
40
|
-
input$autocomplete="new-password"
|
|
41
|
-
{...prefixFilter(restProps, 'newPassword$')}
|
|
42
|
-
/>
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
<div>
|
|
46
|
-
<Textfield
|
|
47
|
-
bind:value={newPassword2}
|
|
48
|
-
label="Re-enter New Password"
|
|
49
|
-
type="password"
|
|
50
|
-
style="width: 100%;"
|
|
51
|
-
input$autocomplete="new-password"
|
|
52
|
-
{...prefixFilter(restProps, 'newPassword2$')}
|
|
53
|
-
/>
|
|
54
|
-
</div>
|
|
55
|
-
|
|
56
|
-
<div style="margin: 1em 0;">
|
|
57
|
-
<FormField>
|
|
58
|
-
<Checkbox
|
|
59
|
-
bind:checked={revokeCurrentTokens}
|
|
60
|
-
{...prefixFilter(restProps, 'revokeTokens$')}
|
|
23
|
+
<form onsubmit={preventDefault(stopPropagation(changePassword))}>
|
|
24
|
+
<div>
|
|
25
|
+
<Textfield
|
|
26
|
+
bind:value={currentPassword}
|
|
27
|
+
label="Current Password"
|
|
28
|
+
type="password"
|
|
29
|
+
style="width: 100%;"
|
|
30
|
+
input$autocomplete="current-password"
|
|
31
|
+
{...prefixFilter(restProps, 'password$')}
|
|
61
32
|
/>
|
|
62
|
-
|
|
63
|
-
Log out of all other sessions.
|
|
64
|
-
<span
|
|
65
|
-
style="display: block; font-size: 0.7em; height: 0; overflow: visible;"
|
|
66
|
-
>
|
|
67
|
-
Use this if you think you've been hacked.
|
|
68
|
-
</span>
|
|
69
|
-
{/snippet}
|
|
70
|
-
</FormField>
|
|
71
|
-
</div>
|
|
72
|
-
|
|
73
|
-
{@render additional?.()}
|
|
33
|
+
</div>
|
|
74
34
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
35
|
+
<div>
|
|
36
|
+
<Textfield
|
|
37
|
+
bind:value={newPassword}
|
|
38
|
+
label="New Password"
|
|
39
|
+
type="password"
|
|
40
|
+
style="width: 100%;"
|
|
41
|
+
input$autocomplete="new-password"
|
|
42
|
+
{...prefixFilter(restProps, 'newPassword$')}
|
|
43
|
+
/>
|
|
78
44
|
</div>
|
|
79
|
-
{/if}
|
|
80
45
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
46
|
+
<div>
|
|
47
|
+
<Textfield
|
|
48
|
+
bind:value={newPassword2}
|
|
49
|
+
label="Re-enter New Password"
|
|
50
|
+
type="password"
|
|
51
|
+
style="width: 100%;"
|
|
52
|
+
input$autocomplete="new-password"
|
|
53
|
+
{...prefixFilter(restProps, 'newPassword2$')}
|
|
87
54
|
/>
|
|
88
55
|
</div>
|
|
89
|
-
|
|
56
|
+
|
|
57
|
+
<div style="margin: 1em 0;">
|
|
58
|
+
<FormField>
|
|
59
|
+
<Checkbox
|
|
60
|
+
bind:checked={revokeCurrentTokens}
|
|
61
|
+
{...prefixFilter(restProps, 'revokeTokens$')}
|
|
62
|
+
/>
|
|
63
|
+
{#snippet label()}
|
|
64
|
+
Log out of all other sessions.
|
|
65
|
+
<span
|
|
66
|
+
style="display: block; font-size: 0.7em; height: 0; overflow: visible;"
|
|
67
|
+
>
|
|
68
|
+
Use this if you think you've been hacked.
|
|
69
|
+
</span>
|
|
70
|
+
{/snippet}
|
|
71
|
+
</FormField>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
{@render additional?.()}
|
|
75
|
+
|
|
76
|
+
{#if failureMessage}
|
|
77
|
+
<div class="tilmeld-password-failure">
|
|
78
|
+
{failureMessage}
|
|
79
|
+
</div>
|
|
80
|
+
{/if}
|
|
81
|
+
|
|
82
|
+
{#if loading}
|
|
83
|
+
<div class="tilmeld-password-loading">
|
|
84
|
+
<CircularProgress
|
|
85
|
+
style="height: 24px; width: 24px;"
|
|
86
|
+
indeterminate
|
|
87
|
+
{...prefixFilter(restProps, 'progress$')}
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
{/if}
|
|
91
|
+
</form>
|
|
90
92
|
</Content>
|
|
91
93
|
<Actions>
|
|
92
94
|
<Button disabled={loading} {...prefixFilter(restProps, 'closeButton$')}>
|
package/dist/Login.svelte
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
{successLoginMessage}
|
|
41
41
|
</div>
|
|
42
42
|
{:else if totp}
|
|
43
|
-
<form onsubmit={
|
|
43
|
+
<form onsubmit={preventDefault(stopPropagation(login))}>
|
|
44
44
|
<div {...prefixFilter(restProps, 'codeMessage$')}>
|
|
45
45
|
Enter the 6-digit 2FA code from your authenticator app.
|
|
46
46
|
</div>
|
|
@@ -74,7 +74,17 @@
|
|
|
74
74
|
</div>
|
|
75
75
|
</form>
|
|
76
76
|
{:else}
|
|
77
|
-
<form
|
|
77
|
+
<form
|
|
78
|
+
onsubmit={preventDefault(
|
|
79
|
+
stopPropagation(() => {
|
|
80
|
+
if (mode === 'login') {
|
|
81
|
+
login();
|
|
82
|
+
} else {
|
|
83
|
+
register();
|
|
84
|
+
}
|
|
85
|
+
}),
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
78
88
|
<div>
|
|
79
89
|
<Textfield
|
|
80
90
|
bind:value={username}
|
|
@@ -259,6 +269,7 @@
|
|
|
259
269
|
import HelperText from '@smui/textfield/helper-text';
|
|
260
270
|
import type { ActionArray } from '@smui/common/internal';
|
|
261
271
|
import { exclude, prefixFilter, useActions } from '@smui/common/internal';
|
|
272
|
+
import { preventDefault, stopPropagation } from '@smui/common/events';
|
|
262
273
|
import type { SmuiElementPropMap } from '@smui/common';
|
|
263
274
|
import type {
|
|
264
275
|
User as UserClass,
|