@lukso/up-connector 0.4.0-dev.a8c9315

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 (109) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +280 -0
  3. package/dist/account-modal.cjs +9 -0
  4. package/dist/account-modal.cjs.map +1 -0
  5. package/dist/account-modal.d.cts +16 -0
  6. package/dist/account-modal.d.ts +16 -0
  7. package/dist/account-modal.js +9 -0
  8. package/dist/account-modal.js.map +1 -0
  9. package/dist/auto-setup.cjs +17 -0
  10. package/dist/auto-setup.cjs.map +1 -0
  11. package/dist/auto-setup.d.cts +123 -0
  12. package/dist/auto-setup.d.ts +123 -0
  13. package/dist/auto-setup.js +17 -0
  14. package/dist/auto-setup.js.map +1 -0
  15. package/dist/avatar-CmUCtW_w.d.cts +205 -0
  16. package/dist/avatar-CmUCtW_w.d.ts +205 -0
  17. package/dist/avatar.cjs +12 -0
  18. package/dist/avatar.cjs.map +1 -0
  19. package/dist/avatar.d.cts +1 -0
  20. package/dist/avatar.d.ts +1 -0
  21. package/dist/avatar.js +12 -0
  22. package/dist/avatar.js.map +1 -0
  23. package/dist/backup-modal.cjs +9 -0
  24. package/dist/backup-modal.cjs.map +1 -0
  25. package/dist/backup-modal.d.cts +41 -0
  26. package/dist/backup-modal.d.ts +41 -0
  27. package/dist/backup-modal.js +9 -0
  28. package/dist/backup-modal.js.map +1 -0
  29. package/dist/chunk-3SGSPHOZ.js +595 -0
  30. package/dist/chunk-3SGSPHOZ.js.map +1 -0
  31. package/dist/chunk-6AYZOIFY.js +181 -0
  32. package/dist/chunk-6AYZOIFY.js.map +1 -0
  33. package/dist/chunk-6N35TCFT.js +852 -0
  34. package/dist/chunk-6N35TCFT.js.map +1 -0
  35. package/dist/chunk-7ETKG6KR.cjs +387 -0
  36. package/dist/chunk-7ETKG6KR.cjs.map +1 -0
  37. package/dist/chunk-EUXUH3YW.js +15 -0
  38. package/dist/chunk-EUXUH3YW.js.map +1 -0
  39. package/dist/chunk-GFVUWAG4.cjs +158 -0
  40. package/dist/chunk-GFVUWAG4.cjs.map +1 -0
  41. package/dist/chunk-IAKQFHFD.cjs +595 -0
  42. package/dist/chunk-IAKQFHFD.cjs.map +1 -0
  43. package/dist/chunk-MH7MP7XK.cjs +181 -0
  44. package/dist/chunk-MH7MP7XK.cjs.map +1 -0
  45. package/dist/chunk-NWCNJSG3.js +387 -0
  46. package/dist/chunk-NWCNJSG3.js.map +1 -0
  47. package/dist/chunk-NXU2DQAV.js +1128 -0
  48. package/dist/chunk-NXU2DQAV.js.map +1 -0
  49. package/dist/chunk-ORJK2YGG.cjs +852 -0
  50. package/dist/chunk-ORJK2YGG.cjs.map +1 -0
  51. package/dist/chunk-RFA6SEIS.cjs +1128 -0
  52. package/dist/chunk-RFA6SEIS.cjs.map +1 -0
  53. package/dist/chunk-XGIT7YUY.js +31 -0
  54. package/dist/chunk-XGIT7YUY.js.map +1 -0
  55. package/dist/chunk-XOKG3KIL.cjs +31 -0
  56. package/dist/chunk-XOKG3KIL.cjs.map +1 -0
  57. package/dist/chunk-YIWSPI4I.js +158 -0
  58. package/dist/chunk-YIWSPI4I.js.map +1 -0
  59. package/dist/chunk-ZBDE64SD.cjs +15 -0
  60. package/dist/chunk-ZBDE64SD.cjs.map +1 -0
  61. package/dist/connect-modal/index.cjs +20 -0
  62. package/dist/connect-modal/index.cjs.map +1 -0
  63. package/dist/connect-modal/index.d.cts +9 -0
  64. package/dist/connect-modal/index.d.ts +9 -0
  65. package/dist/connect-modal/index.js +20 -0
  66. package/dist/connect-modal/index.js.map +1 -0
  67. package/dist/index-D2orHGFi.d.cts +8 -0
  68. package/dist/index-D2orHGFi.d.ts +8 -0
  69. package/dist/index.cjs +793 -0
  70. package/dist/index.cjs.map +1 -0
  71. package/dist/index.d.cts +189 -0
  72. package/dist/index.d.ts +189 -0
  73. package/dist/index.js +793 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/restore-modal.cjs +9 -0
  76. package/dist/restore-modal.cjs.map +1 -0
  77. package/dist/restore-modal.d.cts +68 -0
  78. package/dist/restore-modal.d.ts +68 -0
  79. package/dist/restore-modal.js +9 -0
  80. package/dist/restore-modal.js.map +1 -0
  81. package/dist/wagmi-CVuDs_0h.d.cts +386 -0
  82. package/dist/wagmi-CVuDs_0h.d.ts +386 -0
  83. package/package.json +158 -0
  84. package/src/account-modal.ts +142 -0
  85. package/src/auto-setup.ts +362 -0
  86. package/src/avatar.ts +1135 -0
  87. package/src/backup-modal.ts +439 -0
  88. package/src/connect-modal/components/connection-view.ts +398 -0
  89. package/src/connect-modal/components/eoa-connection-view.ts +408 -0
  90. package/src/connect-modal/components/qr-code-view.ts +71 -0
  91. package/src/connect-modal/connect-modal.base.ts +18 -0
  92. package/src/connect-modal/connect-modal.config.ts +27 -0
  93. package/src/connect-modal/connect-modal.templates.ts +21 -0
  94. package/src/connect-modal/connect-modal.ts +270 -0
  95. package/src/connect-modal/connect-modal.types.ts +104 -0
  96. package/src/connect-modal/images/up-cube-glass.png +0 -0
  97. package/src/connect-modal/index.ts +23 -0
  98. package/src/connect-modal/services/wagmi.ts +266 -0
  99. package/src/connect-modal/styles/styles.css +1 -0
  100. package/src/connect-modal/utils/walletConnectDeepLinkUrl.ts +43 -0
  101. package/src/connector.ts +544 -0
  102. package/src/index.ts +62 -0
  103. package/src/popup-instance.ts +537 -0
  104. package/src/restore-modal.ts +702 -0
  105. package/src/styles/index.ts +28 -0
  106. package/src/styles/styles.css +1 -0
  107. package/src/types/css-raw.d.ts +4 -0
  108. package/src/types/images.d.ts +4 -0
  109. package/src/types.ts +168 -0
