@cardano-slips/flow 0.2.0 → 0.3.0

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 (73) hide show
  1. package/README.md +53 -9
  2. package/dist/address.d.ts +12 -0
  3. package/dist/address.d.ts.map +1 -1
  4. package/dist/address.js +43 -0
  5. package/dist/address.js.map +1 -1
  6. package/dist/card.css +492 -0
  7. package/dist/card.d.ts +41 -0
  8. package/dist/card.d.ts.map +1 -0
  9. package/dist/card.js +69 -0
  10. package/dist/card.js.map +1 -0
  11. package/dist/complete-error.d.ts +8 -1
  12. package/dist/complete-error.d.ts.map +1 -1
  13. package/dist/complete-error.js +6 -1
  14. package/dist/complete-error.js.map +1 -1
  15. package/dist/complete.d.ts +29 -10
  16. package/dist/complete.d.ts.map +1 -1
  17. package/dist/complete.js +83 -9
  18. package/dist/complete.js.map +1 -1
  19. package/dist/derived.d.ts +8 -0
  20. package/dist/derived.d.ts.map +1 -0
  21. package/dist/derived.js +2 -0
  22. package/dist/derived.js.map +1 -0
  23. package/dist/effects-panel.d.ts +37 -0
  24. package/dist/effects-panel.d.ts.map +1 -0
  25. package/dist/effects-panel.js +64 -0
  26. package/dist/effects-panel.js.map +1 -0
  27. package/dist/effects.css +629 -0
  28. package/dist/exchange.d.ts +54 -0
  29. package/dist/exchange.d.ts.map +1 -0
  30. package/dist/exchange.js +136 -0
  31. package/dist/exchange.js.map +1 -0
  32. package/dist/explain.d.ts +39 -0
  33. package/dist/explain.d.ts.map +1 -0
  34. package/dist/explain.js +172 -0
  35. package/dist/explain.js.map +1 -0
  36. package/dist/index.d.ts +19 -3
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +9 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/ledger.d.ts +74 -0
  41. package/dist/ledger.d.ts.map +1 -0
  42. package/dist/ledger.js +402 -0
  43. package/dist/ledger.js.map +1 -0
  44. package/dist/outcome-panel.d.ts +63 -0
  45. package/dist/outcome-panel.d.ts.map +1 -0
  46. package/dist/outcome-panel.js +40 -0
  47. package/dist/outcome-panel.js.map +1 -0
  48. package/dist/parameter-form.d.ts +26 -0
  49. package/dist/parameter-form.d.ts.map +1 -0
  50. package/dist/parameter-form.js +42 -0
  51. package/dist/parameter-form.js.map +1 -0
  52. package/dist/slip-card.d.ts +55 -0
  53. package/dist/slip-card.d.ts.map +1 -0
  54. package/dist/slip-card.js +89 -0
  55. package/dist/slip-card.js.map +1 -0
  56. package/dist/tokens.css +57 -32
  57. package/package.json +9 -5
  58. package/src/address.ts +53 -0
  59. package/src/card.css +492 -0
  60. package/src/card.ts +86 -0
  61. package/src/complete-error.ts +14 -2
  62. package/src/complete.ts +128 -19
  63. package/src/derived.ts +8 -0
  64. package/src/effects-panel.tsx +386 -0
  65. package/src/effects.css +629 -0
  66. package/src/exchange.ts +212 -0
  67. package/src/explain.ts +211 -0
  68. package/src/index.ts +39 -3
  69. package/src/ledger.ts +503 -0
  70. package/src/outcome-panel.tsx +263 -0
  71. package/src/parameter-form.tsx +138 -0
  72. package/src/slip-card.tsx +244 -0
  73. package/src/tokens.css +57 -32
