hd-wallet-ui 1.6.0 → 2.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hd-wallet-ui",
3
- "version": "1.6.0",
3
+ "version": "2.0.1",
4
4
  "description": "HD Wallet modal UI — login, keys, identity, trust map, and security bond. Attach to any button in your app.",
5
5
  "type": "module",
6
6
  "main": "src/app.js",
@@ -40,7 +40,7 @@
40
40
  "buffer": "^6.0.3",
41
41
  "flatbuffers": "^25.9.23",
42
42
  "flatc-wasm": "^26.1.15",
43
- "hd-wallet-wasm": "^1.6.0",
43
+ "hd-wallet-wasm": "^2.0.1",
44
44
  "qrcode": "^1.5.3",
45
45
  "spacedatastandards.org": "^23.3.3-0.3.4",
46
46
  "vcard-cryptoperson": "^1.1.11"
package/src/app.js CHANGED
@@ -3498,11 +3498,49 @@ function verifyVCardSignature(vcardText) {
3498
3498
  }
3499
3499
  }
3500
3500
 
3501
+ function hideImportedVcardPreview() {
3502
+ state.importedVcardPreview = null;
3503
+ const resultEl = $('vcf-import-result');
3504
+ const fieldsEl = $('vcf-import-fields');
3505
+ const sigStatus = $('vcf-import-sig-status');
3506
+ if (fieldsEl) fieldsEl.innerHTML = '';
3507
+ if (sigStatus) {
3508
+ sigStatus.innerHTML = '';
3509
+ sigStatus.style.display = 'none';
3510
+ }
3511
+ if (resultEl) resultEl.style.display = 'none';
3512
+ }
3513
+
3514
+ function applyImportedVcardPreview() {
3515
+ const imported = state.importedVcardPreview;
3516
+ if (!imported) return;
3517
+
3518
+ for (const id of vcardFieldIds) {
3519
+ const el = $(id);
3520
+ if (el) el.value = imported.formValues[id] || '';
3521
+ }
3522
+
3523
+ state.vcardPhoto = imported.photo || null;
3524
+ if (imported.photo) {
3525
+ showPhotoPreview(imported.photo);
3526
+ } else {
3527
+ resetPhotoPreview();
3528
+ }
3529
+
3530
+ saveVcardIdentity();
3531
+ updateIdentityCardSummary();
3532
+ setPhotoActionsVisible(false);
3533
+ $('vcard-edit-view').style.display = 'none';
3534
+ $('vcard-form-view').style.display = '';
3535
+ hideImportedVcardPreview();
3536
+ }
3537
+
3501
3538
  function parseAndDisplayVCF(vcfText) {
3502
3539
  const lines = vcfText.replace(/\r?\n /g, '').split(/\r?\n/);
3503
3540
  const fields = {};
3504
3541
  const keys = [];
3505
3542
  let photo = null;
3543
+ const formValues = Object.fromEntries(vcardFieldIds.map(id => [id, '']));
3506
3544
 
3507
3545
  for (const line of lines) {
3508
3546
  const colonIdx = line.indexOf(':');
@@ -3512,19 +3550,38 @@ function parseAndDisplayVCF(vcfText) {
3512
3550
 
3513
3551
  if (prop === 'FN') {
3514
3552
  fields.name = value;
3515
- } else if (prop.startsWith('N')) {
3553
+ } else if (prop === 'N') {
3554
+ const parts = value.split(';');
3555
+ formValues['vcard-lastname'] = parts[0] || '';
3556
+ formValues['vcard-firstname'] = parts[1] || '';
3557
+ formValues['vcard-middlename'] = parts[2] || '';
3558
+ formValues['vcard-prefix'] = parts[3] || '';
3559
+ formValues['vcard-suffix'] = parts[4] || '';
3516
3560
  if (!fields.name) {
3517
- const parts = value.split(';');
3518
3561
  fields.name = [parts[3], parts[1], parts[2], parts[0], parts[4]].filter(Boolean).join(' ');
3519
3562
  }
3563
+ } else if (prop === 'NICKNAME') {
3564
+ formValues['vcard-nickname'] = value;
3520
3565
  } else if (prop.startsWith('EMAIL')) {
3566
+ formValues['vcard-email'] ||= value;
3521
3567
  fields.email = value;
3522
3568
  } else if (prop.startsWith('ORG')) {
3523
- fields.org = value.replace(/;/g, ', ');
3569
+ const normalized = value.replace(/;/g, ', ');
3570
+ formValues['vcard-org'] ||= normalized;
3571
+ fields.org = normalized;
3524
3572
  } else if (prop.startsWith('TITLE')) {
3573
+ formValues['vcard-title'] ||= value;
3525
3574
  fields.title = value;
3526
3575
  } else if (prop.startsWith('TEL')) {
3576
+ formValues['vcard-phone'] ||= value;
3527
3577
  fields.tel = value;
3578
+ } else if (prop.startsWith('ADR')) {
3579
+ const parts = value.split(';');
3580
+ formValues['vcard-street'] ||= [parts[1], parts[2]].filter(Boolean).join(' ');
3581
+ formValues['vcard-city'] ||= parts[3] || '';
3582
+ formValues['vcard-region'] ||= parts[4] || '';
3583
+ formValues['vcard-postal'] ||= parts[5] || '';
3584
+ formValues['vcard-country'] ||= parts[6] || '';
3528
3585
  } else if (prop.startsWith('PHOTO')) {
3529
3586
  if (prop.includes('VALUE=URI') || value.startsWith('data:') || value.startsWith('http')) {
3530
3587
  photo = value;
@@ -3541,6 +3598,10 @@ function parseAndDisplayVCF(vcfText) {
3541
3598
  }
3542
3599
  }
3543
3600
 
3601
+ if (!formValues['vcard-firstname'] && !formValues['vcard-lastname'] && fields.name) {
3602
+ formValues['vcard-firstname'] = fields.name;
3603
+ }
3604
+
3544
3605
  const resultEl = $('vcf-import-result');
3545
3606
  const photoEl = $('vcf-import-photo');
3546
3607
  const fieldsEl = $('vcf-import-fields');
@@ -3601,6 +3662,11 @@ function parseAndDisplayVCF(vcfText) {
3601
3662
  sigStatus.style.display = 'flex';
3602
3663
  }
3603
3664
 
3665
+ state.importedVcardPreview = {
3666
+ formValues,
3667
+ photo,
3668
+ };
3669
+
3604
3670
  fieldsEl.innerHTML = html;
3605
3671
  resultEl.style.display = 'block';
3606
3672
  }
@@ -4534,6 +4600,14 @@ function setupMainAppHandlers() {
4534
4600
  e.target.value = '';
4535
4601
  });
4536
4602
 
4603
+ $('vcf-import-apply')?.addEventListener('click', () => {
4604
+ applyImportedVcardPreview();
4605
+ });
4606
+
4607
+ $('vcf-import-close')?.addEventListener('click', () => {
4608
+ hideImportedVcardPreview();
4609
+ });
4610
+
4537
4611
  // Reveal sensitive key buttons
4538
4612
  $qa('.reveal-key-btn').forEach(btn => {
4539
4613
  btn.addEventListener('click', () => {
package/src/template.js CHANGED
@@ -256,6 +256,10 @@ export function getModalHTML() {
256
256
  <div class="vcf-import-fields" id="vcf-import-fields"></div>
257
257
  </div>
258
258
  <div id="vcf-import-sig-status" class="vcard-sig-badge" style="display:none;"></div>
259
+ <div class="vcf-import-actions">
260
+ <button id="vcf-import-apply" class="glass-btn primary">Replace Identity</button>
261
+ <button id="vcf-import-close" class="glass-btn">Dismiss</button>
262
+ </div>
259
263
  </div>
260
264
  </div>
261
265
 
package/styles/main.css CHANGED
@@ -10,6 +10,13 @@
10
10
  padding: 0;
11
11
  }
12
12
 
13
+ /* Button reset — counteract host-page normalize/tachyons leaking into the widget */
14
+ button {
15
+ -webkit-appearance: none;
16
+ appearance: none;
17
+ line-height: inherit;
18
+ }
19
+
13
20
  /* Prevent dragging on headings, headers, and links */
14
21
  h1, h2, h3, h4, h5, h6,
15
22
  a, button, nav, nav * {
@@ -4937,6 +4944,13 @@ body:has(.modal.active) .nav-bar {
4937
4944
  color: rgba(255, 255, 255, 0.9) !important;
4938
4945
  }
4939
4946
 
4947
+ .vcf-import-actions {
4948
+ display: flex;
4949
+ gap: 10px;
4950
+ justify-content: flex-end;
4951
+ margin-top: 14px;
4952
+ }
4953
+
4940
4954
  /* Readonly badge */
4941
4955
  .readonly-badge {
4942
4956
  font-size: 0.6875rem;
@@ -4968,6 +4982,10 @@ body:has(.modal.active) .nav-bar {
4968
4982
  .vcard-form-row.address-row {
4969
4983
  grid-template-columns: 1fr;
4970
4984
  }
4985
+
4986
+ .vcf-import-actions {
4987
+ flex-direction: column;
4988
+ }
4971
4989
 
4972
4990
  .photo-upload-section {
4973
4991
  flex-direction: column;
@@ -5861,6 +5879,76 @@ a.chain-card:hover {
5861
5879
  display: block;
5862
5880
  }
5863
5881
 
5882
+ .x509-overview {
5883
+ display: grid;
5884
+ grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
5885
+ gap: 24px;
5886
+ padding: 32px;
5887
+ margin-bottom: 24px;
5888
+ align-items: start;
5889
+ }
5890
+
5891
+ .x509-copy {
5892
+ min-width: 0;
5893
+ }
5894
+
5895
+ .x509-eyebrow {
5896
+ display: inline-flex;
5897
+ align-items: center;
5898
+ gap: 8px;
5899
+ padding: 6px 10px;
5900
+ margin-bottom: 14px;
5901
+ border-radius: 999px;
5902
+ background: rgba(96, 165, 250, 0.12);
5903
+ color: #93c5fd;
5904
+ font-size: 0.72rem;
5905
+ font-weight: 600;
5906
+ letter-spacing: 0.08em;
5907
+ text-transform: uppercase;
5908
+ }
5909
+
5910
+ .x509-copy h3 {
5911
+ font-size: 1.35rem;
5912
+ font-weight: 600;
5913
+ line-height: 1.25;
5914
+ margin-bottom: 12px;
5915
+ }
5916
+
5917
+ .x509-copy p {
5918
+ color: var(--white-60);
5919
+ font-size: 0.95rem;
5920
+ line-height: 1.75;
5921
+ margin-bottom: 14px;
5922
+ }
5923
+
5924
+ .x509-tag-row {
5925
+ display: flex;
5926
+ flex-wrap: wrap;
5927
+ gap: 10px;
5928
+ margin-top: 18px;
5929
+ }
5930
+
5931
+ .x509-tag {
5932
+ display: inline-flex;
5933
+ align-items: center;
5934
+ padding: 7px 12px;
5935
+ border-radius: 999px;
5936
+ background: rgba(255, 255, 255, 0.06);
5937
+ border: 1px solid rgba(255, 255, 255, 0.08);
5938
+ color: var(--white-80);
5939
+ font-size: 0.78rem;
5940
+ font-family: var(--font-mono);
5941
+ }
5942
+
5943
+ .x509-flow {
5944
+ margin-bottom: 24px;
5945
+ padding: 28px 24px;
5946
+ }
5947
+
5948
+ .x509-grid {
5949
+ grid-template-columns: repeat(2, 1fr);
5950
+ }
5951
+
5864
5952
  @media (max-width: 600px) {
5865
5953
  .code-block pre {
5866
5954
  padding: 14px;
@@ -5875,6 +5963,16 @@ a.chain-card:hover {
5875
5963
  padding-left: 8px;
5876
5964
  padding-right: 8px;
5877
5965
  }
5966
+ .x509-overview {
5967
+ grid-template-columns: 1fr;
5968
+ padding: 20px;
5969
+ }
5970
+ .x509-copy h3 {
5971
+ font-size: 1.1rem;
5972
+ }
5973
+ .x509-copy p {
5974
+ font-size: 0.88rem;
5975
+ }
5878
5976
  }
5879
5977
 
5880
5978
  /* =============================================================================
package/styles/widget.css CHANGED
@@ -20,6 +20,13 @@
20
20
  padding: 0;
21
21
  }
22
22
 
23
+ /* Button reset — counteract host-page normalize/tachyons leaking into the widget */
24
+ #hd-wallet-ui-container button {
25
+ -webkit-appearance: none;
26
+ appearance: none;
27
+ line-height: inherit;
28
+ }
29
+
23
30
  /* Prevent dragging on headings, headers, and links */
24
31
  #hd-wallet-ui-container h1, #hd-wallet-ui-container h2, #hd-wallet-ui-container h3, #hd-wallet-ui-container h4, #hd-wallet-ui-container h5, #hd-wallet-ui-container h6, #hd-wallet-ui-container a, #hd-wallet-ui-container button, #hd-wallet-ui-container nav, #hd-wallet-ui-container nav * {
25
32
  -webkit-user-drag: none;
@@ -4930,6 +4937,13 @@ body:has(#hd-wallet-ui-container .modal.active) #hd-wallet-ui-container .nav-bar
4930
4937
  color: rgba(255, 255, 255, 0.9) !important;
4931
4938
  }
4932
4939
 
4940
+ #hd-wallet-ui-container .vcf-import-actions {
4941
+ display: flex;
4942
+ gap: 10px;
4943
+ justify-content: flex-end;
4944
+ margin-top: 14px;
4945
+ }
4946
+
4933
4947
  /* Readonly badge */
4934
4948
  #hd-wallet-ui-container .readonly-badge {
4935
4949
  font-size: 0.6875rem;
@@ -4961,6 +4975,10 @@ body:has(#hd-wallet-ui-container .modal.active) #hd-wallet-ui-container .nav-bar
4961
4975
  #hd-wallet-ui-container .vcard-form-row.address-row {
4962
4976
  grid-template-columns: 1fr;
4963
4977
  }
4978
+
4979
+ #hd-wallet-ui-container .vcf-import-actions {
4980
+ flex-direction: column;
4981
+ }
4964
4982
 
4965
4983
  #hd-wallet-ui-container .photo-upload-section {
4966
4984
  flex-direction: column;
@@ -5853,6 +5871,76 @@ body:has(#hd-wallet-ui-container .modal.active) #hd-wallet-ui-container .nav-bar
5853
5871
  display: block;
5854
5872
  }
5855
5873
 
5874
+ #hd-wallet-ui-container .x509-overview {
5875
+ display: grid;
5876
+ grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
5877
+ gap: 24px;
5878
+ padding: 32px;
5879
+ margin-bottom: 24px;
5880
+ align-items: start;
5881
+ }
5882
+
5883
+ #hd-wallet-ui-container .x509-copy {
5884
+ min-width: 0;
5885
+ }
5886
+
5887
+ #hd-wallet-ui-container .x509-eyebrow {
5888
+ display: inline-flex;
5889
+ align-items: center;
5890
+ gap: 8px;
5891
+ padding: 6px 10px;
5892
+ margin-bottom: 14px;
5893
+ border-radius: 999px;
5894
+ background: rgba(96, 165, 250, 0.12);
5895
+ color: #93c5fd;
5896
+ font-size: 0.72rem;
5897
+ font-weight: 600;
5898
+ letter-spacing: 0.08em;
5899
+ text-transform: uppercase;
5900
+ }
5901
+
5902
+ #hd-wallet-ui-container .x509-copy h3 {
5903
+ font-size: 1.35rem;
5904
+ font-weight: 600;
5905
+ line-height: 1.25;
5906
+ margin-bottom: 12px;
5907
+ }
5908
+
5909
+ #hd-wallet-ui-container .x509-copy p {
5910
+ color: var(--white-60);
5911
+ font-size: 0.95rem;
5912
+ line-height: 1.75;
5913
+ margin-bottom: 14px;
5914
+ }
5915
+
5916
+ #hd-wallet-ui-container .x509-tag-row {
5917
+ display: flex;
5918
+ flex-wrap: wrap;
5919
+ gap: 10px;
5920
+ margin-top: 18px;
5921
+ }
5922
+
5923
+ #hd-wallet-ui-container .x509-tag {
5924
+ display: inline-flex;
5925
+ align-items: center;
5926
+ padding: 7px 12px;
5927
+ border-radius: 999px;
5928
+ background: rgba(255, 255, 255, 0.06);
5929
+ border: 1px solid rgba(255, 255, 255, 0.08);
5930
+ color: var(--white-80);
5931
+ font-size: 0.78rem;
5932
+ font-family: var(--font-mono);
5933
+ }
5934
+
5935
+ #hd-wallet-ui-container .x509-flow {
5936
+ margin-bottom: 24px;
5937
+ padding: 28px 24px;
5938
+ }
5939
+
5940
+ #hd-wallet-ui-container .x509-grid {
5941
+ grid-template-columns: repeat(2, 1fr);
5942
+ }
5943
+
5856
5944
  @media (max-width: 600px) {
5857
5945
  #hd-wallet-ui-container .code-block pre {
5858
5946
  padding: 14px;
@@ -5867,6 +5955,16 @@ body:has(#hd-wallet-ui-container .modal.active) #hd-wallet-ui-container .nav-bar
5867
5955
  padding-left: 8px;
5868
5956
  padding-right: 8px;
5869
5957
  }
5958
+ #hd-wallet-ui-container .x509-overview {
5959
+ grid-template-columns: 1fr;
5960
+ padding: 20px;
5961
+ }
5962
+ #hd-wallet-ui-container .x509-copy h3 {
5963
+ font-size: 1.1rem;
5964
+ }
5965
+ #hd-wallet-ui-container .x509-copy p {
5966
+ font-size: 0.88rem;
5967
+ }
5870
5968
  }
5871
5969
 
5872
5970
  /* =============================================================================