@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.
Files changed (26) hide show
  1. package/dist/browser/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.d.ts +1 -414
  2. package/dist/browser/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.d.ts.map +1 -1
  3. package/dist/browser/index.mjs +200 -186
  4. package/dist/browser/index.mjs.map +1 -1
  5. package/package.json +113 -33
  6. package/src/components/EstimateName/EstimateNameTextField.stories.tsx +0 -23
  7. package/src/components/EstimateName/EstimateNameTextField.tsx +0 -70
  8. package/src/components/EstimateName/index.ts +0 -1
  9. package/src/components/XnsNameCapture/Errors.tsx +0 -56
  10. package/src/components/XnsNameCapture/Props.ts +0 -48
  11. package/src/components/XnsNameCapture/SecondaryLink.stories.tsx +0 -18
  12. package/src/components/XnsNameCapture/SecondaryLink.tsx +0 -61
  13. package/src/components/XnsNameCapture/XnsNameCapture.stories.tsx +0 -19
  14. package/src/components/XnsNameCapture/XnsNameCapture.tsx +0 -116
  15. package/src/components/XnsNameCapture/XnsNameCaptureWithContext.stories.tsx +0 -61
  16. package/src/components/XnsNameCapture/XnsNameCaptureWithContext.tsx +0 -18
  17. package/src/components/XnsNameCapture/hooks/index.ts +0 -1
  18. package/src/components/XnsNameCapture/hooks/routing/index.ts +0 -2
  19. package/src/components/XnsNameCapture/hooks/routing/useXnsNameCaptureRouting.ts +0 -21
  20. package/src/components/XnsNameCapture/hooks/routing/useXnsNameFromLocation.ts +0 -26
  21. package/src/components/XnsNameCapture/index.ts +0 -6
  22. package/src/components/XnsNameCapture/lib/index.ts +0 -1
  23. package/src/components/XnsNameCapture/lib/navigateWithUsername.ts +0 -21
  24. package/src/components/index.ts +0 -2
  25. package/src/global.d.ts +0 -1
  26. 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.8",
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
- "src"
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
- "@mui/icons-material": "~7.3.9",
55
- "@mui/material": "~7.3.9",
56
- "@storybook/react-vite": "~10.3.3",
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/ts-scripts-common": "~7.5.6",
59
- "@xylabs/ts-scripts-yarn3": "~7.5.6",
60
- "@xylabs/tsconfig": "~7.5.6",
61
- "@xylabs/tsconfig-dom": "~7.5.6",
62
- "@xylabs/tsconfig-react": "~7.5.6",
63
- "react": "^19.2.4",
64
- "react-dom": "^19.2.4",
65
- "react-router-dom": "^7.13.2",
66
- "storybook": "~10.3.3",
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": "~8.0.3",
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": ">=6 <8",
73
- "@mui/material": ">=6 <8",
74
- "@xylabs/pixel": "~2",
75
- "react": "^19",
76
- "react-dom": "^19",
77
- "react-router-dom": "^7",
78
- "zod": "^4"
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'