@@ -0,0 +1,42 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { valueOf } from "./card.js";
4
+ /**
5
+ * The bounds line. The spec requires it beside the field rather than only on
6
+ * failure, so a person can tell what will be accepted before they type.
7
+ */
8
+ export const boundsOf = (parameter) => {
9
+ if (parameter.type === "select") {
10
+ const labels = parameter.options.map((option) => option.label);
11
+ if (labels.length > 3)
12
+ return `${labels.length} options`;
13
+ if (labels.length === 1)
14
+ return labels[0];
15
+ return `${labels.slice(0, -1).join(", ")} or ${labels.at(-1)}`;
16
+ }
17
+ // On `text` the bounds count characters; on `number` they bound the value.
18
+ const unit = parameter.type === "text" ? " characters" : "";
19
+ if (parameter.min !== undefined && parameter.max !== undefined) {
20
+ return `Between ${parameter.min} and ${parameter.max}${unit}`;
21
+ }
22
+ // The same words `checkValues` uses, so the bounds and the sentence a broken
23
+ // value produces read as one voice rather than two.
24
+ if (parameter.min !== undefined)
25
+ return `At least ${parameter.min}${unit}`;
26
+ if (parameter.max !== undefined)
27
+ return `At most ${parameter.max}${unit}`;
28
+ return undefined;
29
+ };
30
+ const errorOf = (errors, name) => errors !== undefined && Object.hasOwn(errors, name) ? errors[name] : undefined;
31
+ const Field = ({ parameter, value, error, id, onChange }) => {
32
+ const helpId = `${id}-help`;
33
+ const invalid = error === undefined ? undefined : "";
34
+ const change = (next) => onChange(parameter.name, next);
35
+ return (_jsxs("div", { className: "slip-field", "data-invalid": invalid, children: [_jsx("label", { className: "slip-field__label", htmlFor: id, children: parameter.label }), _jsx("div", { className: "slip-field__control", children: parameter.type === "select" ? (_jsxs("select", { id: id, className: "slip-field__input", value: value, "aria-describedby": helpId, "aria-invalid": error === undefined ? undefined : true, onChange: (event) => change(event.target.value), children: [parameter.required === true && value !== "" ? undefined : _jsx("option", { value: "" }), parameter.options.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value)))] })) : (_jsx("input", { id: id, className: parameter.type === "number" ? "slip-field__input slip-field__input--numeral" : "slip-field__input", type: "text",
36
+ // Never `type="number"`: it hands back an empty string for anything
37
+ // the browser dislikes, which hides the very value `checkValues` is
38
+ // there to judge — and the person never learns what was wrong.
39
+ inputMode: parameter.type === "number" ? "decimal" : undefined, value: value, "aria-describedby": helpId, "aria-invalid": error === undefined ? undefined : true, onChange: (event) => change(event.target.value) })) }), _jsxs("div", { className: "slip-field__help", id: helpId, children: [_jsx("span", { className: "slip-field__bounds", children: error?.message ?? boundsOf(parameter) }), error?.code === undefined ? (_jsx("span", { className: "slip-field__note", children: parameter.required === true ? "Required" : "Optional" })) : (_jsx("span", { className: "slip-field__code", children: error.code }))] })] }));
40
+ };
41
+ export const ParameterForm = ({ parameters, values, errors, onChange, idPrefix = "slip" }) => (_jsx("div", { className: "slip-fields", children: parameters.map((parameter) => (_jsx(Field, { parameter: parameter, value: valueOf(values, parameter.name), error: errorOf(errors, parameter.name), id: `${idPrefix}-${parameter.name}`, onChange: onChange }, parameter.name))) }));
42
+ //# sourceMappingURL=parameter-form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parameter-form.js","sourceRoot":"","sources":["../src/parameter-form.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * The rendered face of a Slip link — `2 · Action card` on the design sheet.
3
+ * It renders what the endpoint declared and collects what the endpoint asked
4
+ * for; it makes no claim about the transaction, which is the effects panel's
5
+ * job and is checked against the bytes rather than against this card.
6
+ *
7
+ * The Slip is assumed to have been decoded and passed `checkTemplates`: a
8
+ * response with a placeholder naming no parameter is one a client never renders.
9
+ */
10
+ import { type LinkedAction, type ParameterValues, type Slip } from "@cardano-slips/core";
11
+ import { type FieldError } from "./parameter-form.js";
12
+ /** What the person chose, ready to `POST`. */
13
+ export type SlipSubmission = {
14
+ readonly action: LinkedAction;
15
+ /** Only what this action asked for. A caller is handed no answer it did not request. */
16
+ readonly values: ParameterValues;
17
+ /** Absolute, with every placeholder percent-encoded, so no typed value can move the request. */
18
+ readonly href: string;
19
+ };
20
+ export type SlipCardProps = {
21
+ readonly slip: Slip;
22
+ /**
23
+ * Where the metadata came from. Every `href` resolves against it and its host
24
+ * is the publisher the card names, so the card cannot be rendered without it.
25
+ */
26
+ readonly discoveryUrl: string;
27
+ readonly onSubmit?: (submission: SlipSubmission) => void;
28
+ /**
29
+ * What the endpoint refused, by parameter name. The only failure that lands
30
+ * on a field instead of replacing the card, because there is something to fix.
31
+ * It is the caller's to clear, since only the caller knows which answer the
32
+ * endpoint was refusing.
33
+ */
34
+ readonly rejected?: Readonly<Record<string, FieldError>>;
35
+ /** True while a request is in flight: every button stops taking presses. */
36
+ readonly busy?: boolean;
37
+ /** Prefixes generated ids, so two cards on one page do not collide. */
38
+ readonly idPrefix?: string;
39
+ };
40
+ export declare const SlipCard: ({ slip, discoveryUrl, onSubmit, rejected, busy, idPrefix }: SlipCardProps) => React.JSX.Element;
41
+ /** The same box and the same rhythm while the metadata is in flight, so nothing shifts when it lands. */
42
+ export declare const SlipCardSkeleton: () => React.JSX.Element;
43
+ export type SlipCardErrorProps = {
44
+ /** The endpoint that did not answer, in full: the person is being asked to judge it. */
45
+ readonly url: string;
46
+ readonly message: string;
47
+ readonly onRetry?: () => void;
48
+ };
49
+ /**
50
+ * The endpoint did not answer, or answered with something that is not a Slip.
51
+ * This replaces the card rather than landing on a field, because there is
52
+ * nothing here for the person to fix.
53
+ */
54
+ export declare const SlipCardError: ({ url, message, onRetry }: SlipCardErrorProps) => React.JSX.Element;
55
+ //# sourceMappingURL=slip-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slip-card.d.ts","sourceRoot":"","sources":["../src/slip-card.tsx"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,OAAO,EAAyB,KAAK,YAAY,EAAE,KAAK,eAAe,EAAE,KAAK,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAK/G,OAAO,EAAE,KAAK,UAAU,EAAiB,MAAM,qBAAqB,CAAA;AAEpE,8CAA8C;AAC9C,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAA;IAC7B,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAA;IAChC,gGAAgG;IAChG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG;IAC1B,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAA;IACnB;;;OAGG;IACH,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,UAAU,EAAE,cAAc,KAAK,IAAI,CAAA;IACxD;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAA;IACxD,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAA;IACvB,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAC3B,CAAA;AAQD,eAAO,MAAM,QAAQ,GAAI,4DAOtB,aAAa,KAAG,KAAK,CAAC,GAAG,CAAC,OAiI5B,CAAA;AAED,yGAAyG;AACzG,eAAO,MAAM,gBAAgB,QAAO,KAAK,CAAC,GAAG,CAAC,OAgB7C,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,wFAAwF;IACxF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAC9B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,2BAA2B,kBAAkB,KAAG,KAAK,CAAC,GAAG,CAAC,OAoBvF,CAAA"}
@@ -0,0 +1,89 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ /**
4
+ * The rendered face of a Slip link — `2 · Action card` on the design sheet.
5
+ * It renders what the endpoint declared and collects what the endpoint asked
6
+ * for; it makes no claim about the transaction, which is the effects panel's
7
+ * job and is checked against the bytes rather than against this card.
8
+ *
9
+ * The Slip is assumed to have been decoded and passed `checkTemplates`: a
10
+ * response with a placeholder naming no parameter is one a client never renders.
11
+ */
12
+ import { checkValues, fillHref } from "@cardano-slips/core";
13
+ import { Either } from "effect";
14
+ import { useState } from "react";
15
+ import { actionLabel, actionsOf, blockedLabel, closureOf, monogramOf, originOf, valuesFor } from "./card.js";
16
+ import { ParameterForm } from "./parameter-form.js";
17
+ /** The line that is the whole point of the card, and the reason it is worth pressing. */
18
+ const promise = "You'll see the exact effects, checked against this card, before you sign.";
19
+ /** Nothing to choose between means the one action is already the open one. */
20
+ const opened = (count) => (count === 1 ? 0 : undefined);
21
+ export const SlipCard = ({ slip, discoveryUrl, onSubmit, rejected, busy = false, idPrefix = "slip" }) => {
22
+ const actions = actionsOf(slip, discoveryUrl);
23
+ const [values, setValues] = useState({});
24
+ // Errors stay quiet until a send is attempted: a card that opens red is
25
+ // scolding someone for not having typed yet.
26
+ const [attempted, setAttempted] = useState(false);
27
+ const [open, setOpen] = useState(opened(actions.length));
28
+ const [failedIcon, setFailedIcon] = useState(undefined);
29
+ // Resetting during render is React's own answer to a prop moving out from
30
+ // under the state derived from it. A second Slip must not open pre-filled
31
+ // with the first one's answers, and remembering to pass a `key` is not a
32
+ // thing to leave to whoever embeds this.
33
+ const [shown, setShown] = useState(discoveryUrl);
34
+ if (shown !== discoveryUrl) {
35
+ setShown(discoveryUrl);
36
+ setValues({});
37
+ setAttempted(false);
38
+ setOpen(opened(actions.length));
39
+ setFailedIcon(undefined);
40
+ }
41
+ const closed = slip.disabled === true;
42
+ const parameters = (open === undefined ? undefined : actions[open]?.parameters) ?? [];
43
+ const issues = checkValues(parameters, values);
44
+ const blocked = attempted && issues.length > 0;
45
+ // `??=` would be wrong here: a parameter may be called `constructor`, and a
46
+ // plain object already answers to that with something that is not nullish.
47
+ const errors = {};
48
+ const note = (name, error) => {
49
+ if (!Object.hasOwn(errors, name))
50
+ errors[name] = error;
51
+ };
52
+ if (attempted)
53
+ for (const issue of issues)
54
+ note(issue.name, { message: issue.message });
55
+ for (const [name, error] of Object.entries(rejected ?? {}))
56
+ note(name, error);
57
+ const press = (index) => {
58
+ const action = actions[index];
59
+ // The spec: an action without parameters is submitted as soon as it is
60
+ // chosen. One that has them opens its form instead of sending blind.
61
+ if (action.parameters !== undefined && index !== open) {
62
+ setOpen(index);
63
+ setAttempted(false);
64
+ return;
65
+ }
66
+ const target = fillHref(action, values, discoveryUrl);
67
+ if (Either.isLeft(target)) {
68
+ setAttempted(true);
69
+ return;
70
+ }
71
+ onSubmit?.({ action, values: valuesFor(action, values), href: target.right });
72
+ };
73
+ const monogram = monogramOf(discoveryUrl);
74
+ const origin = originOf(discoveryUrl);
75
+ return (_jsxs("div", { className: "slip-root slip-card", "data-closed": closed ? "" : undefined, "data-busy": busy ? "" : undefined, children: [_jsxs("div", { className: "slip-card__head", children: [_jsx("div", { className: "slip-card__icon", children: failedIcon !== slip.icon ? (_jsx("img", { className: "slip-card__image", src: slip.icon, alt: "", onError: () => setFailedIcon(slip.icon) })) : monogram === undefined ? (_jsx("span", { className: "slip-card__pattern" })) : (_jsx("span", { className: "slip-card__monogram", children: monogram })) }), _jsxs("div", { className: "slip-card__identity", children: [_jsx("h2", { className: "slip-card__title", children: slip.title }), origin === undefined ? undefined : _jsx("span", { className: "slip-card__origin", children: origin })] })] }), _jsx("p", { className: "slip-card__description", children: slip.description }), parameters.length === 0 ? undefined : (_jsx(ParameterForm, { parameters: parameters, values: values, errors: errors, idPrefix: idPrefix, onChange: (name, value) => setValues((held) => ({ ...held, [name]: value })) })), _jsx("div", { className: "slip-card__actions", children: actions.map((action, index) => {
76
+ const closure = closureOf(slip, action);
77
+ const stopped = index === (open ?? 0) && blocked;
78
+ return (_jsx("button", { type: "button", className: "slip-card__action", "data-primary": index === (open ?? 0) ? "" : undefined, disabled: busy || closure !== undefined || stopped, onClick: () => press(index), children: stopped ? blockedLabel(issues) : actionLabel(slip, action, values) }, index));
79
+ }) }), closed ? (_jsx("p", { className: "slip-card__reason", children: slip.reason?.message })) : (actions.map((action, index) => action.disabled === true && action.reason !== undefined ? (_jsx("p", { className: "slip-card__reason", children: action.reason.message }, index)) : undefined)), closed ? undefined : _jsx("p", { className: "slip-card__note", children: promise })] }));
80
+ };
81
+ /** The same box and the same rhythm while the metadata is in flight, so nothing shifts when it lands. */
82
+ export const SlipCardSkeleton = () => (_jsxs("div", { className: "slip-root slip-card slip-card--loading", role: "status", "aria-busy": "true", children: [_jsx("span", { className: "slip-hidden", children: "Loading this Slip" }), _jsxs("div", { className: "slip-card__head", children: [_jsx("span", { className: "slip-skeleton slip-skeleton--icon" }), _jsxs("div", { className: "slip-card__identity", children: [_jsx("span", { className: "slip-skeleton slip-skeleton--title" }), _jsx("span", { className: "slip-skeleton slip-skeleton--origin" })] })] }), _jsxs("div", { className: "slip-skeleton__lines", children: [_jsx("span", { className: "slip-skeleton slip-skeleton--line" }), _jsx("span", { className: "slip-skeleton slip-skeleton--line slip-skeleton--short" })] }), _jsx("span", { className: "slip-skeleton slip-skeleton--action" })] }));
83
+ /**
84
+ * The endpoint did not answer, or answered with something that is not a Slip.
85
+ * This replaces the card rather than landing on a field, because there is
86
+ * nothing here for the person to fix.
87
+ */
88
+ export const SlipCardError = ({ url, message, onRetry }) => (_jsxs("div", { className: "slip-root slip-card slip-card--failed", role: "alert", children: [_jsxs("div", { className: "slip-card__head", children: [_jsx("span", { className: "slip-card__alarm", "aria-hidden": "true", children: "!" }), _jsxs("div", { className: "slip-card__identity", children: [_jsx("h2", { className: "slip-card__title", children: "This Slip didn't load" }), _jsx("span", { className: "slip-card__origin", children: url })] })] }), _jsx("p", { className: "slip-card__description", children: message }), onRetry === undefined ? undefined : (_jsx("div", { className: "slip-card__actions", children: _jsx("button", { type: "button", className: "slip-card__action", onClick: onRetry, children: "Try again" }) }))] }));
89
+ //# sourceMappingURL=slip-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slip-card.js","sourceRoot":"","sources":["../src/slip-card.tsx"],"names":[],"mappings":"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"}
package/dist/tokens.css CHANGED
@@ -10,7 +10,7 @@
10
10
  * already called `--ink`. Put `slip-root` on the element that wraps the Slip.
