react-components-rails 1.0.0.beta1 → 1.0.0.beta4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -3
- data/README.md +8 -2
- data/lib/react-components-rails.rb +3 -0
- data/package.json +22 -21
- data/pnpm-lock.yaml +1064 -0
- data/react-components-rails.gemspec +3 -3
- data/src/index.ts +86 -38
- data/tsconfig.json +12 -8
- metadata +4 -17
- data/yarn.lock +0 -5101
@@ -6,7 +6,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "react-components-rails"
|
8
8
|
spec.licenses = ["MIT"]
|
9
|
-
spec.version = "1.0.0.
|
9
|
+
spec.version = "1.0.0.beta4"
|
10
10
|
spec.authors = ["Renaud Chaput"]
|
11
11
|
spec.email = ["renchap@gmail.com"]
|
12
12
|
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
|
|
15
15
|
spec.homepage = "https://github.com/renchap/webpacker-react"
|
16
16
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
-
f.match(%r{^(test|spec|features)/})
|
18
|
+
f.match(%r{^(test|spec|features|pnpm-lock.yaml)/})
|
19
19
|
end
|
20
20
|
spec.bindir = "exe"
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.required_ruby_version = ">= 2.7.0"
|
25
25
|
|
26
26
|
spec.add_development_dependency "bundler", "~> 2.3"
|
27
|
-
spec.add_development_dependency "rake", "~>
|
27
|
+
# spec.add_development_dependency "rake", "~> 12.0"
|
28
28
|
# spec.add_development_dependency "minitest", "~> 5.0"
|
29
29
|
# spec.add_development_dependency "capybara"
|
30
30
|
# spec.add_development_dependency "selenium-webdriver"
|
data/src/index.ts
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
import React from "react"
|
2
2
|
import ReactDOM from "react-dom"
|
3
|
-
import
|
4
|
-
|
5
|
-
import assign from "lodash/assign"
|
6
|
-
import omit from "lodash/omit"
|
3
|
+
import type ReactDOMClient from "react-dom/client"
|
4
|
+
|
7
5
|
// import ujs from './ujs'
|
8
6
|
|
9
7
|
const CLASS_ATTRIBUTE_NAME = "data-react-class"
|
@@ -11,46 +9,79 @@ const PROPS_ATTRIBUTE_NAME = "data-react-props"
|
|
11
9
|
|
12
10
|
declare global {
|
13
11
|
interface Window {
|
14
|
-
ReactComponentsRails:
|
12
|
+
ReactComponentsRails: ReactComponentsRails
|
15
13
|
}
|
16
14
|
}
|
17
15
|
|
18
|
-
|
19
|
-
registeredComponents
|
16
|
+
class ReactComponentsRails {
|
17
|
+
#registeredComponents = {} as { [name: string]: React.ComponentType }
|
18
|
+
#mountedRoots = [] as ReactDOMClient.Root[]
|
19
|
+
#ReactDOMClient = undefined as typeof ReactDOMClient | undefined | false
|
20
|
+
|
21
|
+
static getInstance() {
|
22
|
+
if (typeof window.ReactComponentsRails === "undefined") {
|
23
|
+
const instance = new ReactComponentsRails()
|
24
|
+
window.ReactComponentsRails = instance
|
25
|
+
|
26
|
+
// ujs.setup(this.mountComponents.bind(this), this.unmountComponents.bind(this))
|
27
|
+
}
|
28
|
+
|
29
|
+
return window.ReactComponentsRails
|
30
|
+
}
|
20
31
|
|
21
|
-
render(node: Element, component: React.ComponentType) {
|
32
|
+
private render(node: Element, component: React.ComponentType) {
|
22
33
|
const propsJson = node.getAttribute(PROPS_ATTRIBUTE_NAME)
|
23
34
|
const props = propsJson && JSON.parse(propsJson)
|
24
35
|
|
25
36
|
const reactElement = React.createElement(component, props)
|
26
37
|
|
27
|
-
|
28
|
-
|
38
|
+
if (this.#ReactDOMClient) {
|
39
|
+
const root = this.#ReactDOMClient.createRoot(node)
|
40
|
+
root.render(reactElement)
|
41
|
+
this.#mountedRoots.push(root)
|
42
|
+
} else {
|
43
|
+
ReactDOM.render(reactElement, node)
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
private registerComponents(components: {
|
48
|
+
[name: string]: React.ComponentType
|
49
|
+
}) {
|
50
|
+
const alreadyExisting: string[] = []
|
29
51
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
52
|
+
Object.keys(components).forEach((key) => {
|
53
|
+
if (this.#registeredComponents[key]) alreadyExisting.push(key)
|
54
|
+
else {
|
55
|
+
const comp = components[key]
|
56
|
+
this.#registeredComponents[key] = comp
|
57
|
+
}
|
58
|
+
})
|
59
|
+
|
60
|
+
if (alreadyExisting.length > 0) {
|
36
61
|
console.error(
|
37
|
-
`react-components-rails: can not register components. Following components are already registered: ${
|
62
|
+
`react-components-rails: can not register components. Following components are already registered: ${alreadyExisting.join(
|
63
|
+
", "
|
64
|
+
)}`
|
38
65
|
)
|
39
66
|
}
|
40
67
|
|
41
|
-
assign(this.registeredComponents, omit(components, collisions))
|
42
68
|
return true
|
43
|
-
}
|
44
|
-
|
45
|
-
unmountComponents() {
|
46
|
-
const mounted = document.querySelectorAll(`[${CLASS_ATTRIBUTE_NAME}]`)
|
47
|
-
for (let i = 0; i < mounted.length; i += 1) {
|
48
|
-
ReactDOM.unmountComponentAtNode(mounted[i])
|
49
|
-
}
|
50
|
-
},
|
69
|
+
}
|
51
70
|
|
52
|
-
|
53
|
-
|
71
|
+
// Not used for now, useful for UJS
|
72
|
+
// private unmountComponents() {
|
73
|
+
// if (this.#ReactDOMClient) {
|
74
|
+
// this.#mountedRoots.forEach((root) => root.unmount())
|
75
|
+
// this.#mountedRoots = []
|
76
|
+
// } else {
|
77
|
+
// const mounted = document.querySelectorAll(`[${CLASS_ATTRIBUTE_NAME}]`)
|
78
|
+
// for (let i = 0; i < mounted.length; i += 1) {
|
79
|
+
// ReactDOM.unmountComponentAtNode(mounted[i])
|
80
|
+
// }
|
81
|
+
// }
|
82
|
+
// }
|
83
|
+
|
84
|
+
private mountComponents() {
|
54
85
|
const toMount = document.querySelectorAll(`[${CLASS_ATTRIBUTE_NAME}]`)
|
55
86
|
|
56
87
|
for (let i = 0; i < toMount.length; i += 1) {
|
@@ -64,7 +95,7 @@ const ReactComponentsRails = {
|
|
64
95
|
continue
|
65
96
|
}
|
66
97
|
|
67
|
-
const component = registeredComponents[className]
|
98
|
+
const component = this.#registeredComponents[className]
|
68
99
|
|
69
100
|
if (component) {
|
70
101
|
if (node.innerHTML.length === 0) this.render(node, component)
|
@@ -74,17 +105,34 @@ const ReactComponentsRails = {
|
|
74
105
|
)
|
75
106
|
}
|
76
107
|
}
|
77
|
-
}
|
108
|
+
}
|
78
109
|
|
79
110
|
setup(components = {}) {
|
80
|
-
|
81
|
-
window.ReactComponentsRails
|
82
|
-
|
83
|
-
}
|
111
|
+
this.loadReactDOMClient().then(() => {
|
112
|
+
window.ReactComponentsRails.registerComponents(components)
|
113
|
+
window.ReactComponentsRails.mountComponents()
|
114
|
+
})
|
115
|
+
}
|
84
116
|
|
85
|
-
|
86
|
-
|
87
|
-
|
117
|
+
private loadReactDOMClient() {
|
118
|
+
return new Promise<void>((resolve) => {
|
119
|
+
if (this.#ReactDOMClient) resolve()
|
120
|
+
|
121
|
+
import("react-dom/client")
|
122
|
+
.then((i) => {
|
123
|
+
// with some bundlers, it can be imported as `.default`, while not with some others
|
124
|
+
this.#ReactDOMClient = i.default || i
|
125
|
+
resolve()
|
126
|
+
})
|
127
|
+
.catch(() => {
|
128
|
+
// if this fails, then we will fallback to the legacy API
|
129
|
+
this.#ReactDOMClient = false
|
130
|
+
resolve()
|
131
|
+
})
|
132
|
+
})
|
133
|
+
}
|
88
134
|
}
|
89
135
|
|
90
|
-
|
136
|
+
const instance = ReactComponentsRails.getInstance()
|
137
|
+
|
138
|
+
export default instance
|
data/tsconfig.json
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
{
|
2
|
+
"exclude": ["dist/**/*"],
|
2
3
|
"compilerOptions": {
|
3
4
|
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
4
5
|
|
@@ -11,8 +12,11 @@
|
|
11
12
|
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
12
13
|
|
13
14
|
/* Language and Environment */
|
14
|
-
"target": "es2016"
|
15
|
-
"lib": [
|
15
|
+
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
16
|
+
"lib": [
|
17
|
+
"DOM",
|
18
|
+
"ES2016"
|
19
|
+
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
|
16
20
|
// "jsx": "preserve", /* Specify what JSX code is generated. */
|
17
21
|
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
18
22
|
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
@@ -24,8 +28,8 @@
|
|
24
28
|
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
25
29
|
|
26
30
|
/* Modules */
|
27
|
-
"module": "
|
28
|
-
|
31
|
+
"module": "CommonJS" /* Specify what module code is generated. */,
|
32
|
+
"rootDir": "./src" /* Specify the root folder within your source files. */,
|
29
33
|
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
|
30
34
|
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
31
35
|
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
@@ -69,12 +73,12 @@
|
|
69
73
|
/* Interop Constraints */
|
70
74
|
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
|
71
75
|
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
|
72
|
-
"esModuleInterop": true
|
76
|
+
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
|
73
77
|
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
74
|
-
"forceConsistentCasingInFileNames": true
|
78
|
+
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
75
79
|
|
76
80
|
/* Type Checking */
|
77
|
-
"strict": true
|
81
|
+
"strict": true /* Enable all strict type-checking options. */,
|
78
82
|
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
79
83
|
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
80
84
|
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
@@ -96,6 +100,6 @@
|
|
96
100
|
|
97
101
|
/* Completeness */
|
98
102
|
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
99
|
-
"skipLibCheck": true
|
103
|
+
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
100
104
|
}
|
101
105
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: react-components-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.beta4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renaud Chaput
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-08-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -24,20 +24,6 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.3'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - "~>"
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '13.0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '13.0'
|
41
27
|
description:
|
42
28
|
email:
|
43
29
|
- renchap@gmail.com
|
@@ -56,12 +42,13 @@ files:
|
|
56
42
|
- lib/component.rb
|
57
43
|
- lib/helpers.rb
|
58
44
|
- lib/railtie.rb
|
45
|
+
- lib/react-components-rails.rb
|
59
46
|
- package.json
|
47
|
+
- pnpm-lock.yaml
|
60
48
|
- react-components-rails.gemspec
|
61
49
|
- src/index.ts
|
62
50
|
- src/ujs.ts
|
63
51
|
- tsconfig.json
|
64
|
-
- yarn.lock
|
65
52
|
homepage: https://github.com/renchap/webpacker-react
|
66
53
|
licenses:
|
67
54
|
- MIT
|