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.
@@ -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.beta1"
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", "~> 13.0"
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 intersection from "lodash/intersection"
4
- import keys from "lodash/keys"
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: typeof ReactComponentsRails
12
+ ReactComponentsRails: ReactComponentsRails
15
13
  }
16
14
  }
17
15
 
18
- const ReactComponentsRails = {
19
- registeredComponents: {} as { [name: string]: React.ComponentType },
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
- ReactDOM.render(reactElement, node)
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
- registerComponents(components: { [name: string]: React.Component }) {
31
- const collisions = intersection(
32
- keys(this.registeredComponents),
33
- keys(components)
34
- )
35
- if (collisions.length > 0) {
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: ${collisions}`
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
- mountComponents() {
53
- const { registeredComponents } = this
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
- if (typeof window.ReactComponentsRails === "undefined") {
81
- window.ReactComponentsRails = this
82
- // ujs.setup(this.mountComponents.bind(this), this.unmountComponents.bind(this))
83
- }
111
+ this.loadReactDOMClient().then(() => {
112
+ window.ReactComponentsRails.registerComponents(components)
113
+ window.ReactComponentsRails.mountComponents()
114
+ })
115
+ }
84
116
 
85
- window.ReactComponentsRails.registerComponents(components)
86
- window.ReactComponentsRails.mountComponents()
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
- export default ReactComponentsRails
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", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
15
- "lib": ["DOM", "ES2016"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
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": "commonjs", /* Specify what module code is generated. */
28
- // "rootDir": "./", /* Specify the root folder within your source files. */
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, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
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, /* Ensure that casing is correct in imports. */
78
+ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
75
79
 
76
80
  /* Type Checking */
77
- "strict": true, /* Enable all strict type-checking options. */
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 /* Skip type checking all .d.ts files. */
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.beta1
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-02-27 00:00:00.000000000 Z
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