react-components-rails 1.0.0.beta1 → 1.0.0.beta4

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.
@@ -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