diff --git a/app/javascript/react-components/src/components/HelloWorld.jsx b/app/javascript/react-components/src/components/HelloWorld.jsx
new file mode 100644
index 000000000..bdad263b8
--- /dev/null
+++ b/app/javascript/react-components/src/components/HelloWorld.jsx
@@ -0,0 +1,49 @@
+import React, { useState } from 'react';
+
+export const HelloWorld = () => {
+ const [count, setCount] = useState(0);
+
+ return (
+
+
Hello from Chatwoot React!
+
Count: {count}
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/app/javascript/react-components/src/index.jsx b/app/javascript/react-components/src/index.jsx
new file mode 100644
index 000000000..45893072f
--- /dev/null
+++ b/app/javascript/react-components/src/index.jsx
@@ -0,0 +1,2 @@
+// Export all React components for the Chatwoot React Components library
+export { HelloWorld } from './components/HelloWorld';
\ No newline at end of file
diff --git a/package.json b/package.json
index 502a144cd..296fd1fa2 100644
--- a/package.json
+++ b/package.json
@@ -14,6 +14,7 @@
"ruby:prettier": "bundle exec rubocop -a",
"build:sdk": "BUILD_MODE=library vite build",
"build:ui": "BUILD_MODE=ui vite build",
+ "build:react": "BUILD_MODE=react-components vite build",
"prepare": "husky install",
"size": "size-limit",
"story:dev": "histoire dev",
@@ -116,6 +117,7 @@
"@iconify-json/teenyicons": "^1.2.1",
"@intlify/eslint-plugin-vue-i18n": "^3.2.0",
"@size-limit/file": "^8.2.4",
+ "@vitejs/plugin-react": "^4.5.2",
"@vitest/coverage-v8": "3.0.5",
"@vue/test-utils": "^2.4.6",
"autoprefixer": "^10.4.20",
@@ -137,6 +139,8 @@
"postcss-preset-env": "^8.5.1",
"prettier": "^3.3.3",
"prosemirror-model": "^1.22.3",
+ "react": "^19.1.0",
+ "react-dom": "^19.1.0",
"size-limit": "^8.2.4",
"tailwindcss": "^3.4.13",
"vite": "^5.4.19",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index db7589569..d410a7ded 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -260,6 +260,9 @@ importers:
'@size-limit/file':
specifier: ^8.2.4
version: 8.2.6(size-limit@8.2.6)
+ '@vitejs/plugin-react':
+ specifier: ^4.5.2
+ version: 4.5.2(vite@5.4.19(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
'@vitest/coverage-v8':
specifier: 3.0.5
version: 3.0.5(vitest@3.0.5(@types/node@22.7.0)(jsdom@24.1.3)(sass@1.79.3)(terser@5.33.0))
@@ -323,6 +326,12 @@ importers:
prosemirror-model:
specifier: ^1.22.3
version: 1.22.3
+ react:
+ specifier: ^19.1.0
+ version: 19.1.0
+ react-dom:
+ specifier: ^19.1.0
+ version: 19.1.0(react@19.1.0)
size-limit:
specifier: ^8.2.4
version: 8.2.6
@@ -363,14 +372,64 @@ packages:
'@antfu/utils@0.7.10':
resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==}
+ '@babel/code-frame@7.27.1':
+ resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/compat-data@7.27.5':
+ resolution: {integrity: sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/core@7.27.4':
+ resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/generator@7.27.5':
+ resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-compilation-targets@7.27.2':
+ resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-imports@7.27.1':
+ resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-module-transforms@7.27.3':
+ resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
+ '@babel/helper-plugin-utils@7.27.1':
+ resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-string-parser@7.25.9':
resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-validator-identifier@7.25.9':
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-validator-identifier@7.27.1':
+ resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/helpers@7.27.6':
+ resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==}
+ engines: {node: '>=6.9.0'}
+
'@babel/parser@7.25.6':
resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==}
engines: {node: '>=6.0.0'}
@@ -381,6 +440,23 @@ packages:
engines: {node: '>=6.0.0'}
hasBin: true
+ '@babel/parser@7.27.5':
+ resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1':
+ resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1':
+ resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0-0
+
'@babel/runtime@7.25.6':
resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==}
engines: {node: '>=6.9.0'}
@@ -389,10 +465,22 @@ packages:
resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==}
engines: {node: '>=6.9.0'}
+ '@babel/template@7.27.2':
+ resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==}
+ engines: {node: '>=6.9.0'}
+
+ '@babel/traverse@7.27.4':
+ resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/types@7.26.0':
resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==}
engines: {node: '>=6.9.0'}
+ '@babel/types@7.27.6':
+ resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==}
+ engines: {node: '>=6.9.0'}
+
'@bcoe/v8-coverage@1.0.2':
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'}
@@ -1039,6 +1127,9 @@ packages:
'@rails/ujs@7.1.400':
resolution: {integrity: sha512-YwvXm3BR5tn+VCAKYGycLejMRVZE3Ionj5gFjEeGXCZnI0Rpi+7dKpmyu90kdUY7dRUFpHTdu9zZceEzFLl38w==}
+ '@rolldown/pluginutils@1.0.0-beta.11':
+ resolution: {integrity: sha512-L/gAA/hyCSuzTF1ftlzUSI/IKr2POHsv1Dd78GfqkR83KMNuswWD61JxGV2L7nRwBBBSDr6R1gCkdTmoN7W4ag==}
+
'@rollup/rollup-android-arm-eabi@4.40.2':
resolution: {integrity: sha512-JkdNEq+DFxZfUwxvB58tHMHBHVgX23ew41g1OQinthJ+ryhdRk67O31S7sYw8u2lTjHUPFxwar07BBt1KHp/hg==}
cpu: [arm]
@@ -1746,6 +1837,18 @@ packages:
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
engines: {node: '>= 10'}
+ '@types/babel__core@7.20.5':
+ resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
+
+ '@types/babel__generator@7.27.0':
+ resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==}
+
+ '@types/babel__template@7.4.4':
+ resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==}
+
+ '@types/babel__traverse@7.20.7':
+ resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==}
+
'@types/estree@1.0.7':
resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==}
@@ -1796,6 +1899,12 @@ packages:
'@videojs/xhr@2.6.0':
resolution: {integrity: sha512-7J361GiN1tXpm+gd0xz2QWr3xNWBE+rytvo8J3KuggFaLg+U37gZQ2BuPLcnkfGffy2e+ozY70RHC8jt7zjA6Q==}
+ '@vitejs/plugin-react@4.5.2':
+ resolution: {integrity: sha512-QNVT3/Lxx99nMQWJWF7K4N6apUEuT0KlZA3mx/mVaoGj3smm/8rc8ezz15J1pcbcjDK0V15rpHetVfya08r76Q==}
+ engines: {node: ^14.18.0 || >=16.0.0}
+ peerDependencies:
+ vite: 5.4.19
+
'@vitejs/plugin-vue@5.1.4':
resolution: {integrity: sha512-N2XSI2n3sQqp5w7Y/AN/L2XDjBIRGqXko+eDp42sydYSBeJuSm5a1sLf8zakmo8u7tA8NmBgoDLA1HeOESjp9A==}
engines: {node: ^18.0.0 || >=20.0.0}
@@ -2162,6 +2271,11 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
+ browserslist@4.25.0:
+ resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==}
+ engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
+ hasBin: true
+
buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
@@ -2206,6 +2320,9 @@ packages:
caniuse-lite@1.0.30001651:
resolution: {integrity: sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==}
+ caniuse-lite@1.0.30001721:
+ resolution: {integrity: sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==}
+
capital-case@1.0.4:
resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==}
@@ -2332,6 +2449,9 @@ packages:
constant-case@3.0.4:
resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==}
+ convert-source-map@2.0.0:
+ resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+
core-js@3.38.1:
resolution: {integrity: sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==}
@@ -2573,6 +2693,9 @@ packages:
electron-to-chromium@1.5.13:
resolution: {integrity: sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==}
+ electron-to-chromium@1.5.166:
+ resolution: {integrity: sha512-QPWqHL0BglzPYyJJ1zSSmwFFL6MFXhbACOCcsCdUMCkzPdS9/OIBVxg516X/Ado2qwAq8k0nJJ7phQPCqiaFAw==}
+
email-validator@2.0.4:
resolution: {integrity: sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ==}
engines: {node: '>4.0'}
@@ -2948,6 +3071,10 @@ packages:
functions-have-names@1.2.3:
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
+ gensync@1.0.0-beta.2:
+ resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
+ engines: {node: '>=6.9.0'}
+
get-caller-file@2.0.5:
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
engines: {node: 6.* || 8.* || >= 10.*}
@@ -3003,6 +3130,10 @@ packages:
global@4.4.0:
resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==}
+ globals@11.12.0:
+ resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
+ engines: {node: '>=4'}
+
globals@13.24.0:
resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==}
engines: {node: '>=8'}
@@ -3377,6 +3508,9 @@ packages:
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==}
engines: {node: '>=14'}
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
@@ -3403,6 +3537,11 @@ packages:
canvas:
optional: true
+ jsesc@3.1.0:
+ resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
+ engines: {node: '>=6'}
+ hasBin: true
+
json-buffer@3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
@@ -3547,6 +3686,9 @@ packages:
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
lru-cache@6.0.0:
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
engines: {node: '>=10'}
@@ -3751,6 +3893,9 @@ packages:
node-releases@2.0.18:
resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
+ node-releases@2.0.19:
+ resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==}
+
nopt@7.2.1:
resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==}
engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0}
@@ -4280,6 +4425,19 @@ packages:
resolution: {integrity: sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==}
engines: {node: '>=12'}
+ react-dom@19.1.0:
+ resolution: {integrity: sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==}
+ peerDependencies:
+ react: ^19.1.0
+
+ react-refresh@0.17.0:
+ resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==}
+ engines: {node: '>=0.10.0'}
+
+ react@19.1.0:
+ resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==}
+ engines: {node: '>=0.10.0'}
+
read-cache@1.0.0:
resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==}
@@ -4398,6 +4556,9 @@ packages:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
+ scheduler@0.26.0:
+ resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
+
sdp@3.2.0:
resolution: {integrity: sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw==}
@@ -4815,6 +4976,12 @@ packages:
peerDependencies:
browserslist: '>= 4.21.0'
+ update-browserslist-db@1.1.3:
+ resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
+ hasBin: true
+ peerDependencies:
+ browserslist: '>= 4.21.0'
+
upper-case-first@2.0.2:
resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==}
@@ -5150,6 +5317,9 @@ packages:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
@@ -5202,10 +5372,83 @@ snapshots:
'@antfu/utils@0.7.10': {}
+ '@babel/code-frame@7.27.1':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.27.1
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
+ '@babel/compat-data@7.27.5': {}
+
+ '@babel/core@7.27.4':
+ dependencies:
+ '@ampproject/remapping': 2.3.0
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.5
+ '@babel/helper-compilation-targets': 7.27.2
+ '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4)
+ '@babel/helpers': 7.27.6
+ '@babel/parser': 7.27.5
+ '@babel/template': 7.27.2
+ '@babel/traverse': 7.27.4
+ '@babel/types': 7.27.6
+ convert-source-map: 2.0.0
+ debug: 4.4.0
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/generator@7.27.5':
+ dependencies:
+ '@babel/parser': 7.27.5
+ '@babel/types': 7.27.6
+ '@jridgewell/gen-mapping': 0.3.8
+ '@jridgewell/trace-mapping': 0.3.25
+ jsesc: 3.1.0
+
+ '@babel/helper-compilation-targets@7.27.2':
+ dependencies:
+ '@babel/compat-data': 7.27.5
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.25.0
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
+ '@babel/helper-module-imports@7.27.1':
+ dependencies:
+ '@babel/traverse': 7.27.4
+ '@babel/types': 7.27.6
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)':
+ dependencies:
+ '@babel/core': 7.27.4
+ '@babel/helper-module-imports': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+ '@babel/traverse': 7.27.4
+ transitivePeerDependencies:
+ - supports-color
+
+ '@babel/helper-plugin-utils@7.27.1': {}
+
'@babel/helper-string-parser@7.25.9': {}
+ '@babel/helper-string-parser@7.27.1': {}
+
'@babel/helper-validator-identifier@7.25.9': {}
+ '@babel/helper-validator-identifier@7.27.1': {}
+
+ '@babel/helper-validator-option@7.27.1': {}
+
+ '@babel/helpers@7.27.6':
+ dependencies:
+ '@babel/template': 7.27.2
+ '@babel/types': 7.27.6
+
'@babel/parser@7.25.6':
dependencies:
'@babel/types': 7.26.0
@@ -5214,6 +5457,20 @@ snapshots:
dependencies:
'@babel/types': 7.26.0
+ '@babel/parser@7.27.5':
+ dependencies:
+ '@babel/types': 7.27.6
+
+ '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.4)':
+ dependencies:
+ '@babel/core': 7.27.4
+ '@babel/helper-plugin-utils': 7.27.1
+
+ '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.27.4)':
+ dependencies:
+ '@babel/core': 7.27.4
+ '@babel/helper-plugin-utils': 7.27.1
+
'@babel/runtime@7.25.6':
dependencies:
regenerator-runtime: 0.14.1
@@ -5222,11 +5479,34 @@ snapshots:
dependencies:
regenerator-runtime: 0.14.1
+ '@babel/template@7.27.2':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/parser': 7.27.5
+ '@babel/types': 7.27.6
+
+ '@babel/traverse@7.27.4':
+ dependencies:
+ '@babel/code-frame': 7.27.1
+ '@babel/generator': 7.27.5
+ '@babel/parser': 7.27.5
+ '@babel/template': 7.27.2
+ '@babel/types': 7.27.6
+ debug: 4.4.0
+ globals: 11.12.0
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/types@7.26.0':
dependencies:
'@babel/helper-string-parser': 7.25.9
'@babel/helper-validator-identifier': 7.25.9
+ '@babel/types@7.27.6':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.27.1
+
'@bcoe/v8-coverage@1.0.2': {}
'@breezystack/lamejs@1.2.7': {}
@@ -5944,6 +6224,8 @@ snapshots:
'@rails/ujs@7.1.400': {}
+ '@rolldown/pluginutils@1.0.0-beta.11': {}
+
'@rollup/rollup-android-arm-eabi@4.40.2':
optional: true
@@ -6744,6 +7026,27 @@ snapshots:
'@tootallnate/once@2.0.0': {}
+ '@types/babel__core@7.20.5':
+ dependencies:
+ '@babel/parser': 7.26.2
+ '@babel/types': 7.26.0
+ '@types/babel__generator': 7.27.0
+ '@types/babel__template': 7.4.4
+ '@types/babel__traverse': 7.20.7
+
+ '@types/babel__generator@7.27.0':
+ dependencies:
+ '@babel/types': 7.26.0
+
+ '@types/babel__template@7.4.4':
+ dependencies:
+ '@babel/parser': 7.26.2
+ '@babel/types': 7.26.0
+
+ '@types/babel__traverse@7.20.7':
+ dependencies:
+ '@babel/types': 7.26.0
+
'@types/estree@1.0.7': {}
'@types/flexsearch@0.7.6': {}
@@ -6802,6 +7105,18 @@ snapshots:
global: 4.4.0
is-function: 1.0.2
+ '@vitejs/plugin-react@4.5.2(vite@5.4.19(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))':
+ dependencies:
+ '@babel/core': 7.27.4
+ '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.4)
+ '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.27.4)
+ '@rolldown/pluginutils': 1.0.0-beta.11
+ '@types/babel__core': 7.20.5
+ react-refresh: 0.17.0
+ vite: 5.4.19(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
+ transitivePeerDependencies:
+ - supports-color
+
'@vitejs/plugin-vue@5.1.4(vite@5.4.19(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))(vue@3.5.12(typescript@5.6.2))':
dependencies:
vite: 5.4.19(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
@@ -7294,6 +7609,13 @@ snapshots:
node-releases: 2.0.18
update-browserslist-db: 1.1.0(browserslist@4.23.3)
+ browserslist@4.25.0:
+ dependencies:
+ caniuse-lite: 1.0.30001721
+ electron-to-chromium: 1.5.166
+ node-releases: 2.0.19
+ update-browserslist-db: 1.1.3(browserslist@4.25.0)
+
buffer-from@1.1.2:
optional: true
@@ -7339,6 +7661,8 @@ snapshots:
caniuse-lite@1.0.30001651: {}
+ caniuse-lite@1.0.30001721: {}
+
capital-case@1.0.4:
dependencies:
no-case: 3.0.4
@@ -7492,6 +7816,8 @@ snapshots:
tslib: 2.8.1
upper-case: 2.0.2
+ convert-source-map@2.0.0: {}
+
core-js@3.38.1: {}
countries-and-timezones@3.6.0: {}
@@ -7702,6 +8028,8 @@ snapshots:
electron-to-chromium@1.5.13: {}
+ electron-to-chromium@1.5.166: {}
+
email-validator@2.0.4: {}
emoji-regex@10.4.0: {}
@@ -8225,6 +8553,8 @@ snapshots:
functions-have-names@1.2.3: {}
+ gensync@1.0.0-beta.2: {}
+
get-caller-file@2.0.5: {}
get-east-asian-width@1.2.0: {}
@@ -8303,6 +8633,8 @@ snapshots:
min-document: 2.19.0
process: 0.11.10
+ globals@11.12.0: {}
+
globals@13.24.0:
dependencies:
type-fest: 0.20.2
@@ -8703,6 +9035,8 @@ snapshots:
js-cookie@3.0.5: {}
+ js-tokens@4.0.0: {}
+
js-yaml@3.14.1:
dependencies:
argparse: 1.0.10
@@ -8773,6 +9107,8 @@ snapshots:
- supports-color
- utf-8-validate
+ jsesc@3.1.0: {}
+
json-buffer@3.0.1: {}
json-logic-js@2.0.5: {}
@@ -8931,6 +9267,10 @@ snapshots:
lru-cache@10.4.3: {}
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
lru-cache@6.0.0:
dependencies:
yallist: 4.0.0
@@ -9127,6 +9467,8 @@ snapshots:
node-releases@2.0.18: {}
+ node-releases@2.0.19: {}
+
nopt@7.2.1:
dependencies:
abbrev: 2.0.0
@@ -9706,6 +10048,15 @@ snapshots:
quick-lru@6.1.2: {}
+ react-dom@19.1.0(react@19.1.0):
+ dependencies:
+ react: 19.1.0
+ scheduler: 0.26.0
+
+ react-refresh@0.17.0: {}
+
+ react@19.1.0: {}
+
read-cache@1.0.0:
dependencies:
pify: 2.3.0
@@ -9853,6 +10204,8 @@ snapshots:
dependencies:
xmlchars: 2.2.0
+ scheduler@0.26.0: {}
+
sdp@3.2.0: {}
section-matter@1.0.0:
@@ -10313,6 +10666,12 @@ snapshots:
escalade: 3.2.0
picocolors: 1.0.1
+ update-browserslist-db@1.1.3(browserslist@4.25.0):
+ dependencies:
+ browserslist: 4.25.0
+ escalade: 3.2.0
+ picocolors: 1.1.1
+
upper-case-first@2.0.2:
dependencies:
tslib: 2.8.1
@@ -10665,6 +11024,8 @@ snapshots:
y18n@5.0.8: {}
+ yallist@3.1.1: {}
+
yallist@4.0.0: {}
yaml-eslint-parser@1.2.3:
diff --git a/vite.config.ts b/vite.config.ts
index 58571e0cc..56e9a0d15 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -22,9 +22,11 @@ import { defineConfig } from 'vite';
import ruby from 'vite-plugin-ruby';
import path from 'path';
import vue from '@vitejs/plugin-vue';
+import react from '@vitejs/plugin-react';
const isLibraryMode = process.env.BUILD_MODE === 'library';
const uiMode = process.env.BUILD_MODE === 'ui';
+const reactComponentMode = process.env.BUILD_MODE === 'react-components';
const isTestMode = process.env.TEST === 'true';
const vueOptions = {
@@ -41,11 +43,15 @@ if (isLibraryMode) {
plugins = [];
} else if (uiMode) {
plugins = [vue()];
+} else if (reactComponentMode) {
+ plugins = [vue(vueOptions), react()];
} else if (isTestMode) {
plugins = [vue(vueOptions)];
}
let lib = undefined;
+let rollupOptions = {};
+
if (isLibraryMode) {
lib = {
entry: path.resolve(__dirname, './app/javascript/entrypoints/sdk.js'),
@@ -58,6 +64,23 @@ if (isLibraryMode) {
formats: ['iife'], // IIFE format for single file
name: 'ui',
};
+} else if (reactComponentMode) {
+ lib = {
+ entry: path.resolve(__dirname, './app/javascript/react-components/src/index.jsx'),
+ formats: ['iife'], // IIFE format for single file
+ name: 'ChatwootReactComponents',
+ fileName: () => 'index.js'
+ };
+
+ rollupOptions = {
+ external: ['react', 'react-dom'],
+ output: {
+ globals: {
+ react: 'React',
+ 'react-dom': 'ReactDOM'
+ }
+ }
+ };
}
const chunkBuilder = chunkInfo => {
@@ -78,16 +101,18 @@ export default defineConfig({
},
build: {
rollupOptions: {
+ ...rollupOptions,
output: {
+ ...rollupOptions.output,
// [NOTE] when not in library mode, no new keys will be addedd or overwritten
// setting dir: isLibraryMode ? 'public/packs' : undefined will not work
- ...(isLibraryMode || uiMode
+ ...(isLibraryMode || uiMode || reactComponentMode
? {
dir: 'public/packs',
entryFileNames: chunkBuilder,
}
: {}),
- inlineDynamicImports: isLibraryMode || uiMode, // Disable code-splitting for SDK
+ inlineDynamicImports: isLibraryMode || uiMode || reactComponentMode, // Disable code-splitting for SDK
},
},
lib,