@nymphjs/tilmeld-components 1.0.0-beta.13 → 1.0.0-beta.131

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.
@@ -1,14 +1,17 @@
1
- {#if user != null}
1
+ <svelte:options runes />
2
+
3
+ {#if $user != null}
2
4
  <Dialog
3
- use={usePass}
5
+ {use}
4
6
  bind:open
5
7
  aria-labelledby="tilmeld-password-title"
6
8
  aria-describedby="tilmeld-password-content"
7
9
  surface$class="tilmeld-password-dialog-surface"
8
- {...exclude($$restProps, [
10
+ {...exclude(restProps, [
9
11
  'password$',
10
12
  'newPassword$',
11
13
  'newPassword2$',
14
+ 'revokeTokens$',
12
15
  'closeButton$',
13
16
  'saveButton$',
14
17
  'progress$',
@@ -24,7 +27,7 @@
24
27
  type="password"
25
28
  style="width: 100%;"
26
29
  input$autocomplete="current-password"
27
- {...prefixFilter($$restProps, 'password$')}
30
+ {...prefixFilter(restProps, 'password$')}
28
31
  />
29
32
  </div>
30
33
 
@@ -35,7 +38,7 @@
35
38
  type="password"
36
39
  style="width: 100%;"
37
40
  input$autocomplete="new-password"
38
- {...prefixFilter($$restProps, 'newPassword$')}
41
+ {...prefixFilter(restProps, 'newPassword$')}
39
42
  />
40
43
  </div>
41
44
 
@@ -46,11 +49,28 @@
46
49
  type="password"
47
50
  style="width: 100%;"
48
51
  input$autocomplete="new-password"
49
- {...prefixFilter($$restProps, 'newPassword2$')}
52
+ {...prefixFilter(restProps, 'newPassword2$')}
50
53
  />
51
54
  </div>
52
55
 
53
- <slot name="additional" />
56
+ <div style="margin: 1em 0;">
57
+ <FormField>
58
+ <Checkbox
59
+ bind:checked={revokeCurrentTokens}
60
+ {...prefixFilter(restProps, 'revokeTokens$')}
61
+ />
62
+ {#snippet label()}
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?.()}
54
74
 
55
75
  {#if failureMessage}
56
76
  <div class="tilmeld-password-failure">
@@ -58,27 +78,24 @@
58
78
  </div>
59
79
  {/if}
60
80
 
61
- {#if changing}
81
+ {#if loading}
62
82
  <div class="tilmeld-password-loading">
63
83
  <CircularProgress
64
84
  style="height: 24px; width: 24px;"
65
85
  indeterminate
66
- {...prefixFilter($$restProps, 'progress$')}
86
+ {...prefixFilter(restProps, 'progress$')}
67
87
  />
68
88
  </div>
69
89
  {/if}
70
90
  </Content>
71
91
  <Actions>
72
- <Button
73
- disabled={changing}
74
- {...prefixFilter($$restProps, 'closeButton$')}
75
- >
92
+ <Button disabled={loading} {...prefixFilter(restProps, 'closeButton$')}>
76
93
  <Label>Close</Label>
77
94
  </Button>
78
95
  <Button
79
- on:click$preventDefault$stopPropagation={changePassword}
80
- disabled={changing}
81
- {...prefixFilter($$restProps, 'saveButton$')}
96
+ onclick={preventDefault(stopPropagation(changePassword))}
97
+ disabled={loading}
98
+ {...prefixFilter(restProps, 'saveButton$')}
82
99
  >
83
100
  <Label>Change Password</Label>
84
101
  </Button>
@@ -87,62 +104,140 @@
87
104
  {/if}
88
105
 
89
106
  <script lang="ts">
107
+ import type { ComponentProps, Snippet } from 'svelte';
90
108
  import { onMount, onDestroy } from 'svelte';
91
- import { get_current_component } from 'svelte/internal';
109
+ import type { Writable } from 'svelte/store';
110
+ import { writable } from 'svelte/store';
92
111
  import CircularProgress from '@smui/circular-progress';
93
112
  import Dialog, { Title, Content, Actions } from '@smui/dialog';
94
113
  import Textfield from '@smui/textfield';
114
+ import Checkbox from '@smui/checkbox';
115
+ import FormField from '@smui/form-field';
95
116
  import Button, { Label } from '@smui/button';
96
117
  import type { ActionArray } from '@smui/common/internal';
97
- import {
98
- forwardEventsBuilder,
99
- exclude,
100
- prefixFilter,
101
- } from '@smui/common/internal';
118
+ import { exclude, prefixFilter } from '@smui/common/internal';
119
+ import { preventDefault, stopPropagation } from '@smui/common/events';
102
120
  import type { CurrentUserData } from '@nymphjs/tilmeld-client';
103
121
  import type { User as UserClass } from '@nymphjs/tilmeld-client';
104
122
 
105
- const forwardEvents = forwardEventsBuilder(get_current_component());
106
-
107
- export let use: ActionArray = [];
108
- $: usePass = [forwardEvents, ...use] as ActionArray;
109
- export let open = false;
110
- export let title = 'Change Your Password';
111
- export let User: typeof UserClass;
112
- export let user: (UserClass & CurrentUserData) | undefined = undefined;
123
+ type OwnProps = {
124
+ /**
125
+ * An array of Action or [Action, ActionProps] to be applied to the element.
126
+ */
127
+ use?: ActionArray;
128
+ /**
129
+ * Whether the dialog is open.
130
+ */
131
+ open?: boolean;
132
+ /**
133
+ * The title of the dialog.
134
+ */
135
+ title?: string;
136
+ /**
137
+ * The User class from Nymph.
138
+ */
139
+ User: typeof UserClass;
140
+ /**
141
+ * A writable store of the current user.
142
+ *
143
+ * It will be retrieved from the server if not provided.
144
+ */
145
+ user?: Writable<(UserClass & CurrentUserData) | null | undefined>;
146
+ /**
147
+ * User provided. You can bind to it if you need to.
148
+ */
149
+ currentPassword?: string;
150
+ /**
151
+ * User provided. You can bind to it if you need to.
152
+ */
153
+ newPassword?: string;
154
+ /**
155
+ * User provided. You can bind to it if you need to.
156
+ */
157
+ newPassword2?: string;
158
+ /**
159
+ * User provided. You can bind to it if you need to.
160
+ */
161
+ revokeCurrentTokens?: boolean;
113
162
 
114
- let changing = false;
115
- let failureMessage: string | undefined = undefined;
163
+ /**
164
+ * A spot for additional content.
165
+ */
166
+ additional?: Snippet;
167
+ };
168
+ let {
169
+ use = [],
170
+ open = $bindable(false),
171
+ title = 'Change Your Password',
172
+ User,
173
+ user = $bindable(writable(false as unknown as undefined)),
174
+ currentPassword = $bindable(''),
175
+ newPassword = $bindable(''),
176
+ newPassword2 = $bindable(''),
177
+ revokeCurrentTokens = $bindable(false),
178
+ additional,
179
+ ...restProps
180
+ }: OwnProps & {
181
+ [
182
+ k in keyof ComponentProps<typeof Textfield> as `password\$${k}`
183
+ ]?: ComponentProps<typeof Textfield>[k];
184
+ } & {
185
+ [
186
+ k in keyof ComponentProps<typeof Textfield> as `newPassword\$${k}`
187
+ ]?: ComponentProps<typeof Textfield>[k];
188
+ } & {
189
+ [
190
+ k in keyof ComponentProps<typeof Textfield> as `newPassword2\$${k}`
191
+ ]?: ComponentProps<typeof Textfield>[k];
192
+ } & {
193
+ [
194
+ k in keyof ComponentProps<typeof Checkbox> as `revokeTokens\$${k}`
195
+ ]?: ComponentProps<typeof Checkbox>[k];
196
+ } & {
197
+ [
198
+ k in keyof ComponentProps<typeof CircularProgress> as `progress\$${k}`
199
+ ]?: ComponentProps<typeof CircularProgress>[k];
200
+ } & {
201
+ [
202
+ k in keyof ComponentProps<
203
+ typeof Button<undefined, 'button'>
204
+ > as `closeButton\$${k}`
205
+ ]?: ComponentProps<typeof Button<undefined, 'button'>>[k];
206
+ } & {
207
+ [
208
+ k in keyof ComponentProps<
209
+ typeof Button<undefined, 'button'>
210
+ > as `saveButton\$${k}`
211
+ ]?: ComponentProps<typeof Button<undefined, 'button'>>[k];
212
+ } = $props();
116
213
 
117
- /** User provided. You can bind to it if you need to. */
118
- export let currentPassword = '';
119
- /** User provided. You can bind to it if you need to. */
120
- export let newPassword = '';
121
- /** User provided. You can bind to it if you need to. */
122
- export let newPassword2 = '';
214
+ let loading = $state(false);
215
+ let failureMessage: string | undefined = $state();
123
216
 
124
- $: {
217
+ $effect(() => {
125
218
  if (!open) {
126
- changing = false;
219
+ loading = false;
127
220
  failureMessage = undefined;
128
221
  currentPassword = '';
129
222
  newPassword = '';
130
223
  newPassword2 = '';
224
+ revokeCurrentTokens = false;
131
225
  }
132
- }
226
+ });
133
227
 
134
228
  const onLogin = (currentUser: UserClass & CurrentUserData) => {
135
- user = currentUser;
229
+ $user = currentUser;
136
230
  };
137
231
  const onLogout = () => {
138
- user = undefined;
232
+ $user = null;
139
233
  };
140
234
 
141
235
  onMount(async () => {
142
236
  User.on('login', onLogin);
143
237
  User.on('logout', onLogout);
144
- if (user === undefined) {
145
- user = (await User.current()) ?? undefined;
238
+ if ($user === (false as unknown as undefined)) {
239
+ $user = undefined;
240
+ $user = await User.current();
146
241
  }
147
242
  });
148
243
 
@@ -166,22 +261,23 @@
166
261
  }
167
262
 
168
263
  failureMessage = undefined;
169
- changing = true;
264
+ loading = true;
170
265
 
171
266
  // Get the current user again, in case their data has changed.
172
- user = (await User.current()) ?? undefined;
267
+ $user = await User.current();
173
268
 
174
- if (user == null) {
269
+ if ($user == null) {
175
270
  failureMessage = 'You must be logged in.';
176
- changing = false;
271
+ loading = false;
177
272
  return;
178
273
  }
179
274
 
180
275
  try {
181
276
  // Change the user's password.
182
- const data = await user.$changePassword({
277
+ const data = await $user.$changePassword({
183
278
  currentPassword,
184
279
  newPassword,
280
+ revokeCurrentTokens,
185
281
  });
186
282
 
187
283
  if (!data.result) {
@@ -192,7 +288,7 @@
192
288
  } catch (e: any) {
193
289
  failureMessage = e?.message;
194
290
  }
195
- changing = false;
291
+ loading = false;
196
292
  }
197
293
  </script>
198
294