@1sat/permission-module-ui 0.0.39 → 0.0.41

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.
@@ -15,7 +15,7 @@ export interface OneSatPermissionPromptProps {
15
15
  *
16
16
  * The host wallet feeds in the `request` it received from its promptHandler
17
17
  * callback and wires `onApprove`/`onReject` to resolve the same Promise.
18
- * Layout mirrors the design in `1sat-permissions-popups.pen` — 1Sat coin
18
+ * Layout mirrors `docs/plans/mockups/p1sat-permissions.pen` — 1Sat coin
19
19
  * badge, intent title, asset detail card, network/fee, approve/reject.
20
20
  */
21
21
  export declare function OneSatPermissionPrompt({ request, onApprove, onReject, theme, }: OneSatPermissionPromptProps): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"OneSatPermissionPrompt.d.ts","sourceRoot":"","sources":["../src/OneSatPermissionPrompt.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAU5D,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;AAE7C,MAAM,WAAW,2BAA2B;IAC3C,mEAAmE;IACnE,OAAO,EAAE,aAAa,CAAA;IACtB,yFAAyF;IACzF,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,KAAK,CAAA;CACb;AAqCD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,EACtC,OAAO,EACP,SAAS,EACT,QAAQ,EACR,KAAc,GACd,EAAE,2BAA2B,+BAuH7B"}
1
+ {"version":3,"file":"OneSatPermissionPrompt.d.ts","sourceRoot":"","sources":["../src/OneSatPermissionPrompt.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAU5D,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAA;AAE7C,MAAM,WAAW,2BAA2B;IAC3C,mEAAmE;IACnE,OAAO,EAAE,aAAa,CAAA;IACtB,yFAAyF;IACzF,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,KAAK,CAAA;CACb;AAkED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,EACtC,OAAO,EACP,SAAS,EACT,QAAQ,EACR,KAAc,GACd,EAAE,2BAA2B,+BAyL7B"}
package/dist/index.js CHANGED
@@ -5,6 +5,30 @@ var ORDINALS_BASKET = "p 1sat ordinals";
5
5
  var BSV21_BASKET = "p 1sat bsv21";
6
6
  var OPNS_BASKET = "p 1sat opns";
7
7
  var LOCK_BASKET = "p 1sat lock";
8
+ var P1SAT_INTENTS = {
9
+ OPNS_REGISTER: "opns.register",
10
+ OPNS_DEREGISTER: "opns.deregister",
11
+ OPNS_LIST: "opns.list",
12
+ OPNS_TRANSFER: "opns.transfer",
13
+ OPNS_CANCEL_LISTING: "opns.cancel-listing",
14
+ OPNS_PURCHASE: "opns.purchase",
15
+ ORDINAL_TRANSFER: "ordinal.transfer",
16
+ ORDINAL_LIST: "ordinal.list",
17
+ ORDINAL_CANCEL_LISTING: "ordinal.cancel-listing",
18
+ ORDINAL_PURCHASE: "ordinal.purchase",
19
+ ORDINAL_BURN: "ordinal.burn",
20
+ ORDINAL_INSCRIBE: "ordinal.inscribe",
21
+ ORDINAL_INSCRIBE_SIGMA: "ordinal.inscribe-sigma",
22
+ ORDINAL_MINT_COLLECTION: "ordinal.mint-collection",
23
+ ORDINAL_MINT_ITEM: "ordinal.mint-item",
24
+ LOCK_LOCK: "lock.lock",
25
+ LOCK_UNLOCK: "lock.unlock",
26
+ BSV21_TRANSFER: "bsv21.transfer",
27
+ BSV21_PURCHASE: "bsv21.purchase",
28
+ BSV21_MINT: "bsv21.mint",
29
+ BSV21_DEPLOY: "bsv21.deploy"
30
+ };
31
+ var P1SAT_INTENT_IDS = new Set(Object.values(P1SAT_INTENTS));
8
32
  var MAX_INSCRIPTION_BYTES = 50 * 1024 * 1024;
9
33
  var EXCHANGE_RATE_CACHE_TTL = 5 * 60 * 1000;
10
34
  var DEFAULT_STREAM_CHUNK_SIZE = 1024 * 1024;
@@ -53,6 +77,12 @@ var promptStyles = `
53
77
  --opp-reject-border: #d1d5db;
54
78
  --opp-status-bg: #FFFBE6;
55
79
  --opp-status-fg: #E5A920;
80
+ --opp-trust-ok-bg: #ECFDF5;
81
+ --opp-trust-ok-fg: #059669;
82
+ --opp-trust-warn-bg: #FFFBEB;
83
+ --opp-trust-warn-fg: #D97706;
84
+ --opp-trust-bad-bg: #FEF2F2;
85
+ --opp-trust-bad-fg: #DC2626;
56
86
 
57
87
  font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
58
88
  background: var(--opp-bg);
@@ -84,6 +114,12 @@ var promptStyles = `
84
114
  --opp-reject-border: #2D3142;
85
115
  --opp-status-bg: #2A2408;
86
116
  --opp-status-fg: #E5A920;
117
+ --opp-trust-ok-bg: #0A2E1F;
118
+ --opp-trust-ok-fg: #34D399;
119
+ --opp-trust-warn-bg: #2A2008;
120
+ --opp-trust-warn-fg: #FBBF24;
121
+ --opp-trust-bad-bg: #2A1215;
122
+ --opp-trust-bad-fg: #F87171;
87
123
  }
88
124
 
89
125
  .opp-body {
@@ -145,7 +181,7 @@ var promptStyles = `
145
181
  background: var(--opp-card-bg);
146
182
  border: 1px solid var(--opp-card-border);
147
183
  border-radius: 10px;
148
- margin: 0 20px;
184
+ margin: 0 20px 8px;
149
185
  padding: 16px;
150
186
  }
151
187
 
@@ -154,15 +190,30 @@ var promptStyles = `
154
190
  height: 80px;
155
191
  border-radius: 8px;
156
192
  object-fit: cover;
157
- background: rgba(0, 0, 0, 0.1);
193
+ background: rgba(0, 0, 0, 0.08);
158
194
  flex-shrink: 0;
159
195
  }
160
196
 
197
+ .opp-featured-image-token {
198
+ width: 48px;
199
+ height: 48px;
200
+ border-radius: 999px;
201
+ }
202
+
203
+ .opp-featured-placeholder {
204
+ display: flex;
205
+ align-items: center;
206
+ justify-content: center;
207
+ color: var(--opp-muted);
208
+ font-size: 18px;
209
+ }
210
+
161
211
  .opp-featured-meta {
162
212
  display: flex;
163
213
  flex-direction: column;
164
214
  gap: 4px;
165
215
  min-width: 0;
216
+ flex: 1;
166
217
  }
167
218
 
168
219
  .opp-featured-title {
@@ -176,9 +227,71 @@ var promptStyles = `
176
227
  .opp-featured-subtitle {
177
228
  font-size: 12px;
178
229
  color: var(--opp-muted);
230
+ display: flex;
231
+ align-items: center;
232
+ gap: 6px;
233
+ min-width: 0;
234
+ }
235
+
236
+ .opp-featured-subtitle-text {
179
237
  white-space: nowrap;
180
238
  overflow: hidden;
181
239
  text-overflow: ellipsis;
240
+ min-width: 0;
241
+ font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;
242
+ }
243
+
244
+ .opp-trust-wrap {
245
+ display: flex;
246
+ flex-direction: column;
247
+ gap: 8px;
248
+ margin: 0 20px 8px;
249
+ }
250
+
251
+ .opp-trust {
252
+ display: inline-flex;
253
+ align-self: flex-start;
254
+ padding: 3px 8px;
255
+ border-radius: 999px;
256
+ font-size: 10px;
257
+ font-weight: 600;
258
+ }
259
+
260
+ .opp-trust-verified {
261
+ background: var(--opp-trust-ok-bg);
262
+ color: var(--opp-trust-ok-fg);
263
+ }
264
+
265
+ .opp-trust-unverified {
266
+ background: var(--opp-trust-warn-bg);
267
+ color: var(--opp-trust-warn-fg);
268
+ }
269
+
270
+ .opp-trust-mismatch {
271
+ background: var(--opp-trust-bad-bg);
272
+ color: var(--opp-trust-bad-fg);
273
+ }
274
+
275
+ .opp-trust-note {
276
+ padding: 10px;
277
+ border-radius: 8px;
278
+ font-size: 11px;
279
+ line-height: 1.35;
280
+ }
281
+
282
+ .opp-trust-note-verified {
283
+ background: var(--opp-trust-ok-bg);
284
+ color: var(--opp-trust-ok-fg);
285
+ }
286
+
287
+ .opp-trust-note-unverified {
288
+ background: var(--opp-trust-warn-bg);
289
+ color: var(--opp-trust-warn-fg);
290
+ }
291
+
292
+ .opp-trust-note-mismatch {
293
+ background: var(--opp-trust-bad-bg);
294
+ color: var(--opp-trust-bad-fg);
182
295
  }
183
296
 
184
297
  .opp-row {
@@ -190,31 +303,54 @@ var promptStyles = `
190
303
 
191
304
  .opp-row-key {
192
305
  color: var(--opp-muted);
306
+ flex-shrink: 0;
307
+ }
308
+
309
+ .opp-row-value-wrap {
310
+ display: flex;
311
+ align-items: center;
312
+ gap: 6px;
313
+ min-width: 0;
314
+ max-width: 70%;
315
+ justify-content: flex-end;
193
316
  }
194
317
 
195
318
  .opp-row-value {
196
319
  font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;
197
- font-size: 13px;
320
+ font-size: 12px;
198
321
  font-weight: 500;
199
322
  text-align: right;
200
323
  white-space: nowrap;
201
324
  overflow: hidden;
202
325
  text-overflow: ellipsis;
203
326
  min-width: 0;
204
- max-width: 60%;
205
327
  }
206
328
 
207
- .opp-meta {
208
- display: flex;
209
- justify-content: space-between;
210
- padding: 12px 20px;
211
- font-size: 12px;
212
- color: var(--opp-muted);
329
+ .opp-copy {
330
+ flex-shrink: 0;
331
+ width: 22px;
332
+ height: 22px;
333
+ padding: 0;
334
+ display: inline-flex;
335
+ align-items: center;
336
+ justify-content: center;
337
+ border-radius: 6px;
338
+ border: 1px solid var(--opp-reject-border);
339
+ background: var(--opp-bg);
340
+ color: var(--opp-fg);
341
+ cursor: pointer;
213
342
  }
214
343
 
215
- .opp-meta-value {
216
- color: var(--opp-fg);
217
- font-weight: 500;
344
+ .opp-copy:hover {
345
+ border-color: var(--opp-accent);
346
+ color: var(--opp-accent);
347
+ }
348
+
349
+ .opp-fee-note {
350
+ font-size: 11px;
351
+ color: var(--opp-muted);
352
+ line-height: 1.3;
353
+ margin-top: -4px;
218
354
  }
219
355
 
220
356
  .opp-actions {
@@ -264,7 +400,7 @@ var promptStyles = `
264
400
  `;
265
401
 
266
402
  // src/OneSatPermissionPrompt.tsx
267
- import { jsx, jsxs } from "react/jsx-runtime";
403
+ import { jsx, jsxs, Fragment } from "react/jsx-runtime";
268
404
  function OneSatPermissionPrompt({
269
405
  request,
270
406
  onApprove,
@@ -272,8 +408,25 @@ function OneSatPermissionPrompt({
272
408
  theme = "auto"
273
409
  }) {
274
410
  const resolvedTheme = useResolvedTheme(theme);
275
- const summary = summarizeRequest(request);
411
+ const base = summarizeRequest(request);
276
412
  const [busy, setBusy] = useState(false);
413
+ const [verified, setVerified] = useState(undefined);
414
+ const verification = request.intent?.verification;
415
+ useEffect(() => {
416
+ if (!verification)
417
+ return;
418
+ let live = true;
419
+ verification.then((res) => {
420
+ if (live && res)
421
+ setVerified(res);
422
+ }).catch(() => {
423
+ return;
424
+ });
425
+ return () => {
426
+ live = false;
427
+ };
428
+ }, [verification]);
429
+ const summary = verified ? applyVerification(base, verified) : base;
277
430
  const handle = (action) => () => {
278
431
  if (busy)
279
432
  return;
@@ -289,6 +442,8 @@ function OneSatPermissionPrompt({
289
442
  };
290
443
  useEffect(() => {
291
444
  const onKey = (e) => {
445
+ if (busy)
446
+ return;
292
447
  if (e.key === "Escape")
293
448
  onReject();
294
449
  else if (e.key === "Enter")
@@ -296,8 +451,9 @@ function OneSatPermissionPrompt({
296
451
  };
297
452
  window.addEventListener("keydown", onKey);
298
453
  return () => window.removeEventListener("keydown", onKey);
299
- }, [onApprove, onReject]);
454
+ }, [onApprove, onReject, busy]);
300
455
  const className = `opp-root${resolvedTheme === "dark" ? " opp-dark" : ""}`;
456
+ const featuredVariant = summary.featured?.variant ?? "ordinal";
301
457
  return /* @__PURE__ */ jsxs("div", {
302
458
  className,
303
459
  children: [
@@ -355,12 +511,16 @@ function OneSatPermissionPrompt({
355
511
  ]
356
512
  }),
357
513
  summary.featured && /* @__PURE__ */ jsxs("div", {
358
- className: "opp-featured",
514
+ className: `opp-featured${featuredVariant === "token" ? " opp-featured-token" : ""}`,
359
515
  children: [
360
- /* @__PURE__ */ jsx("img", {
361
- className: "opp-featured-image",
516
+ summary.featured.imageUrl ? /* @__PURE__ */ jsx("img", {
517
+ className: featuredVariant === "token" ? "opp-featured-image opp-featured-image-token" : "opp-featured-image",
362
518
  src: summary.featured.imageUrl,
363
519
  alt: summary.featured.title
520
+ }) : /* @__PURE__ */ jsx("div", {
521
+ className: featuredVariant === "token" ? "opp-featured-image opp-featured-image-token opp-featured-placeholder" : "opp-featured-image opp-featured-placeholder",
522
+ "aria-hidden": true,
523
+ children: featuredVariant === "token" ? "◎" : "▭"
364
524
  }),
365
525
  /* @__PURE__ */ jsxs("div", {
366
526
  className: "opp-featured-meta",
@@ -369,61 +529,89 @@ function OneSatPermissionPrompt({
369
529
  className: "opp-featured-title",
370
530
  children: summary.featured.title
371
531
  }),
372
- summary.featured.subtitle && /* @__PURE__ */ jsx("div", {
532
+ summary.featured.subtitle && /* @__PURE__ */ jsxs("div", {
373
533
  className: "opp-featured-subtitle",
374
- children: summary.featured.subtitle
534
+ children: [
535
+ /* @__PURE__ */ jsx("span", {
536
+ className: "opp-featured-subtitle-text",
537
+ children: summary.featured.subtitle
538
+ }),
539
+ summary.featured.subtitleCopy && /* @__PURE__ */ jsx(CopyButton, {
540
+ text: summary.featured.subtitleCopy
541
+ })
542
+ ]
375
543
  })
376
544
  ]
377
545
  })
378
546
  ]
379
547
  }),
380
- summary.rows.length > 0 && /* @__PURE__ */ jsx("div", {
381
- className: "opp-card",
382
- children: summary.rows.map((row) => /* @__PURE__ */ jsxs("div", {
383
- className: "opp-row",
384
- children: [
385
- /* @__PURE__ */ jsx("span", {
386
- className: "opp-row-key",
387
- children: row.key
388
- }),
389
- /* @__PURE__ */ jsx("span", {
390
- className: "opp-row-value",
391
- children: row.value
392
- })
393
- ]
394
- }, `${row.key}:${row.value}`))
548
+ summary.trust && /* @__PURE__ */ jsxs("div", {
549
+ className: "opp-trust-wrap",
550
+ children: [
551
+ /* @__PURE__ */ jsx("span", {
552
+ className: `opp-trust opp-trust-${summary.trust.state}`,
553
+ children: trustLabel(summary.trust.state)
554
+ }),
555
+ summary.trust.note && /* @__PURE__ */ jsx("div", {
556
+ className: `opp-trust-note opp-trust-note-${summary.trust.state}`,
557
+ children: summary.trust.note
558
+ })
559
+ ]
395
560
  }),
396
- /* @__PURE__ */ jsxs("div", {
397
- className: "opp-bottom",
561
+ (summary.rows.length > 0 || summary.indexerFee) && /* @__PURE__ */ jsxs("div", {
562
+ className: "opp-card",
398
563
  children: [
399
- (summary.network || summary.feeSats !== undefined) && /* @__PURE__ */ jsxs("div", {
400
- className: "opp-meta",
564
+ summary.rows.map((row) => /* @__PURE__ */ jsxs("div", {
565
+ className: "opp-row",
401
566
  children: [
402
- summary.network && /* @__PURE__ */ jsxs("span", {
567
+ /* @__PURE__ */ jsx("span", {
568
+ className: "opp-row-key",
569
+ children: row.key
570
+ }),
571
+ /* @__PURE__ */ jsxs("span", {
572
+ className: "opp-row-value-wrap",
403
573
  children: [
404
- "Network",
405
- " ",
406
574
  /* @__PURE__ */ jsx("span", {
407
- className: "opp-meta-value",
408
- children: summary.network
575
+ className: "opp-row-value",
576
+ title: row.copyValue ?? row.value,
577
+ children: row.value
578
+ }),
579
+ row.copyValue && /* @__PURE__ */ jsx(CopyButton, {
580
+ text: row.copyValue
409
581
  })
410
582
  ]
411
- }),
412
- summary.feeSats !== undefined && /* @__PURE__ */ jsxs("span", {
583
+ })
584
+ ]
585
+ }, `${row.key}:${row.value}`)),
586
+ summary.indexerFee && /* @__PURE__ */ jsxs(Fragment, {
587
+ children: [
588
+ /* @__PURE__ */ jsxs("div", {
589
+ className: "opp-row",
413
590
  children: [
414
- "Estimated Fee",
415
- " ",
591
+ /* @__PURE__ */ jsx("span", {
592
+ className: "opp-row-key",
593
+ children: "Indexer fee"
594
+ }),
416
595
  /* @__PURE__ */ jsxs("span", {
417
- className: "opp-meta-value",
596
+ className: "opp-row-value",
418
597
  children: [
419
- summary.feeSats,
598
+ formatSats(summary.indexerFee.sats),
420
599
  " sats"
421
600
  ]
422
601
  })
423
602
  ]
603
+ }),
604
+ summary.indexerFee.note && /* @__PURE__ */ jsx("div", {
605
+ className: "opp-fee-note",
606
+ children: summary.indexerFee.note
424
607
  })
425
608
  ]
426
- }),
609
+ })
610
+ ]
611
+ }),
612
+ /* @__PURE__ */ jsxs("div", {
613
+ className: "opp-bottom",
614
+ children: [
427
615
  /* @__PURE__ */ jsxs("div", {
428
616
  className: "opp-actions",
429
617
  children: [
@@ -454,6 +642,72 @@ function OneSatPermissionPrompt({
454
642
  ]
455
643
  });
456
644
  }
645
+ function trustLabel(state) {
646
+ if (state === "verified")
647
+ return "Verified";
648
+ if (state === "mismatch")
649
+ return "Mismatch";
650
+ return "Unverified";
651
+ }
652
+ function formatSats(n) {
653
+ return n.toLocaleString("en-US");
654
+ }
655
+ function CopyButton({ text }) {
656
+ const [copied, setCopied] = useState(false);
657
+ const onCopy = () => {
658
+ navigator.clipboard?.writeText(text).then(() => {
659
+ setCopied(true);
660
+ window.setTimeout(() => setCopied(false), 1200);
661
+ });
662
+ };
663
+ return /* @__PURE__ */ jsx("button", {
664
+ type: "button",
665
+ className: "opp-copy",
666
+ onClick: onCopy,
667
+ "aria-label": copied ? "Copied" : "Copy full value",
668
+ title: copied ? "Copied" : "Copy",
669
+ children: copied ? /* @__PURE__ */ jsx("svg", {
670
+ width: "12",
671
+ height: "12",
672
+ viewBox: "0 0 24 24",
673
+ fill: "none",
674
+ "aria-hidden": true,
675
+ children: /* @__PURE__ */ jsx("path", {
676
+ d: "M5 13l4 4L19 7",
677
+ stroke: "currentColor",
678
+ strokeWidth: "2.5",
679
+ strokeLinecap: "round",
680
+ strokeLinejoin: "round"
681
+ })
682
+ }) : /* @__PURE__ */ jsxs("svg", {
683
+ width: "12",
684
+ height: "12",
685
+ viewBox: "0 0 24 24",
686
+ fill: "none",
687
+ "aria-hidden": true,
688
+ children: [
689
+ /* @__PURE__ */ jsx("rect", {
690
+ x: "9",
691
+ y: "9",
692
+ width: "11",
693
+ height: "11",
694
+ rx: "2",
695
+ stroke: "currentColor",
696
+ strokeWidth: "2"
697
+ }),
698
+ /* @__PURE__ */ jsx("path", {
699
+ d: "M5 15V5a2 2 0 012-2h10",
700
+ stroke: "currentColor",
701
+ strokeWidth: "2",
702
+ strokeLinecap: "round"
703
+ })
704
+ ]
705
+ })
706
+ });
707
+ }
708
+ function copyable(key, full) {
709
+ return { key, value: shortenValue(full), copyValue: full };
710
+ }
457
711
  function useResolvedTheme(theme) {
458
712
  const [resolved, setResolved] = useState(() => theme === "auto" ? readSystemTheme() : theme);
459
713
  useEffect(() => {
@@ -474,9 +728,38 @@ function readSystemTheme() {
474
728
  return "light";
475
729
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
476
730
  }
731
+ function applyVerification(base, res) {
732
+ const rows = base.rows.map((row) => {
733
+ if (row.key === "Origin" && res.origin)
734
+ return copyable("Origin", res.origin);
735
+ if (row.key === "Type" && res.contentType) {
736
+ return { key: "Type", value: res.contentType };
737
+ }
738
+ return row;
739
+ });
740
+ if (res.contentLength !== undefined && !rows.some((r) => r.key === "Size")) {
741
+ rows.push({
742
+ key: "Size",
743
+ value: `${res.contentLength.toLocaleString("en-US")} bytes`
744
+ });
745
+ }
746
+ return {
747
+ ...base,
748
+ rows,
749
+ trust: { state: res.state, note: res.note },
750
+ featured: base.featured ? {
751
+ ...base.featured,
752
+ title: res.name ?? base.featured.title,
753
+ imageUrl: res.contentUrl ?? base.featured.imageUrl
754
+ } : undefined
755
+ };
756
+ }
477
757
  function summarizeRequest(req) {
478
758
  if (req.kind === "transaction") {
479
759
  const intent = req.intent;
760
+ const byIntent = summarizeByP1SatIntent(req, intent);
761
+ if (byIntent)
762
+ return byIntent;
480
763
  switch (intent.kind) {
481
764
  case "ordinal-transfer":
482
765
  return summarizeOrdinalTransfer(req, intent);
@@ -522,6 +805,128 @@ function summarizeBasketAccess(req) {
522
805
  }))
523
806
  };
524
807
  }
808
+ var INTENT_TITLES = {
809
+ "opns.register": "Publish name",
810
+ "opns.deregister": "Unpublish name",
811
+ "opns.list": "List name for sale",
812
+ "opns.transfer": "Transfer name",
813
+ "opns.cancel-listing": "Cancel listing",
814
+ "opns.purchase": "Buy name",
815
+ "ordinal.transfer": "Send ordinal",
816
+ "ordinal.list": "List for sale",
817
+ "ordinal.cancel-listing": "Cancel listing",
818
+ "ordinal.purchase": "Buy ordinal",
819
+ "ordinal.burn": "Burn ordinal",
820
+ "ordinal.inscribe": "Create inscription",
821
+ "ordinal.inscribe-sigma": "Create inscription",
822
+ "ordinal.mint-collection": "Mint collection",
823
+ "ordinal.mint-item": "Mint collection item",
824
+ "lock.lock": "Lock BSV",
825
+ "lock.unlock": "Unlock BSV",
826
+ "bsv21.transfer": "Send tokens",
827
+ "bsv21.purchase": "Buy tokens",
828
+ "bsv21.mint": "Mint tokens",
829
+ "bsv21.deploy": "Deploy token"
830
+ };
831
+ function summarizeByP1SatIntent(req, intent) {
832
+ const id = intent.p1satIntent;
833
+ if (!id || !INTENT_TITLES[id])
834
+ return;
835
+ let base;
836
+ switch (intent.kind) {
837
+ case "ordinal-transfer":
838
+ base = summarizeOrdinalTransfer(req, intent);
839
+ break;
840
+ case "token-transfer":
841
+ base = summarizeTokenTransfer(req, intent);
842
+ break;
843
+ case "lock":
844
+ base = summarizeLock(req, intent);
845
+ break;
846
+ case "unlock":
847
+ base = summarizeUnlock(req, intent);
848
+ break;
849
+ case "inscription":
850
+ base = summarizeInscription(req, intent);
851
+ break;
852
+ case "listing":
853
+ base = summarizeListing(req, intent);
854
+ break;
855
+ case "cancel-listing":
856
+ base = summarizeCancelListing(req, intent);
857
+ break;
858
+ case "purchase":
859
+ base = summarizePurchase(req, intent);
860
+ break;
861
+ case "opns":
862
+ base = summarizeOpns(req, intent);
863
+ break;
864
+ default:
865
+ base = summarizeUnknownTx(req, intent);
866
+ }
867
+ return {
868
+ ...base,
869
+ title: INTENT_TITLES[id],
870
+ subtitle: intentSubtitle(req, id, intent),
871
+ feeSats: undefined,
872
+ network: undefined,
873
+ trust: intent.trust ?? base.trust,
874
+ indexerFee: intent.indexerFeeSats != null && intent.indexerFeeSats > 0 ? {
875
+ sats: intent.indexerFeeSats,
876
+ note: intent.indexerFeeNote
877
+ } : base.indexerFee
878
+ };
879
+ }
880
+ function intentSubtitle(req, id, intent) {
881
+ const o = shortenOriginator(req.originator);
882
+ const name = tagValue(intent.inputs[0]?.tags, "name") ?? tagValue(intent.outputs.find((out) => out.tags.some((t) => t.startsWith("name:")))?.tags, "name");
883
+ const quoted = name ? `“${name}”` : undefined;
884
+ switch (id) {
885
+ case "opns.register":
886
+ return `${o} wants to publish ${quoted ?? "an OpNS name"}`;
887
+ case "opns.deregister":
888
+ return `${o} wants to unpublish ${quoted ?? "an OpNS name"}`;
889
+ case "opns.list":
890
+ return `${o} wants to list ${quoted ?? "an OpNS name"} for sale`;
891
+ case "opns.transfer":
892
+ return `${o} wants to transfer ${quoted ?? "an OpNS name"}`;
893
+ case "opns.cancel-listing":
894
+ return `${o} wants to cancel ${quoted ? `the listing of ${quoted}` : "an OpNS listing"}`;
895
+ case "opns.purchase":
896
+ return `${o} wants to buy ${quoted ?? "an OpNS name"}`;
897
+ case "ordinal.transfer":
898
+ return `${o} wants to transfer an ordinal`;
899
+ case "ordinal.list":
900
+ return `${o} wants to list ${quoted ?? "an ordinal"} for sale`;
901
+ case "ordinal.cancel-listing":
902
+ return `${o} wants to cancel ${quoted ? `the listing of ${quoted}` : "an ordinal listing"}`;
903
+ case "ordinal.purchase":
904
+ return `${o} wants to purchase an ordinal into your wallet`;
905
+ case "ordinal.burn":
906
+ return `${o} wants to burn an ordinal`;
907
+ case "ordinal.inscribe":
908
+ case "ordinal.inscribe-sigma":
909
+ return `${o} wants to inscribe content into your wallet`;
910
+ case "ordinal.mint-collection":
911
+ return `${o} wants to mint a collection`;
912
+ case "ordinal.mint-item":
913
+ return `${o} wants to mint a collection item`;
914
+ case "lock.lock":
915
+ return `${o} wants to time-lock funds`;
916
+ case "lock.unlock":
917
+ return `${o} wants to unlock matured locks`;
918
+ case "bsv21.transfer":
919
+ return `${o} wants to send tokens`;
920
+ case "bsv21.purchase":
921
+ return `${o} wants to purchase tokens into your wallet`;
922
+ case "bsv21.mint":
923
+ return `${o} wants to mint tokens`;
924
+ case "bsv21.deploy":
925
+ return `${o} wants to deploy a BSV21 token`;
926
+ default:
927
+ return `${o} wants to ${req.summary.toLowerCase()}`;
928
+ }
929
+ }
525
930
  function tagValue(tags, key) {
526
931
  if (!tags)
527
932
  return;
@@ -542,21 +947,20 @@ function summarizeOrdinalTransfer(req, intent) {
542
947
  const imageUrl = origin ? intent.contentUrls?.[origin] : undefined;
543
948
  const rows = [];
544
949
  if (recipient)
545
- rows.push({ key: "Recipient", value: shortenValue(recipient) });
950
+ rows.push(copyable("Recipient", recipient));
546
951
  if (origin)
547
- rows.push({ key: "Origin", value: shortenValue(origin) });
952
+ rows.push(copyable("Origin", origin));
548
953
  if (contentType)
549
954
  rows.push({ key: "Type", value: contentType });
550
955
  return {
551
- title: "NFT Transfer",
956
+ title: "Send ordinal",
552
957
  subtitle: `${shortenOriginator(req.originator)} wants to transfer an ordinal`,
553
958
  rows,
554
959
  featured: imageUrl ? {
555
960
  imageUrl,
556
961
  title: name ?? "Untitled ordinal",
557
962
  subtitle: collectionId ?? contentType
558
- } : undefined,
559
- network: networkLabel(intent.chain)
963
+ } : undefined
560
964
  };
561
965
  }
562
966
  function summarizeTokenTransfer(req, intent) {
@@ -565,12 +969,12 @@ function summarizeTokenTransfer(req, intent) {
565
969
  const tokenId = tagValue(input.tags, "bsv21");
566
970
  if (!tokenId)
567
971
  continue;
568
- const sym = tagValue(input.tags, "sym");
972
+ const sym2 = tagValue(input.tags, "sym");
569
973
  const amt = BigInt(tagValue(input.tags, "amt") ?? "0");
570
- const cur = totals.get(tokenId) ?? { sym, inAmt: 0n, changeAmt: 0n };
974
+ const cur = totals.get(tokenId) ?? { sym: sym2, inAmt: 0n, changeAmt: 0n };
571
975
  cur.inAmt += amt;
572
- if (!cur.sym && sym)
573
- cur.sym = sym;
976
+ if (!cur.sym && sym2)
977
+ cur.sym = sym2;
574
978
  totals.set(tokenId, cur);
575
979
  }
576
980
  for (const output of intent.outputs) {
@@ -585,36 +989,75 @@ function summarizeTokenTransfer(req, intent) {
585
989
  cur.changeAmt += amt;
586
990
  }
587
991
  const rows = [];
992
+ let featured;
993
+ let primaryTokenId;
588
994
  for (const [tokenId, info] of totals) {
589
- rows.push({
590
- key: "Token",
591
- value: info.sym ? `${info.sym} — ${shortenId(tokenId)}` : shortenId(tokenId)
592
- });
995
+ if (!primaryTokenId)
996
+ primaryTokenId = tokenId;
593
997
  const sent = info.inAmt - info.changeAmt;
594
- rows.push({ key: "Amount", value: sent.toString() });
998
+ rows.push({ key: "Amount", value: sent.toLocaleString("en-US") });
595
999
  }
596
- const recipient = intent.outputs.find((o) => o.recipient && o.basket !== BSV21_BASKET)?.recipient;
597
- if (recipient)
598
- rows.push({ key: "Recipient", value: shortenValue(recipient) });
1000
+ const to = intent.outputs.find((o) => o.recipient && o.satoshis === 1)?.recipient;
1001
+ if (to)
1002
+ rows.push(copyable("Recipient", to));
1003
+ const firstIn = intent.inputs.find((i) => tagValue(i.tags, "bsv21"));
1004
+ const sym = (primaryTokenId ? totals.get(primaryTokenId)?.sym : undefined) ?? tagValue(firstIn?.tags, "sym");
1005
+ const iconRef = tagValue(firstIn?.tags, "icon");
1006
+ const iconUrl = iconRef && intent.contentUrls?.[iconRef] || primaryTokenId && intent.contentUrls?.[primaryTokenId] || undefined;
1007
+ if (primaryTokenId) {
1008
+ featured = {
1009
+ variant: "token",
1010
+ imageUrl: iconUrl,
1011
+ title: sym ?? "Token",
1012
+ subtitle: shortenId(primaryTokenId),
1013
+ subtitleCopy: primaryTokenId
1014
+ };
1015
+ }
1016
+ const indexerFee = resolveIndexerFee(intent);
599
1017
  return {
600
- title: "Token Transfer",
1018
+ title: "Send tokens",
601
1019
  subtitle: `${shortenOriginator(req.originator)} wants to send tokens`,
602
1020
  rows,
603
- network: networkLabel(intent.chain)
1021
+ featured,
1022
+ indexerFee
604
1023
  };
605
1024
  }
1025
+ function resolveIndexerFee(intent) {
1026
+ if (intent.indexerFeeSats != null && intent.indexerFeeSats > 0) {
1027
+ return {
1028
+ sats: intent.indexerFeeSats,
1029
+ note: intent.indexerFeeNote
1030
+ };
1031
+ }
1032
+ const tokenOutCount = intent.outputs.filter((o) => o.basket === BSV21_BASKET || tagValue(o.tags, "bsv21")).length;
1033
+ const feeLike = intent.outputs.filter((o) => !o.basket && o.recipient && o.satoshis > 1);
1034
+ const isPurchase = intent.p1satIntent?.endsWith(".purchase") || intent.kind === "purchase";
1035
+ if (isPurchase || feeLike.length !== 1)
1036
+ return;
1037
+ const fee = feeLike[0];
1038
+ if (!fee || fee.satoshis <= 0)
1039
+ return;
1040
+ const note = tokenOutCount > 0 ? `Overlay processing · ${formatSats(Math.round(fee.satoshis / tokenOutCount))} sats × ${tokenOutCount} token outs` : "Overlay processing fee";
1041
+ return { sats: fee.satoshis, note };
1042
+ }
606
1043
  function summarizeLock(req, intent) {
607
- const lockOutputs = intent.outputs.filter((o) => o.basket === LOCK_BASKET);
1044
+ const decoded = intent.outputs.filter((o) => o.lockUntilHeight !== undefined);
1045
+ const lockOutputs = decoded.length > 0 ? decoded : intent.outputs.filter((o) => o.basket === LOCK_BASKET);
608
1046
  const sats = (lockOutputs.length > 0 ? lockOutputs : intent.outputs).reduce((s, o) => s + o.satoshis, 0);
609
- const until = (lockOutputs.length > 0 ? lockOutputs : intent.outputs).flatMap((o) => o.tags).find((t) => t.startsWith("until:"))?.slice("until:".length);
610
- const rows = [{ key: "Amount", value: `${sats} sats` }];
611
- if (until)
612
- rows.push({ key: "Lock until block", value: until });
1047
+ const until = decoded[0]?.lockUntilHeight;
1048
+ const rows = [
1049
+ { key: "Amount", value: `${sats.toLocaleString("en-US")} sats` }
1050
+ ];
1051
+ if (until !== undefined) {
1052
+ rows.push({
1053
+ key: "Lock until block",
1054
+ value: until.toLocaleString("en-US")
1055
+ });
1056
+ }
613
1057
  return {
614
1058
  title: "Lock BSV",
615
1059
  subtitle: `${shortenOriginator(req.originator)} wants to time-lock funds`,
616
- rows,
617
- network: networkLabel(intent.chain)
1060
+ rows
618
1061
  };
619
1062
  }
620
1063
  function summarizeUnlock(req, intent) {
@@ -622,8 +1065,7 @@ function summarizeUnlock(req, intent) {
622
1065
  return {
623
1066
  title: "Unlock Matured",
624
1067
  subtitle: `${shortenOriginator(req.originator)} wants to unlock matured locks`,
625
- rows: [{ key: "Amount", value: `${sats} sats` }],
626
- network: networkLabel(intent.chain)
1068
+ rows: [{ key: "Amount", value: `${sats} sats` }]
627
1069
  };
628
1070
  }
629
1071
  function summarizeInscription(req, intent) {
@@ -637,30 +1079,30 @@ function summarizeInscription(req, intent) {
637
1079
  if (name)
638
1080
  rows.push({ key: "Name", value: name });
639
1081
  if (recipient)
640
- rows.push({ key: "Recipient", value: shortenValue(recipient) });
1082
+ rows.push(copyable("Recipient", recipient));
641
1083
  return {
642
1084
  title: "Create Inscription",
643
1085
  subtitle: `${shortenOriginator(req.originator)} wants to inscribe content into your wallet`,
644
- rows,
645
- network: networkLabel(intent.chain)
1086
+ rows
646
1087
  };
647
1088
  }
648
1089
  function summarizeListing(req, intent) {
649
- const listingOutput = intent.outputs.find((o) => o.tags.some((t) => t.startsWith("price:")));
1090
+ const listingOutput = intent.outputs.find((o) => o.listingPriceSats !== undefined) ?? intent.outputs.find((o) => o.tags.some((t) => t.startsWith("price:")));
650
1091
  const ordinal = intent.inputs[0];
651
1092
  const origin = tagValue(ordinal?.tags, "origin") ?? tagValue(listingOutput?.tags, "origin");
652
1093
  const name = tagValue(ordinal?.tags, "name") ?? tagValue(listingOutput?.tags, "name");
653
1094
  const contentType = tagValue(ordinal?.tags, "type") ?? tagValue(listingOutput?.tags, "type");
654
1095
  const collectionId = tagValue(ordinal?.tags, "collectionId");
655
1096
  const imageUrl = origin ? intent.contentUrls?.[origin] : undefined;
656
- const price = tagValue(listingOutput?.tags, "price");
1097
+ const price = listingOutput?.listingPriceSats;
657
1098
  const rows = [];
658
1099
  if (name)
659
1100
  rows.push({ key: "Name", value: name });
660
- if (price)
661
- rows.push({ key: "Price", value: `${price} sats` });
1101
+ if (price !== undefined) {
1102
+ rows.push({ key: "Price", value: `${price.toLocaleString("en-US")} sats` });
1103
+ }
662
1104
  if (origin)
663
- rows.push({ key: "Origin", value: shortenValue(origin) });
1105
+ rows.push(copyable("Origin", origin));
664
1106
  if (contentType)
665
1107
  rows.push({ key: "Type", value: contentType });
666
1108
  return {
@@ -671,8 +1113,7 @@ function summarizeListing(req, intent) {
671
1113
  imageUrl,
672
1114
  title: name ?? "Untitled ordinal",
673
1115
  subtitle: collectionId ?? contentType
674
- } : undefined,
675
- network: networkLabel(intent.chain)
1116
+ } : undefined
676
1117
  };
677
1118
  }
678
1119
  function summarizeCancelListing(req, intent) {
@@ -690,7 +1131,7 @@ function summarizeCancelListing(req, intent) {
690
1131
  if (price)
691
1132
  rows.push({ key: "Original price", value: `${price} sats` });
692
1133
  if (origin)
693
- rows.push({ key: "Origin", value: shortenValue(origin) });
1134
+ rows.push(copyable("Origin", origin));
694
1135
  if (contentType)
695
1136
  rows.push({ key: "Type", value: contentType });
696
1137
  return {
@@ -701,8 +1142,7 @@ function summarizeCancelListing(req, intent) {
701
1142
  imageUrl,
702
1143
  title: name ?? "Untitled ordinal",
703
1144
  subtitle: collectionId ?? contentType
704
- } : undefined,
705
- network: networkLabel(intent.chain)
1145
+ } : undefined
706
1146
  };
707
1147
  }
708
1148
  function summarizePurchase(req, intent) {
@@ -719,41 +1159,49 @@ function summarizePurchase(req, intent) {
719
1159
  const price = sellerOutput?.satoshis;
720
1160
  const rows = [];
721
1161
  if (price !== undefined)
722
- rows.push({ key: "Price", value: `${price} sats` });
1162
+ rows.push({ key: "Price", value: `${price.toLocaleString("en-US")} sats` });
723
1163
  if (isToken) {
724
1164
  if (amt)
725
1165
  rows.push({ key: "Amount", value: amt });
726
- if (sym || tokenId) {
727
- rows.push({
728
- key: "Token",
729
- value: sym && tokenId ? `${sym} — ${shortenId(tokenId)}` : sym ?? shortenId(tokenId ?? "")
730
- });
731
- }
732
1166
  } else {
733
1167
  if (origin)
734
- rows.push({ key: "Origin", value: shortenValue(origin) });
1168
+ rows.push(copyable("Origin", origin));
735
1169
  if (contentType)
736
1170
  rows.push({ key: "Type", value: contentType });
737
1171
  }
738
1172
  const featuredImage = !isToken && origin ? intent.contentUrls?.[origin] : undefined;
739
- return {
740
- title: isToken ? "Purchase Tokens" : "Purchase Ordinal",
741
- subtitle: isToken ? `${shortenOriginator(req.originator)} wants to purchase tokens into your wallet` : `${shortenOriginator(req.originator)} wants to purchase an ordinal into your wallet`,
742
- rows,
743
- featured: !isToken && featuredImage ? {
1173
+ const iconRef = tagValue(incoming?.tags, "icon");
1174
+ const iconUrl = iconRef && intent.contentUrls?.[iconRef] || tokenId && intent.contentUrls?.[tokenId] || undefined;
1175
+ let featured;
1176
+ if (isToken && (sym || tokenId)) {
1177
+ featured = {
1178
+ variant: "token",
1179
+ imageUrl: iconUrl,
1180
+ title: sym ?? "Token",
1181
+ subtitle: tokenId ? shortenId(tokenId) : undefined,
1182
+ subtitleCopy: tokenId
1183
+ };
1184
+ } else if (featuredImage) {
1185
+ featured = {
744
1186
  imageUrl: featuredImage,
745
1187
  title: name ?? "Untitled ordinal",
746
1188
  subtitle: collectionId ?? contentType
747
- } : undefined,
748
- network: networkLabel(intent.chain)
1189
+ };
1190
+ }
1191
+ return {
1192
+ title: isToken ? "Buy tokens" : "Buy ordinal",
1193
+ subtitle: isToken ? `${shortenOriginator(req.originator)} wants to purchase tokens into your wallet` : `${shortenOriginator(req.originator)} wants to purchase an ordinal into your wallet`,
1194
+ rows,
1195
+ featured,
1196
+ trust: intent.trust,
1197
+ indexerFee: resolveIndexerFee(intent)
749
1198
  };
750
1199
  }
751
1200
  function summarizeSocialPost(req, intent) {
752
1201
  return {
753
1202
  title: "Social Post",
754
1203
  subtitle: `${shortenOriginator(req.originator)} wants to publish a post`,
755
- rows: [],
756
- network: networkLabel(intent.chain)
1204
+ rows: []
757
1205
  };
758
1206
  }
759
1207
  function summarizeOpns(req, intent) {
@@ -762,34 +1210,65 @@ function summarizeOpns(req, intent) {
762
1210
  const recipient = intent.outputs.find((o) => !o.basket && o.recipient)?.recipient;
763
1211
  const name = tagValue(input?.tags, "name") ?? tagValue(opnsOutput?.tags, "name");
764
1212
  const origin = tagValue(input?.tags, "origin") ?? tagValue(opnsOutput?.tags, "origin");
1213
+ const priceTag = intent.outputs.flatMap((o) => o.tags).find((t) => t.startsWith("price:"));
1214
+ const price = priceTag?.slice("price:".length);
765
1215
  const rows = [];
766
1216
  if (name)
767
1217
  rows.push({ key: "Name", value: name });
1218
+ if (opnsOutput?.opnsProfileName) {
1219
+ rows.push({ key: "Display name", value: opnsOutput.opnsProfileName });
1220
+ }
768
1221
  if (recipient)
769
- rows.push({ key: "Recipient", value: shortenValue(recipient) });
1222
+ rows.push(copyable("Recipient", recipient));
1223
+ if (price)
1224
+ rows.push({ key: "Price", value: `${price} sats` });
770
1225
  if (origin)
771
- rows.push({ key: "Origin", value: shortenValue(origin) });
772
- const isTransfer = Boolean(recipient);
1226
+ rows.push(copyable("Origin", origin));
1227
+ const copy = opnsCopy(intent.p1satIntent, Boolean(recipient));
1228
+ const nameBit = name ? `“${name}”` : "an OpNS name";
1229
+ const avatarOrigin = opnsOutput?.opnsAvatarOrigin;
1230
+ const avatarUrl = avatarOrigin ? intent.contentUrls?.[avatarOrigin] : undefined;
773
1231
  return {
774
- title: isTransfer ? "Transfer OpNS Name" : "Update OpNS Name",
775
- subtitle: `${shortenOriginator(req.originator)} wants to ${isTransfer ? "transfer" : "update"} ${name ? `“${name}”` : "an OpNS name"}`,
1232
+ title: copy.title,
1233
+ subtitle: `${shortenOriginator(req.originator)} wants to ${copy.verb} ${nameBit}`,
776
1234
  rows,
777
- network: networkLabel(intent.chain)
1235
+ ...avatarUrl && {
1236
+ featured: {
1237
+ variant: "token",
1238
+ imageUrl: avatarUrl,
1239
+ title: opnsOutput?.opnsProfileName ?? name ?? "Avatar",
1240
+ ...name && { subtitle: name }
1241
+ }
1242
+ }
778
1243
  };
779
1244
  }
1245
+ function opnsCopy(p1satIntent, isTransferHeuristic) {
1246
+ switch (p1satIntent) {
1247
+ case "opns.register":
1248
+ return { title: "Publish name", verb: "publish" };
1249
+ case "opns.deregister":
1250
+ return { title: "Unpublish name", verb: "unpublish" };
1251
+ case "opns.list":
1252
+ return { title: "List name for sale", verb: "list" };
1253
+ case "opns.transfer":
1254
+ return { title: "Transfer name", verb: "transfer" };
1255
+ case "opns.cancel-listing":
1256
+ return { title: "Cancel listing", verb: "cancel the listing of" };
1257
+ case "opns.purchase":
1258
+ return { title: "Buy name", verb: "buy" };
1259
+ default:
1260
+ return isTransferHeuristic ? { title: "Transfer OpNS Name", verb: "transfer" } : { title: "Update OpNS Name", verb: "update" };
1261
+ }
1262
+ }
780
1263
  function summarizeUnknownTx(req, intent) {
781
1264
  const ins = intent.inputs.length;
782
1265
  const outs = intent.outputs.length;
783
1266
  return {
784
1267
  title: "Transaction Request",
785
1268
  subtitle: `${shortenOriginator(req.originator)} wants to ${req.summary.toLowerCase()}`,
786
- rows: [{ key: "Inputs / Outputs", value: `${ins} / ${outs}` }],
787
- network: networkLabel(intent.chain)
1269
+ rows: [{ key: "Inputs / Outputs", value: `${ins} / ${outs}` }]
788
1270
  };
789
1271
  }
790
- function networkLabel(chain) {
791
- return chain === "testnet" ? "BSV Testnet" : "BSV Mainnet";
792
- }
793
1272
  function shortenId(id, max = 24) {
794
1273
  if (id.length <= max)
795
1274
  return id;
package/dist/styles.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * CSS string for the OneSatPermissionPrompt component. Inlined as a style
3
3
  * tag so the host wallet doesn't have to wire up CSS imports.
4
4
  *
5
- * Colors match the design in `1sat-permissions-popups.pen`.
5
+ * Colors match `docs/plans/mockups/p1sat-permissions.pen`.
6
6
  */
7
- export declare const promptStyles = "\n.opp-root {\n --opp-bg: #ffffff;\n --opp-fg: #111827;\n --opp-muted: #6b7280;\n --opp-card-bg: #f7f8fa;\n --opp-card-border: #eceef2;\n --opp-accent: #E5A920;\n --opp-approve-bg: #E5A920;\n --opp-approve-fg: #ffffff;\n --opp-reject-bg: #ffffff;\n --opp-reject-fg: #111827;\n --opp-reject-border: #d1d5db;\n --opp-status-bg: #FFFBE6;\n --opp-status-fg: #E5A920;\n\n font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--opp-bg);\n color: var(--opp-fg);\n border-radius: 16px;\n display: flex;\n flex-direction: column;\n width: 100%;\n max-width: 480px;\n min-height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.opp-bottom {\n margin-top: auto;\n display: flex;\n flex-direction: column;\n}\n\n.opp-root.opp-dark {\n --opp-bg: #0F1117;\n --opp-fg: #F9FAFB;\n --opp-muted: #9ca3af;\n --opp-card-bg: #1A1D27;\n --opp-card-border: #232636;\n --opp-reject-bg: #0F1117;\n --opp-reject-fg: #F9FAFB;\n --opp-reject-border: #2D3142;\n --opp-status-bg: #2A2408;\n --opp-status-fg: #E5A920;\n}\n\n.opp-body {\n padding: 24px 20px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n}\n\n.opp-coin {\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n}\n\n.opp-title {\n font-size: 16px;\n font-weight: 700;\n margin: 0;\n text-align: center;\n}\n\n.opp-subtitle {\n font-size: 12px;\n color: var(--opp-muted);\n margin: 0;\n text-align: center;\n line-height: 1.4;\n}\n\n.opp-status {\n background: var(--opp-status-bg);\n color: var(--opp-status-fg);\n padding: 4px 12px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n margin-top: 4px;\n border: 1px solid var(--opp-card-border);\n}\n\n.opp-card {\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n border-radius: 10px;\n margin: 0 20px;\n padding: 16px;\n font-size: 13px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.opp-featured {\n display: flex;\n align-items: center;\n gap: 12px;\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n border-radius: 10px;\n margin: 0 20px;\n padding: 16px;\n}\n\n.opp-featured-image {\n width: 80px;\n height: 80px;\n border-radius: 8px;\n object-fit: cover;\n background: rgba(0, 0, 0, 0.1);\n flex-shrink: 0;\n}\n\n.opp-featured-meta {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n}\n\n.opp-featured-title {\n font-size: 14px;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.opp-featured-subtitle {\n font-size: 12px;\n color: var(--opp-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.opp-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n}\n\n.opp-row-key {\n color: var(--opp-muted);\n}\n\n.opp-row-value {\n font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;\n font-size: 13px;\n font-weight: 500;\n text-align: right;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n max-width: 60%;\n}\n\n.opp-meta {\n display: flex;\n justify-content: space-between;\n padding: 12px 20px;\n font-size: 12px;\n color: var(--opp-muted);\n}\n\n.opp-meta-value {\n color: var(--opp-fg);\n font-weight: 500;\n}\n\n.opp-actions {\n display: flex;\n gap: 12px;\n padding: 20px 20px 12px;\n}\n\n.opp-button {\n flex: 1;\n padding: 0 16px;\n height: 48px;\n border-radius: 10px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n border: 1px solid transparent;\n transition: opacity 120ms ease;\n}\n\n.opp-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.opp-button-reject {\n background: var(--opp-reject-bg);\n color: var(--opp-reject-fg);\n border-color: var(--opp-reject-border);\n}\n\n.opp-button-approve {\n background: var(--opp-approve-bg);\n color: var(--opp-approve-fg);\n}\n\n.opp-footer {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 20px 16px;\n font-size: 11px;\n font-weight: 500;\n color: var(--opp-muted);\n}\n";
7
+ export declare const promptStyles = "\n.opp-root {\n --opp-bg: #ffffff;\n --opp-fg: #111827;\n --opp-muted: #6b7280;\n --opp-card-bg: #f7f8fa;\n --opp-card-border: #eceef2;\n --opp-accent: #E5A920;\n --opp-approve-bg: #E5A920;\n --opp-approve-fg: #ffffff;\n --opp-reject-bg: #ffffff;\n --opp-reject-fg: #111827;\n --opp-reject-border: #d1d5db;\n --opp-status-bg: #FFFBE6;\n --opp-status-fg: #E5A920;\n --opp-trust-ok-bg: #ECFDF5;\n --opp-trust-ok-fg: #059669;\n --opp-trust-warn-bg: #FFFBEB;\n --opp-trust-warn-fg: #D97706;\n --opp-trust-bad-bg: #FEF2F2;\n --opp-trust-bad-fg: #DC2626;\n\n font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--opp-bg);\n color: var(--opp-fg);\n border-radius: 16px;\n display: flex;\n flex-direction: column;\n width: 100%;\n max-width: 480px;\n min-height: 100%;\n overflow-x: hidden;\n overflow-y: auto;\n}\n\n.opp-bottom {\n margin-top: auto;\n display: flex;\n flex-direction: column;\n}\n\n.opp-root.opp-dark {\n --opp-bg: #0F1117;\n --opp-fg: #F9FAFB;\n --opp-muted: #9ca3af;\n --opp-card-bg: #1A1D27;\n --opp-card-border: #232636;\n --opp-reject-bg: #0F1117;\n --opp-reject-fg: #F9FAFB;\n --opp-reject-border: #2D3142;\n --opp-status-bg: #2A2408;\n --opp-status-fg: #E5A920;\n --opp-trust-ok-bg: #0A2E1F;\n --opp-trust-ok-fg: #34D399;\n --opp-trust-warn-bg: #2A2008;\n --opp-trust-warn-fg: #FBBF24;\n --opp-trust-bad-bg: #2A1215;\n --opp-trust-bad-fg: #F87171;\n}\n\n.opp-body {\n padding: 24px 20px 16px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n align-items: center;\n}\n\n.opp-coin {\n width: 48px;\n height: 48px;\n flex-shrink: 0;\n}\n\n.opp-title {\n font-size: 16px;\n font-weight: 700;\n margin: 0;\n text-align: center;\n}\n\n.opp-subtitle {\n font-size: 12px;\n color: var(--opp-muted);\n margin: 0;\n text-align: center;\n line-height: 1.4;\n}\n\n.opp-status {\n background: var(--opp-status-bg);\n color: var(--opp-status-fg);\n padding: 4px 12px;\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n margin-top: 4px;\n border: 1px solid var(--opp-card-border);\n}\n\n.opp-card {\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n border-radius: 10px;\n margin: 0 20px;\n padding: 16px;\n font-size: 13px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.opp-featured {\n display: flex;\n align-items: center;\n gap: 12px;\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n border-radius: 10px;\n margin: 0 20px 8px;\n padding: 16px;\n}\n\n.opp-featured-image {\n width: 80px;\n height: 80px;\n border-radius: 8px;\n object-fit: cover;\n background: rgba(0, 0, 0, 0.08);\n flex-shrink: 0;\n}\n\n.opp-featured-image-token {\n width: 48px;\n height: 48px;\n border-radius: 999px;\n}\n\n.opp-featured-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--opp-muted);\n font-size: 18px;\n}\n\n.opp-featured-meta {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 0;\n flex: 1;\n}\n\n.opp-featured-title {\n font-size: 14px;\n font-weight: 600;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.opp-featured-subtitle {\n font-size: 12px;\n color: var(--opp-muted);\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n\n.opp-featured-subtitle-text {\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;\n}\n\n.opp-trust-wrap {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin: 0 20px 8px;\n}\n\n.opp-trust {\n display: inline-flex;\n align-self: flex-start;\n padding: 3px 8px;\n border-radius: 999px;\n font-size: 10px;\n font-weight: 600;\n}\n\n.opp-trust-verified {\n background: var(--opp-trust-ok-bg);\n color: var(--opp-trust-ok-fg);\n}\n\n.opp-trust-unverified {\n background: var(--opp-trust-warn-bg);\n color: var(--opp-trust-warn-fg);\n}\n\n.opp-trust-mismatch {\n background: var(--opp-trust-bad-bg);\n color: var(--opp-trust-bad-fg);\n}\n\n.opp-trust-note {\n padding: 10px;\n border-radius: 8px;\n font-size: 11px;\n line-height: 1.35;\n}\n\n.opp-trust-note-verified {\n background: var(--opp-trust-ok-bg);\n color: var(--opp-trust-ok-fg);\n}\n\n.opp-trust-note-unverified {\n background: var(--opp-trust-warn-bg);\n color: var(--opp-trust-warn-fg);\n}\n\n.opp-trust-note-mismatch {\n background: var(--opp-trust-bad-bg);\n color: var(--opp-trust-bad-fg);\n}\n\n.opp-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n}\n\n.opp-row-key {\n color: var(--opp-muted);\n flex-shrink: 0;\n}\n\n.opp-row-value-wrap {\n display: flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n max-width: 70%;\n justify-content: flex-end;\n}\n\n.opp-row-value {\n font-family: 'Roboto Mono', ui-monospace, SFMono-Regular, monospace;\n font-size: 12px;\n font-weight: 500;\n text-align: right;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.opp-copy {\n flex-shrink: 0;\n width: 22px;\n height: 22px;\n padding: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n border: 1px solid var(--opp-reject-border);\n background: var(--opp-bg);\n color: var(--opp-fg);\n cursor: pointer;\n}\n\n.opp-copy:hover {\n border-color: var(--opp-accent);\n color: var(--opp-accent);\n}\n\n.opp-fee-note {\n font-size: 11px;\n color: var(--opp-muted);\n line-height: 1.3;\n margin-top: -4px;\n}\n\n.opp-actions {\n display: flex;\n gap: 12px;\n padding: 20px 20px 12px;\n}\n\n.opp-button {\n flex: 1;\n padding: 0 16px;\n height: 48px;\n border-radius: 10px;\n font-size: 15px;\n font-weight: 600;\n cursor: pointer;\n border: 1px solid transparent;\n transition: opacity 120ms ease;\n}\n\n.opp-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.opp-button-reject {\n background: var(--opp-reject-bg);\n color: var(--opp-reject-fg);\n border-color: var(--opp-reject-border);\n}\n\n.opp-button-approve {\n background: var(--opp-approve-bg);\n color: var(--opp-approve-fg);\n}\n\n.opp-footer {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n padding: 8px 20px 16px;\n font-size: 11px;\n font-weight: 500;\n color: var(--opp-muted);\n}\n";
8
8
  //# sourceMappingURL=styles.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,0nIA+NxB,CAAA"}
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,eAAO,MAAM,YAAY,g3MA+UxB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@1sat/permission-module-ui",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "description": "React component for the 1Sat permission module's prompt UX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -28,8 +28,8 @@
28
28
  ],
29
29
  "license": "MIT",
30
30
  "dependencies": {
31
- "@1sat/permission-module": "0.0.43",
32
- "@1sat/types": "0.0.37"
31
+ "@1sat/permission-module": "0.0.46",
32
+ "@1sat/types": "0.0.39"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": "^18.0.0 || ^19.0.0"