react-component-instance 0.0.0 → 0.0.1
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/README.md +27 -0
- package/babel.config.cjs +42 -0
- package/eslint.config.mjs +146 -14
- package/index.d.mts +70 -1
- package/jest.config.mjs +15 -0
- package/package.json +31 -9
- package/src/__tests__/index.spec.jsx +58 -0
- package/src/container/__tests__/index.spec.jsx +29 -0
- package/src/container/index.mjs +44 -0
- package/src/index.mjs +101 -0
- package/tsconfig.json +2 -1
- package/index.mjs +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# react-component-instance
|
|
2
|
+
|
|
3
|
+
Get a React class component instance from its `DOM` elements
|
|
4
|
+
|
|
5
|
+
```javascript
|
|
6
|
+
import getInstance from 'react-component-instance'
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## With `@testing-library/react`
|
|
10
|
+
|
|
11
|
+
**Note** that for use with _Testing Library_ import from `react-component-instance/container`
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import getInstance from 'react-component-instance/container'
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
render
|
|
18
|
+
} from '@testing-library/react'
|
|
19
|
+
|
|
20
|
+
const {
|
|
21
|
+
container
|
|
22
|
+
} = render(
|
|
23
|
+
<Component />
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
const instance = getInstance(container)
|
|
27
|
+
```
|
package/babel.config.cjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const debug = require('debug')
|
|
2
|
+
|
|
3
|
+
const log = debug('react-component-instance')
|
|
4
|
+
|
|
5
|
+
const {
|
|
6
|
+
env: {
|
|
7
|
+
NODE_ENV = 'development'
|
|
8
|
+
}
|
|
9
|
+
} = process
|
|
10
|
+
|
|
11
|
+
log('`react-component-instance` is awake')
|
|
12
|
+
|
|
13
|
+
function env () {
|
|
14
|
+
log({ NODE_ENV })
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
NODE_ENV === 'production'
|
|
18
|
+
)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const presets = [
|
|
22
|
+
[
|
|
23
|
+
'@babel/env',
|
|
24
|
+
{
|
|
25
|
+
targets: {
|
|
26
|
+
node: 'current'
|
|
27
|
+
},
|
|
28
|
+
useBuiltIns: 'usage',
|
|
29
|
+
corejs: 3
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
'@babel/react'
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
module.exports = (api) => {
|
|
37
|
+
if (api) api.cache.using(env)
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
presets
|
|
41
|
+
}
|
|
42
|
+
}
|
package/eslint.config.mjs
CHANGED
|
@@ -1,36 +1,168 @@
|
|
|
1
1
|
import globals from 'globals'
|
|
2
|
+
import standard from '@sequencemedia/eslint-config-standard/configs/recommended/merge'
|
|
3
|
+
import typescript from '@sequencemedia/eslint-config-typescript/configs/recommended/merge'
|
|
4
|
+
import babelParser from '@babel/eslint-parser'
|
|
5
|
+
import typescriptParser from '@typescript-eslint/parser'
|
|
6
|
+
import reactPlugin from 'eslint-plugin-react'
|
|
2
7
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
8
|
+
const reactParserOptions = {
|
|
9
|
+
ecmaFeatures: {
|
|
10
|
+
jsx: true
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const reactPlugins = {
|
|
15
|
+
react: reactPlugin
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const reactRules = {
|
|
19
|
+
'no-unused-vars': [
|
|
20
|
+
'error',
|
|
21
|
+
{
|
|
22
|
+
varsIgnorePattern: 'React'
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
quotes: [
|
|
26
|
+
'error',
|
|
27
|
+
'single'
|
|
28
|
+
],
|
|
29
|
+
'jsx-quotes': [
|
|
30
|
+
'error',
|
|
31
|
+
'prefer-single'
|
|
32
|
+
],
|
|
33
|
+
'react/jsx-indent': [
|
|
34
|
+
'error',
|
|
35
|
+
2,
|
|
36
|
+
{
|
|
37
|
+
checkAttributes: true,
|
|
38
|
+
indentLogicalExpressions: true
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
6
42
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
43
|
+
const reactSettings = {
|
|
44
|
+
react: {
|
|
45
|
+
version: 'detect'
|
|
46
|
+
}
|
|
47
|
+
}
|
|
10
48
|
|
|
11
49
|
export default [
|
|
50
|
+
/**
|
|
51
|
+
* React config for all `jsx` files
|
|
52
|
+
*/
|
|
12
53
|
{
|
|
13
|
-
...
|
|
54
|
+
...reactPlugin.configs.flat.recommended,
|
|
55
|
+
settings: {
|
|
56
|
+
...reactSettings
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
/**
|
|
60
|
+
* Standard config
|
|
61
|
+
*/
|
|
62
|
+
standard({
|
|
14
63
|
files: [
|
|
15
64
|
'**/*.{mjs,cjs,mts,cts}'
|
|
16
65
|
],
|
|
66
|
+
ignores: [
|
|
67
|
+
'src'
|
|
68
|
+
],
|
|
17
69
|
languageOptions: {
|
|
18
|
-
...standard.recommended.languageOptions,
|
|
19
70
|
globals: {
|
|
20
71
|
...globals.node
|
|
21
72
|
}
|
|
73
|
+
},
|
|
74
|
+
rules: {
|
|
75
|
+
'no-use-before-define': 'off'
|
|
22
76
|
}
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
|
|
77
|
+
}),
|
|
78
|
+
/**
|
|
79
|
+
* Standard config for `mjs` and `mts` files
|
|
80
|
+
*/
|
|
81
|
+
standard({
|
|
82
|
+
files: [
|
|
83
|
+
'src/**/*.{mjs,cjs,mts,cts}'
|
|
84
|
+
],
|
|
85
|
+
languageOptions: {
|
|
86
|
+
globals: {
|
|
87
|
+
...globals.browser
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}),
|
|
91
|
+
/**
|
|
92
|
+
* Standard config for `jsx` files
|
|
93
|
+
*/
|
|
94
|
+
standard({
|
|
95
|
+
files: [
|
|
96
|
+
'src/**/*.jsx'
|
|
97
|
+
],
|
|
98
|
+
ignores: [
|
|
99
|
+
'src/**/__tests__/**/*.jsx'
|
|
100
|
+
],
|
|
101
|
+
languageOptions: {
|
|
102
|
+
parser: babelParser,
|
|
103
|
+
parserOptions: {
|
|
104
|
+
...reactParserOptions,
|
|
105
|
+
project: null
|
|
106
|
+
},
|
|
107
|
+
globals: {
|
|
108
|
+
...globals.browser
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
plugins: {
|
|
112
|
+
...reactPlugins
|
|
113
|
+
}, // @ts-expect-error Storybook
|
|
114
|
+
rules: {
|
|
115
|
+
...reactRules
|
|
116
|
+
},
|
|
117
|
+
settings: {
|
|
118
|
+
...reactSettings
|
|
119
|
+
}
|
|
120
|
+
}),
|
|
121
|
+
/**
|
|
122
|
+
* Standard config for `jsx` files
|
|
123
|
+
*/
|
|
124
|
+
standard({
|
|
125
|
+
files: [
|
|
126
|
+
'src/**/__tests__/**/*.jsx'
|
|
127
|
+
],
|
|
128
|
+
languageOptions: {
|
|
129
|
+
parser: babelParser,
|
|
130
|
+
parserOptions: {
|
|
131
|
+
...reactParserOptions,
|
|
132
|
+
project: null
|
|
133
|
+
},
|
|
134
|
+
globals: {
|
|
135
|
+
...globals.browser,
|
|
136
|
+
...globals.jest
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
plugins: {
|
|
140
|
+
...reactPlugins
|
|
141
|
+
}, // @ts-expect-error Storybook
|
|
142
|
+
rules: {
|
|
143
|
+
...reactRules
|
|
144
|
+
},
|
|
145
|
+
settings: {
|
|
146
|
+
...reactSettings
|
|
147
|
+
}
|
|
148
|
+
}),
|
|
149
|
+
/**
|
|
150
|
+
* TypeScript config
|
|
151
|
+
*/
|
|
152
|
+
typescript({
|
|
26
153
|
files: [
|
|
27
154
|
'**/*.{mts,cts}'
|
|
28
155
|
],
|
|
29
156
|
languageOptions: {
|
|
30
|
-
|
|
157
|
+
parser: typescriptParser,
|
|
158
|
+
parserOptions: {
|
|
159
|
+
projectService: true,
|
|
160
|
+
project: 'tsconfig.json'
|
|
161
|
+
},
|
|
31
162
|
globals: {
|
|
32
|
-
...globals.
|
|
163
|
+
...globals.browser,
|
|
164
|
+
ReactComponentInstanceTypes: 'readonly'
|
|
33
165
|
}
|
|
34
166
|
}
|
|
35
|
-
}
|
|
167
|
+
})
|
|
36
168
|
]
|
package/index.d.mts
CHANGED
|
@@ -1,5 +1,74 @@
|
|
|
1
|
+
import type React from 'react'
|
|
2
|
+
|
|
1
3
|
declare global {
|
|
2
|
-
namespace ReactComponentInstanceTypes {
|
|
4
|
+
namespace ReactComponentInstanceTypes {
|
|
5
|
+
/**
|
|
6
|
+
* https://github.com/bendtherules/react-fiber-traverse
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export type FiberNode =
|
|
10
|
+
| FiberNodeForComponentClass
|
|
11
|
+
| FiberNodeForFunctionComponent
|
|
12
|
+
| FiberNodeForInstrinsicElement
|
|
13
|
+
| FiberNodeForTextNode
|
|
14
|
+
|
|
15
|
+
export interface FiberRootNode {
|
|
16
|
+
child: FiberNode
|
|
17
|
+
sibling: FiberNode | null
|
|
18
|
+
|
|
19
|
+
elementType: React.FunctionComponent
|
|
20
|
+
type: React.FunctionComponent
|
|
21
|
+
|
|
22
|
+
stateNode: {
|
|
23
|
+
current: FiberRootNode
|
|
24
|
+
}
|
|
25
|
+
return: FiberRootNode
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface FiberNodeForFunctionComponent {
|
|
29
|
+
child: FiberNode | null
|
|
30
|
+
sibling: FiberNode | null
|
|
31
|
+
|
|
32
|
+
elementType: React.FunctionComponent
|
|
33
|
+
type: React.FunctionComponent
|
|
34
|
+
|
|
35
|
+
stateNode: null
|
|
36
|
+
return: FiberNode
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface FiberNodeForComponentClass {
|
|
40
|
+
child: FiberNode | null
|
|
41
|
+
sibling: FiberNode | null
|
|
42
|
+
|
|
43
|
+
elementType: React.ComponentClass
|
|
44
|
+
type: React.ComponentClass
|
|
45
|
+
|
|
46
|
+
stateNode: React.Component
|
|
47
|
+
return: FiberNode
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface FiberNodeForInstrinsicElement {
|
|
51
|
+
child: FiberNode | null
|
|
52
|
+
sibling: FiberNode | null
|
|
53
|
+
|
|
54
|
+
elementType: keyof React.JSX.IntrinsicElements
|
|
55
|
+
type: keyof React.JSX.IntrinsicElements
|
|
56
|
+
|
|
57
|
+
stateNode: HTMLElement
|
|
58
|
+
return: FiberNode
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface FiberNodeForTextNode {
|
|
62
|
+
child: null
|
|
63
|
+
sibling: FiberNode | null
|
|
64
|
+
|
|
65
|
+
elementType: null
|
|
66
|
+
type: null
|
|
67
|
+
|
|
68
|
+
stateNode: Text
|
|
69
|
+
return: FiberNode
|
|
70
|
+
}
|
|
71
|
+
}
|
|
3
72
|
}
|
|
4
73
|
|
|
5
74
|
export {}
|
package/jest.config.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
bail: 1,
|
|
3
|
+
verbose: true,
|
|
4
|
+
rootDir: '.',
|
|
5
|
+
roots: [
|
|
6
|
+
'./src'
|
|
7
|
+
],
|
|
8
|
+
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(mjs?|jsx?)$',
|
|
9
|
+
testEnvironment: 'jsdom',
|
|
10
|
+
transform: {
|
|
11
|
+
'^.+\\.jsx$': 'babel-jest',
|
|
12
|
+
'^.+\\.mjs$': 'babel-jest'
|
|
13
|
+
},
|
|
14
|
+
moduleFileExtensions: ['js', 'mjs', 'cjs', 'jsx']
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-component-instance",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"main": "./index.mjs",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "./src/index.mjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.mts",
|
|
7
7
|
"author": {
|
|
8
|
-
"name": "Jonathan Perry for
|
|
9
|
-
"email": "jonathanperry@
|
|
10
|
-
"url": "https://
|
|
8
|
+
"name": "Jonathan Perry for Modern Poacher Limited",
|
|
9
|
+
"email": "jonathanperry@modernpoacher.com",
|
|
10
|
+
"url": "https://modernpoacher.com"
|
|
11
11
|
},
|
|
12
12
|
"license": "ISC",
|
|
13
13
|
"engines": {
|
|
@@ -15,19 +15,41 @@
|
|
|
15
15
|
},
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "git://github.com/
|
|
18
|
+
"url": "git://github.com/modernpoacher/react-component-instance.git"
|
|
19
19
|
},
|
|
20
20
|
"scripts": {
|
|
21
21
|
"lint": "eslint",
|
|
22
|
-
"lint:fix": "npm run lint -- --fix"
|
|
22
|
+
"lint:fix": "npm run lint -- --fix",
|
|
23
|
+
"test": "NODE_ENV=test jest",
|
|
24
|
+
"prepare": "husky"
|
|
23
25
|
},
|
|
24
26
|
"devDependencies": {
|
|
27
|
+
"@babel/core": "^7.26.10",
|
|
28
|
+
"@babel/eslint-parser": "^7.26.10",
|
|
29
|
+
"@babel/preset-env": "^7.26.9",
|
|
30
|
+
"@babel/preset-react": "^7.26.3",
|
|
25
31
|
"@sequencemedia/eslint-config-standard": "^0.2.42",
|
|
26
32
|
"@sequencemedia/eslint-config-typescript": "^0.1.60",
|
|
33
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
34
|
+
"@testing-library/react": "^16.2.0",
|
|
35
|
+
"@types/debug": "^4.1.12",
|
|
36
|
+
"@types/jest": "^29.5.14",
|
|
37
|
+
"@types/react": "^19.0.10",
|
|
38
|
+
"core-js": "^3.41.0",
|
|
27
39
|
"eslint": "^9.22.0",
|
|
28
|
-
"
|
|
40
|
+
"eslint-plugin-react": "^7.37.4",
|
|
41
|
+
"globals": "^16.0.0",
|
|
42
|
+
"husky": "^9.1.7",
|
|
43
|
+
"jest": "^29.7.0",
|
|
44
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
45
|
+
"react": "^19.0.0"
|
|
46
|
+
},
|
|
47
|
+
"imports": {
|
|
48
|
+
"#react-component-instance": "./src/index.mjs",
|
|
49
|
+
"#react-component-instance/container": "./src/container/index.mjs"
|
|
29
50
|
},
|
|
30
51
|
"exports": {
|
|
31
|
-
".": "./src/index.mjs"
|
|
52
|
+
".": "./src/index.mjs",
|
|
53
|
+
"./container": "./src/container/index.mjs"
|
|
32
54
|
}
|
|
33
55
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {ReactComponentInstanceTypes.FiberNode} FiberNode
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import React from 'react'
|
|
6
|
+
|
|
7
|
+
import '@testing-library/jest-dom'
|
|
8
|
+
import {
|
|
9
|
+
render
|
|
10
|
+
} from '@testing-library/react'
|
|
11
|
+
|
|
12
|
+
import getReactComponentInstanceFrom, {
|
|
13
|
+
findReactComponentInstanceFor
|
|
14
|
+
} from '#react-component-instance'
|
|
15
|
+
|
|
16
|
+
describe('#react-component-instance', () => {
|
|
17
|
+
class Component extends React.Component {
|
|
18
|
+
render () {
|
|
19
|
+
return (
|
|
20
|
+
<div>
|
|
21
|
+
<div>
|
|
22
|
+
<div className='target' />
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe('`getReactComponentInstanceFrom`', () => {
|
|
30
|
+
it('gets the instance', () => {
|
|
31
|
+
const {
|
|
32
|
+
container: {
|
|
33
|
+
firstElementChild: element
|
|
34
|
+
}
|
|
35
|
+
} = render(
|
|
36
|
+
<Component />
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
expect(getReactComponentInstanceFrom(element))
|
|
40
|
+
.toBeInstanceOf(Component)
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
describe('`findReactComponentInstanceFor`', () => {
|
|
45
|
+
it('gets the instance', () => {
|
|
46
|
+
const {
|
|
47
|
+
container: {
|
|
48
|
+
firstElementChild: element
|
|
49
|
+
}
|
|
50
|
+
} = render(
|
|
51
|
+
<Component />
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
expect(findReactComponentInstanceFor(element?.querySelector('.target'), Component))
|
|
55
|
+
.toBeInstanceOf(Component)
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
})
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
|
|
3
|
+
import '@testing-library/jest-dom'
|
|
4
|
+
import {
|
|
5
|
+
render
|
|
6
|
+
} from '@testing-library/react'
|
|
7
|
+
|
|
8
|
+
import getReactComponentInstanceFrom from '#react-component-instance/container'
|
|
9
|
+
|
|
10
|
+
describe('#react-component-instance/container', () => {
|
|
11
|
+
describe('`getReactComponentInstanceFrom`', () => {
|
|
12
|
+
class Component extends React.Component {
|
|
13
|
+
render () {
|
|
14
|
+
return <div />
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
it('gets the instance', () => {
|
|
19
|
+
const {
|
|
20
|
+
container
|
|
21
|
+
} = render(
|
|
22
|
+
<Component />
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
expect(getReactComponentInstanceFrom(container))
|
|
26
|
+
.toBeInstanceOf(Component)
|
|
27
|
+
})
|
|
28
|
+
})
|
|
29
|
+
})
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {ReactComponentInstanceTypes.FiberRootNode} FiberRootNode
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {string} key
|
|
7
|
+
* @returns {boolean}
|
|
8
|
+
*/
|
|
9
|
+
function isReactContainerKey (key) {
|
|
10
|
+
return key.startsWith('__reactContainer$')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {HTMLElement} container
|
|
15
|
+
* @returns {React.Component<any, any, any> | HTMLElement | Text | null}
|
|
16
|
+
*/
|
|
17
|
+
export default function getReactComponentInstanceFrom (container) {
|
|
18
|
+
const key = (
|
|
19
|
+
Object.keys(container)
|
|
20
|
+
.find(isReactContainerKey)
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
if (key) {
|
|
24
|
+
const { // @ts-expect-error
|
|
25
|
+
[key]: fiberNode
|
|
26
|
+
} = container
|
|
27
|
+
|
|
28
|
+
if (fiberNode) {
|
|
29
|
+
const {
|
|
30
|
+
stateNode: {
|
|
31
|
+
current: {
|
|
32
|
+
child: {
|
|
33
|
+
stateNode
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
} = fiberNode
|
|
38
|
+
|
|
39
|
+
return stateNode
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
throw new Error('Component instance is not found')
|
|
44
|
+
}
|
package/src/index.mjs
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {ReactComponentInstanceTypes.FiberNode} FiberNode
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {PropertyKey} key
|
|
7
|
+
* @returns {boolean}
|
|
8
|
+
*/
|
|
9
|
+
function isReactFiberKey (key) {
|
|
10
|
+
return String(key).startsWith('__reactFiber$')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {FiberNode} fiberNode
|
|
15
|
+
* @returns {Generator<FiberNode, void, unknown>}
|
|
16
|
+
*/
|
|
17
|
+
function * traverseFiberNodeTree (fiberNode) {
|
|
18
|
+
let currentNode = fiberNode
|
|
19
|
+
|
|
20
|
+
while (true) {
|
|
21
|
+
yield currentNode
|
|
22
|
+
|
|
23
|
+
currentNode = currentNode.return
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Element | null | undefined} element
|
|
29
|
+
* @param {(() => React.JSX.Element) | typeof React.Component} Component
|
|
30
|
+
* @returns {React.Component<any, any, any> | HTMLElement | Text | null}
|
|
31
|
+
*/
|
|
32
|
+
export function findReactComponentInstanceFor (element, Component) {
|
|
33
|
+
if (element instanceof HTMLElement) {
|
|
34
|
+
const key = (
|
|
35
|
+
Object.keys(element)
|
|
36
|
+
.find(isReactFiberKey)
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if (key) {
|
|
40
|
+
const { // @ts-expect-error
|
|
41
|
+
[key]: fiberNode
|
|
42
|
+
} = element
|
|
43
|
+
|
|
44
|
+
if (fiberNode) {
|
|
45
|
+
for (const fiber of traverseFiberNodeTree(fiberNode)) {
|
|
46
|
+
const {
|
|
47
|
+
type
|
|
48
|
+
} = fiber
|
|
49
|
+
|
|
50
|
+
if (type === Component) {
|
|
51
|
+
const {
|
|
52
|
+
stateNode
|
|
53
|
+
} = fiber
|
|
54
|
+
|
|
55
|
+
return stateNode
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw new Error('Component instance is not found')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throw new Error('Element is not an Element')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @param {Element | null} element
|
|
69
|
+
* @returns {React.Component<any, any, any> | HTMLElement | Text | null}
|
|
70
|
+
*/
|
|
71
|
+
export default function getReactComponentInstanceFrom (element) {
|
|
72
|
+
if (element instanceof HTMLElement) {
|
|
73
|
+
const key = (
|
|
74
|
+
Object.keys(element)
|
|
75
|
+
.find(isReactFiberKey)
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
if (key) {
|
|
79
|
+
const { // @ts-expect-error
|
|
80
|
+
[key]: fiberNode
|
|
81
|
+
} = element
|
|
82
|
+
|
|
83
|
+
if (fiberNode) {
|
|
84
|
+
/**
|
|
85
|
+
* `return` is the component which owns `element`
|
|
86
|
+
*/
|
|
87
|
+
const {
|
|
88
|
+
return: {
|
|
89
|
+
stateNode
|
|
90
|
+
}
|
|
91
|
+
} = fiberNode
|
|
92
|
+
|
|
93
|
+
return stateNode
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
throw new Error('Component instance is not found')
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
throw new Error('Element is not an Element')
|
|
101
|
+
}
|
package/tsconfig.json
CHANGED
package/index.mjs
DELETED
|
File without changes
|