{"_id":"@danitulp/aanzee-tina-next","_rev":"2-d5d8faa589f232da8bbdcb55605d155d","name":"@danitulp/aanzee-tina-next","dist-tags":{"latest":"0.1.13"},"versions":{"0.1.12":{"name":"@danitulp/aanzee-tina-next","version":"0.1.12","main":"./build/index.cjs.js","module":"./build/lib/index.js","types":"src/index.ts","sideEffects":false,"scripts":{"test":"jest --ci","test-watch":"jest --watch","watch":"rollup --config --watch","build":"rollup --config"},"dependencies":{"react-hook-form":"^5.7.2"},"devDependencies":{"@babel/preset-env":"^7.10.2","@babel/preset-react":"^7.10.1","@directus/sdk-js":"^6.1.1","@testing-library/jest-dom":"^5.10.1","@testing-library/react":"^10.3.0","@testing-library/react-hooks":"^3.2.1","@tinacms/fields":"^0.12.2","@tinacms/forms":"^0.6.2","@tinacms/react-forms":"^0.2.2","@tinacms/styles":"^0.5.1","@types/jest":"^26.0.0","@types/node":"^14.0.13","@types/prosemirror-model":"^1.7.2","@types/prosemirror-state":"^1.2.4","@types/react":"^16.9.34","@types/react-test-renderer":"^16.9.2","@types/styled-components":"^5.1.0","@types/testing-library__jest-dom":"^5.9.1","@types/testing-library__react":"^10.0.1","@types/testing-library__react-hooks":"^3.2.0","@types/webpack":"^4.41.17","autoprefixer":"^9.7.6","identity-obj-proxy":"^3.0.0","install-peers-cli":"^2.2.0","jest":"^26.0.1","miragejs":"^0.1.40","msw":"0.18","prop-types":"^15.7.2","react":"^16.13.1","react-dom":"^16.13.1","react-test-renderer":"^16.13.1","react-tinacms-editor":"^0.7.2","react-tinacms-inline":"^0.10.0","rollup":"^2.15.0","rollup-plugin-typescript2":"^0.27.1","styled-components":"^5.1.0","tinacms":"^0.22.0","ts-jest":"^26.1.0","tslib":"^2.0.0","typescript":"^3.8.3"},"peerDependencies":{"@directus/sdk-js":"^6.1.1","@tinacms/fields":"^0.12.2","@tinacms/forms":"^0.6.2","@tinacms/react-forms":"^0.2.2","@tinacms/styles":"^0.5.1","react":"^16.13.1","react-dom":"^16.13.1","react-tinacms-editor":"^0.8.3","react-tinacms-inline":"^0.10.0","styled-components":"^5.1.0","tinacms":"^0.22.0"},"repository":{"type":"git","url":"https://github.com/DaniTulp/aanzee-tina-next.git"},"author":{"name":"Dani Tulp","email":"danitulp@gmail.com"},"license":"MIT","description":"``` yarn add @danitulp/aanzee-tina-next ```","_id":"@danitulp/aanzee-tina-next@0.1.12","dist":{"shasum":"c1a0c980935056d411835005ec5d244f8f938b95","integrity":"sha512-1Su9q9hNDNArL3X5dhyTsCsyuFV8I24ku/nKQmvG9IeWjf0NHGiAn7Us5RJm7CWpcdSVp56qz+qFZz6rSXLq0w==","tarball":"https://registry.npmjs.org/@danitulp/aanzee-tina-next/-/aanzee-tina-next-0.1.12.tgz","fileCount":195,"unpackedSize":641054,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBZtfCRA9TVsSAnZWagAAkyEP/iHMLwWAjcTSULsqcwn/\nwDNe1tLIVWaKKpPuSPuSD+Q+AaTd84bq3SzOGjNJv02/l/P5syjscNKh4eEq\nyRfNAwCf9kvTwGjqbdFd03jJ2wTG6v6erGczQe9gMEnN9w7r5nS6+Cx/IHon\nYCxpa8ro6EG7VJNjB1S4Rm75EzqF3iz+hibAAPtCDliVCgI1OcXXWrJMTNVs\n03w7QRvhjx7A8mEeEAvePkA2CQ3thCYb0r2eSYhMk0OzDAr6Q8E9wVSkTrf1\n+D6RA96QbrP4FCJz4+Lmy12SnoJrYTTtYgSB5+d/Q6rRlhRulElkj0PwTA4u\nYQ1qnn7mZs17yDQgLIJXgGTybmdP7hg5m4ZBFT6i/KFugktjotMGjDIgAZXn\nEXvUgqrXVnXGD3hKzt0EgaBIcKJ9fIkHpundNKSCvd799BdEAfM6T2cVOkFX\naR6dyz0619WdhesAtUz/UPIOEIT5zV3BxzLZbR8sQ/+ENfFpLu9wOtnbKSnC\nuc02dFuKbqMIyZ30rq/8Y2qzApp0PgwSkMIHfucSq7n+XHSSP0r/4/e/uyRx\nnUpJovK7u6r+QIN5Kd3IRIjMkgj7pgLR0Wl3kFiWyZI/8UU7pIaYAsn+wZIo\nV7i+1PilXi7I6ueXMgNDGM97Hse/cs4CzOPzl3zkviBTnYEl/MLL9VPChcfK\ndKpZ\r\n=kn8a\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDC9BqNJoe+6wjENGvaQRE3RWP1uLK2w22si1w8xCl0yAiB736NUZi68y4ClBy/Rwfet6szEBB5ivs3JvTgjvnBh6Q=="}]},"maintainers":[{"name":"danitulp","email":"danitulp@gmail.com"}],"_npmUser":{"name":"danitulp","email":"danitulp@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/aanzee-tina-next_0.1.12_1594202975404_0.022319944154614246"},"_hasShrinkwrap":false},"0.1.13":{"name":"@danitulp/aanzee-tina-next","version":"0.1.13","main":"./build/index.cjs.js","module":"./build/lib/index.js","types":"src/index.ts","sideEffects":false,"scripts":{"test":"jest --ci","test-watch":"jest --watch","watch":"rollup --config --watch","build":"rollup --config"},"dependencies":{"react-hook-form":"^5.7.2"},"devDependencies":{"@babel/preset-env":"^7.10.2","@babel/preset-react":"^7.10.1","@directus/sdk-js":"^6.1.1","@testing-library/jest-dom":"^5.10.1","@testing-library/react":"^10.3.0","@testing-library/react-hooks":"^3.2.1","@tinacms/fields":"^0.12.2","@tinacms/forms":"^0.6.2","@tinacms/react-forms":"^0.2.2","@tinacms/styles":"^0.5.1","@types/jest":"^26.0.0","@types/node":"^14.0.13","@types/prosemirror-model":"^1.7.2","@types/prosemirror-state":"^1.2.4","@types/react":"^16.9.34","@types/react-test-renderer":"^16.9.2","@types/styled-components":"^5.1.0","@types/testing-library__jest-dom":"^5.9.1","@types/testing-library__react":"^10.0.1","@types/testing-library__react-hooks":"^3.2.0","@types/webpack":"^4.41.17","autoprefixer":"^9.7.6","identity-obj-proxy":"^3.0.0","install-peers-cli":"^2.2.0","jest":"^26.0.1","miragejs":"^0.1.40","msw":"0.18","prop-types":"^15.7.2","react":"^16.13.1","react-dom":"^16.13.1","react-test-renderer":"^16.13.1","react-tinacms-editor":"^0.7.2","react-tinacms-inline":"^0.10.0","rollup":"^2.15.0","rollup-plugin-typescript2":"^0.27.1","styled-components":"^5.1.0","tinacms":"^0.22.0","ts-jest":"^26.1.0","tslib":"^2.0.0","typescript":"^3.8.3"},"peerDependencies":{"@directus/sdk-js":"^6.1.1","@tinacms/fields":"^0.12.2","@tinacms/forms":"^0.6.2","@tinacms/react-forms":"^0.2.2","@tinacms/styles":"^0.5.1","react":"^16.13.1","react-dom":"^16.13.1","react-tinacms-editor":"^0.8.3","react-tinacms-inline":"^0.10.0","styled-components":"^5.1.0","tinacms":"^0.22.0"},"repository":{"type":"git","url":"https://github.com/DaniTulp/aanzee-tina-next.git"},"author":{"name":"Dani Tulp","email":"danitulp@gmail.com"},"license":"MIT","description":"``` yarn add @danitulp/aanzee-tina-next ```","_id":"@danitulp/aanzee-tina-next@0.1.13","dist":{"shasum":"7bf1b17d19e86094b2afdb6c1654a221eec186f3","integrity":"sha512-NR/40dinz8uXhPhutfMSxQNYnWU6THF+kyJQDMZiUearGCaRJbgX9sY7nx2P94QCR8Dj8F5Zmas5UUZTt2rnqQ==","tarball":"https://registry.npmjs.org/@danitulp/aanzee-tina-next/-/aanzee-tina-next-0.1.13.tgz","fileCount":106,"unpackedSize":97391,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJfBZz+CRA9TVsSAnZWagAAie4QAIwPZUYEorT2sFN7N1x3\nYSr2Xb5zWw0I+Q8rQSTequpzvA+3TRo8v8ncnmqm1HC4cUZUwXFmElsJ8N6R\nbK+zZzIARSYonF5xisp3I7Ri8LVSJJsrHP+SmW5xqeqo3Vxk1npbWF/cuIKx\nnELM6u3csVxQnqX0Aoal7gdZLlIb69kAi95Y24er1EB0xbxCHeYgLQJpn2we\n0Jxh4p/ftwtacOERx8ZmKvf/hgoB2i1ZFHRZIjaU7OiAOKw17zoSw53x7tf7\n2L+ByuQg0MdglkcWHUZqeG+bAKAGvzLYrpF1XWhYuGRSxRUuLW6Wz4kzVLYW\nWZ04AobNY+lfkk6FDAIvpz8nbWR+lkdpCvPuBeprz1rzBV/5f/sT7wYN00qQ\ncC0onxB3CUMP53OJoziJc846tedit8ucyra76OabF1snXmuXHadbpmSKSEHc\nw7LY1q6lRjGycgbsP5yKmPOe8DQm/f0eidsvRPClNmNGRw4Q6N0bA/ToTSBv\n5oEbPMC8rFmqimtMWDVUtu9RsQ/SiJkLdYnFMwZpGE5xcLSyM3NFeJ7GHb8Z\n8/sV8SECyNOYr7JgGEGZwBcGS+kNwhejg9jurrjU/JhSb0kTwUgYL5rYYa/w\n89Ivfbf06zxohAb3MrsFWecdxZQyMu0w9LhsPQ3092Ly+MeibEb3fEsczwBi\nHxkM\r\n=uCy3\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCVTb78NIzP6ncrJYFei17McCjaItD+rSNpPO3RbLemDAIhAPx/gTnP8CfdzX4O4/L3EovwwxpKdw/6Y322ToU2fNmx"}]},"maintainers":[{"name":"danitulp","email":"danitulp@gmail.com"}],"_npmUser":{"name":"danitulp","email":"danitulp@gmail.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/aanzee-tina-next_0.1.13_1594203389788_0.6723349219186121"},"_hasShrinkwrap":false}},"time":{"created":"2020-07-08T10:09:35.358Z","0.1.12":"2020-07-08T10:09:35.565Z","modified":"2022-04-05T02:41:50.959Z","0.1.13":"2020-07-08T10:16:29.979Z"},"maintainers":[{"name":"danitulp","email":"danitulp@gmail.com"}],"description":"``` yarn add @danitulp/aanzee-tina-next ```","repository":{"type":"git","url":"https://github.com/DaniTulp/aanzee-tina-next.git"},"author":{"name":"Dani Tulp","email":"danitulp@gmail.com"},"license":"MIT","readme":"![Run Jest Tests](https://github.com/DaniTulp/aanzee-tina-next/workflows/Run%20Jest%20Tests/badge.svg)\n\n# Setup\n\n```\nyarn add @danitulp/aanzee-tina-next\n```\n\nAdd all the peer dependencies.\n\n```\nyarn add @directus/sdk-js @tinacms/fields @tinacms/forms @tinacms/react-forms @tinacms/styles react react-dom react-tinacms-editor react-tinacms-inline styled-components tinacms\n```\n\n## The goal\n\nThe goal of this package is to be able to create a working CMS using [TinaCMS](https://tinacms.org) and [Directus](https://directus.io). Currently we achieve this by adding a component which wraps the React application (optimized for NextJS). When adding this wrapper you get access to React Hooks which make it possible to easily add page editing functionality to your project. The three things it currently does is:\n\n- Authentication management\n- Dynamically add form fields based on configuration\n- Directus integration\n\nBy doing this we can handle some boilerplate configuration while still retaining the flexibility you need.\n\nThe setup process below will show how it can be implemented in a NextJS application. Note: this is the way we settled on but you could change the way you implement these.\n\n## NextJS setup\n\n### pages/\\_app.js\n\nThe `pages/_app.js` file is the wrapper for NextJS applications. In here we can initialize the `Tina` component. We import it dynamically using Next dynamic imports because we don't want to increase the bundle size when not in use, see [this Github issue](https://github.com/tinacms/tinacms/issues/771). This way it only gets loaded when it's needed. In this example we use [Preview Mode](https://nextjs.org/docs/advanced-features/preview-mode) to decide when the `Tina` should be loaded. The `Tina` component requires a prop `options` to know what the url is for the Directus API and which Directus project it is.\n\n**NOTE:** this only works if the page exports a `preview` prop from the [`getStaticProps()`](https://nextjs.org/docs/advanced-features/preview-mode#step-2-update-getstaticprops) function. When you don't expose a `preview` prop from `getStaticProps()` it won't render `Tina` even if it is enabled.\n\nThe `PreviewProvider` component isn't required but it exposes a `usePreview()` hook which can be used inside all the nested components.\n\n```jsx\n// pages/_app.js\n\nimport { PreviewProvider } from \"@danitulp/aanzee-tina-next\";\nimport dynamic from \"next/dynamic\";\nconst Tina = dynamic(\n  async () => (await import(\"@danitulp/aanzee-tina-next\")).Tina\n);\n\nfunction App({ Component, pageProps }) {\n  if (pageProps.preview) {\n    return (\n      <Tina\n        options={{\n          url: \"http://directus-api.test/\",\n          project: \"api\",\n        }}\n      >\n        <PreviewProvider value={pageProps.preview}>\n          <Component {...pageProps}></Component>\n        </PreviewProvider>\n      </Tina>\n    );\n  }\n  return (\n    <PreviewProvider value={pageProps.preview}>\n      <Component {...pageProps}></Component>\n    </PreviewProvider>\n  );\n}\n\nexport default App;\n```\n\nTo enable preview mode reference [this documentation](https://nextjs.org/docs/advanced-features/preview-mode). You could have a custom login page which uses the Directus api to authenticate. You could then validate the token inside the preview mode lambda function. Here's an example of a function you could use to validate the token:\n\n```js\nimport { createServerClient } from \"@danitulp/aanzee-tina-next/\";\n\nexport default async (req, res) => {\n  const token = req.body.token;\n  if (!token) {\n    res.clearPreviewData();\n    return res.status(400).json({\n      message: \"No token set\",\n    });\n  }\n  const client = createServerClient({\n    url: \"http://directus-api.test/\",\n    project: \"api\",\n    token: \"admin\",\n  });\n  client.config.token = token;\n\n  if (!(await client.isLoggedIn())) {\n    res.clearPreviewData();\n    return res.status(400).end({\n      message: \"Invalid token\",\n    });\n  }\n  res.setPreviewData({});\n  return res.status(200).end();\n};\n```\nUsually the way you want to setup a page is as follows:\n\n```jsx\n// pages/index.js\nimport { usePreview } from \"@danitulp/aanzee-tina-next\";\nimport dynamic from \"next/dynamic\";\n\nconst PreviewComponent = dynamic(() => import(\"./../components/Preview\"));\nexport default function Home({ news }) {\n  const preview = usePreview();\n  return preview ? (\n    <PreviewComponent>Preview</PreviewComponent>\n  ) : (\n    <div>No Preview</div>\n  );\n}\n\nexport async function getStaticProps(context) {\n  const preview = !!context.preview;\n  const client = createServerClient({\n    url: \"http://directus-api.test/\",\n    project: \"api\",\n    token: \"static-token\",\n  });\n  const news = await client.getItems(\"news\", {\n    status: !context.preview ? \"published\" : \"*\",\n  });\n  //NOTE if you don't export a preview prop, the provider won't know when it's enabled.\n  return {\n    props: {\n      news,\n      preview,\n    },\n  };\n}\n```\n\nFirst of all we add another dynamic import for the preview component, this is again so we don't load all of the dependencies when they are not needed. Based on the value of the `usePreview` hook we can check whether it's in preview mode (**This requires the `PreviewProvider` to work**).\n\nIn the `getStaticProps` method we check if the preview mode is enabled and we create a [Directus Client](https://docs.directus.io/guides/js-sdk.html) for the serverside code. Because the serverside client doesn't handle authentication we have to give it a [static token](https://docs.directus.io/api/authentication.html#tokens), this should be kept secret from the client. Based on if the preview mode is enabled we can manipulate the client to only show all published news posts or all the news post for example. In the `Home` function we then have access to all the variables that are defined in the `props` object. In this case don't actually need the `news` object but you could render a list of news items.\n\nInside the `PreviewComponent` is where the logic lives to interact with TinaCMS.\n\n```jsx\n//components/preview.js\nimport {\n  AbstractField,\n  useDirectusFields,\n  useDirectusClient,\n} from \"@danitulp/aanzee-tina-next\";\nimport { useForm, usePlugin } from \"tinacms\";\n\nexport default function ({ children }) {\n  const client = useDirectusClient();\n  const fields = useDirectusFields(\"news\", {\n    customFields: {\n      switch: ToggleField,\n    },\n  });\n  const [values, form] = useForm(\n    {\n      onSubmit: async (values) => await client.createItem(\"news\", values),\n      fields,\n      label: \"Create news item\",\n      id: \"add-news\",\n    },\n    {\n      fields,\n    }\n  );\n  usePlugin(form);\n  return <>{children}</>;\n}\n\nclass ToggleField extends AbstractField {\n  map() {\n    this.tinaField.component = \"toggle\";\n    return this.tinaField;\n  }\n}\n```\n\nIn the `PreviewComponent` we use the `useDirectusFields` hook we pass in an argument which represents a Directus collection, in this case \"news\". We use the collection to retrieve the field definition defined in Directus. This returns an array of fields which can be used by TinaCMS. Not all interfaces defined by Directus are currently implemented yet, things like text inputs, textarea and wysiwyg fields are defined by default. You can override these or add new ones too. In this case we add a custom field \"switch\" which expects a class that extends the `AbstractField` class. In this case [toggle](https://tinacms.org/docs/fields/toggle) is already defined inside TinaCMS, if you want to add your own [Custom Field reading this part of the TinaCMS documentation can be referenced](https://tinacms.org/docs/fields/custom-fields). When a field isn't defined it will show a warning in the console and in the sidebar it will render \"Unrecognized field type\".\n\nThe `useForm` hook is provided by TinaCMS, for a full reference check [this link](https://tinacms.org/docs/forms#form-configuration). We add the fields we just got back from the `useDirectusFields` hook. We also add it to the second argument because the fields are fetched asynchronously and this argument watches for changes. The `onSubmit` handler defines what happens when the form gets submitted. In this case we create a news item when the form is submitted. We get a directus client by using the `useDirectusClient` hook. **NOTE: all of these hooks have to be inside the Tina component defined in the `_app.js` file.**\n\n## Problems\n\nI don't really like the way we have to check on each page that uses the CMS if the preview is enabled, but currently this solution offers you the most flexbility. You could potentially add your own abstractions on top of these. I don't know if there is a generic way to do it. When the TinaCMS package gets the bundle sizes under control it could be less of a problem.\n\nI'm also not loving the current way to override the custom fields I feel like a class is to heavy, it might be beter to just be able to pass in a closure with all the properties you might need.\n","readmeFilename":"README.md"}