11
11
  *
12
12
  * There is no reset here and no rule that selects an element. Nothing sets a
13
- * font-family on anything — a component reads `var(--font-text)` — so a host
13
+ * font-family on anything — a component reads a `--type-*` role — so a host
14
14
  * page's own stack stays where it is until something of ours asks for a token.
15
15
  *
16
16
  * One theme. The sheet collapsed an earlier light/dark pair into a single
@@ -47,21 +47,26 @@
47
47
  * for and not about the ratio it happens to reach.
48
48
  */
49
49
  --accent-fill: #728ef3;
50
- --accent-text: #2f4bc4; /* links */
51
- --accent-action: #4361e8; /* button background */
52
- --accent-hover: #2f4bc4;
50
+ --accent-text: #123cd3; /* links */
51
+ --accent-action: #123cd3; /* the outline and the label of a button */
52
+ --accent-hover: #0e2fa6;
53
53
  --accent-deep: #0c288d; /* headings */
54
- --on-accent: #ffffff; /* anything drawn on --accent-action */
55
- --focus: #4361e8;
54
+ --on-accent: #ffffff; /* anything drawn on a filled accent */
55
+ --focus: #123cd3;
56
+
57
+ /* The accent lightened for slate, where #123cd3 disappears into the ground. */
58
+ --accent-on-slate: #8fa9ff;
56
59
 
