@bootnodedev/canton-dappbooster 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.
- package/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/connect.d.ts +135 -0
- package/dist/connect.js +296 -0
- package/dist/index.d.ts +704 -0
- package/dist/index.js +1675 -0
- package/dist/json-CVZFwEw1.js +29 -0
- package/dist/sumHoldings-BS0bHl7z.d.ts +94 -0
- package/package.json +74 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/utils/cx.ts
|
|
2
|
+
const cx = (...classes) => classes.filter(Boolean).join(" ");
|
|
3
|
+
//#endregion
|
|
4
|
+
//#region src/utils/srOnly.ts
|
|
5
|
+
/**
|
|
6
|
+
* Hides an element visually while leaving it in the accessibility tree. Inline rather than themed
|
|
7
|
+
* because a live region is load-bearing with no CSS loaded, and `display: none` would drop it out
|
|
8
|
+
* of the tree entirely.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* <span role="status" style={SR_ONLY}>{message}</span>
|
|
12
|
+
*/
|
|
13
|
+
const SR_ONLY = {
|
|
14
|
+
position: "absolute",
|
|
15
|
+
width: 1,
|
|
16
|
+
height: 1,
|
|
17
|
+
margin: -1,
|
|
18
|
+
padding: 0,
|
|
19
|
+
overflow: "hidden",
|
|
20
|
+
whiteSpace: "nowrap",
|
|
21
|
+
border: 0,
|
|
22
|
+
clipPath: "inset(50%)"
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/utils/json.ts
|
|
26
|
+
const asRecord = (value) => typeof value === "object" && value !== null ? value : void 0;
|
|
27
|
+
const valueAt = (value, ...path) => path.reduce((at, key) => asRecord(at)?.[key], value);
|
|
28
|
+
//#endregion
|
|
29
|
+
export { cx as i, valueAt as n, SR_ONLY as r, asRecord as t };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
//#region src/providers/TokenListProvider/context.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* What identifies a token on Canton: the party administering the registry that issued it, and the
|
|
5
|
+
* id it carries there. Two fields, so {@link tokenKey} is what turns one into a map or React key.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const amulet: InstrumentId = { admin: 'DSO::1220ab', id: 'Amulet' }
|
|
9
|
+
*
|
|
10
|
+
* @category Hooks
|
|
11
|
+
*/
|
|
12
|
+
interface InstrumentId {
|
|
13
|
+
admin: string;
|
|
14
|
+
id: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A token in the list a picker chooses from. Structurally a `TokenMeta`, so a selected `Token` goes
|
|
18
|
+
* straight to `<TokenInput token={...}>`. `balance` is what the party can spend and `locked` what it
|
|
19
|
+
* cannot, both off a holdings read: with no `balance` the row shows no figure and sorts last.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* const cc: Token = {
|
|
23
|
+
* balance: '12.5',
|
|
24
|
+
* instrumentId: { admin: 'DSO::1220ab', id: 'Amulet' },
|
|
25
|
+
* locked: '100',
|
|
26
|
+
* name: 'Canton Coin',
|
|
27
|
+
* symbol: 'CC',
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* @category Hooks
|
|
31
|
+
*/
|
|
32
|
+
interface Token {
|
|
33
|
+
balance?: string;
|
|
34
|
+
instrumentId: InstrumentId;
|
|
35
|
+
locked?: string;
|
|
36
|
+
logo?: ReactNode;
|
|
37
|
+
name: string;
|
|
38
|
+
symbol: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Return shape of {@link useTokenList}. `byKey` is built from `tokens`, so the two never disagree,
|
|
42
|
+
* and both carry the balance-first order the provider settled on.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const { byKey, tokens } = useTokenList()
|
|
46
|
+
* const selected = byKey.get(tokenKey(instrumentId)) ?? tokens[0]
|
|
47
|
+
*
|
|
48
|
+
* @category Hooks
|
|
49
|
+
*/
|
|
50
|
+
interface UseTokenListResult {
|
|
51
|
+
byKey: ReadonlyMap<string, Token>;
|
|
52
|
+
tokens: readonly Token[];
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/utils/sumHoldings.d.ts
|
|
56
|
+
/**
|
|
57
|
+
* One holding contract a party owns, as {@link useHoldings} reports it. A locked one is escrowed,
|
|
58
|
+
* which is why the two are summed apart.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const spendable = holdings.filter((holding) => !holding.isLocked)
|
|
62
|
+
*
|
|
63
|
+
* @category Utilities
|
|
64
|
+
*/
|
|
65
|
+
interface Holding {
|
|
66
|
+
amount: string;
|
|
67
|
+
instrumentId: InstrumentId;
|
|
68
|
+
isLocked: boolean;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* What a party holds of one instrument: `balance` is spendable, `locked` is escrowed.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* const [{ balance, locked }] = sumHoldings(holdings)
|
|
75
|
+
*
|
|
76
|
+
* @category Utilities
|
|
77
|
+
*/
|
|
78
|
+
interface InstrumentBalance {
|
|
79
|
+
balance: string;
|
|
80
|
+
instrumentId: InstrumentId;
|
|
81
|
+
locked: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Groups a holdings read by instrument and sums it, spendable apart from locked.
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* sumHoldings([{ amount: '1.5', instrumentId, isLocked: false }])
|
|
88
|
+
* // [{ balance: '1.5', instrumentId, locked: '0' }]
|
|
89
|
+
*
|
|
90
|
+
* @category Utilities
|
|
91
|
+
*/
|
|
92
|
+
declare const sumHoldings: (holdings: readonly Holding[]) => readonly InstrumentBalance[];
|
|
93
|
+
//#endregion
|
|
94
|
+
export { Token as a, InstrumentId as i, InstrumentBalance as n, UseTokenListResult as o, sumHoldings as r, Holding as t };
|
package/package.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bootnodedev/canton-dappbooster",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Reusable UI components for Canton dApps",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"private": false,
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"sideEffects": false,
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=24.15.0"
|
|
14
|
+
},
|
|
15
|
+
"module": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"exports": {
|
|
21
|
+
".": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"import": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./connect": {
|
|
26
|
+
"types": "./dist/connect.d.ts",
|
|
27
|
+
"import": "./dist/connect.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"imports": {
|
|
31
|
+
"#src/*": {
|
|
32
|
+
"types": [
|
|
33
|
+
"./src/*.ts",
|
|
34
|
+
"./src/*.tsx",
|
|
35
|
+
"./src/*/index.ts",
|
|
36
|
+
"./src/*/index.tsx"
|
|
37
|
+
],
|
|
38
|
+
"default": "./src/*"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@bootnodedev/canton-connect": "^0.3.0",
|
|
43
|
+
"@testing-library/dom": "^10.4.1",
|
|
44
|
+
"@testing-library/jest-dom": "^7.0.0",
|
|
45
|
+
"@testing-library/react": "^16.3.2",
|
|
46
|
+
"@types/react": "^19.2.17",
|
|
47
|
+
"@types/react-dom": "^19.2.3",
|
|
48
|
+
"@vitejs/plugin-react": "^6.0.4",
|
|
49
|
+
"jsdom": "^30.0.0",
|
|
50
|
+
"react": "^19.2.8",
|
|
51
|
+
"react-dom": "^19.2.8",
|
|
52
|
+
"tsdown": "^0.22.14",
|
|
53
|
+
"typescript": "^5.9.3",
|
|
54
|
+
"vite": "^8.1.5",
|
|
55
|
+
"vitest": "^4.1.10"
|
|
56
|
+
},
|
|
57
|
+
"peerDependencies": {
|
|
58
|
+
"@bootnodedev/canton-connect": "^0.3.0",
|
|
59
|
+
"react": "^19.0.0",
|
|
60
|
+
"react-dom": "^19.0.0"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"@zag-js/dialog": "^1.43.0",
|
|
64
|
+
"@zag-js/react": "^1.43.0"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"build": "tsdown",
|
|
68
|
+
"lint:fix": "biome check --write",
|
|
69
|
+
"lint": "biome check",
|
|
70
|
+
"test:watch": "vitest",
|
|
71
|
+
"test": "vitest run",
|
|
72
|
+
"typecheck": "tsc --noEmit"
|
|
73
|
+
}
|
|
74
|
+
}
|