@lukso/transaction-view-headless 0.2.2-dev.a8c9315

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 (76) hide show
  1. package/.turbo/turbo-build.log +51 -0
  2. package/CHANGELOG.md +88 -0
  3. package/COMPONENT_ARCHITECTURE.md +190 -0
  4. package/COMPONENT_CONVERSION_ANALYSIS.md +371 -0
  5. package/CONTEXT_VARIANT_GUIDE.md +425 -0
  6. package/LAZY_LOADING_GUIDE.md +534 -0
  7. package/LICENSE +201 -0
  8. package/PLAYBACK_EXAMPLES.md +658 -0
  9. package/PLAYBACK_GUIDE.md +402 -0
  10. package/README.md +43 -0
  11. package/REGISTRY_SUMMARY.md +638 -0
  12. package/SUFFERING_ECONOMICS.md +346 -0
  13. package/SUFFERING_ECONOMICS.zip +0 -0
  14. package/VIEW_REGISTRATION_GUIDE.md +795 -0
  15. package/dist/composables/index.cjs +1321 -0
  16. package/dist/composables/index.cjs.map +1 -0
  17. package/dist/composables/index.d.cts +6 -0
  18. package/dist/composables/index.d.ts +6 -0
  19. package/dist/composables/index.js +1276 -0
  20. package/dist/composables/index.js.map +1 -0
  21. package/dist/index-CMLU1hKL.d.ts +374 -0
  22. package/dist/index-CSDjhiKV.d.cts +374 -0
  23. package/dist/index.cjs +1534 -0
  24. package/dist/index.cjs.map +1 -0
  25. package/dist/index.d.cts +93 -0
  26. package/dist/index.d.ts +93 -0
  27. package/dist/index.js +1463 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/registry/index.cjs +522 -0
  30. package/dist/registry/index.cjs.map +1 -0
  31. package/dist/registry/index.d.cts +46 -0
  32. package/dist/registry/index.d.ts +46 -0
  33. package/dist/registry/index.js +487 -0
  34. package/dist/registry/index.js.map +1 -0
  35. package/dist/types/index.cjs +19 -0
  36. package/dist/types/index.cjs.map +1 -0
  37. package/dist/types/index.d.cts +203 -0
  38. package/dist/types/index.d.ts +203 -0
  39. package/dist/types/index.js +1 -0
  40. package/dist/types/index.js.map +1 -0
  41. package/dist/utils/index.cjs +217 -0
  42. package/dist/utils/index.cjs.map +1 -0
  43. package/dist/utils/index.d.cts +47 -0
  44. package/dist/utils/index.d.ts +47 -0
  45. package/dist/utils/index.js +188 -0
  46. package/dist/utils/index.js.map +1 -0
  47. package/dist/view-loader-dD86QAlQ.d.cts +121 -0
  48. package/dist/view-loader-ii8AxiQR.d.ts +121 -0
  49. package/package.json +64 -0
  50. package/publish.log +0 -0
  51. package/src/composables/index.ts +59 -0
  52. package/src/composables/use-image-loader.ts +315 -0
  53. package/src/composables/use-transaction-playback.ts +396 -0
  54. package/src/composables/use-transaction-view.ts +309 -0
  55. package/src/config/lukso-config.ts +171 -0
  56. package/src/examples/context-aware-views.ts +300 -0
  57. package/src/examples/example-views.ts +197 -0
  58. package/src/examples/lit-plus-rn-strategy.ts +448 -0
  59. package/src/examples/lsp7-custom-matcher-examples.ts +174 -0
  60. package/src/examples/opt-in-context-examples.ts +372 -0
  61. package/src/examples/optimized-view-definitions.ts +408 -0
  62. package/src/examples/vue-to-lit-compilation.ts +358 -0
  63. package/src/hooks/useAddressQuery.ts +135 -0
  64. package/src/hooks/useAddressResolution.ts +437 -0
  65. package/src/index.ts +36 -0
  66. package/src/registry/index.ts +13 -0
  67. package/src/registry/view-loader.ts +305 -0
  68. package/src/registry/view-registry.ts +135 -0
  69. package/src/types/index.ts +16 -0
  70. package/src/types/view-contexts.ts +72 -0
  71. package/src/types/view-matching.ts +173 -0
  72. package/src/utils/context-matcher.ts +165 -0
  73. package/src/utils/index.ts +5 -0
  74. package/src/utils/view-matcher.ts +338 -0
  75. package/tsconfig.json +20 -0
  76. package/tsup.config.ts +34 -0