57
60
  /* Semantic, and rare. A page that colours everything says nothing. */
58
- --pos: #1f7a5c; /* positive, refundable */
59
- --warn: #8c5a12;
60
- --bad: #b3261e;
61
- --bad-tint: rgba(179, 38, 30, 0.06);
62
- --bad-line: rgba(179, 38, 30, 0.24);
63
- --warn-tint: rgba(233, 180, 76, 0.16);
64
- --warn-line: rgba(233, 180, 76, 0.5);
61
+ --pos: #065708; /* value arriving */
62
+ --warn: #7a5200; /* held, taken, caution */
63
+ --bad: #d20a19; /* problem, blocked */
64
+ --bad-tint: rgba(210, 10, 25, 0.06);
65
+ --bad-line: rgba(210, 10, 25, 0.24);
66
+ --warn-tint: rgba(254, 206, 82, 0.22);
67
+ --warn-line: rgba(254, 206, 82, 0.85);
68
+ --warn-fill: #fece52; /* the warning as a fill, never as a word on a light ground */
69
+ --on-warn: #3a2600; /* words on the warning fill: the testnet bar */
65
70
 
66
71
  /* The alternating rows of the effects list, on and off. */
67
72
  --stripe-a: rgba(90, 110, 205, 0.16);
@@ -82,14 +87,19 @@
82
87
  --vault-border: rgba(255, 255, 255, 0.16);