@@ -0,0 +1,387 @@
1
+ import {
2
+ CoreLitElement
3
+ } from "./chunk-XGIT7YUY.js";
4
+ import {
5
+ __decorateClass
6
+ } from "./chunk-EUXUH3YW.js";
7
+
8
+ // src/backup-modal.ts
9
+ import { downloadBackup } from "@lukso/passkey-auth";
10
+ import { html, nothing } from "lit";
11
+ import { customElement, property, state } from "lit/decorators.js";
12
+ import zxcvbn from "zxcvbn";
13
+ import "@lukso/web-components/dist/components/lukso-modal";
14
+ import "@lukso/web-components/dist/components/lukso-button";
15
+ import "@lukso/web-components/dist/components/lukso-input";
16
+ var BackupModal = class extends CoreLitElement {
17
+ constructor() {
18
+ super(...arguments);
19
+ this.open = false;
20
+ this.theme = "auto";
21
+ this.currentStep = 1 /* CHOICE */;
22
+ this.useEncryption = true;
23
+ this.password = "";
24
+ this.passwordConfirm = "";
25
+ this.passwordErrors = [];
26
+ this.isCreatingBackup = false;
27
+ this.generatedBackup = null;
28
+ }
29
+ /**
30
+ * Public method for parent to set backup result
31
+ * Called after parent handles the 'create' event
32
+ */
33
+ setBackupResult(backupFile, options) {
34
+ this.isCreatingBackup = false;
35
+ if (options?.error) {
36
+ this.passwordErrors = [options.error];
37
+ this.generatedBackup = null;
38
+ } else if (backupFile) {
39
+ this.generatedBackup = backupFile;
40
+ this.currentStep = 3 /* DOWNLOAD */;
41
+ }
42
+ }
43
+ render() {
44
+ return html`
45
+ <lukso-modal
46
+ ?is-open=${this.open}
47
+ size="medium"
48
+ @on-backdrop-click=${this.close}
49
+ >
50
+ <div class="p-6">
51
+ <!-- Header -->
52
+ <h2 class="m-0 mb-6 text-neutral-20 dark:text-white heading-inter-21-semi-bold">
53
+ ${this.getStepTitle()}
54
+ </h2>
55
+
56
+ <!-- Step content -->
57
+ ${this.renderStep()}
58
+ </div>
59
+ </lukso-modal>
60
+ `;
61
+ }
62
+ renderStep() {
63
+ switch (this.currentStep) {
64
+ case 1 /* CHOICE */:
65
+ return this.renderChoiceStep();
66
+ case 2 /* PASSWORD */:
67
+ return this.renderPasswordStep();
68
+ case 3 /* DOWNLOAD */:
69
+ return this.renderDownloadStep();
70
+ default:
71
+ return nothing;
72
+ }
73
+ }
74
+ renderChoiceStep() {
75
+ return html`
76
+ <div class="flex flex-col gap-3 mb-6">
77
+ <!-- Encrypted option (recommended) -->
78
+ <div
79
+ class="border-2 border-neutral-90 dark:border-neutral-70 rounded-lg p-4 cursor-pointer transition-all hover:border-neutral-60 dark:hover:border-neutral-60"
80
+ @click=${() => this.selectBackupType(true)}
81
+ >
82
+ <div class="flex items-center gap-3 mb-2">
83
+ <span class="text-neutral-10 dark:text-white heading-inter-16-semi-bold flex-1">
84
+ Encrypt backup file
85
+ </span>
86
+ <span class="text-xs text-neutral-50 dark:text-neutral-60 uppercase tracking-wide">
87
+ Recommended
88
+ </span>
89
+ </div>
90
+ <p class="m-0 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular">
91
+ Uses password-based encryption to protect the secrets in this file.
92
+ </p>
93
+ </div>
94
+
95
+ <!-- Unencrypted option -->
96
+ <div
97
+ class="border-2 border-neutral-90 dark:border-neutral-70 rounded-lg p-4 cursor-pointer transition-all hover:border-neutral-60 dark:hover:border-neutral-60"
98
+ @click=${() => this.selectBackupType(false)}
99
+ >
100
+ <div class="flex items-center gap-3 mb-2">
101
+ <span class="text-neutral-10 dark:text-white heading-inter-16-semi-bold flex-1">
102
+ Plain text backup
103
+ </span>
104
+ <span class="text-xs text-neutral-50 dark:text-neutral-60 uppercase tracking-wide">
105
+ For development only
106
+ </span>
107
+ </div>
108
+ <p class="m-0 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular">
109
+ Secrets will be stored in plain text.
110
+ </p>
111
+ </div>
112
+ </div>
113
+
114
+ <div class="flex justify-between gap-3">
115
+ <lukso-button variant="text" @click=${this.close}>
116
+ Cancel
117
+ </lukso-button>
118
+ </div>
119
+ `;
120
+ }
121
+ renderPasswordStep() {
122
+ const passwordStrength = this.password ? this.calculatePasswordStrength() : null;
123
+ const passwordsMatch = this.password && this.passwordConfirm && this.password === this.passwordConfirm;
124
+ const canProceed = this.password && this.passwordConfirm && passwordsMatch;
125
+ return html`
126
+ <p class="mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-16-regular">
127
+ Choose a strong password to encrypt your backup. You'll need this password to restore your wallet.
128
+ </p>
129
+
130
+ <div class="space-y-4">
131
+ <lukso-input
132
+ type="password"
133
+ label="Password"
134
+ placeholder="Enter a strong password"
135
+ .value=${this.password}
136
+ @on-input=${(e) => this.password = e.detail.value}
137
+ is-full-width
138
+ autofocus
139
+ ></lukso-input>
140
+
141
+ ${this.passwordErrors.map(
142
+ (error) => html`
143
+ <div class="mt-1 text-red-55 paragraph-inter-13-regular">${error}</div>
144
+ `
145
+ )}
146
+
147
+ ${passwordStrength ? html`
148
+ <div class="mt-3">
149
+ <div class="flex items-center justify-between mb-1">
150
+ <span class="paragraph-inter-13-regular text-neutral-40">Password strength:</span>
151
+ <span class="paragraph-inter-13-semi-bold ${passwordStrength.color}">${passwordStrength.label}</span>
152
+ </div>
153
+ <div class="h-1.5 bg-neutral-90 dark:bg-neutral-70 rounded-full overflow-hidden">
154
+ <div
155
+ class="h-full ${passwordStrength.bgColor} transition-all duration-300"
156
+ style="width: ${passwordStrength.width}%"
157
+ ></div>
158
+ </div>
159
+ <p class="mt-1 mb-0 text-neutral-40 paragraph-inter-12-regular">
160
+ Time to crack: ${passwordStrength.crackTime}
161
+ </p>
162
+ ${passwordStrength.feedback ? html`
163
+ <p class="mt-2 mb-0 text-neutral-40 paragraph-inter-12-regular">${passwordStrength.feedback}</p>
164
+ ` : nothing}
165
+ </div>
166
+ ` : nothing}
167
+
168
+ <lukso-input
169
+ type="password"
170
+ label="Confirm Password"
171
+ placeholder="Re-enter your password"
172
+ .value=${this.passwordConfirm}
173
+ @on-input=${(e) => this.passwordConfirm = e.detail.value}
174
+ is-full-width
175
+ ></lukso-input>
176
+
177
+ ${this.passwordConfirm ? html`
178
+ <div class="flex items-center justify-between mt-2">
179
+ <span class="paragraph-inter-13-regular text-neutral-40">Passwords match:</span>
180
+ <span class="paragraph-inter-13-semi-bold ${passwordsMatch ? "text-green-54" : "text-red-55"}">
181
+ ${passwordsMatch ? "Yes" : "No"}
182
+ </span>
183
+ </div>
184
+ ` : nothing}
185
+ </div>
186
+
187
+ <div class="flex justify-between gap-3 mt-6">
188
+ <div class="flex gap-3">
189
+ <lukso-button variant="text" @click=${this.close}>
190
+ Cancel
191
+ </lukso-button>
192
+ <lukso-button variant="secondary" @click=${this.goBack}>
193
+ Back
194
+ </lukso-button>
195
+ </div>
196
+ <lukso-button
197
+ variant="primary"
198
+ ?disabled=${!canProceed || this.isCreatingBackup}
199
+ ?is-loading=${this.isCreatingBackup}
200
+ @click=${this.createBackup}
201
+ >
202
+ Create Backup
203
+ </lukso-button>
204
+ </div>
205
+ `;
206
+ }
207
+ renderDownloadStep() {
208
+ return html`
209
+ <p class="mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-16-regular">
210
+ Your backup has been created${this.useEncryption ? " and encrypted" : ""}. Download it and keep it in a safe place.
211
+ </p>
212
+
213
+ ${!this.useEncryption ? html`
214
+ <p class="mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular">
215
+ This unencrypted backup is intended for development purposes. Use it when creating dapps that need access to the profile for testing.
216
+ </p>
217
+ ` : nothing}
218
+
219
+ <div class="flex justify-end gap-3">
220
+ <lukso-button variant="primary" @click=${this.handleDownload}>
221
+ Download Backup
222
+ </lukso-button>
223
+ </div>
224
+ `;
225
+ }
226
+ getStepTitle() {
227
+ switch (this.currentStep) {
228
+ case 1 /* CHOICE */:
229
+ return "Backup Wallet";
230
+ case 2 /* PASSWORD */:
231
+ return "Set Password";
232
+ case 3 /* DOWNLOAD */:
233
+ return "Download Backup";
234
+ default:
235
+ return "Backup Wallet";
236
+ }
237
+ }
238
+ selectBackupType(encrypted) {
239
+ this.useEncryption = encrypted;
240
+ if (encrypted) {
241
+ this.currentStep = 2 /* PASSWORD */;
242
+ } else {
243
+ this.createBackup();
244
+ }
245
+ }
246
+ async createBackup() {
247
+ this.isCreatingBackup = true;
248
+ this.passwordErrors = [];
249
+ const createEvent = new CustomEvent("create", {
250
+ detail: {
251
+ password: this.useEncryption ? this.password : void 0,
252
+ encrypted: this.useEncryption
253
+ },
254
+ bubbles: true,
255
+ composed: true,
256
+ cancelable: true
257
+ });
258
+ this.dispatchEvent(createEvent);
259
+ if (!createEvent.defaultPrevented) {
260
+ this.passwordErrors = [
261
+ 'No backup handler configured. Please handle the "create" event.'
262
+ ];
263
+ this.isCreatingBackup = false;
264
+ }
265
+ }
266
+ handleDownload() {
267
+ if (this.generatedBackup) {
268
+ downloadBackup(this.generatedBackup);
269
+ this.dispatchEvent(
270
+ new CustomEvent("download", {
271
+ detail: this.generatedBackup,
272
+ bubbles: true,
273
+ composed: true
274
+ })
275
+ );
276
+ setTimeout(() => {
277
+ this.close();
278
+ }, 100);
279
+ }
280
+ }
281
+ goBack() {
282
+ if (this.currentStep === 2 /* PASSWORD */) {
283
+ this.currentStep = 1 /* CHOICE */;
284
+ this.password = "";
285
+ this.passwordConfirm = "";
286
+ this.passwordErrors = [];
287
+ }
288
+ }
289
+ close() {
290
+ this.open = false;
291
+ this.dispatchEvent(
292
+ new CustomEvent("close", { bubbles: true, composed: true })
293
+ );
294
+ setTimeout(() => {
295
+ this.currentStep = 1 /* CHOICE */;
296
+ this.useEncryption = true;
297
+ this.password = "";
298
+ this.passwordConfirm = "";
299
+ this.passwordErrors = [];
300
+ this.isCreatingBackup = false;
301
+ this.generatedBackup = null;
302
+ }, 300);
303
+ }
304
+ calculatePasswordStrength() {
305
+ const result = zxcvbn(this.password);
306
+ const strengthMap = [
307
+ {
308
+ level: "very-weak",
309
+ label: "Very Weak",
310
+ color: "text-red-55",
311
+ bgColor: "bg-red-55",
312
+ width: 20
313
+ },
314
+ {
315
+ level: "weak",
316
+ label: "Weak",
317
+ color: "text-red-65",
318
+ bgColor: "bg-red-65",
319
+ width: 40
320
+ },
321
+ {
322
+ level: "fair",
323
+ label: "Fair",
324
+ color: "text-yellow-55",
325
+ bgColor: "bg-yellow-55",
326
+ width: 60
327
+ },
328
+ {
329
+ level: "good",
330
+ label: "Good",
331
+ color: "text-green-54",
332
+ bgColor: "bg-green-54",
333
+ width: 80
334
+ },
335
+ {
336
+ level: "strong",
337
+ label: "Strong",
338
+ color: "text-green-45",
339
+ bgColor: "bg-green-45",
340
+ width: 100
341
+ }
342
+ ];
343
+ const strength = strengthMap[result.score];
344
+ const feedback = result.feedback.suggestions.join(" ") || result.feedback.warning || "";
345
+ const crackTime = result.crack_times_display.offline_slow_hashing_1e4_per_second;
346
+ return {
347
+ ...strength,
348
+ feedback,
349
+ crackTime
350
+ };
351
+ }
352
+ };
353
+ __decorateClass([
354
+ property({ type: Boolean, reflect: true })
355
+ ], BackupModal.prototype, "open", 2);
356
+ __decorateClass([
357
+ property({ type: String })
358
+ ], BackupModal.prototype, "theme", 2);
359
+ __decorateClass([
360
+ state()
361
+ ], BackupModal.prototype, "currentStep", 2);
362
+ __decorateClass([
363
+ state()
364
+ ], BackupModal.prototype, "useEncryption", 2);
365
+ __decorateClass([
366
+ state()
367
+ ], BackupModal.prototype, "password", 2);
368
+ __decorateClass([
369
+ state()
370
+ ], BackupModal.prototype, "passwordConfirm", 2);
371
+ __decorateClass([
372
+ state()
373
+ ], BackupModal.prototype, "passwordErrors", 2);
374
+ __decorateClass([
375
+ state()
376
+ ], BackupModal.prototype, "isCreatingBackup", 2);
377
+ __decorateClass([
378
+ state()
379
+ ], BackupModal.prototype, "generatedBackup", 2);
380
+ BackupModal = __decorateClass([
381
+ customElement("backup-modal")
382
+ ], BackupModal);
383
+
384
+ export {
385
+ BackupModal
386
+ };
387
+ //# sourceMappingURL=chunk-NWCNJSG3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/backup-modal.ts"],"sourcesContent":["/**\n * Backup Modal - Lit Component\n *\n * Framework-agnostic backup modal for wallet data export.\n * Uses lukso-modal from @lukso/web-components for consistent UI.\n */\n\nimport type { BackupFile } from '@lukso/passkey-auth'\nimport { downloadBackup } from '@lukso/passkey-auth'\nimport { html, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport zxcvbn from 'zxcvbn'\nimport { CoreLitElement } from './styles'\n\n// Import lukso web components\nimport '@lukso/web-components/dist/components/lukso-modal'\nimport '@lukso/web-components/dist/components/lukso-button'\nimport '@lukso/web-components/dist/components/lukso-input'\n\nenum Step {\n CHOICE = 1,\n PASSWORD = 2,\n DOWNLOAD = 3,\n}\n\ninterface PasswordStrength {\n level: string\n label: string\n color: string\n bgColor: string\n width: number\n feedback: string\n crackTime: string | number\n}\n\n@customElement('backup-modal')\nexport class BackupModal extends CoreLitElement {\n // Public properties\n @property({ type: Boolean, reflect: true }) open = false\n @property({ type: String }) theme: 'light' | 'dark' | 'auto' = 'auto'\n\n // Private state - wizard flow\n @state() private currentStep: Step = Step.CHOICE\n @state() private useEncryption = true\n @state() private password = ''\n @state() private passwordConfirm = ''\n @state() private passwordErrors: string[] = []\n @state() private isCreatingBackup = false\n @state() private generatedBackup: BackupFile | null = null\n\n /**\n * Public method for parent to set backup result\n * Called after parent handles the 'create' event\n */\n public setBackupResult(\n backupFile: BackupFile | null,\n options?: {\n error?: string\n }\n ) {\n this.isCreatingBackup = false\n\n if (options?.error) {\n this.passwordErrors = [options.error]\n this.generatedBackup = null\n } else if (backupFile) {\n this.generatedBackup = backupFile\n this.currentStep = Step.DOWNLOAD\n }\n }\n\n render() {\n return html`\n <lukso-modal\n ?is-open=${this.open}\n size=\"medium\"\n @on-backdrop-click=${this.close}\n >\n <div class=\"p-6\">\n <!-- Header -->\n <h2 class=\"m-0 mb-6 text-neutral-20 dark:text-white heading-inter-21-semi-bold\">\n ${this.getStepTitle()}\n </h2>\n\n <!-- Step content -->\n ${this.renderStep()}\n </div>\n </lukso-modal>\n `\n }\n\n private renderStep() {\n switch (this.currentStep) {\n case Step.CHOICE:\n return this.renderChoiceStep()\n case Step.PASSWORD:\n return this.renderPasswordStep()\n case Step.DOWNLOAD:\n return this.renderDownloadStep()\n default:\n return nothing\n }\n }\n\n private renderChoiceStep() {\n return html`\n <div class=\"flex flex-col gap-3 mb-6\">\n <!-- Encrypted option (recommended) -->\n <div\n class=\"border-2 border-neutral-90 dark:border-neutral-70 rounded-lg p-4 cursor-pointer transition-all hover:border-neutral-60 dark:hover:border-neutral-60\"\n @click=${() => this.selectBackupType(true)}\n >\n <div class=\"flex items-center gap-3 mb-2\">\n <span class=\"text-neutral-10 dark:text-white heading-inter-16-semi-bold flex-1\">\n Encrypt backup file\n </span>\n <span class=\"text-xs text-neutral-50 dark:text-neutral-60 uppercase tracking-wide\">\n Recommended\n </span>\n </div>\n <p class=\"m-0 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular\">\n Uses password-based encryption to protect the secrets in this file.\n </p>\n </div>\n\n <!-- Unencrypted option -->\n <div\n class=\"border-2 border-neutral-90 dark:border-neutral-70 rounded-lg p-4 cursor-pointer transition-all hover:border-neutral-60 dark:hover:border-neutral-60\"\n @click=${() => this.selectBackupType(false)}\n >\n <div class=\"flex items-center gap-3 mb-2\">\n <span class=\"text-neutral-10 dark:text-white heading-inter-16-semi-bold flex-1\">\n Plain text backup\n </span>\n <span class=\"text-xs text-neutral-50 dark:text-neutral-60 uppercase tracking-wide\">\n For development only\n </span>\n </div>\n <p class=\"m-0 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular\">\n Secrets will be stored in plain text.\n </p>\n </div>\n </div>\n\n <div class=\"flex justify-between gap-3\">\n <lukso-button variant=\"text\" @click=${this.close}>\n Cancel\n </lukso-button>\n </div>\n `\n }\n\n private renderPasswordStep() {\n const passwordStrength = this.password\n ? this.calculatePasswordStrength()\n : null\n const passwordsMatch =\n this.password &&\n this.passwordConfirm &&\n this.password === this.passwordConfirm\n const canProceed = this.password && this.passwordConfirm && passwordsMatch\n\n return html`\n <p class=\"mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-16-regular\">\n Choose a strong password to encrypt your backup. You'll need this password to restore your wallet.\n </p>\n\n <div class=\"space-y-4\">\n <lukso-input\n type=\"password\"\n label=\"Password\"\n placeholder=\"Enter a strong password\"\n .value=${this.password}\n @on-input=${(e: CustomEvent) => (this.password = e.detail.value)}\n is-full-width\n autofocus\n ></lukso-input>\n\n ${this.passwordErrors.map(\n (error) => html`\n <div class=\"mt-1 text-red-55 paragraph-inter-13-regular\">${error}</div>\n `\n )}\n\n ${\n passwordStrength\n ? html`\n <div class=\"mt-3\">\n <div class=\"flex items-center justify-between mb-1\">\n <span class=\"paragraph-inter-13-regular text-neutral-40\">Password strength:</span>\n <span class=\"paragraph-inter-13-semi-bold ${passwordStrength.color}\">${passwordStrength.label}</span>\n </div>\n <div class=\"h-1.5 bg-neutral-90 dark:bg-neutral-70 rounded-full overflow-hidden\">\n <div\n class=\"h-full ${passwordStrength.bgColor} transition-all duration-300\"\n style=\"width: ${passwordStrength.width}%\"\n ></div>\n </div>\n <p class=\"mt-1 mb-0 text-neutral-40 paragraph-inter-12-regular\">\n Time to crack: ${passwordStrength.crackTime}\n </p>\n ${\n passwordStrength.feedback\n ? html`\n <p class=\"mt-2 mb-0 text-neutral-40 paragraph-inter-12-regular\">${passwordStrength.feedback}</p>\n `\n : nothing\n }\n </div>\n `\n : nothing\n }\n\n <lukso-input\n type=\"password\"\n label=\"Confirm Password\"\n placeholder=\"Re-enter your password\"\n .value=${this.passwordConfirm}\n @on-input=${(e: CustomEvent) => (this.passwordConfirm = e.detail.value)}\n is-full-width\n ></lukso-input>\n\n ${\n this.passwordConfirm\n ? html`\n <div class=\"flex items-center justify-between mt-2\">\n <span class=\"paragraph-inter-13-regular text-neutral-40\">Passwords match:</span>\n <span class=\"paragraph-inter-13-semi-bold ${passwordsMatch ? 'text-green-54' : 'text-red-55'}\">\n ${passwordsMatch ? 'Yes' : 'No'}\n </span>\n </div>\n `\n : nothing\n }\n </div>\n\n <div class=\"flex justify-between gap-3 mt-6\">\n <div class=\"flex gap-3\">\n <lukso-button variant=\"text\" @click=${this.close}>\n Cancel\n </lukso-button>\n <lukso-button variant=\"secondary\" @click=${this.goBack}>\n Back\n </lukso-button>\n </div>\n <lukso-button\n variant=\"primary\"\n ?disabled=${!canProceed || this.isCreatingBackup}\n ?is-loading=${this.isCreatingBackup}\n @click=${this.createBackup}\n >\n Create Backup\n </lukso-button>\n </div>\n `\n }\n\n private renderDownloadStep() {\n return html`\n <p class=\"mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-16-regular\">\n Your backup has been created${this.useEncryption ? ' and encrypted' : ''}. Download it and keep it in a safe place.\n </p>\n\n ${\n !this.useEncryption\n ? html`\n <p class=\"mb-6 text-neutral-40 dark:text-neutral-50 paragraph-inter-14-regular\">\n This unencrypted backup is intended for development purposes. Use it when creating dapps that need access to the profile for testing.\n </p>\n `\n : nothing\n }\n\n <div class=\"flex justify-end gap-3\">\n <lukso-button variant=\"primary\" @click=${this.handleDownload}>\n Download Backup\n </lukso-button>\n </div>\n `\n }\n\n private getStepTitle(): string {\n switch (this.currentStep) {\n case Step.CHOICE:\n return 'Backup Wallet'\n case Step.PASSWORD:\n return 'Set Password'\n case Step.DOWNLOAD:\n return 'Download Backup'\n default:\n return 'Backup Wallet'\n }\n }\n\n private selectBackupType(encrypted: boolean) {\n this.useEncryption = encrypted\n if (encrypted) {\n this.currentStep = Step.PASSWORD\n } else {\n // Unencrypted backup - create immediately\n this.createBackup()\n }\n }\n\n private async createBackup() {\n this.isCreatingBackup = true\n this.passwordErrors = []\n\n // Emit create event with password (if encrypted)\n // Parent should handle backup creation\n const createEvent = new CustomEvent('create', {\n detail: {\n password: this.useEncryption ? this.password : undefined,\n encrypted: this.useEncryption,\n },\n bubbles: true,\n composed: true,\n cancelable: true,\n })\n\n this.dispatchEvent(createEvent)\n\n // If parent didn't prevent default, show error\n if (!createEvent.defaultPrevented) {\n this.passwordErrors = [\n 'No backup handler configured. Please handle the \"create\" event.',\n ]\n this.isCreatingBackup = false\n }\n // Otherwise, parent will call setBackupResult()\n }\n\n private handleDownload() {\n if (this.generatedBackup) {\n downloadBackup(this.generatedBackup)\n\n // Dispatch download event\n this.dispatchEvent(\n new CustomEvent('download', {\n detail: this.generatedBackup,\n bubbles: true,\n composed: true,\n })\n )\n\n // Close modal after download\n setTimeout(() => {\n this.close()\n }, 100)\n }\n }\n\n private goBack() {\n if (this.currentStep === Step.PASSWORD) {\n this.currentStep = Step.CHOICE\n this.password = ''\n this.passwordConfirm = ''\n this.passwordErrors = []\n }\n }\n\n private close() {\n this.open = false\n this.dispatchEvent(\n new CustomEvent('close', { bubbles: true, composed: true })\n )\n\n // Reset state after animation\n setTimeout(() => {\n this.currentStep = Step.CHOICE\n this.useEncryption = true\n this.password = ''\n this.passwordConfirm = ''\n this.passwordErrors = []\n this.isCreatingBackup = false\n this.generatedBackup = null\n }, 300)\n }\n\n private calculatePasswordStrength(): PasswordStrength {\n const result = zxcvbn(this.password)\n\n const strengthMap = [\n {\n level: 'very-weak',\n label: 'Very Weak',\n color: 'text-red-55',\n bgColor: 'bg-red-55',\n width: 20,\n },\n {\n level: 'weak',\n label: 'Weak',\n color: 'text-red-65',\n bgColor: 'bg-red-65',\n width: 40,\n },\n {\n level: 'fair',\n label: 'Fair',\n color: 'text-yellow-55',\n bgColor: 'bg-yellow-55',\n width: 60,\n },\n {\n level: 'good',\n label: 'Good',\n color: 'text-green-54',\n bgColor: 'bg-green-54',\n width: 80,\n },\n {\n level: 'strong',\n label: 'Strong',\n color: 'text-green-45',\n bgColor: 'bg-green-45',\n width: 100,\n },\n ]\n\n const strength = strengthMap[result.score]\n const feedback =\n result.feedback.suggestions.join(' ') || result.feedback.warning || ''\n const crackTime =\n result.crack_times_display.offline_slow_hashing_1e4_per_second\n\n return {\n ...strength,\n feedback,\n crackTime,\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'backup-modal': BackupModal\n }\n}\n"],"mappings":"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","names":[]}