{"_id":"@actualwave/react-custom-component","_rev":"1-6748f7dca4c3ef93cebdadcfd385a8d2","name":"@actualwave/react-custom-component","dist-tags":{"latest":"0.0.1"},"versions":{"0.0.1":{"name":"@actualwave/react-custom-component","description":"An approach to microfrontends via custom elements and module isolation","version":"0.0.1","license":"MIT","types":"./index.d.ts","main":"./cjs/index.js","module":"./es/index.js","type":"commonjs","exports":{"types":"./index.d.ts","import":"./es/index.js","default":"./cjs/index.js"},"keywords":["react","custom","element","microfrontend"],"scripts":{"build":"rollup -c"},"peerDependencies":{"react":"^18.2.0","react-dom":"^18.2.0"},"devDependencies":{"@rollup/plugin-commonjs":"^24.0.1","@rollup/plugin-node-resolve":"^15.0.1","@rollup/plugin-typescript":"^11.0.0","@types/react":"^18.0.27","@types/react-dom":"^18.0.10","react":"^18.2.0","react-dom":"^18.2.0","rollup":"^3.12.0","rollup-plugin-dts":"^5.1.1","tslib":"^2.5.0","typescript":"^4.9.4"},"gitHead":"d120ef9b05c7b53b6b1ad4f38d832a731900bae1","_id":"@actualwave/react-custom-component@0.0.1","_nodeVersion":"16.13.0","_npmVersion":"8.1.0","dist":{"integrity":"sha512-A2n8Bnl//kH/Gh5i3m2RY8zxE7X0S0Utf7aA5FVy1Rd9scPEHe5y9cg+lgklivSgcqjFboaGnuHcgUTH5sKpnQ==","shasum":"76cb44a1d2b08ea442767d19e21b9ebfe91fcaaa","tarball":"https://registry.npmjs.org/@actualwave/react-custom-component/-/react-custom-component-0.0.1.tgz","fileCount":9,"unpackedSize":58956,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHHhtOjMQAG9pHE5Jmb40mO45Usaq44ebk0OYqj5VPDAAiEAtn8MmgDkDv0vOg1QcZ4+Qu6NRTqwVI3ewjCwYWGAPVw="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJj1rc0ACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmodKA//Wy3JnR62YZW1uur0GhWmc0a7NWTOWme8cpxKQLH+flD9CPxd\r\n+KSq4IHr+IbjHXpNbQs2CvkuJhB9G8uHZjpc2Z+nctB513Krdmdq2LQ9lhZK\r\nnA96RMCca2buAEHH94Et2tkKXXMryGuVod0IPHiOYmJJ6iD3F4qtg6SNqBWq\r\nc270X81wGnmGRcQCDP3YZSjb/x9VWnT18at24jKSDlZwl5rRbGsRgyuniM4/\r\n6r+gfdC9uRJxRfVTGSsoQSphnXG4HfUUbqA1OxqRIE7Sr8ffuCmKzvHk92LE\r\nLMucN5VKdW93fWmcj0gI68AucSGm41wXluDeeJrzXLk2GFnMKbnbWSY7n8ro\r\nhemH6O6iFHqaBlX6WOnwiIPo89BQ0tyemlLMbMj8W5vL707ORucMDuH0l6qc\r\nnzix5IUeV8wfNDZxehSszK4r/GS6IwB7t5hvkaAW2n9C8kKujRkUXqAcorMw\r\nXy1VMxcBg5ycsiiJf0025ptT02B3mT+N9L1hXoUYoWQZzTj7PL61JH0P94ZT\r\nZEc7xhGfXLwOYHD36h3V6nossSRhExI636CxymwCwGeVirqNSZnCKRXMopvG\r\nZZy9WrGwBcm4m1fnOGxybfGq0Pl2456m/0T59TnmegRxwOkYIZhx2VxVJ4+R\r\nRyu2iSYQ6SCv05sYcDI5UirQvgvcoKiSb7k=\r\n=8grL\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"actualwave","email":"burdiuz@gmail.com"},"directories":{},"maintainers":[{"name":"actualwave","email":"burdiuz@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/react-custom-component_0.0.1_1675015988237_0.25891861204347166"},"_hasShrinkwrap":false,"deprecated":"Was"}},"time":{"created":"2023-01-29T18:13:08.179Z","0.0.1":"2023-01-29T18:13:08.382Z","modified":"2023-01-29T18:35:13.150Z"},"maintainers":[{"name":"actualwave","email":"burdiuz@gmail.com"}],"description":"An approach to microfrontends via custom elements and module isolation","keywords":["react","custom","element","microfrontend"],"license":"MIT","readme":"# @actualwave/react-custom-component\n\nAdds support for independent modules wrapped in [HTML Custom Elements](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements). It provides a set of react hooks to establish communication through custom element container, so it is possible to pass data IN via custom element attributes and IN/OUT via events.\n\n> Note: This does not isolate environments of running applications, all sub-applications running on one page will have access to same globals and it is possible for one application to interfere with others.\n\n## Installation\n\nThis package can be installed via its name `@actualwave/react-custom-component`.\nUsing NPM\n\n```\nnpm install @actualwave/react-custom-component\n```\n\nOr Yarn\n\n```\nyarn add @actualwave/react-custom-component\n```\n\n## Integration\n\nWe have a react component which we want to use as an independent module, it is a normal react component.\n\n```jsx\nconst MyComponent = () => {\n  return (\n    <div>\n      <h1>Hello World!</h1>\n    </div>\n  );\n```\n\nInstead of bootstrapping it via ReactDOM.render(), we register it as a custom element.\n\n```jsx\nimport { createCustomElement } from \"@actualwave/react-custom-element\";\n\ncreateCustomElement({\n  name: \"my-component\",\n  render: () => <MyComponent />,\n});\n\n/**\n * For TypeScript you might need to add declaration fo custom element,\n * so it knows which attributes can be added to it.\n */\n\ndeclare global {\n  namespace JSX {\n    interface IntrinsicElements {\n      [\"my-component\"]: DetailedHTMLProps<\n        HTMLAttributes<HTMLElement> & {\n          onSomething: (event: Event) => void;\n        },\n        HTMLElement\n      >;\n    }\n  }\n}\n\ncreateCustomElement({\n  name: \"my-component\",\n  render: () => <MyComponent />,\n});\n```\n\nThen you have to import this component and use `<my-component>` HTML element.\n\n```jsx\nimport { useEffect, useRef } from \"react\";\nimport \"./App.css\";\nimport \"./MyComponent\";\n\nfunction App() {\n  return (\n    <div className=\"app\">\n      <header className=\"App-header\">\n        <p>\n          Edit <code>src/App.js</code> and save to reload.\n        </p>\n        <a\n          className=\"App-link\"\n          href=\"https://reactjs.org\"\n          target=\"_blank\"\n          rel=\"noopener noreferrer\"\n        >\n          Learn React\n        </a>\n      </header>\n      <my-component></my-component>\n    </div>\n  );\n}\n\nexport default App;\n```\n\nWhen custom HTML element is constructed, it will render `MyComponent` component as an independent React application.\n\n## Communication\n\nSince modules integrated with custom elements are independent sub-applications, there are no way to communicate with them traditional React ways -- props or context. But you can communicate with sub-application by passing attributes or dispatching events.\n\n### Attributes\n\nAttributes for custom element can be set or changed at any time and these changes could be captured by sub-application.\nSetting attribute\n\n```jsx\n<my-component data-value=\"Something here\"></my-component>\n```\n\nReading attribute\n\n```jsx\nimport {\n  createCustomElement,\n  useContainerAttribute,\n} from \"@actualwave/react-custom-element\";\n\nconst MyComponent = () => {\n  const [readValue] = useContainerAttribute(\"data-value\");\n\n  return (\n    <div>\n      <h1>Hello World!</h1>\n      <span>{readValue()}</span>\n    </div>\n  );\n};\n```\n\nWe can read any custom element attribute but listen for changes only for registered attributes. To register an attribute we have to provide it when registering custom element.\n\n```jsx\ncreateCustomElement({\n  name: \"my-component\",\n  render: () => <MyComponent />,\n  attributes: [\"data-value\", \"id\"],\n});\n```\n\nThen we can use a change listener and it will be called whenever value of attribute is changed.\n\n```jsx\nconst MyComponent = () => {\n  const [value, setValue] = useState(\"\");\n\n  const [readValue] = useContainerAttribute(\n    \"data-value\",\n    (name, oldValue, newValue) => setValue(newValue)\n  );\n\n  useEffect(() => {\n    setValue(readValue());\n  }, [setValue, readValue]);\n\n  return (\n    <div>\n      <h1>Hello World!</h1>\n      <span>{value}</span>\n    </div>\n  );\n};\n```\n\nAnd whenever attribute is changed, sub-application will be aware of that change.\n\n```jsx\nimport { useEffect, useRef } from \"react\";\nimport \"./App.css\";\nimport \"./MyComponent\";\n\nfunction App() {\n  const [value, setValue] = useState(\"\");\n\n  return (\n    <div className=\"app\">\n      <my-component data-value={value}></my-component>\n      <button onClick={() => updateValue(\"New attribute value\")}>\n        Change Value\n      </button>\n    </div>\n  );\n}\n\nexport default App;\n```\n\n### Events\n\nEvents allow to communicate both ways and pass non-serialized data by reference.\nReact/JSX currently does not register custom events on custom elements. So, something like this may not work.\n\n```jsx\n<my-component\n  data-value=\"My value\"\n  onSomething={(event) => console.log(\"on something:\", event)}\n/>\n```\n\nOne of the ways to make it work is to use `CustomElementShim` which manually assigns event listeners.\n\n```jsx\n<CustomElementShim\n  name=\"my-component\"\n  data-value=\"My value\"\n  onSomething={(event) => console.log(\"on something:\", event)}\n/>\n```\n\n> Note: `CustomElementShim` is not aware of event phases and when using, for example, `onClickCapture` will not register `click` event for capture phase but will register `clickCapture` event for bubbling phase.\n\nThese events can be captured from within sub-application components using `useContainerListener` hook\n\n```js\nuseContainerListener(\n  \"something\",\n  (event) => console.log(\"Event:\", event),\n  false,\n  []\n);\n```\n\nTo dispatch an event from sub-application on custom element use `useContainerDispatch` hook.\n\n```jsx\nimport { createCustomElement, useContainerDispatch } from \"./custom-element\";\n\nconst MyComponent = () => {\n  const doSomething = useContainerDispatch(\"something\");\n\n  return (\n    <div>\n      <h1>Hello World!</h1>\n      <button\n        onClick={() => doSomething(\"There's something interesting here.\")}\n      >\n        Do Something\n      </button>\n    </div>\n  );\n};\n```\n","readmeFilename":"README.md"}