83
88
  --vault-chip: rgba(168, 188, 255, 0.22);
84
89
  --vault-rule: rgba(168, 188, 255, 0.7);
85
- --vault-pos: #5fd1a6;
86
- --vault-warn: #e9b44c;
87
- --vault-bad: #ffa39b;
88
- --vault-bad-tint: rgba(255, 163, 155, 0.1);
89
- --vault-bad-line: rgba(255, 163, 155, 0.45);
90
- --vault-bad-chip: rgba(255, 163, 155, 0.18);
91
- --vault-warn-tint: rgba(233, 180, 76, 0.12);
92
- --vault-warn-line: rgba(233, 180, 76, 0.5);
90
+ --vault-pos: #6fcb72;
91
+ --vault-warn: #fece52;
92
+ /*
93
+ * #ff5247 on the sheet, lightened here: that value measures 4.42:1 on the
94
+ * vault and the sheet's own row calls it a pass. This is the colour the
95
+ * mismatch block is written in, so it clears AA or it does not ship.
96
+ */
97
+ --vault-bad: #ff5a50;
98
+ --vault-bad-tint: rgba(210, 10, 25, 0.16);
99
+ --vault-bad-line: rgba(255, 82, 71, 0.55);
100
+ --vault-bad-chip: rgba(210, 10, 25, 0.28);
101
+ --vault-warn-tint: rgba(254, 206, 82, 0.14);
102
+ --vault-warn-line: rgba(254, 206, 82, 0.55);
93
103
 
