@xyo-network/react-xns 7.5.8 → 7.5.11
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/browser/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.d.ts +1 -414
- package/dist/browser/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.d.ts.map +1 -1
- package/dist/browser/index.mjs +200 -186
- package/dist/browser/index.mjs.map +1 -1
- package/package.json +113 -33
- package/src/components/EstimateName/EstimateNameTextField.stories.tsx +0 -23
- package/src/components/EstimateName/EstimateNameTextField.tsx +0 -70
- package/src/components/EstimateName/index.ts +0 -1
- package/src/components/XnsNameCapture/Errors.tsx +0 -56
- package/src/components/XnsNameCapture/Props.ts +0 -48
- package/src/components/XnsNameCapture/SecondaryLink.stories.tsx +0 -18
- package/src/components/XnsNameCapture/SecondaryLink.tsx +0 -61
- package/src/components/XnsNameCapture/XnsNameCapture.stories.tsx +0 -19
- package/src/components/XnsNameCapture/XnsNameCapture.tsx +0 -116
- package/src/components/XnsNameCapture/XnsNameCaptureWithContext.stories.tsx +0 -61
- package/src/components/XnsNameCapture/XnsNameCaptureWithContext.tsx +0 -18
- package/src/components/XnsNameCapture/hooks/index.ts +0 -1
- package/src/components/XnsNameCapture/hooks/routing/index.ts +0 -2
- package/src/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.ts +0 -21
- package/src/components/XnsNameCapture/hooks/routing/useXnsNameFromLocation.ts +0 -26
- package/src/components/XnsNameCapture/index.ts +0 -6
- package/src/components/XnsNameCapture/lib/index.ts +0 -1
- package/src/components/XnsNameCapture/lib/navigateWithUsername.ts +0 -21
- package/src/components/index.ts +0 -2
- package/src/global.d.ts +0 -1
- package/src/index.ts +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xyo-network/react-xns",
|
|
3
|
-
"version": "7.5.
|
|
3
|
+
"version": "7.5.11",
|
|
4
4
|
"description": "Common React library for all XYO projects that use React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"xyo",
|
|
@@ -36,49 +36,129 @@
|
|
|
36
36
|
},
|
|
37
37
|
"./package.json": "./package.json"
|
|
38
38
|
},
|
|
39
|
-
"module": "dist/browser/index.mjs",
|
|
40
|
-
"types": "dist/browser/index.d.ts",
|
|
41
39
|
"files": [
|
|
42
40
|
"dist",
|
|
43
|
-
"
|
|
41
|
+
"README.md"
|
|
44
42
|
],
|
|
45
|
-
"dependencies": {
|
|
46
|
-
"@xylabs/react-button": "~7.1.17",
|
|
47
|
-
"@xylabs/react-flexbox": "~7.1.17",
|
|
48
|
-
"@xylabs/react-link": "~7.1.17",
|
|
49
|
-
"@xylabs/react-pixel": "~7.1.17",
|
|
50
|
-
"@xylabs/react-theme": "~7.1.17",
|
|
51
|
-
"@xyo-network/xns-record-payloadset-plugins": "~5.3.1"
|
|
52
|
-
},
|
|
53
43
|
"devDependencies": {
|
|
54
|
-
"@
|
|
55
|
-
"@
|
|
56
|
-
"@
|
|
44
|
+
"@bitauth/libauth": "~3.0.0",
|
|
45
|
+
"@metamask/providers": "^22.1.1",
|
|
46
|
+
"@mui/icons-material": "^7.3.10",
|
|
47
|
+
"@mui/material": "^7.3.10",
|
|
48
|
+
"@opentelemetry/api": "^1.9.1",
|
|
49
|
+
"@opentelemetry/sdk-trace-base": "^2.7.0",
|
|
50
|
+
"@scure/base": "~2.2.0",
|
|
51
|
+
"@scure/bip39": "~2.2.0",
|
|
52
|
+
"@storybook/react-vite": "~10.3.5",
|
|
53
|
+
"@types/node": "~25.6.0",
|
|
57
54
|
"@types/react": "^19.2.14",
|
|
58
|
-
"@xylabs/
|
|
59
|
-
"@xylabs/
|
|
60
|
-
"@xylabs/
|
|
61
|
-
"@xylabs/
|
|
62
|
-
"@xylabs/
|
|
63
|
-
"react": "
|
|
64
|
-
"react-
|
|
65
|
-
"react-
|
|
66
|
-
"
|
|
55
|
+
"@xylabs/geo": "^5.0.100",
|
|
56
|
+
"@xylabs/react-async-effect": "~7.1.20",
|
|
57
|
+
"@xylabs/react-button": "~7.1.20",
|
|
58
|
+
"@xylabs/react-flexbox": "~7.1.20",
|
|
59
|
+
"@xylabs/react-link": "~7.1.20",
|
|
60
|
+
"@xylabs/react-pixel": "~7.1.20",
|
|
61
|
+
"@xylabs/react-promise": "~7.1.20",
|
|
62
|
+
"@xylabs/react-theme": "~7.1.20",
|
|
63
|
+
"@xylabs/sdk-js": "^5.0.100",
|
|
64
|
+
"@xylabs/threads": "~5.0.100",
|
|
65
|
+
"@xylabs/toolchain": "~7.11.9",
|
|
66
|
+
"@xylabs/tsconfig": "^7.11.9",
|
|
67
|
+
"@xylabs/tsconfig-dom": "^7.11.9",
|
|
68
|
+
"@xylabs/tsconfig-react": "~7.11.9",
|
|
69
|
+
"@xylabs/zod": "~5.0.100",
|
|
70
|
+
"@xyo-network/account": "~5.5.1",
|
|
71
|
+
"@xyo-network/account-model": "^5.5.1",
|
|
72
|
+
"@xyo-network/api": "~5.5.1",
|
|
73
|
+
"@xyo-network/api-models": "~5.5.1",
|
|
74
|
+
"@xyo-network/boundwitness-builder": "^5.5.1",
|
|
75
|
+
"@xyo-network/boundwitness-model": "^5.5.1",
|
|
76
|
+
"@xyo-network/boundwitness-validator": "^5.5.1",
|
|
77
|
+
"@xyo-network/boundwitness-wrapper": "~5.5.1",
|
|
78
|
+
"@xyo-network/config-payload-plugin": "~5.5.1",
|
|
79
|
+
"@xyo-network/diviner-hash-lease": "^5.5.5",
|
|
80
|
+
"@xyo-network/huri": "^5.5.1",
|
|
81
|
+
"@xyo-network/manifest-model": "~5.5.1",
|
|
82
|
+
"@xyo-network/module-model": "^5.5.5",
|
|
83
|
+
"@xyo-network/payload-builder": "^5.5.1",
|
|
84
|
+
"@xyo-network/payload-model": "^5.5.1",
|
|
85
|
+
"@xyo-network/payload-plugin": "^5.5.1",
|
|
86
|
+
"@xyo-network/payload-wrapper": "~5.5.1",
|
|
87
|
+
"@xyo-network/query-payload-plugin": "~5.5.1",
|
|
88
|
+
"@xyo-network/sdk-js": "^5.5.5",
|
|
89
|
+
"@xyo-network/sdk-protocol-js": "~5.5.1",
|
|
90
|
+
"@xyo-network/wallet": "~5.5.1",
|
|
91
|
+
"@xyo-network/wallet-model": "^5.5.1",
|
|
92
|
+
"@xyo-network/witness-model": "^5.5.5",
|
|
93
|
+
"@xyo-network/xns-record-payloadset-plugins": "~5.4.9",
|
|
94
|
+
"ajv": "^8.18.0",
|
|
95
|
+
"async-mutex": "^0.5.0",
|
|
96
|
+
"axios": "^1.15.2",
|
|
97
|
+
"bn.js": "^5.2.3",
|
|
98
|
+
"bowser": "^2.14.1",
|
|
99
|
+
"buffer": "^6.0.3",
|
|
100
|
+
"chalk": "^5.6.2",
|
|
101
|
+
"debug": "~4.4.3",
|
|
102
|
+
"esbuild": "~0.28.0",
|
|
103
|
+
"eslint": "^10.2.1",
|
|
104
|
+
"ethers": "^6.16.0",
|
|
105
|
+
"fast-deep-equal": "~3.1.3",
|
|
106
|
+
"hash-wasm": "~4.12.0",
|
|
107
|
+
"idb": "^8.0.3",
|
|
108
|
+
"js-cookie": "~3.0.5",
|
|
109
|
+
"lru-cache": "^11.3.5",
|
|
110
|
+
"mapbox-gl": "^3.22.0",
|
|
111
|
+
"observable-fns": "~0.6.1",
|
|
112
|
+
"pako": "^2.1.0",
|
|
113
|
+
"react": "^19.2.5",
|
|
114
|
+
"react-dom": "^19.2.5",
|
|
115
|
+
"react-router-dom": "^7.14.2",
|
|
116
|
+
"spark-md5": "~3.0.2",
|
|
117
|
+
"store2": "~2.14.4",
|
|
118
|
+
"storybook": "^10.3.5",
|
|
67
119
|
"typescript": "^5.9.3",
|
|
68
|
-
"vite": "
|
|
120
|
+
"vite": "^8.0.10",
|
|
121
|
+
"wasm-feature-detect": "~1.8.0",
|
|
122
|
+
"webextension-polyfill": "^0.12.0",
|
|
69
123
|
"zod": "^4.3.6"
|
|
70
124
|
},
|
|
71
125
|
"peerDependencies": {
|
|
72
|
-
"@mui/icons-material": "
|
|
73
|
-
"@mui/material": "
|
|
74
|
-
"@
|
|
75
|
-
"react": "
|
|
76
|
-
"react-
|
|
77
|
-
"react-
|
|
78
|
-
"
|
|
126
|
+
"@mui/icons-material": "^7.3.10",
|
|
127
|
+
"@mui/material": "^7.3.10",
|
|
128
|
+
"@opentelemetry/sdk-trace-base": "^2.7.0",
|
|
129
|
+
"@xylabs/react-async-effect": "~7.1.20",
|
|
130
|
+
"@xylabs/react-button": "~7.1.20",
|
|
131
|
+
"@xylabs/react-flexbox": "~7.1.20",
|
|
132
|
+
"@xylabs/react-link": "~7.1.20",
|
|
133
|
+
"@xylabs/react-pixel": "~7.1.20",
|
|
134
|
+
"@xylabs/react-theme": "~7.1.20",
|
|
135
|
+
"@xylabs/sdk-js": "^5.0.100",
|
|
136
|
+
"@xylabs/zod": "~5.0.100",
|
|
137
|
+
"@xyo-network/boundwitness-model": "^5.5.1",
|
|
138
|
+
"@xyo-network/boundwitness-validator": "^5.5.1",
|
|
139
|
+
"@xyo-network/diviner-hash-lease": "^5.5.5",
|
|
140
|
+
"@xyo-network/module-model": "^5.5.5",
|
|
141
|
+
"@xyo-network/payload-model": "^5.5.1",
|
|
142
|
+
"@xyo-network/sdk-js": "^5.5.5",
|
|
143
|
+
"@xyo-network/witness-model": "^5.5.5",
|
|
144
|
+
"@xyo-network/xns-record-payloadset-plugins": "~5.4.9",
|
|
145
|
+
"async-mutex": "^0.5.0",
|
|
146
|
+
"axios": "^1.15.2",
|
|
147
|
+
"bn.js": "^5.2.3",
|
|
148
|
+
"bowser": "^2.14.1",
|
|
149
|
+
"buffer": "^6.0.3",
|
|
150
|
+
"chalk": "^5.6.2",
|
|
151
|
+
"fast-deep-equal": "~3.1.3",
|
|
152
|
+
"js-cookie": "~3.0.5",
|
|
153
|
+
"pako": "^2.1.0",
|
|
154
|
+
"react": "^19.2.5",
|
|
155
|
+
"react-dom": "^19.2.5",
|
|
156
|
+
"react-router-dom": "^7.14.2",
|
|
157
|
+
"spark-md5": "~3.0.2",
|
|
158
|
+
"zod": "^4.3.6"
|
|
79
159
|
},
|
|
80
160
|
"publishConfig": {
|
|
81
161
|
"access": "public"
|
|
82
162
|
},
|
|
83
163
|
"docs": "dist/docs.json"
|
|
84
|
-
}
|
|
164
|
+
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryFn } from '@storybook/react-vite'
|
|
2
|
-
import React, { useState } from 'react'
|
|
3
|
-
|
|
4
|
-
import { XnsEstimateNameTextField } from './EstimateNameTextField.tsx'
|
|
5
|
-
|
|
6
|
-
export default { title: 'modules/xns/XnsNameEstimateTextField' } as Meta
|
|
7
|
-
|
|
8
|
-
const Template: StoryFn<typeof XnsEstimateNameTextField> = (args) => {
|
|
9
|
-
return <XnsEstimateNameTextField {...args}></XnsEstimateNameTextField>
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const TemplateWithExternalValue: StoryFn<typeof XnsEstimateNameTextField> = (args) => {
|
|
13
|
-
const [value] = useState('foobar')
|
|
14
|
-
return <XnsEstimateNameTextField value={value} {...args}></XnsEstimateNameTextField>
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const Default = Template.bind({})
|
|
18
|
-
Default.args = {}
|
|
19
|
-
|
|
20
|
-
const WithExternalValue = TemplateWithExternalValue.bind({})
|
|
21
|
-
WithExternalValue.args = {}
|
|
22
|
-
|
|
23
|
-
export { Default, WithExternalValue }
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import type { StandardTextFieldProps, TextFieldProps } from '@mui/material'
|
|
2
|
-
import { TextField, useTheme } from '@mui/material'
|
|
3
|
-
import { alphaCss } from '@xylabs/react-theme'
|
|
4
|
-
import { MIN_DOMAIN_LENGTH, XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'
|
|
5
|
-
import React, {
|
|
6
|
-
useLayoutEffect,
|
|
7
|
-
useRef, useState,
|
|
8
|
-
} from 'react'
|
|
9
|
-
|
|
10
|
-
export interface XnsEstimateNameTextFieldProps {
|
|
11
|
-
maskOutput?: boolean
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const XnsEstimateNameTextField: React.FC<XnsEstimateNameTextFieldProps & TextFieldProps> = ({
|
|
15
|
-
maskOutput = true, onChange: onChangeProp, onBlur: onBlurProp, value, ...props
|
|
16
|
-
}) => {
|
|
17
|
-
const theme = useTheme()
|
|
18
|
-
const [validLength, setValidLength] = useState(false)
|
|
19
|
-
|
|
20
|
-
const inputRef = useRef<HTMLInputElement>(null)
|
|
21
|
-
|
|
22
|
-
// watch for external changes to the value and update the validLength state
|
|
23
|
-
const [previousValue, setPreviousValue] = useState<unknown>(value)
|
|
24
|
-
if (value !== previousValue) {
|
|
25
|
-
setPreviousValue(value)
|
|
26
|
-
const validValueLength = !!(value && typeof value === 'string' && value.length >= MIN_DOMAIN_LENGTH)
|
|
27
|
-
setValidLength(validValueLength)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// Update the input value when the value prop changes
|
|
31
|
-
// The intent of this component is to remain uncontrolled to avoid the need to manage the value state
|
|
32
|
-
// Therefore, we use useLayoutEffect to update the input value directly.
|
|
33
|
-
useLayoutEffect(() => {
|
|
34
|
-
if (inputRef.current && typeof value === 'string') {
|
|
35
|
-
inputRef.current.value = value
|
|
36
|
-
}
|
|
37
|
-
}, [value])
|
|
38
|
-
|
|
39
|
-
// override onChange to mask the input and update the event value
|
|
40
|
-
const handleChange: StandardTextFieldProps['onChange'] = (event) => {
|
|
41
|
-
if (maskOutput) {
|
|
42
|
-
const value = event.target.value
|
|
43
|
-
event.target.value = XnsNameHelper.mask(value)
|
|
44
|
-
}
|
|
45
|
-
onChangeProp?.(event)
|
|
46
|
-
|
|
47
|
-
if (inputRef.current) {
|
|
48
|
-
setValidLength(inputRef.current.value.length >= MIN_DOMAIN_LENGTH)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// override onBlur to do a final mask of the input and update the event value
|
|
53
|
-
const handleBlur: StandardTextFieldProps['onBlur'] = (event) => {
|
|
54
|
-
if (maskOutput) {
|
|
55
|
-
const value = event.target.value
|
|
56
|
-
event.target.value = XnsNameHelper.mask(value, { maskStartEndHyphens: true })
|
|
57
|
-
}
|
|
58
|
-
onBlurProp?.(event)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<TextField
|
|
63
|
-
inputRef={inputRef}
|
|
64
|
-
onBlur={handleBlur}
|
|
65
|
-
onChange={handleChange}
|
|
66
|
-
{...props}
|
|
67
|
-
slotProps={{ htmlInput: { style: { color: validLength ? theme.vars.palette.text.primary : alphaCss(theme.vars.palette.text.primary, 0.5) } } }}
|
|
68
|
-
/>
|
|
69
|
-
)
|
|
70
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './EstimateNameTextField.tsx'
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Alert, Snackbar, useMediaQuery, useTheme,
|
|
3
|
-
} from '@mui/material'
|
|
4
|
-
import { FlexRow } from '@xylabs/react-flexbox'
|
|
5
|
-
import React from 'react'
|
|
6
|
-
|
|
7
|
-
export interface XnsNameCaptureErrorsProps {
|
|
8
|
-
error?: Error
|
|
9
|
-
errorUi?: 'alert' | 'toast'
|
|
10
|
-
resetError?: () => void
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const XnsNameCaptureErrors: React.FC<XnsNameCaptureErrorsProps> = ({
|
|
14
|
-
error, errorUi, resetError,
|
|
15
|
-
}) => {
|
|
16
|
-
const theme = useTheme()
|
|
17
|
-
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<>
|
|
21
|
-
{(errorUi === 'toast')
|
|
22
|
-
? (
|
|
23
|
-
<Snackbar
|
|
24
|
-
open={!!error}
|
|
25
|
-
message={error?.toString()}
|
|
26
|
-
autoHideDuration={3000}
|
|
27
|
-
onClose={() => resetError?.()}
|
|
28
|
-
anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }}
|
|
29
|
-
>
|
|
30
|
-
<Alert
|
|
31
|
-
severity="error"
|
|
32
|
-
sx={{
|
|
33
|
-
width: '100%', display: (isMobile && !error) ? 'none' : undefined, visibility: error ? 'visible' : 'hidden',
|
|
34
|
-
}}
|
|
35
|
-
>
|
|
36
|
-
{error?.message}
|
|
37
|
-
</Alert>
|
|
38
|
-
</Snackbar>
|
|
39
|
-
)
|
|
40
|
-
// eslint-disable-next-line react-x/unsupported-syntax
|
|
41
|
-
: (() => {
|
|
42
|
-
// setTimeout(() => setError(undefined), 1500)
|
|
43
|
-
return (
|
|
44
|
-
<FlexRow alignSelf="stretch">
|
|
45
|
-
<Alert
|
|
46
|
-
severity="error"
|
|
47
|
-
sx={{ display: (isMobile && !error) ? 'none' : undefined, visibility: error ? 'visible' : 'hidden' }}
|
|
48
|
-
>
|
|
49
|
-
{error?.message}
|
|
50
|
-
</Alert>
|
|
51
|
-
</FlexRow>
|
|
52
|
-
)
|
|
53
|
-
})()}
|
|
54
|
-
</>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { FlexBoxProps } from '@xylabs/react-flexbox'
|
|
2
|
-
import type { ReactNode } from 'react'
|
|
3
|
-
import type { To } from 'react-router-dom'
|
|
4
|
-
|
|
5
|
-
export interface XnsNameCaptureBuyCallbacks {
|
|
6
|
-
onCaptureName?: (name: string) => Promise<void>
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Trackers for user actions
|
|
11
|
-
*/
|
|
12
|
-
export interface XnsNameCaptureTrackingProps {
|
|
13
|
-
funnel?: string
|
|
14
|
-
intent?: string
|
|
15
|
-
placement?: string
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Properties derived from the route and used for navigation
|
|
20
|
-
*/
|
|
21
|
-
export interface XnsNameCaptureRoutingProps {
|
|
22
|
-
navigate?: (to: string) => void
|
|
23
|
-
paramsString?: string
|
|
24
|
-
routingError?: Error
|
|
25
|
-
to?: To
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Base properties for the XnsNameCapture component related to the UI and Events
|
|
30
|
-
*/
|
|
31
|
-
export interface XnsNameCaptureBaseProps {
|
|
32
|
-
autoFocus?: boolean
|
|
33
|
-
buttonText?: string
|
|
34
|
-
defaultXnsName?: string
|
|
35
|
-
disabled?: boolean
|
|
36
|
-
errorUi?: 'alert' | 'toast'
|
|
37
|
-
mobileButtonText?: string
|
|
38
|
-
onNameChange?: (name: string) => void
|
|
39
|
-
showSecondary?: boolean | ReactNode
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface XnsNameCaptureProps extends XnsNameCaptureBaseProps,
|
|
43
|
-
XnsNameCaptureTrackingProps,
|
|
44
|
-
XnsNameCaptureBuyCallbacks,
|
|
45
|
-
XnsNameCaptureRoutingProps,
|
|
46
|
-
FlexBoxProps {}
|
|
47
|
-
|
|
48
|
-
export type WithXnsCapture<T> = T & { XnsCapture?: React.FC<XnsNameCaptureProps> }
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryFn } from '@storybook/react-vite'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
|
|
4
|
-
import { XnsCaptureSecondaryLink } from './SecondaryLink.tsx'
|
|
5
|
-
|
|
6
|
-
export default { title: 'modules/xns/XnsCaptureSecondaryLink' } as Meta
|
|
7
|
-
|
|
8
|
-
const Template: StoryFn<typeof XnsCaptureSecondaryLink> = (args) => {
|
|
9
|
-
return <XnsCaptureSecondaryLink {...args}></XnsCaptureSecondaryLink>
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const Default = Template.bind({})
|
|
13
|
-
Default.args = {}
|
|
14
|
-
|
|
15
|
-
const WithOnBuyName = Template.bind({})
|
|
16
|
-
WithOnBuyName.args = { xnsName: 'testing123', onCaptureName: (name: string) => Promise.resolve(alert(`Buy Name: ${name}`)) }
|
|
17
|
-
|
|
18
|
-
export { Default, WithOnBuyName }
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { ArrowForwardRounded } from '@mui/icons-material'
|
|
2
|
-
import { Stack } from '@mui/material'
|
|
3
|
-
import type { LinkExProps } from '@xylabs/react-link'
|
|
4
|
-
import { LinkEx } from '@xylabs/react-link'
|
|
5
|
-
import { useUserEvents } from '@xylabs/react-pixel'
|
|
6
|
-
import { XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'
|
|
7
|
-
import type { Dispatch } from 'react'
|
|
8
|
-
import React from 'react'
|
|
9
|
-
|
|
10
|
-
import type {
|
|
11
|
-
XnsNameCaptureBuyCallbacks, XnsNameCaptureRoutingProps, XnsNameCaptureTrackingProps,
|
|
12
|
-
} from './Props.ts'
|
|
13
|
-
|
|
14
|
-
export type XnsCaptureSecondaryLinkProps = XnsNameCaptureTrackingProps & XnsNameCaptureRoutingProps & XnsNameCaptureBuyCallbacks & LinkExProps & {
|
|
15
|
-
setError?: Dispatch<Error | undefined>
|
|
16
|
-
text?: string
|
|
17
|
-
xnsName: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const XnsCaptureSecondaryLink: React.FC<XnsCaptureSecondaryLinkProps> = ({
|
|
21
|
-
funnel = 'xns',
|
|
22
|
-
navigate,
|
|
23
|
-
onCaptureName,
|
|
24
|
-
paramsString = '',
|
|
25
|
-
intent,
|
|
26
|
-
placement = '',
|
|
27
|
-
setError,
|
|
28
|
-
text = 'Or make a free reservation',
|
|
29
|
-
to = '/xns/reservation',
|
|
30
|
-
xnsName,
|
|
31
|
-
...props
|
|
32
|
-
}) => {
|
|
33
|
-
const userEvents = useUserEvents('warn')
|
|
34
|
-
return (
|
|
35
|
-
<LinkEx
|
|
36
|
-
paddingX={0}
|
|
37
|
-
color="inherit"
|
|
38
|
-
style={{ textDecoration: 'underline', textUnderlineOffset: '5px' }}
|
|
39
|
-
onClick={async () => {
|
|
40
|
-
const formattedXnsName = `${xnsName}.xyo`
|
|
41
|
-
const helper = XnsNameHelper.fromString(formattedXnsName)
|
|
42
|
-
const [valid, errors] = await helper.validate()
|
|
43
|
-
if (valid) {
|
|
44
|
-
await userEvents?.userClick({
|
|
45
|
-
funnel, placement, intent,
|
|
46
|
-
})
|
|
47
|
-
navigate?.(`${to}?username=${xnsName}${paramsString}`)
|
|
48
|
-
await onCaptureName?.(xnsName)
|
|
49
|
-
} else {
|
|
50
|
-
setError?.(new Error(errors.join(', ')))
|
|
51
|
-
}
|
|
52
|
-
}}
|
|
53
|
-
{...props}
|
|
54
|
-
>
|
|
55
|
-
<Stack flexDirection="row" gap={0.5} alignItems="center" sx={{ cursor: 'pointer' }}>
|
|
56
|
-
{text}
|
|
57
|
-
<ArrowForwardRounded />
|
|
58
|
-
</Stack>
|
|
59
|
-
</LinkEx>
|
|
60
|
-
)
|
|
61
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryFn } from '@storybook/react-vite'
|
|
2
|
-
import React from 'react'
|
|
3
|
-
import type { To } from 'react-router-dom'
|
|
4
|
-
|
|
5
|
-
import { XnsNameCapture } from './XnsNameCapture.tsx'
|
|
6
|
-
|
|
7
|
-
export default { title: 'modules/xns/XnsNameCapture' } as Meta
|
|
8
|
-
|
|
9
|
-
const Template: StoryFn<typeof XnsNameCapture> = (args) => {
|
|
10
|
-
return <XnsNameCapture {...args}></XnsNameCapture>
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const Default = Template.bind({})
|
|
14
|
-
Default.args = {}
|
|
15
|
-
|
|
16
|
-
const WithOnBuyName = Template.bind({})
|
|
17
|
-
WithOnBuyName.args = { navigate: (to: To) => alert(`navigated to: ${to}`), onCaptureName: (name: string) => Promise.resolve(alert(`Buy Name: ${name}`)) }
|
|
18
|
-
|
|
19
|
-
export { Default, WithOnBuyName }
|
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
import { KeyboardArrowRightRounded } from '@mui/icons-material'
|
|
2
|
-
import type { StandardTextFieldProps } from '@mui/material'
|
|
3
|
-
import { useMediaQuery, useTheme } from '@mui/material'
|
|
4
|
-
import { ButtonEx } from '@xylabs/react-button'
|
|
5
|
-
import { FlexCol, FlexRow } from '@xylabs/react-flexbox'
|
|
6
|
-
import { MIN_DOMAIN_LENGTH, XnsNameHelper } from '@xyo-network/xns-record-payloadset-plugins'
|
|
7
|
-
import type { KeyboardEventHandler } from 'react'
|
|
8
|
-
import React, { useCallback, useState } from 'react'
|
|
9
|
-
|
|
10
|
-
import { XnsEstimateNameTextField } from '../EstimateName/index.ts'
|
|
11
|
-
import { XnsNameCaptureErrors } from './Errors.tsx'
|
|
12
|
-
import { navigateWithUsername } from './lib/index.ts'
|
|
13
|
-
import type { XnsNameCaptureProps } from './Props.ts'
|
|
14
|
-
import { XnsCaptureSecondaryLink } from './SecondaryLink.js'
|
|
15
|
-
|
|
16
|
-
export const XnsNameCapture: React.FC<XnsNameCaptureProps> = ({
|
|
17
|
-
autoFocus = false,
|
|
18
|
-
buttonText = 'Buy My Name',
|
|
19
|
-
children,
|
|
20
|
-
defaultXnsName,
|
|
21
|
-
disabled,
|
|
22
|
-
errorUi = 'alert',
|
|
23
|
-
funnel = 'xns',
|
|
24
|
-
intent = 'unset',
|
|
25
|
-
mobileButtonText = 'Buy',
|
|
26
|
-
navigate,
|
|
27
|
-
onCaptureName: onCaptureNameProp,
|
|
28
|
-
onNameChange,
|
|
29
|
-
paramsString = '',
|
|
30
|
-
placement = '',
|
|
31
|
-
routingError,
|
|
32
|
-
showSecondary = false,
|
|
33
|
-
to = '/xns/estimation',
|
|
34
|
-
...props
|
|
35
|
-
}) => {
|
|
36
|
-
const [xnsName, setXnsName] = useState<string>(() => defaultXnsName ?? '')
|
|
37
|
-
const [error, setError] = useState<Error | undefined>(routingError)
|
|
38
|
-
|
|
39
|
-
const theme = useTheme()
|
|
40
|
-
const isMobile = useMediaQuery(theme.breakpoints.down('md'))
|
|
41
|
-
|
|
42
|
-
const captureDisabled = !xnsName || xnsName.length < MIN_DOMAIN_LENGTH
|
|
43
|
-
|
|
44
|
-
const handleChange: StandardTextFieldProps['onChange'] = (event) => {
|
|
45
|
-
const NsName = XnsNameHelper.mask(event.target.value)
|
|
46
|
-
onNameChange?.(NsName)
|
|
47
|
-
setXnsName(NsName)
|
|
48
|
-
setError(undefined)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const onCaptureName = useCallback(async () => {
|
|
52
|
-
if (captureDisabled) return
|
|
53
|
-
const formattedXnsName = `${xnsName}.xyo`
|
|
54
|
-
const helper = XnsNameHelper.fromString(formattedXnsName)
|
|
55
|
-
const [valid, errors] = await helper.validate()
|
|
56
|
-
if (valid) {
|
|
57
|
-
await onCaptureNameProp?.(xnsName)
|
|
58
|
-
|
|
59
|
-
navigateWithUsername(xnsName, paramsString, navigate, to)
|
|
60
|
-
} else {
|
|
61
|
-
setError(new Error(errors.join(', ')))
|
|
62
|
-
}
|
|
63
|
-
}, [captureDisabled, xnsName, onCaptureNameProp, paramsString, navigate, to])
|
|
64
|
-
|
|
65
|
-
const onKeyDown: KeyboardEventHandler<HTMLDivElement> = useCallback(async (event) => {
|
|
66
|
-
if (event.key === 'Enter' && !captureDisabled) {
|
|
67
|
-
await onCaptureName?.()
|
|
68
|
-
}
|
|
69
|
-
}, [captureDisabled, onCaptureName])
|
|
70
|
-
|
|
71
|
-
return (
|
|
72
|
-
<FlexCol gap={showSecondary ? 1.5 : 0} alignItems="center" {...props}>
|
|
73
|
-
<FlexRow gap={1}>
|
|
74
|
-
<XnsEstimateNameTextField
|
|
75
|
-
autoFocus={autoFocus}
|
|
76
|
-
disabled={disabled}
|
|
77
|
-
label="xNS Name"
|
|
78
|
-
variant="outlined"
|
|
79
|
-
size="small"
|
|
80
|
-
value={xnsName ?? ''}
|
|
81
|
-
onKeyDown={onKeyDown}
|
|
82
|
-
onChange={handleChange}
|
|
83
|
-
onBlur={handleChange}
|
|
84
|
-
/>
|
|
85
|
-
<ButtonEx
|
|
86
|
-
disabled={captureDisabled}
|
|
87
|
-
funnel={funnel}
|
|
88
|
-
intent={intent}
|
|
89
|
-
placement={placement}
|
|
90
|
-
variant="contained"
|
|
91
|
-
color="success"
|
|
92
|
-
endIcon={<KeyboardArrowRightRounded />}
|
|
93
|
-
onClick={onCaptureName}
|
|
94
|
-
>
|
|
95
|
-
{isMobile ? mobileButtonText : buttonText}
|
|
96
|
-
</ButtonEx>
|
|
97
|
-
</FlexRow>
|
|
98
|
-
{(showSecondary === true)
|
|
99
|
-
? (
|
|
100
|
-
<XnsCaptureSecondaryLink
|
|
101
|
-
xnsName={xnsName}
|
|
102
|
-
placement={placement}
|
|
103
|
-
funnel={funnel}
|
|
104
|
-
setError={setError}
|
|
105
|
-
/>
|
|
106
|
-
)
|
|
107
|
-
: null}
|
|
108
|
-
{
|
|
109
|
-
// eslint-disable-next-line unicorn/prefer-logical-operator-over-ternary
|
|
110
|
-
showSecondary ? showSecondary : null
|
|
111
|
-
}
|
|
112
|
-
{children}
|
|
113
|
-
<XnsNameCaptureErrors error={error} errorUi={errorUi} resetError={() => setError(undefined)} />
|
|
114
|
-
</FlexCol>
|
|
115
|
-
)
|
|
116
|
-
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
Decorator, Meta, StoryFn,
|
|
3
|
-
} from '@storybook/react-vite'
|
|
4
|
-
import React from 'react'
|
|
5
|
-
import type { To } from 'react-router-dom'
|
|
6
|
-
import { BrowserRouter } from 'react-router-dom'
|
|
7
|
-
|
|
8
|
-
import { XnsNameCaptureWithContext } from './XnsNameCaptureWithContext.tsx'
|
|
9
|
-
|
|
10
|
-
export default { title: 'modules/xns/XnsNameCaptureWithContext' } as Meta
|
|
11
|
-
|
|
12
|
-
const testableParams = ['signature', 'username'] as const
|
|
13
|
-
type RouteDecorator = (params: [typeof testableParams[number], string][]) => Decorator
|
|
14
|
-
|
|
15
|
-
const RouteDecorator: RouteDecorator = params => (Story, args) => {
|
|
16
|
-
// Get the URL object
|
|
17
|
-
const url = new URL(globalThis.location.href)
|
|
18
|
-
|
|
19
|
-
// Remove all stale testable params from the URL
|
|
20
|
-
for (const param of testableParams) url.searchParams.delete(param)
|
|
21
|
-
globalThis.history.replaceState({}, '', url)
|
|
22
|
-
|
|
23
|
-
// Add the new testable params to the URL
|
|
24
|
-
for (const [param, value] of params) url.searchParams.set(param, value)
|
|
25
|
-
|
|
26
|
-
// Replace the URL without reloading
|
|
27
|
-
globalThis.history.replaceState({}, '', url)
|
|
28
|
-
|
|
29
|
-
return <Story {...args} />
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const Template: StoryFn<typeof XnsNameCaptureWithContext> = (args) => {
|
|
33
|
-
return (
|
|
34
|
-
<BrowserRouter>
|
|
35
|
-
<XnsNameCaptureWithContext {...args}></XnsNameCaptureWithContext>
|
|
36
|
-
</BrowserRouter>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const Default = Template.bind({})
|
|
41
|
-
Default.decorators = [RouteDecorator([['signature', '0x1234567890abcdef']])]
|
|
42
|
-
Default.args = {}
|
|
43
|
-
|
|
44
|
-
const WithOnCaptureName = Template.bind({})
|
|
45
|
-
WithOnCaptureName.decorators = [RouteDecorator([['signature', '0x1234567890abcdef']])]
|
|
46
|
-
WithOnCaptureName.args = { navigate: (to: To) => alert(`navigated to: ${to}`), onCaptureName: (name: string) => Promise.resolve(alert(`Buy Name: ${name}`)) }
|
|
47
|
-
|
|
48
|
-
const WithBadXnsNameInRoute = Template.bind({})
|
|
49
|
-
WithBadXnsNameInRoute.decorators = [RouteDecorator([['signature', '0x1234567890abcdef'], ['username', 'badname.xyo.xyo']])]
|
|
50
|
-
WithBadXnsNameInRoute.args = {
|
|
51
|
-
navigate: (to: To) => alert(`navigated to: ${to}`),
|
|
52
|
-
onCaptureName: (name: string) => Promise.resolve(alert(`Buy Name: ${name}`)),
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const WithUserName = Template.bind({})
|
|
56
|
-
WithUserName.decorators = [RouteDecorator([['username', 'foobar']])]
|
|
57
|
-
WithUserName.args = { navigate: (to: To) => alert(`navigated to: ${to}`) }
|
|
58
|
-
|
|
59
|
-
export {
|
|
60
|
-
Default, WithBadXnsNameInRoute, WithOnCaptureName, WithUserName,
|
|
61
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React, { useMemo } from 'react'
|
|
2
|
-
|
|
3
|
-
import { useXnsNameCaptureRouting } from './hooks/index.ts'
|
|
4
|
-
import type { XnsNameCaptureProps } from './Props.ts'
|
|
5
|
-
import { XnsNameCapture } from './XnsNameCapture.tsx'
|
|
6
|
-
|
|
7
|
-
export const XnsNameCaptureWithContext: React.FC<XnsNameCaptureProps> = (props) => {
|
|
8
|
-
const routingProps = useXnsNameCaptureRouting(props)
|
|
9
|
-
|
|
10
|
-
const updatedProps = useMemo<XnsNameCaptureProps>(() => ({
|
|
11
|
-
...props,
|
|
12
|
-
...routingProps,
|
|
13
|
-
}), [routingProps, props])
|
|
14
|
-
|
|
15
|
-
return (
|
|
16
|
-
<XnsNameCapture {...updatedProps} />
|
|
17
|
-
)
|
|
18
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './routing/index.ts'
|