@1sat/permission-module-ui 0.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/dist/OneSatPermissionPrompt.d.ts +26 -0
- package/dist/OneSatPermissionPrompt.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +473 -0
- package/dist/styles.d.ts +9 -0
- package/dist/styles.d.ts.map +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { PromptRequest } from '@1sat/permission-module';
|
|
2
|
+
export type Theme = 'light' | 'dark' | 'auto';
|
|
3
|
+
export interface OneSatPermissionPromptProps {
|
|
4
|
+
/** The structured request handed to the wallet's promptHandler. */
|
|
5
|
+
request: PromptRequest;
|
|
6
|
+
/** Called when the user approves. The host wallet resolves promptHandler with `true`. */
|
|
7
|
+
onApprove: () => void;
|
|
8
|
+
/** Called when the user rejects. The host wallet resolves promptHandler with `false`. */
|
|
9
|
+
onReject: () => void;
|
|
10
|
+
/** Theme override. Defaults to 'auto' (matches `prefers-color-scheme`). */
|
|
11
|
+
theme?: Theme;
|
|
12
|
+
/** App name shown in the header. Defaults to '1Sat Ordinals'. */
|
|
13
|
+
appName?: string;
|
|
14
|
+
/** Version string shown in the footer (e.g. wallet version). */
|
|
15
|
+
version?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Drop-in component for rendering 1Sat permission prompts.
|
|
19
|
+
*
|
|
20
|
+
* The host wallet feeds in the `request` it received from its promptHandler
|
|
21
|
+
* callback and wires `onApprove`/`onReject` to resolve the same Promise.
|
|
22
|
+
* Layout mirrors the design in `1sat-permissions-popups.pen` — branding
|
|
23
|
+
* header, intent title, asset detail card, network/fee, approve/reject.
|
|
24
|
+
*/
|
|
25
|
+
export declare function OneSatPermissionPrompt({ request, onApprove, onReject, theme, appName, version, }: OneSatPermissionPromptProps): import("react/jsx-runtime").JSX.Element;
|
|
26
|
+
//# sourceMappingURL=OneSatPermissionPrompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OneSatPermissionPrompt.d.ts","sourceRoot":"","sources":["../src/OneSatPermissionPrompt.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAI5D,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;IACb,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAA;CAChB;AAeD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,EACtC,OAAO,EACP,SAAS,EACT,QAAQ,EACR,KAAc,EACd,OAAyB,EACzB,OAAO,GACP,EAAE,2BAA2B,2CAyG7B"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,sBAAsB,EACtB,KAAK,2BAA2B,EAChC,KAAK,KAAK,GACV,MAAM,0BAA0B,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/OneSatPermissionPrompt.tsx
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
|
|
6
|
+
// src/styles.ts
|
|
7
|
+
var promptStyles = `
|
|
8
|
+
.opp-root {
|
|
9
|
+
--opp-bg: #ffffff;
|
|
10
|
+
--opp-fg: #1a1a1a;
|
|
11
|
+
--opp-muted: #6b7280;
|
|
12
|
+
--opp-card-bg: #f5f5f7;
|
|
13
|
+
--opp-card-border: #e5e7eb;
|
|
14
|
+
--opp-accent: #f59e0b;
|
|
15
|
+
--opp-approve-bg: #f59e0b;
|
|
16
|
+
--opp-approve-fg: #ffffff;
|
|
17
|
+
--opp-reject-bg: #ffffff;
|
|
18
|
+
--opp-reject-fg: #1a1a1a;
|
|
19
|
+
--opp-reject-border: #d1d5db;
|
|
20
|
+
--opp-status-bg: #fde68a;
|
|
21
|
+
--opp-status-fg: #92400e;
|
|
22
|
+
|
|
23
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
24
|
+
background: var(--opp-bg);
|
|
25
|
+
color: var(--opp-fg);
|
|
26
|
+
border-radius: 12px;
|
|
27
|
+
display: flex;
|
|
28
|
+
flex-direction: column;
|
|
29
|
+
width: 100%;
|
|
30
|
+
max-width: 480px;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.opp-root.opp-dark {
|
|
35
|
+
--opp-bg: #1a1a1a;
|
|
36
|
+
--opp-fg: #f5f5f7;
|
|
37
|
+
--opp-muted: #9ca3af;
|
|
38
|
+
--opp-card-bg: #262626;
|
|
39
|
+
--opp-card-border: #3a3a3a;
|
|
40
|
+
--opp-reject-bg: #262626;
|
|
41
|
+
--opp-reject-fg: #f5f5f7;
|
|
42
|
+
--opp-reject-border: #3a3a3a;
|
|
43
|
+
--opp-status-bg: rgba(245, 158, 11, 0.2);
|
|
44
|
+
--opp-status-fg: #fbbf24;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.opp-header {
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: center;
|
|
50
|
+
justify-content: space-between;
|
|
51
|
+
padding: 12px 16px;
|
|
52
|
+
border-bottom: 1px solid var(--opp-card-border);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.opp-header-brand,
|
|
56
|
+
.opp-header-app {
|
|
57
|
+
display: flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
gap: 8px;
|
|
60
|
+
font-size: 13px;
|
|
61
|
+
font-weight: 600;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.opp-avatar {
|
|
65
|
+
width: 24px;
|
|
66
|
+
height: 24px;
|
|
67
|
+
border-radius: 50%;
|
|
68
|
+
background: var(--opp-accent);
|
|
69
|
+
color: #ffffff;
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
justify-content: center;
|
|
73
|
+
font-size: 12px;
|
|
74
|
+
font-weight: 700;
|
|
75
|
+
flex-shrink: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.opp-avatar.opp-app {
|
|
79
|
+
background: #3b82f6;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.opp-body {
|
|
83
|
+
padding: 24px 20px 16px;
|
|
84
|
+
display: flex;
|
|
85
|
+
flex-direction: column;
|
|
86
|
+
gap: 12px;
|
|
87
|
+
align-items: center;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.opp-icon {
|
|
91
|
+
width: 36px;
|
|
92
|
+
height: 36px;
|
|
93
|
+
border-radius: 50%;
|
|
94
|
+
background: var(--opp-card-bg);
|
|
95
|
+
border: 1px solid var(--opp-card-border);
|
|
96
|
+
display: flex;
|
|
97
|
+
align-items: center;
|
|
98
|
+
justify-content: center;
|
|
99
|
+
margin-bottom: 4px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.opp-title {
|
|
103
|
+
font-size: 18px;
|
|
104
|
+
font-weight: 700;
|
|
105
|
+
margin: 0;
|
|
106
|
+
text-align: center;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.opp-subtitle {
|
|
110
|
+
font-size: 13px;
|
|
111
|
+
color: var(--opp-muted);
|
|
112
|
+
margin: 0;
|
|
113
|
+
text-align: center;
|
|
114
|
+
line-height: 1.4;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.opp-status {
|
|
118
|
+
background: var(--opp-status-bg);
|
|
119
|
+
color: var(--opp-status-fg);
|
|
120
|
+
padding: 4px 12px;
|
|
121
|
+
border-radius: 999px;
|
|
122
|
+
font-size: 12px;
|
|
123
|
+
font-weight: 600;
|
|
124
|
+
margin-top: 4px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.opp-card {
|
|
128
|
+
background: var(--opp-card-bg);
|
|
129
|
+
border-radius: 8px;
|
|
130
|
+
margin: 0 16px;
|
|
131
|
+
padding: 12px 16px;
|
|
132
|
+
font-size: 13px;
|
|
133
|
+
display: flex;
|
|
134
|
+
flex-direction: column;
|
|
135
|
+
gap: 8px;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.opp-row {
|
|
139
|
+
display: flex;
|
|
140
|
+
justify-content: space-between;
|
|
141
|
+
align-items: center;
|
|
142
|
+
gap: 12px;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.opp-row-key {
|
|
146
|
+
color: var(--opp-muted);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.opp-row-value {
|
|
150
|
+
font-family: ui-monospace, SFMono-Regular, monospace;
|
|
151
|
+
font-size: 12px;
|
|
152
|
+
word-break: break-all;
|
|
153
|
+
text-align: right;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.opp-meta {
|
|
157
|
+
display: flex;
|
|
158
|
+
justify-content: space-between;
|
|
159
|
+
padding: 12px 20px;
|
|
160
|
+
font-size: 12px;
|
|
161
|
+
color: var(--opp-muted);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.opp-meta-value {
|
|
165
|
+
color: var(--opp-fg);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.opp-actions {
|
|
169
|
+
display: flex;
|
|
170
|
+
gap: 12px;
|
|
171
|
+
padding: 16px 20px 12px;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.opp-button {
|
|
175
|
+
flex: 1;
|
|
176
|
+
padding: 12px 16px;
|
|
177
|
+
border-radius: 8px;
|
|
178
|
+
font-size: 14px;
|
|
179
|
+
font-weight: 600;
|
|
180
|
+
cursor: pointer;
|
|
181
|
+
border: 1px solid transparent;
|
|
182
|
+
transition: opacity 120ms ease;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.opp-button:disabled {
|
|
186
|
+
opacity: 0.5;
|
|
187
|
+
cursor: not-allowed;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.opp-button-reject {
|
|
191
|
+
background: var(--opp-reject-bg);
|
|
192
|
+
color: var(--opp-reject-fg);
|
|
193
|
+
border-color: var(--opp-reject-border);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.opp-button-approve {
|
|
197
|
+
background: var(--opp-approve-bg);
|
|
198
|
+
color: var(--opp-approve-fg);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.opp-footer {
|
|
202
|
+
display: flex;
|
|
203
|
+
flex-direction: column;
|
|
204
|
+
align-items: center;
|
|
205
|
+
gap: 4px;
|
|
206
|
+
padding: 8px 20px 16px;
|
|
207
|
+
font-size: 11px;
|
|
208
|
+
color: var(--opp-muted);
|
|
209
|
+
text-align: center;
|
|
210
|
+
}
|
|
211
|
+
`;
|
|
212
|
+
|
|
213
|
+
// src/OneSatPermissionPrompt.tsx
|
|
214
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
215
|
+
function OneSatPermissionPrompt({
|
|
216
|
+
request,
|
|
217
|
+
onApprove,
|
|
218
|
+
onReject,
|
|
219
|
+
theme = "auto",
|
|
220
|
+
appName = "1Sat Ordinals",
|
|
221
|
+
version
|
|
222
|
+
}) {
|
|
223
|
+
const resolvedTheme = useResolvedTheme(theme);
|
|
224
|
+
const summary = summarizeRequest(request);
|
|
225
|
+
const [busy, setBusy] = useState(false);
|
|
226
|
+
const handle = (action) => () => {
|
|
227
|
+
if (busy)
|
|
228
|
+
return;
|
|
229
|
+
setBusy(true);
|
|
230
|
+
try {
|
|
231
|
+
if (action === "approve")
|
|
232
|
+
onApprove();
|
|
233
|
+
else
|
|
234
|
+
onReject();
|
|
235
|
+
} finally {
|
|
236
|
+
setBusy(false);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
const onKey = (e) => {
|
|
241
|
+
if (e.key === "Escape")
|
|
242
|
+
onReject();
|
|
243
|
+
else if (e.key === "Enter")
|
|
244
|
+
onApprove();
|
|
245
|
+
};
|
|
246
|
+
window.addEventListener("keydown", onKey);
|
|
247
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
248
|
+
}, [onApprove, onReject]);
|
|
249
|
+
const className = `opp-root${resolvedTheme === "dark" ? " opp-dark" : ""}`;
|
|
250
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
251
|
+
className,
|
|
252
|
+
children: [
|
|
253
|
+
/* @__PURE__ */ jsx("style", {
|
|
254
|
+
children: promptStyles
|
|
255
|
+
}),
|
|
256
|
+
/* @__PURE__ */ jsxs("div", {
|
|
257
|
+
className: "opp-header",
|
|
258
|
+
children: [
|
|
259
|
+
/* @__PURE__ */ jsxs("div", {
|
|
260
|
+
className: "opp-header-brand",
|
|
261
|
+
children: [
|
|
262
|
+
/* @__PURE__ */ jsx("div", {
|
|
263
|
+
className: "opp-avatar",
|
|
264
|
+
children: "1"
|
|
265
|
+
}),
|
|
266
|
+
/* @__PURE__ */ jsx("span", {
|
|
267
|
+
children: appName
|
|
268
|
+
})
|
|
269
|
+
]
|
|
270
|
+
}),
|
|
271
|
+
/* @__PURE__ */ jsxs("div", {
|
|
272
|
+
className: "opp-header-app",
|
|
273
|
+
children: [
|
|
274
|
+
/* @__PURE__ */ jsx("div", {
|
|
275
|
+
className: "opp-avatar opp-app",
|
|
276
|
+
children: originatorInitial(request.originator)
|
|
277
|
+
}),
|
|
278
|
+
/* @__PURE__ */ jsx("span", {
|
|
279
|
+
children: shortenOriginator(request.originator)
|
|
280
|
+
})
|
|
281
|
+
]
|
|
282
|
+
})
|
|
283
|
+
]
|
|
284
|
+
}),
|
|
285
|
+
/* @__PURE__ */ jsxs("div", {
|
|
286
|
+
className: "opp-body",
|
|
287
|
+
children: [
|
|
288
|
+
/* @__PURE__ */ jsx("div", {
|
|
289
|
+
className: "opp-icon",
|
|
290
|
+
"aria-hidden": "true",
|
|
291
|
+
children: "\uD83D\uDEE1"
|
|
292
|
+
}),
|
|
293
|
+
/* @__PURE__ */ jsx("h2", {
|
|
294
|
+
className: "opp-title",
|
|
295
|
+
children: summary.title
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ jsx("p", {
|
|
298
|
+
className: "opp-subtitle",
|
|
299
|
+
children: summary.subtitle
|
|
300
|
+
}),
|
|
301
|
+
/* @__PURE__ */ jsx("div", {
|
|
302
|
+
className: "opp-status",
|
|
303
|
+
children: "Awaiting Approval"
|
|
304
|
+
})
|
|
305
|
+
]
|
|
306
|
+
}),
|
|
307
|
+
summary.rows.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
308
|
+
className: "opp-card",
|
|
309
|
+
children: summary.rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
310
|
+
className: "opp-row",
|
|
311
|
+
children: [
|
|
312
|
+
/* @__PURE__ */ jsx("span", {
|
|
313
|
+
className: "opp-row-key",
|
|
314
|
+
children: row.key
|
|
315
|
+
}),
|
|
316
|
+
/* @__PURE__ */ jsx("span", {
|
|
317
|
+
className: "opp-row-value",
|
|
318
|
+
children: row.value
|
|
319
|
+
})
|
|
320
|
+
]
|
|
321
|
+
}, `${row.key}:${row.value}`))
|
|
322
|
+
}),
|
|
323
|
+
(summary.network || summary.feeSats !== undefined) && /* @__PURE__ */ jsxs("div", {
|
|
324
|
+
className: "opp-meta",
|
|
325
|
+
children: [
|
|
326
|
+
summary.network && /* @__PURE__ */ jsxs("span", {
|
|
327
|
+
children: [
|
|
328
|
+
"Network ",
|
|
329
|
+
/* @__PURE__ */ jsx("span", {
|
|
330
|
+
className: "opp-meta-value",
|
|
331
|
+
children: summary.network
|
|
332
|
+
})
|
|
333
|
+
]
|
|
334
|
+
}),
|
|
335
|
+
summary.feeSats !== undefined && /* @__PURE__ */ jsxs("span", {
|
|
336
|
+
children: [
|
|
337
|
+
"Estimated Fee",
|
|
338
|
+
" ",
|
|
339
|
+
/* @__PURE__ */ jsxs("span", {
|
|
340
|
+
className: "opp-meta-value",
|
|
341
|
+
children: [
|
|
342
|
+
summary.feeSats,
|
|
343
|
+
" sats"
|
|
344
|
+
]
|
|
345
|
+
})
|
|
346
|
+
]
|
|
347
|
+
})
|
|
348
|
+
]
|
|
349
|
+
}),
|
|
350
|
+
/* @__PURE__ */ jsxs("div", {
|
|
351
|
+
className: "opp-actions",
|
|
352
|
+
children: [
|
|
353
|
+
/* @__PURE__ */ jsx("button", {
|
|
354
|
+
type: "button",
|
|
355
|
+
className: "opp-button opp-button-reject",
|
|
356
|
+
onClick: handle("reject"),
|
|
357
|
+
disabled: busy,
|
|
358
|
+
children: "Reject"
|
|
359
|
+
}),
|
|
360
|
+
/* @__PURE__ */ jsx("button", {
|
|
361
|
+
type: "button",
|
|
362
|
+
className: "opp-button opp-button-approve",
|
|
363
|
+
onClick: handle("approve"),
|
|
364
|
+
disabled: busy,
|
|
365
|
+
children: "Approve"
|
|
366
|
+
})
|
|
367
|
+
]
|
|
368
|
+
}),
|
|
369
|
+
/* @__PURE__ */ jsxs("div", {
|
|
370
|
+
className: "opp-footer",
|
|
371
|
+
children: [
|
|
372
|
+
/* @__PURE__ */ jsxs("span", {
|
|
373
|
+
children: [
|
|
374
|
+
"Secured by ",
|
|
375
|
+
appName
|
|
376
|
+
]
|
|
377
|
+
}),
|
|
378
|
+
version && /* @__PURE__ */ jsxs("span", {
|
|
379
|
+
children: [
|
|
380
|
+
"v",
|
|
381
|
+
version
|
|
382
|
+
]
|
|
383
|
+
})
|
|
384
|
+
]
|
|
385
|
+
})
|
|
386
|
+
]
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
function useResolvedTheme(theme) {
|
|
390
|
+
const [resolved, setResolved] = useState(() => theme === "auto" ? readSystemTheme() : theme);
|
|
391
|
+
useEffect(() => {
|
|
392
|
+
if (theme !== "auto") {
|
|
393
|
+
setResolved(theme);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
397
|
+
const sync = () => setResolved(mq.matches ? "dark" : "light");
|
|
398
|
+
sync();
|
|
399
|
+
mq.addEventListener("change", sync);
|
|
400
|
+
return () => mq.removeEventListener("change", sync);
|
|
401
|
+
}, [theme]);
|
|
402
|
+
return resolved;
|
|
403
|
+
}
|
|
404
|
+
function readSystemTheme() {
|
|
405
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
406
|
+
return "light";
|
|
407
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
408
|
+
}
|
|
409
|
+
function summarizeRequest(req) {
|
|
410
|
+
if (req.kind === "transaction") {
|
|
411
|
+
return summarizeTransaction(req);
|
|
412
|
+
}
|
|
413
|
+
return summarizeSignature(req);
|
|
414
|
+
}
|
|
415
|
+
function summarizeTransaction(req) {
|
|
416
|
+
const intent = req.intent;
|
|
417
|
+
const rows = [];
|
|
418
|
+
let totalSats = 0;
|
|
419
|
+
for (const out of intent.outputs ?? []) {
|
|
420
|
+
totalSats += out.satoshis ?? 0;
|
|
421
|
+
if (out.outputDescription) {
|
|
422
|
+
rows.push({
|
|
423
|
+
key: out.outputDescription,
|
|
424
|
+
value: `${out.satoshis ?? 0} sats`
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
if (rows.length === 0 && totalSats > 0) {
|
|
429
|
+
rows.push({ key: "Total Out", value: `${totalSats} sats` });
|
|
430
|
+
}
|
|
431
|
+
return {
|
|
432
|
+
title: "Transaction Request",
|
|
433
|
+
subtitle: `${shortenOriginator(req.originator)} wants to ${req.summary.toLowerCase()}`,
|
|
434
|
+
rows,
|
|
435
|
+
network: "BSV Mainnet"
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function summarizeSignature(req) {
|
|
439
|
+
const intent = req.intent;
|
|
440
|
+
const rows = [];
|
|
441
|
+
if (intent.protocolID) {
|
|
442
|
+
rows.push({ key: "Protocol", value: JSON.stringify(intent.protocolID) });
|
|
443
|
+
}
|
|
444
|
+
if (intent.keyID)
|
|
445
|
+
rows.push({ key: "Key ID", value: intent.keyID });
|
|
446
|
+
if (intent.counterparty) {
|
|
447
|
+
rows.push({
|
|
448
|
+
key: "Counterparty",
|
|
449
|
+
value: shortenOriginator(intent.counterparty)
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
if (typeof intent.dataLength === "number") {
|
|
453
|
+
rows.push({ key: "Payload", value: `${intent.dataLength} bytes` });
|
|
454
|
+
}
|
|
455
|
+
return {
|
|
456
|
+
title: "Signature Request",
|
|
457
|
+
subtitle: `${shortenOriginator(req.originator)} requests a signature`,
|
|
458
|
+
rows
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
function shortenOriginator(origin) {
|
|
462
|
+
if (origin.length <= 28)
|
|
463
|
+
return origin;
|
|
464
|
+
return `${origin.slice(0, 18)}…${origin.slice(-6)}`;
|
|
465
|
+
}
|
|
466
|
+
function originatorInitial(origin) {
|
|
467
|
+
const cleaned = origin.replace(/^https?:\/\//, "");
|
|
468
|
+
const first = cleaned[0];
|
|
469
|
+
return first ? first.toUpperCase() : "?";
|
|
470
|
+
}
|
|
471
|
+
export {
|
|
472
|
+
OneSatPermissionPrompt
|
|
473
|
+
};
|
package/dist/styles.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS string for the OneSatPermissionPrompt component. Inlined as a style
|
|
3
|
+
* tag so the host wallet doesn't have to wire up CSS imports.
|
|
4
|
+
*
|
|
5
|
+
* Colors and spacing are kept minimal and theme-driven via CSS variables;
|
|
6
|
+
* a designer pass will replace these with the production palette.
|
|
7
|
+
*/
|
|
8
|
+
export declare const promptStyles = "\n.opp-root {\n --opp-bg: #ffffff;\n --opp-fg: #1a1a1a;\n --opp-muted: #6b7280;\n --opp-card-bg: #f5f5f7;\n --opp-card-border: #e5e7eb;\n --opp-accent: #f59e0b;\n --opp-approve-bg: #f59e0b;\n --opp-approve-fg: #ffffff;\n --opp-reject-bg: #ffffff;\n --opp-reject-fg: #1a1a1a;\n --opp-reject-border: #d1d5db;\n --opp-status-bg: #fde68a;\n --opp-status-fg: #92400e;\n\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n background: var(--opp-bg);\n color: var(--opp-fg);\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n width: 100%;\n max-width: 480px;\n overflow: hidden;\n}\n\n.opp-root.opp-dark {\n --opp-bg: #1a1a1a;\n --opp-fg: #f5f5f7;\n --opp-muted: #9ca3af;\n --opp-card-bg: #262626;\n --opp-card-border: #3a3a3a;\n --opp-reject-bg: #262626;\n --opp-reject-fg: #f5f5f7;\n --opp-reject-border: #3a3a3a;\n --opp-status-bg: rgba(245, 158, 11, 0.2);\n --opp-status-fg: #fbbf24;\n}\n\n.opp-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid var(--opp-card-border);\n}\n\n.opp-header-brand,\n.opp-header-app {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 13px;\n font-weight: 600;\n}\n\n.opp-avatar {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background: var(--opp-accent);\n color: #ffffff;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n flex-shrink: 0;\n}\n\n.opp-avatar.opp-app {\n background: #3b82f6;\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-icon {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: var(--opp-card-bg);\n border: 1px solid var(--opp-card-border);\n display: flex;\n align-items: center;\n justify-content: center;\n margin-bottom: 4px;\n}\n\n.opp-title {\n font-size: 18px;\n font-weight: 700;\n margin: 0;\n text-align: center;\n}\n\n.opp-subtitle {\n font-size: 13px;\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: 12px;\n font-weight: 600;\n margin-top: 4px;\n}\n\n.opp-card {\n background: var(--opp-card-bg);\n border-radius: 8px;\n margin: 0 16px;\n padding: 12px 16px;\n font-size: 13px;\n display: flex;\n flex-direction: column;\n gap: 8px;\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: ui-monospace, SFMono-Regular, monospace;\n font-size: 12px;\n word-break: break-all;\n text-align: right;\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}\n\n.opp-actions {\n display: flex;\n gap: 12px;\n padding: 16px 20px 12px;\n}\n\n.opp-button {\n flex: 1;\n padding: 12px 16px;\n border-radius: 8px;\n font-size: 14px;\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 flex-direction: column;\n align-items: center;\n gap: 4px;\n padding: 8px 20px 16px;\n font-size: 11px;\n color: var(--opp-muted);\n text-align: center;\n}\n";
|
|
9
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,yyHA4MxB,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@1sat/permission-module-ui",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "React component for the 1Sat permission module's prompt UX",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "bun run build.ts && tsc --emitDeclarationOnly",
|
|
19
|
+
"dev": "tsc --watch",
|
|
20
|
+
"clean": "rm -rf dist"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"1sat",
|
|
24
|
+
"bsv",
|
|
25
|
+
"wallet",
|
|
26
|
+
"permissions",
|
|
27
|
+
"react"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@1sat/permission-module": "0.0.1"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/react": "^19.0.0",
|
|
38
|
+
"react": "^19.0.0",
|
|
39
|
+
"typescript": "^5.9.3"
|
|
40
|
+
}
|
|
41
|
+
}
|