94
104
  /*
95
105
  * Code blocks in the docs and the Open Graph card. Both land on a ground we
@@ -101,21 +111,36 @@
101
111
  --dark-text: #ffffff;
102
112
  --dark-muted: #ccd6ff;
103
113
 
104
- /* Type. Each stack ends in a generic family, so a missing webfont degrades. */
105
- --font-display: Poppins, system-ui, sans-serif;
106
- --font-text: Figtree, system-ui, sans-serif;
107
- --font-mono: "IBM Plex Mono", ui-monospace, monospace;
114
+ /*
115
+ * One family, for everything. The sheet's earlier display/text/mono trio is
116
+ * gone: weight and size separate a heading from a label perfectly well, and
117
+ * three names for one face is three chances to drift apart. The stack ends in
118
+ * a generic family, so a missing webfont degrades rather than disappears.
119
+ */
120
+ --font: Poppins, system-ui, sans-serif;
108
121
 
109
122
  /* Whole roles, so half a role cannot be applied without the other half. */
110
- --type-h1: 700 44px/48px var(--font-display);
123
+ --type-h1: 700 44px/48px var(--font);
111
124
  --type-h1-tracking: -0.01em;
112
- --type-card-title: 700 18px/24px var(--font-display);
113
- --type-numeral: 700 26px/32px var(--font-display); /* a figure is always Poppins 700 */
114
- --type-body: 500 16px/24px var(--font-text);
115
- --type-button: 500 14px/20px var(--font-text);
125
+ --type-card-title: 700 18px/24px var(--font);
126
+ --type-numeral: 700 26px/32px var(--font); /* a figure is always 700 */
127
+ --type-body: 400 16px/24px var(--font);
128
+ --type-button: 500 14px/20px var(--font);
116
129
  --type-button-tracking: 0.1px;