@@ -0,0 +1,358 @@
1
+ /**
2
+ * "Let the developers suffer" - The Compilation Escape Hatch 😈
3
+ *
4
+ * If developers really complain about writing Lit components,
5
+ * we can let them write Vue/React and compile to Lit!
6
+ *
7
+ * This gives us the best of both worlds:
8
+ * - Developers get to write in their preferred framework
9
+ * - End users get universal web components
10
+ * - We still only ship ONE implementation per component
11
+ */
12
+
13
+ export const VueToLitCompilation = {
14
+ // Developer writes Vue (comfortable)
15
+ source: `
16
+ <!-- LSP7Transfer.vue - Developer writes this -->
17
+ <template>
18
+ <div class="lsp7-transfer">
19
+ <div class="transfer-flow">
20
+ <AddressDisplay
21
+ :address="transaction.from"
22
+ :resolved="addressData[transaction.from]"
23
+ @click="$emit('address-click', transaction.from)"
24
+ />
25
+ <div class="arrow">→</div>
26
+ <AddressDisplay
27
+ :address="transaction.to"
28
+ :resolved="addressData[transaction.to]"
29
+ />
30
+ </div>
31
+
32
+ <div class="amount">
33
+ {{ formatAmount(transaction.amount) }} {{ transaction.symbol }}
34
+ </div>
35
+
36
+ <div v-if="showActions" class="actions">
37
+ <button @click="$emit('reject', transaction)">Reject</button>
38
+ <button @click="$emit('approve', transaction)">Approve</button>
39
+ </div>
40
+ </div>
41
+ </template>
42
+
43
+ <script setup>
44
+ import { useTransactionView } from '@lukso/transaction-view-headless'
45
+
46
+ const props = defineProps(['transaction', 'showActions'])
47
+ const emit = defineEmits(['approve', 'reject', 'address-click'])
48
+
49
+ const { addressData, formatAmount } = useTransactionView(props.transaction, {
50
+ framework: 'lit' // Still uses headless system
51
+ })
52
+ </script>
53
+
54
+ <style scoped>
55
+ .lsp7-transfer { padding: 16px; }
56
+ .transfer-flow { display: flex; align-items: center; gap: 12px; }
57
+ .amount { font-size: 18px; font-weight: bold; }
58
+ </style>`,
59
+
60
+ // Build tool compiles to Lit (universal)
61
+ compiled: `
62
+ // lsp7-transfer-view.ts - Build tool generates this
63
+ import { LitElement, html, css } from 'lit'
64
+ import { customElement, property } from 'lit/decorators.js'
65
+ import { useTransactionView } from '@lukso/transaction-view-headless'
66
+
67
+ @customElement('lsp7-transfer-view')
68
+ export class LSP7TransferView extends LitElement {
69
+ @property({ type: Object }) transaction = null
70
+ @property({ type: Boolean }) showActions = false
71
+
72
+ private addressData = {}
73
+ private formatAmount = (x) => x
74
+
75
+ override async connectedCallback() {
76
+ super.connectedCallback()
77
+ if (this.transaction) {
78
+ const viewData = await useTransactionView(this.transaction, {
79
+ framework: 'lit'
80
+ })
81
+ this.addressData = viewData.addressData
82
+ this.formatAmount = viewData.formatAmount
83
+ this.requestUpdate()
84
+ }
85
+ }
86
+
87
+ override render() {
88
+ return html\`
89
+ <div class="lsp7-transfer">
90
+ <div class="transfer-flow">
91
+ <address-display
92
+ .address=\${this.transaction.from}
93
+ .resolved=\${this.addressData[this.transaction.from]}
94
+ @click=\${() => this._emit('address-click', this.transaction.from)}
95
+ ></address-display>
96
+ <div class="arrow">→</div>
97
+ <address-display
98
+ .address=\${this.transaction.to}
99
+ .resolved=\${this.addressData[this.transaction.to]}
100
+ ></address-display>
101
+ </div>
102
+
103
+ <div class="amount">
104
+ \${this.formatAmount(this.transaction.amount)} \${this.transaction.symbol}
105
+ </div>
106
+
107
+ \${this.showActions ? html\`
108
+ <div class="actions">
109
+ <button @click=\${() => this._emit('reject', this.transaction)}>
110
+ Reject
111
+ </button>
112
+ <button @click=\${() => this._emit('approve', this.transaction)}>
113
+ Approve
114
+ </button>
115
+ </div>
116
+ \` : ''}
117
+ </div>
118
+ \`
119
+ }
120
+
121
+ static styles = css\`
122
+ .lsp7-transfer { padding: 16px; }
123
+ .transfer-flow { display: flex; align-items: center; gap: 12px; }
124
+ .amount { font-size: 18px; font-weight: bold; }
125
+ \`
126
+
127
+ private _emit(eventName, detail) {
128
+ this.dispatchEvent(new CustomEvent(eventName, { detail, bubbles: true }))
129
+ }
130
+ }`,
131
+ }
132
+
133
+ /**
134
+ * React to Lit compilation (using existing tools)
135
+ */
136
+ export const ReactToLitCompilation = {
137
+ // Developer writes React
138
+ source: `
139
+ // LSP7Transfer.jsx - Developer writes this
140
+ import { useTransactionView } from '@lukso/transaction-view-headless'
141
+
142
+ export function LSP7Transfer({ transaction, showActions, onApprove, onReject, onAddressClick }) {
143
+ const { addressData, formatAmount } = useTransactionView(transaction, {
144
+ framework: 'lit'
145
+ })
146
+
147
+ return (
148
+ <div className="lsp7-transfer">
149
+ <div className="transfer-flow">
150
+ <AddressDisplay
151
+ address={transaction.from}
152
+ resolved={addressData[transaction.from]}
153
+ onClick={() => onAddressClick?.(transaction.from)}
154
+ />
155
+ <div className="arrow">→</div>
156
+ <AddressDisplay
157
+ address={transaction.to}
158
+ resolved={addressData[transaction.to]}
159
+ />
160
+ </div>
161
+
162
+ <div className="amount">
163
+ {formatAmount(transaction.amount)} {transaction.symbol}
164
+ </div>
165
+
166
+ {showActions && (
167
+ <div className="actions">
168
+ <button onClick={() => onReject?.(transaction)}>Reject</button>
169
+ <button onClick={() => onApprove?.(transaction)}>Approve</button>
170
+ </div>
171
+ )}
172
+ </div>
173
+ )
174
+ }`,
175
+
176
+ // Tools like @lit-labs/react-to-lit could handle compilation
177
+ compiled: `// Same Lit output as above, but compiled from React`,
178
+ }
179
+
180
+ /**
181
+ * Existing tools for compilation approaches
182
+ */
183
+ export const ExistingTools = {
184
+ vueToWebComponents: `
185
+ // Vue has built-in web component compilation!
186
+ // vue.config.js
187
+ module.exports = {
188
+ configureWebpack: {
189
+ output: {
190
+ libraryTarget: 'system'
191
+ }
192
+ }
193
+ }
194
+
195
+ // Build command
196
+ vue-cli-service build --target lib --name lsp7-transfer src/LSP7Transfer.vue
197
+
198
+ // Outputs: Custom element that works everywhere!`,
199
+
200
+ reactToWebComponents: `
201
+ // Multiple options for React -> Web Components:
202
+
203
+ // 1. Stencil.js (most mature)
204
+ import { Component, Prop, h } from '@stencil/core'
205
+
206
+ @Component({ tag: 'lsp7-transfer-view' })
207
+ export class LSP7Transfer {
208
+ @Prop() transaction: any
209
+
210
+ render() {
211
+ return <div>...</div> // JSX works in Stencil
212
+ }
213
+ }
214
+
215
+ // 2. @lit-labs/react (experimental)
216
+ // 3. Preact with custom elements
217
+ // 4. React 18's upcoming web components support`,
218
+
219
+ buildToolIntegration: `
220
+ // Custom build tool integration
221
+ // packages/decoder-web-components/build.config.js
222
+
223
+ export default {
224
+ input: {
225
+ 'vue-components': './src/vue/**/*.vue',
226
+ 'react-components': './src/react/**/*.jsx'
227
+ },
228
+
229
+ plugins: [
230
+ vueToLit(), // Custom plugin
231
+ reactToLit(), // Custom plugin
232
+ ],
233
+
234
+ output: {
235
+ dir: 'dist/web-components',
236
+ format: 'es'
237
+ }
238
+ }
239
+
240
+ // Result: Universal web components from familiar source code`,
241
+ }
242
+
243
+ /**
244
+ * The developer experience strategy
245
+ */
246
+ export const DeveloperExperienceStrategy = {
247
+ // Phase 1: Start with Lit (for the brave)
248
+ phase1: `
249
+ Let experienced developers write Lit directly:
250
+ - Better performance (no compilation overhead)
251
+ - Full control over web component lifecycle
252
+ - Direct access to Shadow DOM features
253
+ - Learning opportunity for modern web standards`,
254
+
255
+ // Phase 2: Compilation escape hatch (for the complainers)
256
+ phase2: `
257
+ If developers really complain:
258
+ - Vue developers can write .vue files
259
+ - React developers can write JSX
260
+ - Build tool compiles to Lit web components
261
+ - Everyone gets the same universal output
262
+ - "You can write Vue, but you're shipping Lit" 😈`,
263
+
264
+ // Phase 3: Best of both worlds
265
+ phase3: `
266
+ Mixed approach:
267
+ - Complex components: Write in Lit (full control)
268
+ - Simple components: Write in Vue/React (faster development)
269
+ - Build system handles compilation
270
+ - All output universal web components
271
+ - Developers pick their poison per component`,
272
+ }
273
+
274
+ /**
275
+ * Package structure with compilation support
276
+ */
277
+ export const CompilationPackageStructure = `
278
+ packages/
279
+ ├── decoder-headless/ # Business logic
280
+ │
281
+ ├── decoder-web-components/ # The universal output
282
+ │ ├── dist/ # Compiled web components
283
+ │ │ ├── lsp7-transfer-view.js # Universal web component
284
+ │ │ ├── lsp8-transfer-view.js # Works in all frameworks
285
+ │ │ └── execute-batch-view.js # Ships to production
286
+ │ │
287
+ │ ├── src/ # Source can be mixed!
288
+ │ │ ├── lit/ # Hand-written Lit (performance-critical)
289
+ │ │ │ └── complex-transaction.ts # When you need full control
290
+ │ │ ├── vue/ # Vue source (developer-friendly)
291
+ │ │ │ ├── LSP7Transfer.vue # Compiled to web component
292
+ │ │ │ └── LSP8Transfer.vue # Vue DX, Lit output
293
+ │ │ └── react/ # React source (developer-friendly)
294
+ │ │ └── ExecuteBatch.jsx # JSX DX, Lit output
295
+ │ │
296
+ │ ├── build.config.js # Handles all compilation
297
+ │ └── package.json
298
+ │
299
+ └── decoder-react-native/ # Mobile native (no compilation)
300
+ └── src/ # Pure React Native
301
+ ├── LSP7Transfer.jsx
302
+ └── ExecuteBatch.jsx
303
+ `
304
+
305
+ /**
306
+ * The ultimate developer suffering mitigation strategy 😈
307
+ */
308
+ export const DeveloperSufferingMitigation = `
309
+ 🎭 THE STRATEGY: "Suffer Now, Benefit Later"
310
+
311
+ Level 1 - The Brave: Write Lit directly
312
+ - Get full control and best performance
313
+ - Learn modern web standards
314
+ - Become web component experts
315
+ - Suffer the learning curve BUT gain superpowers
316
+
317
+ Level 2 - The Practical: Use compilation
318
+ - Write Vue/React (comfortable)
319
+ - Build tool outputs Lit (universal)
320
+ - Get universality without the learning curve
321
+ - Slight build complexity but familiar DX
322
+
323
+ Level 3 - The Lazy: Use existing tools
324
+ - Vue's built-in web component build
325
+ - Stencil for React-like JSX
326
+ - Let tooling handle the suffering
327
+
328
+ RESULT:
329
+ - Developers get to choose their suffering level
330
+ - Users always get universal web components
331
+ - Maintainers only ship one implementation per platform
332
+ - Everyone wins (eventually) 🎉
333
+
334
+ The suffering is temporary, but the universality is forever! 😈✨
335
+ `
336
+
337
+ export const Conclusion = `
338
+ 🤯 THIS IS ACTUALLY BRILLIANT:
339
+
340
+ 1. Ship universal web components (Lit output)
341
+ 2. Let developers write in their preferred framework (Vue/React source)
342
+ 3. Build tools handle the compilation (tooling suffers so humans don't have to)
343
+ 4. React Native stays native (mobile optimization)
344
+ 5. Everyone gets what they want:
345
+ - Users: Universal components that work everywhere
346
+ - Vue devs: Can write .vue files
347
+ - React devs: Can write JSX
348
+ - Maintainers: Only ship 2 implementations
349
+ - Framework wars: Become irrelevant 😎
350
+
351
+ The compilation approach gives you the BEST of both worlds:
352
+ - Developer Experience: Write in familiar frameworks
353
+ - User Experience: Universal web components
354
+ - Maintenance Experience: Minimal implementations
355
+
356
+ Let them write Vue, ship Lit. Let them write React, ship Lit.
357
+ The frameworks become implementation details! 🎭
358
+ `
@@ -0,0 +1,135 @@
1
+ /**
2
+ * TanStack Query integration for address resolution
3
+ * Provides proper cache keys and query functions
4
+ */
5
+
6
+ import type { ResolvedAddress } from './useAddressResolution'
7
+ import { resolveAddress, resolveAddresses } from './useAddressResolution'
8
+
9
+ /**
10
+ * Create TanStack Query key for address resolution
11
+ */
12
+ export function getAddressQueryKey(
13
+ address: string,
14
+ chainId?: number
15
+ ): (string | number)[] {
16
+ // Include chainId to ensure cache isolation per chain
17
+ return ['address', address.toLowerCase(), chainId || 'current']
18
+ }
19
+
20
+ /**
21
+ * Create TanStack Query key for batch address resolution
22
+ */
23
+ export function getAddressesQueryKey(
24
+ addresses: string[],
25
+ chainId?: number
26
+ ): (string | number)[] {
27
+ // Sort addresses for consistent cache keys
28
+ const sortedAddresses = [...addresses]
29
+ .map((addr) => addr.toLowerCase())
30
+ .sort()
31
+ return ['addresses', sortedAddresses.join(','), chainId || 'current']
32
+ }
33
+
34
+ /**
35
+ * Query function for single address resolution
36
+ */
37
+ export async function queryAddress({
38
+ queryKey,
39
+ }: {
40
+ queryKey: (string | number)[]
41
+ }): Promise<ResolvedAddress> {
42
+ const [, address, chainIdOrCurrent] = queryKey
43
+ const chainId =
44
+ chainIdOrCurrent === 'current' ? undefined : (chainIdOrCurrent as number)
45
+
46
+ return resolveAddress(address as string, chainId)
47
+ }
48
+
49
+ /**
50
+ * Query function for batch address resolution
51
+ */
52
+ export async function queryAddresses({
53
+ queryKey,
54
+ }: {
55
+ queryKey: (string | number)[]
56
+ }): Promise<Map<string, ResolvedAddress>> {
57
+ const [, addressesStr, chainIdOrCurrent] = queryKey
58
+ const chainId =
59
+ chainIdOrCurrent === 'current' ? undefined : (chainIdOrCurrent as number)
60
+ const addresses = (addressesStr as string).split(',')
61
+
62
+ return resolveAddresses(addresses, chainId)
63
+ }
64
+
65
+ /**
66
+ * Helper for React TanStack Query usage
67
+ */
68
+ export const addressQueryOptions = {
69
+ /**
70
+ * Single address query options
71
+ */
72
+ single: (address: string, chainId?: number) => ({
73
+ queryKey: getAddressQueryKey(address, chainId),
74
+ queryFn: queryAddress,
75
+ staleTime: 5 * 60 * 1000, // 5 minutes
76
+ gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
77
+ }),
78
+
79
+ /**
80
+ * Batch addresses query options
81
+ */
82
+ batch: (addresses: string[], chainId?: number) => ({
83
+ queryKey: getAddressesQueryKey(addresses, chainId),
84
+ queryFn: queryAddresses,
85
+ staleTime: 5 * 60 * 1000, // 5 minutes
86
+ gcTime: 10 * 60 * 1000, // 10 minutes
87
+ }),
88
+ }
89
+
90
+ /**
91
+ * Helper for Vue TanStack Query usage
92
+ */
93
+ export const addressQueryOptionsVue = {
94
+ /**
95
+ * Single address query options for Vue Query
96
+ */
97
+ single: (address: string, chainId?: number) => ({
98
+ queryKey: getAddressQueryKey(address, chainId),
99
+ queryFn: queryAddress,
100
+ staleTime: 5 * 60 * 1000,
101
+ cacheTime: 10 * 60 * 1000, // Vue Query still uses cacheTime
102
+ }),
103
+
104
+ /**
105
+ * Batch addresses query options for Vue Query
106
+ */
107
+ batch: (addresses: string[], chainId?: number) => ({
108
+ queryKey: getAddressesQueryKey(addresses, chainId),
109
+ queryFn: queryAddresses,
110
+ staleTime: 5 * 60 * 1000,
111
+ cacheTime: 10 * 60 * 1000,
112
+ }),
113
+ }
114
+
115
+ /**
116
+ * Invalidate address cache for a specific chain
117
+ * Useful when switching chains
118
+ */
119
+ export function getInvalidateAddressesPattern(
120
+ chainId?: number
121
+ ): (string | number)[] {
122
+ return ['address', chainId || 'current']
123
+ }
124
+
125
+ /**
126
+ * Get all possible query keys for an address across all chains
127
+ * Useful for invalidating cache when address profile changes
128
+ */
129
+ export function getAllAddressQueryKeys(address: string): (string | number)[][] {
130
+ return [
131
+ ['address', address.toLowerCase(), 'current'],
132
+ ['address', address.toLowerCase(), 42], // mainnet
133
+ ['address', address.toLowerCase(), 4201], // testnet
134
+ ]
135
+ }