117
- --type-label: 500 13px var(--font-text);
118
- --type-mono: 400 12px/20px var(--font-mono); /* addresses, hashes, the tx block */
130
+ --type-label: 500 13px var(--font);
131
+ /* Addresses, hashes, error codes, the tx block — text meant for a machine. */
132
+ --type-technical: 400 12px/20px var(--font);
133
+
134
+ /* The transaction preview's own scale, from `4 · Anatomy` and `6 · Preview states`. */
135
+ --type-headline: 700 32px/38px var(--font); /* the one figure the person is deciding on */
136
+ --type-preview-title: 700 20px/26px var(--font);
137
+ --type-amount: 700 20px/26px var(--font); /* a row's figure, one size so the column scans */
138
+ --type-countdown: 700 16px/20px var(--font);
139
+ --type-row: 400 14px/20px var(--font);
140
+ --type-note: 400 13px/19px var(--font);
141
+ --type-kicker: 400 11px/16px var(--font);
142
+ --type-kicker-tracking: 0.12em;
143
+ --type-chip: 600 11px/20px var(--font);
119
144
 
120
145
  /* Spacing, on a 4px base. */
121
146
  --space-4: 4px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cardano-slips/flow",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "The client side of Cardano Slips: CIP-30 orchestration, local balancing, and the React components that render a Slip and block a signature when its effects disagree",
5
5
  "keywords": [
6
6
  "cardano",
@@ -18,12 +18,16 @@
18
18
  },
19
19
  "license": "MIT",
20
20
  "type": "module",
21
- "sideEffects": false,
21
+ "sideEffects": [
22
+ "*.css"
23
+ ],
22
24
  "exports": {
23
25
  ".": {
24
26
  "types": "./dist/index.d.ts",
25
27
  "default": "./dist/index.js"
26
28
  },
29
+ "./card.css": "./dist/card.css",
30
+ "./effects.css": "./dist/effects.css",
27
31
  "./tokens.css": "./dist/tokens.css",
28
32
  "./package.json": "./package.json"
29
33
  },
@@ -45,8 +49,8 @@
45
49
  "@evolution-sdk/evolution": "^0.5.13",
46
50
  "@noble/hashes": "^2.0.1",
47
51
  "effect": "^3.22.1",
48
- "@cardano-slips/verifier": "^0.3.0",
49
- "@cardano-slips/core": "^0.2.0"
52
+ "@cardano-slips/core": "^0.3.0",
53
+ "@cardano-slips/verifier": "^0.4.0"
50
54
  },
51
55
  "devDependencies": {
52
56
  "@testing-library/react": "^16.3.2",
@@ -58,7 +62,7 @@
58
62
  "@cardano-slips/example-slips": "^0.0.0"
59
63
  },
60
64
  "scripts": {
61
- "build": "tsc -b tsconfig.build.json && mkdir -p dist && cp src/tokens.css dist/tokens.css",
65
+ "build": "tsc -b tsconfig.build.json && mkdir -p dist && cp src/*.css dist/",
62
66
  "typecheck": "tsc -b tsconfig.src.json && tsc -p tsconfig.test.json",
63
67
  "test": "vitest run",
64
68
  "lint": "eslint .",
package/src/address.ts CHANGED
@@ -67,3 +67,56 @@ export const readWalletAddress = (hex: string): Either.Either<WalletAddress, str
67
67
  onRight: () => Either.right({ bech32, networkId: networkId as NetworkId })
68
68
  })
69
69
  }
70
+
71
+ export type OwnAddress = {
72
+ /** Raw, as the verifier compares them against the body's addresses. */
73
+ readonly bytes: Uint8Array
74
+ /** Absent for a Byron address, whose header carries no network. */
75
+ readonly networkId?: NetworkId
76
+ }
77
+
78
+ const BYRON_TYPE = 8
79
+ const FIRST_REWARD_TYPE = 14
80
+ const LAST_REWARD_TYPE = 15
81
+
82
+ /** A header byte and one or two 28-byte hashes. */
83
+ const shelleyLengths: Readonly<Record<number, ReadonlyArray<number>>> = {
84
+ 0: [57],
85
+ 1: [57],
86
+ 2: [57],
87
+ 3: [57],
88
+ 6: [29],
89
+ 7: [29],
90
+ 14: [29],
91
+ 15: [29]
92
+ }
93
+
94
+ /**
95
+ * Reads an address the wallet calls its own: any payment address, a reward
96
+ * account, or a Byron address an old wallet still reports as used. Refusing
97
+ * the Byron one would stop the whole flow over an address nothing here spends.
98
+ */
99
+ export const readOwnAddress = (hex: unknown): Either.Either<OwnAddress, string> => {
100
+ // Typed as hex by CIP-30, and sent by an extension under no obligation to.
101
+ const raw = typeof hex === "string" ? fromHex(hex.trim()) : undefined
102
+ if (raw === undefined) return refuse(`${String(hex).slice(0, 16)}… is not hex`)
103
+
104
+ const bytes = unwrapCbor(raw)
105
+ const header = bytes[0]
106
+ const type = header >> 4
107
+ if (type === BYRON_TYPE) return Either.right({ bytes })
108
+
109
+ const networkId = header & 0x0f
110
+ if (networkId !== 0 && networkId !== 1) return refuse(`the address header names network ${networkId}`)
111
+
112
+ const payment = type <= LAST_PAYMENT_TYPE
113
+ const reward = type >= FIRST_REWARD_TYPE && type <= LAST_REWARD_TYPE
114
+ if (!payment && !reward) return refuse(`address type ${type} is not one a wallet holds`)
115
+
116
+ // Pointer addresses (4, 5) end in variable-length integers, so only a floor applies.
117
+ const lengths = shelleyLengths[type]
118
+ const fits = lengths === undefined ? bytes.length > 29 : lengths.includes(bytes.length)
119
+ if (!fits) return refuse(`${bytes.length} bytes is the wrong length for address type ${type}`)
120
+
121
+ return Either.right({ bytes, networkId: networkId as NetworkId })
122
+ }