From 2503d7efcd1622385432ffec7670acee974da284 Mon Sep 17 00:00:00 2001 From: Jon Miller Date: Mon, 21 Apr 2025 14:29:47 -0500 Subject: [PATCH 1/6] update docs to point to dev docs on main site --- README.md | 49 +++++++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 0626848..fac732e 100644 --- a/README.md +++ b/README.md @@ -2,42 +2,19 @@ ## Documentation -Check out an expanded documentation page at https://github.hubspot.com/cms-react/ +Check out an expanded documentation page at https://developers.hubspot.com/docs/guides/cms/react/overview ## Welcome! Thank you for taking the time to learn about HubSpot CMS React. As always our goal is to solve for our customers so we welcome any and all feedback. Chat away in [\#cms-react](https://hubspotdev.slack.com/archives/C04AY1H2204) with other HubSpot developers who are pushing forward with developing with React on the Hubspot CMS. If you do not have access to the developer slack, you can request access [here](https://developers.hubspot.com/slack). -## How do React modules on the CMS work? - -CMS React Modules and Partials are building blocks you can use to write React and JavaScript instead of HubL inside the HubSpot CMS. Note this doesn’t mean you will switch entirely away from HubL, rather we want to provide a pathway to begin writing React to render on both on the server and client. JS modules and partials are built from React components and can directly be referenced via HubL tags in your templates. - ## Can I use React modules on my CMS account? -Yes! Working with React modules is generally available and can be used with all tiers of the CMS, including free. - -## [Default React modules](default-react-modules) - -This directory contains a copy of all of our internal default React modules. As React modules do not appear in the Design manager, we made them available within this public repository so you can make your own copy and edit as you like. The modules you find in this directory are synced up with our internal code to ensure we keep them up to date. - -### What if I don't see a default React module in this repo but that is available for use within Hubspot? -Some default React modules contain code that is internal to Hubspot and thus cannot be used in a general way by external developers. If you are are seeking to utilize one of these modules, or otherwise get a better sense of how it works, please reach out to a developer advocate for more information. - -## [React module boilerplate](react-module-boilerplate) - -If you'd like to get started with your own React module or one of our defaults, we have provided a boilerplate project for you to pick up and get started right away. This boilerplate comes complete with a Sample module so you can test working with this repo with only a few steps on your part. In order to get working with this boilerplate you simply have to: - -- Become familiar with working with our CLI, if you are not already, with our [Hubspot CLI documentation](https://developers.hubspot.com/docs/cms/guides/getting-started) -- Run `hs init` and select your portal. -- Within the react-module-boilerplate/src run `yarn deploy` or `npm deploy`, which is a helper script we offer which runs the `hs project upload` CLI command. -- You will be prompted to create this project in your portal. Confirm and the project will be created. -- Wait a few moments for the deploy to finish. You can view the projects within your portal at `https://app.hubspot.com/developer-projects/{YOUR_PORTAL_ID}` - -Once the module is uploaded you should be able to see it when you go to edit a page, adding it like any other module. +Yes! Working with React modules can be used with all tiers of the CMS, including free. ## Examples +In this repository is example usage of some of key features of React modules. These examples are are best understood alongside our official docs. You can quickly try things out without any local setup by [opening this repo in Codesandbox.io](https://codesandbox.io/p/sandbox/stoic-pateu-g20chg?file=%2Fcms-react%2FREADME.md). -In this repository is example usage of some of key features of React modules. These examples are are best understood alongside our official docs. You can quickly try things out without any local setup by [opening this repo in Codesandbox.io](https://codesandbox.io/p/sandbox/stoic-pateu-g20chg?file=%2Fcms-react%2FREADME.md). ### [Getting Started](examples/getting-started) @@ -64,3 +41,23 @@ GraphQL is the future for querying HubSpot data in your CMS pages. As part of JS ### [Todo MVC](examples/todo-mvc) It seems with every new FE technology on the web comes an implemetation of TodoMVC. We didn't want to be left out and ported a recent version that made use of React and React hooks to work as a JS Module with Islands. Additionally there is an example of our `sharedIslandReducer` which provides a redux like interface for sharing state across islands. + + +### [Default React modules](default-react-modules) + +This directory contains a copy of all of our internal default React modules. As React modules do not appear in the Design manager, we made them available within this public repository so you can make your own copy and edit as you like. The modules you find in this directory are synced up with our internal code to ensure we keep them up to date. + +#### What if I don't see a default React module in this repo but that is available for use within Hubspot? +Some default React modules contain code that is internal to Hubspot and thus cannot be used in a general way by external developers. If you are are seeking to utilize one of these modules, or otherwise get a better sense of how it works, please reach out to a developer advocate for more information. + +### [React module boilerplate](react-module-boilerplate) + +If you'd like to get started with your own React module or one of our defaults, we have provided a boilerplate project for you to pick up and get started right away. This boilerplate comes complete with a Sample module so you can test working with this repo with only a few steps on your part. In order to get working with this boilerplate you simply have to: + +- Become familiar with working with our CLI, if you are not already, with our [Hubspot CLI documentation](https://developers.hubspot.com/docs/cms/guides/getting-started) +- Run `hs init` and select your portal. +- Within the react-module-boilerplate/src run `yarn deploy` or `npm deploy`, which is a helper script we offer which runs the `hs project upload` CLI command. +- You will be prompted to create this project in your portal. Confirm and the project will be created. +- Wait a few moments for the deploy to finish. You can view the projects within your portal at `https://app.hubspot.com/developer-projects/{YOUR_PORTAL_ID}` + +Once the module is uploaded you should be able to see it when you go to edit a page, adding it like any other modules. From 2166006e2745855297085e5ab8feeb31cb980105 Mon Sep 17 00:00:00 2001 From: Jon Miller Date: Mon, 21 Apr 2025 14:38:44 -0500 Subject: [PATCH 2/6] remove docs that have been migrated to main site --- docs/.vitepress/config.ts | 100 +---- docs/appendix.md | 106 ----- docs/field-types/.nojekyll | 1 - docs/field-types/index.md | 59 --- .../type-alias.AdvancedVisibility.md | 31 -- .../type-alias.AlignmentFieldType.md | 40 -- .../type-aliases/type-alias.AudioFieldType.md | 50 --- .../type-alias.BackgroundImageFieldType.md | 40 -- .../type-aliases/type-alias.BaseField.md | 153 ------- .../type-aliases/type-alias.BlogFieldType.md | 27 -- .../type-alias.BooleanFieldType.md | 27 -- .../type-alias.BorderFieldType.md | 68 --- .../type-aliases/type-alias.BorderSideType.md | 45 -- .../type-alias.ChoiceFieldType.md | 47 --- .../type-aliases/type-alias.ColorFieldType.md | 60 --- .../type-alias.CrmObjectFieldType.md | 55 --- .../type-alias.CrmObjectPropertyFieldType.md | 40 -- .../type-aliases/type-alias.CssUnit.md | 9 - .../type-aliases/type-alias.CtaFieldType.md | 22 - .../type-aliases/type-alias.DateFieldType.md | 22 - .../type-alias.DateTimeFieldType.md | 27 -- .../type-aliases/type-alias.EmailFieldType.md | 27 -- .../type-aliases/type-alias.EmbedFieldType.md | 100 ----- .../type-aliases/type-alias.Field.md | 9 - .../type-alias.FieldComponentProps.md | 17 - .../type-aliases/type-alias.FieldType.md | 9 - .../type-aliases/type-alias.FileFieldType.md | 27 -- .../type-alias.FollowUpEmailFieldType.md | 27 -- .../type-aliases/type-alias.FontFieldType.md | 88 ---- .../type-aliases/type-alias.FormFieldType.md | 65 --- .../type-alias.GradientColorType.md | 40 -- .../type-alias.GradientFieldType.md | 48 --- .../type-aliases/type-alias.GroupFieldType.md | 37 -- .../type-aliases/type-alias.HtmlFieldType.md | 22 - .../type-alias.HubdbRowFieldType.md | 55 --- .../type-alias.HubdbTableFieldType.md | 27 -- .../type-aliases/type-alias.HublFieldType.md | 22 - .../type-aliases/type-alias.IconFieldType.md | 45 -- .../type-aliases/type-alias.ImageFieldType.md | 80 ---- .../type-aliases/type-alias.LinkFieldType.md | 83 ---- .../type-aliases/type-alias.LogoFieldType.md | 65 --- .../type-alias.MeetingFieldType.md | 32 -- .../type-aliases/type-alias.MenuFieldType.md | 27 -- .../type-alias.NumberFieldType.md | 62 --- .../type-aliases/type-alias.PageFieldType.md | 27 -- .../type-alias.PaymentFieldType.md | 30 -- .../type-alias.PodcastFieldType.md | 35 -- .../type-alias.RichTextFieldType.md | 27 -- .../type-alias.SfdcCamapaignFieldType.md | 22 - .../type-alias.SimpleMenuFieldType.md | 22 - .../type-alias.SpacingFieldType.md | 145 ------- .../type-alias.SpacingLimitType.md | 27 -- .../type-alias.SpacingValueType.md | 21 - .../type-alias.SurveyFieldType.md | 40 -- .../type-aliases/type-alias.TagFieldType.md | 35 -- .../type-alias.TextAlignmentFieldType.md | 30 -- .../type-aliases/type-alias.TextFieldType.md | 37 -- .../type-aliases/type-alias.UrlFieldType.md | 50 --- .../type-aliases/type-alias.VideoFieldType.md | 100 ----- .../type-alias.WorkflowFieldType.md | 22 - docs/field-types/typedoc-sidebar.json | 332 --------------- docs/index.md | 47 +-- docs/reference.md | 3 - docs/reference/build-healthchecks.md | 50 --- docs/reference/cms-components.md | 391 ------------------ docs/reference/cms-dev-server.md | 169 -------- docs/reference/data-fetching.md | 189 --------- docs/reference/dependencies.md | 5 - docs/reference/islands.md | 70 ---- docs/reference/js-modules.md | 305 -------------- docs/reference/js-partials.md | 37 -- docs/reference/prerendering.md | 3 - docs/reference/project-structure.md | 34 -- docs/reference/secrets.md | 41 -- docs/reference/serverless.md | 33 -- docs/reference/static-assets.md | 13 - docs/reference/styling.md | 137 ------ docs/reference/testing.md | 24 -- 78 files changed, 2 insertions(+), 4594 deletions(-) delete mode 100644 docs/appendix.md delete mode 100644 docs/field-types/.nojekyll delete mode 100644 docs/field-types/index.md delete mode 100644 docs/field-types/type-aliases/type-alias.AdvancedVisibility.md delete mode 100644 docs/field-types/type-aliases/type-alias.AlignmentFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.AudioFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.BackgroundImageFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.BaseField.md delete mode 100644 docs/field-types/type-aliases/type-alias.BlogFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.BooleanFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.BorderFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.BorderSideType.md delete mode 100644 docs/field-types/type-aliases/type-alias.ChoiceFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.ColorFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.CrmObjectFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.CrmObjectPropertyFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.CssUnit.md delete mode 100644 docs/field-types/type-aliases/type-alias.CtaFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.DateFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.DateTimeFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.EmailFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.EmbedFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.Field.md delete mode 100644 docs/field-types/type-aliases/type-alias.FieldComponentProps.md delete mode 100644 docs/field-types/type-aliases/type-alias.FieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.FileFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.FollowUpEmailFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.FontFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.FormFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.GradientColorType.md delete mode 100644 docs/field-types/type-aliases/type-alias.GradientFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.GroupFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.HtmlFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.HubdbRowFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.HubdbTableFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.HublFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.IconFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.ImageFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.LinkFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.LogoFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.MeetingFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.MenuFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.NumberFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.PageFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.PaymentFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.PodcastFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.RichTextFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.SfdcCamapaignFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.SimpleMenuFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.SpacingFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.SpacingLimitType.md delete mode 100644 docs/field-types/type-aliases/type-alias.SpacingValueType.md delete mode 100644 docs/field-types/type-aliases/type-alias.SurveyFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.TagFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.TextAlignmentFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.TextFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.UrlFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.VideoFieldType.md delete mode 100644 docs/field-types/type-aliases/type-alias.WorkflowFieldType.md delete mode 100644 docs/field-types/typedoc-sidebar.json delete mode 100644 docs/reference.md delete mode 100644 docs/reference/build-healthchecks.md delete mode 100644 docs/reference/cms-components.md delete mode 100644 docs/reference/cms-dev-server.md delete mode 100644 docs/reference/data-fetching.md delete mode 100644 docs/reference/dependencies.md delete mode 100644 docs/reference/islands.md delete mode 100644 docs/reference/js-modules.md delete mode 100644 docs/reference/js-partials.md delete mode 100644 docs/reference/prerendering.md delete mode 100644 docs/reference/project-structure.md delete mode 100644 docs/reference/secrets.md delete mode 100644 docs/reference/serverless.md delete mode 100644 docs/reference/static-assets.md delete mode 100644 docs/reference/styling.md delete mode 100644 docs/reference/testing.md diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 4487a6a..782610e 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -4,110 +4,12 @@ import fieldTypesSidebar from '../field-types/typedoc-sidebar.json'; // https://vitepress.dev/reference/site-config export default defineConfig({ title: 'HubSpot - CMS React', - description: 'Documentation for HubSpot CMS React', + description: 'Archived documentation site for HubSpot CMS React', base: '/cms-react/', themeConfig: { // https://vitepress.dev/reference/default-theme-config nav: [ - { text: 'Home', link: '/' }, - { - text: 'Getting Started', - link: 'https://github.com/HubSpot/cms-react/tree/main/examples/hello-world', - }, - { text: 'API Reference', link: '/reference/project-structure' }, - { text: 'Appendix', link: '/appendix' }, { text: 'Release Log', link: 'release-log' }, ], - - sidebar: { - '/': [ - { - text: 'Documentation', - items: [ - { - text: 'Getting started', - link: 'https://github.com/HubSpot/cms-react/tree/main/examples/hello-world', - }, - { text: 'API reference', link: '/reference/project-structure' }, - { text: 'Field types', link: '/field-types/' }, - { text: 'Appendix', link: '/appendix' }, - { text: 'Release Log', link: 'release-log' }, - ], - }, - ], - '/reference/': { - base: '/reference/', - items: [ - { - text: 'API Reference', - items: [ - { - text: 'Project Structure', - link: 'project-structure', - }, - { text: 'React Partials', link: 'js-partials' }, - { - text: 'React Modules', - link: 'js-modules', - items: [ - { - text: 'Directory Structure', - link: 'js-modules#directory-structure-requirements', - }, - { - text: 'Module Fields', - link: 'js-modules#module-fields', - }, - { text: 'GraphQL', link: 'js-modules#graphql' }, - { text: 'hublDataTemplate', link: 'js-modules#hubldatatemplate' }, - ], - }, - { text: 'Islands', link: 'islands' }, - { text: '@hubspot/cms-components', link: 'cms-components' }, - { text: '@hubspot/cms-dev-server', link: 'cms-dev-server' }, - { text: 'Styling', link: 'styling' }, - { text: 'Static assets', link: 'static-assets' }, - { - text: 'Third-party dependencies', - link: 'dependencies', - }, - { text: 'Prerendering', link: 'prerendering' }, - { text: 'Testing', link: 'testing' }, - { text: 'Data Fetching', link: 'data-fetching' }, - { text: 'Secrets', link: 'secrets' }, - { text: 'Working with Serverless', link: 'serverless' }, - { text: 'Build Health Checks', link: 'build-healthchecks' }, - ], - }, - { - text: 'Module field types', - link: '../field-types/', - }, - ], - }, - '/field-types/': { - base: '/field-types/', - items: fieldTypesSidebar.map((sidebarItem) => { - // remove nesting in sidebar, at least while it doesn't include - // anything - const { items, collapsed, ...rest } = sidebarItem; - if (items.length === 0) { - return rest; - } - return sidebarItem; - }), - }, - }, - - socialLinks: [ - { - icon: 'github', - link: 'https://github.com/HubSpot/cms-react/', - }, - ], - - search: { - provider: 'local' - } }, }); diff --git a/docs/appendix.md b/docs/appendix.md deleted file mode 100644 index fa6e992..0000000 --- a/docs/appendix.md +++ /dev/null @@ -1,106 +0,0 @@ -# Appendix - -## Deployment - -JS Rendering uses the [Projects](https://developers.hubspot.com/docs/platform/build-and-deploy-using-hubspot-projects) system to manage your JS components. The Projects system is also used to build [private apps](https://developers.hubspot.com/docs/platform/create-private-apps-with-projects), [CRM extensions](https://developers.hubspot.com/docs/platform/create-custom-cards-with-projects), and [serverless functions](https://developers.hubspot.com/docs/platform/serverless-functions). By creating the proper directory structure like in the [js-rendering-hello-world](https://git.hubteam.com/HubSpot/js-rendering-hello-world/tree/master/hello-world-project) repo you can use the `hs project upload` command to upload your code to HubSpot where we will then build it and deploy it, making your components available for reference in HubL templates via the `module` and `js_partial` tags. - -After running `hs project upload` you’ll be able to see its build/deploy status in the [Projects UI](https://app.hubspot.com/l/developer-projects/). - -**NOTE:** There is a maximum, uncompressed file size limit of 250mb for a given build. If your project exceeds this limit an error will be thrown at build time alerting you of the issue. - -HubL assets, such as HubL templates that reference JS partials or modules, aren’t managed with Projects but you can upload them as a theme with the `hs upload` command, making them available in the Design Manager. - -Just like in the [js-rendering-hello-world repo](https://git.hubteam.com/HubSpot/js-rendering-hello-world/tree/master/hello-world-project), we recommend separating your JS rendering components and HubL assets into different directories. - -## Server-side/Client-side Rendering - -One concept that can be difficult to understand is the relation between server-side rendering, client-side rendering, and hydration - -This page gives a good overview of these terms: https://web.dev/rendering-on-the-web - -Once familiar with these terms, let's look at an example component and how it can be rendered server-side only, client-side only, and server-side with client-side hydration. - -```javascript -function HelloWorldComponent() { - const afterHydration = useAfterIslandHydration(); - if (afterHydration) { - return
Hello, hydration!
; - } - return
Hello, world!
; -} -``` - -In the left-most column, a server-side only render, notice that we don’t wrap our component with the Island component. Since there is no Island the client will display the server-side rendered “Hello, world!”. This HTML will never be modified on the client as it is not an Island. - -In the middle column, a client-side-only render, we wrap the component in an Island, but set the `clientOnly` flag to `true`. This means the server will skip rendering the component on the server and will only return an empty `div` for React to attach to. On the client, the Island’s React code will be downloaded and [instantiated](https://react.dev/reference/react-dom/client/createRoot#root-render) for the component. The client will display “Hello, hydration!” immediately, as `useAfterIslandHydration` always resolves to `true` when `clientOnly` is set to `true` (since there is no hydration). - -In the right-most column, a server-side render with client hydration, we wrap the component in an Island without the `clientOnly` option set. Immediately the client will display the server-side rendered “Hello, world!”, and then the Island’s React code will be downloaded and [instantiated](https://react.dev/reference/react-dom/client/hydrateRoot) (“hydrated”), with the first render also returning “Hello, world!”, since `useAfterIslandHydration` will return `false` on its first invocation. Automatically, there is a subsequent render where `useAfterIslandHydration` will resolve to `true` and the client will show “Hello, hydration!”. - -### Mismatch Error Example - -This example leads to an error because the result of client hydration does not match the server render. When there’s a mismatch this can cause problems with React.This is why `useAfterIslandHydration` is helpful. More information on this error can be found in the [React docs](https://react.dev/reference/react-dom/client/hydrateRoot#handling-different-client-and-server-content). - -```javascript -function HelloWorldComponent() { - // resolves to true in browser - if (typeof window !== 'undefined') { - return
Hello, client!
; - } - return
Hello, server!
; -} -``` - -The difference in this example is in the right column, the server-side render with client hydration. When the Island’s React code gets downloaded and instantiated, the first render will result in HTML that’s different from what we received from the server (since the `if` statement will always resolve to `true` on the client). These renders must match. This is fixed by using `useAfterIslandHydration` like in the previous example. - -Recipes (todo: add diagrams) - -## Learning links - -### Learning JavaScript: - -- [Modern JavaScript tutorial \(javascript.info\)](https://javascript.info/) -- [Just JavaScript course \(for purchase\)](https://justjavascript.com/) - -### Learning React: - -- [React Quick start tutorial \(official docs\)](https://react.dev/learn) -- [React API reference \(official docs\)](https://react.dev/reference/react) -- [The Perils of Rehydration](https://www.joshwcomeau.com/react/the-perils-of-rehydration/) - -Other media and recordings: - -- [HubSpot.Extend\(\) “How JavaScript Rendering Powers Business-enabled Sites” talk recording](https://www.youtube.com/watch?v=chj-_yBN5_c) - -## Concepts/Glossary - -### Partials, Modules - -A JS Partial is a React component that can be loaded directly into a template, using the HubL tag render_js_partial. It must be located in the `components/partials/` subdirectory of the JavaScript project component. A JS Module behaves just like a traditional HubL module, but defined with JavaScript and a React component. It must be located in the `components/modules/` subdirectory of the JavaScript project component. - -### CSR and SSR - -Client Side Rendering (CSR) and Server Side Rendering (SSR) are two different ways of rendering web pages to serve to the end user. At a high level, SSR is when the HTML for a page is generated on the server and then sent to the client. CSR on the other hand sends a bundle of JavaScript to the user, which is then run on the browser to generate the HTML for the page. Some web performance metrics relevant to tradeoffs between client and server renders are: - -- [Time to First Byte \(TTFB\)](https://web.dev/ttfb/) -- [First Contentful Paint \(FCP\)](https://web.dev/first-contentful-paint/) -- [Time To Interactive \(TTI\)](https://web.dev/interactive/) -- [Total Blocking Time \(TBT\)](https://web.dev/tbt/) -- [Cumulative Layout Shift \(CLS\)](https://web.dev/cls/) - -A server side render of a web page generates the full HTML on the server when the user makes a request, and sends it to the user. By running any logic for the page on the server instead of the user's machine, you can avoid sending JavaScript to the client, allowing for a TTI equal to your FCP and minimal TBT. Since you are sending all of the HTML the user needs to see your website at once, the FCP of your page is very fast relative to TTFB. Since the initial page render is complete, any CLS is avoided. The main downside to full server rendering is a higher TTFB, since generating a full page on the server can take time depending on the complexity of the page. Additionally, if your page has interactivity, it usually requires some amount of JavaScript sent to the browser that can be time-consuming to manage alongside your server-rendered page, especially if server render is in a non-JavaScript runtime (such as HubL). - -Server-rendered pages that do not have much dynamic content, such as blogs, or knowledge base articles, can take advantage of a static render. A statically-rendered page is one that is prerendered ahead of time and stored on the server (or a [CDN](https://web.dev/content-delivery-networks/)) to be immediately served to the user when a request is made. This is distinct from SSR since the same HTML is reused on every request. [Eligible HubSpot pages make use of static rendering by default](https://developers.hubspot.com/docs/cms/developer-reference/cdn/prerendering?__hstc=75491725.e2098b212e147a7b9be6fd756c0c6815.1649440584659.1667397195793.1667489478959.105&__hssc=75491725.4.1667489478959&__hsfp=1149209764). This technique improves server-rendered TTFB, and indirectly all other metrics, at the cost of your page being less dynamic. - -A client side render of a web page is done by sending a small, visually empty HTML file and a bundle of JavaScript that will run to render the full page content on the user’s browser. This can require sending quite a large amount of JavaScript to the user, and can be slowed down by how fast the user’s hardware can process the JavaScript. But for pages or applications that are very dynamic or interactive, this can be a good approach that avoids a lot of infrastructure overhead. For client side renders, TTFB will be very low, since no rendering logic happens before the first byte, but FCP, TTI, and TBT will be much higher. Client side pages also experience layout shift since the initial render is an empty page that gets filled out later. - -### Islands - -As a HubSpot developer, quite a few of the pages you will be developing will be static. Content such as blog posts, knowledge base articles, landing pages, are primarily static HTML. But often you will need to have some sort of interactivity on your page, such as image carousels, a form with client validation, or a live-chat widget. - -In the traditional HubL world, adding interactivity to your page often requires rendering the entire interactive chunk of your page client side using JavaScript. This can impact page performance negatively, since it requires the user to download, parse, and execute a large amount of JavaScript to render. This method can also impact the SEO of your page since the initial HTML response is often empty of any content. - -[Islands](https://www.patterns.dev/posts/islands-architecture/) address this issue by aiming for the best of both worlds between CSR and SSR. An island is a subtree of your partial or module that contains interactivity, such as buttons or a search field. When serving a page to the user, your page is fully server rendered, and that HTML is initially rendered to the user without interactivity. Then, when needed, the interactive JavaScript in the island is automatically [hydrated](https://reactjs.org/docs/react-dom-client.html#hydrateroot), which is the process of loading, running, and attaching the client-side React component to the server-rendered HTML. - -Loading the interactive parts of your page using islands can improve page performance compared to a fully client-side approach. Since most of your page is rendered to HTML on the server, the only JavaScript a user’s browser needs to download is what is required to hydrate your islands. While more work is done to create the initial server-side HTML relative to a client-side page’s initial empty HTML response, the time from first paint to interactive is reduced. This usually results in a sharp decrease in FCP and a decrease in TTI. Since Island content renders on the server initially, it eliminates layout shift in most scenarios. Islands also help with SEO for interactive pages, since the initial HTML response contains all content. - -Another benefit of islands is the flexibility to choose when they are hydrated, known as [progressive hydration](https://www.patterns.dev/posts/progressive-hydration/). Rather than doing all the hydration on page load, which might be expensive for complex pages, you can defer hydration of non-critical pieces of your page to when the browser has finished all other work, or when the user scrolls down to an island initially below the page fold. For complex islands, this can be a significant performance benefit: if the user never scrolls to see it, it will never be loaded. diff --git a/docs/field-types/.nojekyll b/docs/field-types/.nojekyll deleted file mode 100644 index e2ac661..0000000 --- a/docs/field-types/.nojekyll +++ /dev/null @@ -1 +0,0 @@ -TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/field-types/index.md b/docs/field-types/index.md deleted file mode 100644 index b39601a..0000000 --- a/docs/field-types/index.md +++ /dev/null @@ -1,59 +0,0 @@ -# API - -## Type Aliases - -- [AdvancedVisibility](type-aliases/type-alias.AdvancedVisibility.md) -- [AlignmentFieldType](type-aliases/type-alias.AlignmentFieldType.md) -- [AudioFieldType](type-aliases/type-alias.AudioFieldType.md) -- [BackgroundImageFieldType](type-aliases/type-alias.BackgroundImageFieldType.md) -- [BaseField](type-aliases/type-alias.BaseField.md) -- [BlogFieldType](type-aliases/type-alias.BlogFieldType.md) -- [BooleanFieldType](type-aliases/type-alias.BooleanFieldType.md) -- [BorderFieldType](type-aliases/type-alias.BorderFieldType.md) -- [BorderSideType](type-aliases/type-alias.BorderSideType.md) -- [ChoiceFieldType](type-aliases/type-alias.ChoiceFieldType.md) -- [ColorFieldType](type-aliases/type-alias.ColorFieldType.md) -- [CrmObjectFieldType](type-aliases/type-alias.CrmObjectFieldType.md) -- [CrmObjectPropertyFieldType](type-aliases/type-alias.CrmObjectPropertyFieldType.md) -- [CssUnit](type-aliases/type-alias.CssUnit.md) -- [CtaFieldType](type-aliases/type-alias.CtaFieldType.md) -- [DateFieldType](type-aliases/type-alias.DateFieldType.md) -- [DateTimeFieldType](type-aliases/type-alias.DateTimeFieldType.md) -- [EmailFieldType](type-aliases/type-alias.EmailFieldType.md) -- [EmbedFieldType](type-aliases/type-alias.EmbedFieldType.md) -- [Field](type-aliases/type-alias.Field.md) -- [FieldComponentProps](type-aliases/type-alias.FieldComponentProps.md) -- [FieldType](type-aliases/type-alias.FieldType.md) -- [FileFieldType](type-aliases/type-alias.FileFieldType.md) -- [FollowUpEmailFieldType](type-aliases/type-alias.FollowUpEmailFieldType.md) -- [FontFieldType](type-aliases/type-alias.FontFieldType.md) -- [FormFieldType](type-aliases/type-alias.FormFieldType.md) -- [GradientColorType](type-aliases/type-alias.GradientColorType.md) -- [GradientFieldType](type-aliases/type-alias.GradientFieldType.md) -- [GroupFieldType](type-aliases/type-alias.GroupFieldType.md) -- [HtmlFieldType](type-aliases/type-alias.HtmlFieldType.md) -- [HubDbRowFieldType](type-aliases/type-alias.HubdbRowFieldType.md) -- [HubDbTableFieldType](type-aliases/type-alias.HubdbTableFieldType.md) -- [HublFieldType](type-aliases/type-alias.HublFieldType.md) -- [IconFieldType](type-aliases/type-alias.IconFieldType.md) -- [ImageFieldType](type-aliases/type-alias.ImageFieldType.md) -- [LinkFieldType](type-aliases/type-alias.LinkFieldType.md) -- [LogoFieldType](type-aliases/type-alias.LogoFieldType.md) -- [MeetingFieldType](type-aliases/type-alias.MeetingFieldType.md) -- [MenuFieldType](type-aliases/type-alias.MenuFieldType.md) -- [NumberFieldType](type-aliases/type-alias.NumberFieldType.md) -- [PageFieldType](type-aliases/type-alias.PageFieldType.md) -- [PaymentFieldType](type-aliases/type-alias.PaymentFieldType.md) -- [RichTextFieldType](type-aliases/type-alias.RichTextFieldType.md) -- [SfdcCamapaignFieldType](type-aliases/type-alias.SfdcCamapaignFieldType.md) -- [SimpleMenuFieldType](type-aliases/type-alias.SimpleMenuFieldType.md) -- [SpacingFieldType](type-aliases/type-alias.SpacingFieldType.md) -- [SpacingLimitType](type-aliases/type-alias.SpacingLimitType.md) -- [SpacingValueType](type-aliases/type-alias.SpacingValueType.md) -- [SurveyFieldType](type-aliases/type-alias.SurveyFieldType.md) -- [TagFieldType](type-aliases/type-alias.TagFieldType.md) -- [TextAlignmentFieldType](type-aliases/type-alias.TextAlignmentFieldType.md) -- [TextFieldType](type-aliases/type-alias.TextFieldType.md) -- [UrlFieldType](type-aliases/type-alias.UrlFieldType.md) -- [VideoFieldType](type-aliases/type-alias.VideoFieldType.md) -- [WorkflowFieldType](type-aliases/type-alias.WorkflowFieldType.md) diff --git a/docs/field-types/type-aliases/type-alias.AdvancedVisibility.md b/docs/field-types/type-aliases/type-alias.AdvancedVisibility.md deleted file mode 100644 index 0d0c0fb..0000000 --- a/docs/field-types/type-aliases/type-alias.AdvancedVisibility.md +++ /dev/null @@ -1,31 +0,0 @@ -[API](../index.md) > AdvancedVisibility - -# Type alias: AdvancedVisibility - -> **AdvancedVisibility**: `object` - -## Type declaration - -### `boolean_operator` - -**boolean\_operator**: `"AND"` \| `"OR"` - -*** - -### `children` - -**children**?: [`AdvancedVisibility`](type-alias.AdvancedVisibility.md)[] - -*** - -### `criteria` - -**criteria**: \{ - `controlling_field_path`: `string`; - `controlling_value_regex`: `string`; - `operator`: `"NOT_EQUAL"` \| `"EQUAL"` \| `"EMPTY"` \| `"NOT_EMPTY"` \| `"MATCHES_REGEX"`; - }[] - -## Source - -fieldTypes.ts:43 diff --git a/docs/field-types/type-aliases/type-alias.AlignmentFieldType.md b/docs/field-types/type-aliases/type-alias.AlignmentFieldType.md deleted file mode 100644 index b75af35..0000000 --- a/docs/field-types/type-aliases/type-alias.AlignmentFieldType.md +++ /dev/null @@ -1,40 +0,0 @@ -[API](../index.md) > AlignmentFieldType - -# Type alias: AlignmentFieldType - -> **AlignmentFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `alignmentDirection`: `"HORIZONTAL"` \| `"VERTICAL"` \| `"BOTH"`; - `default`: \{ - `horizontal_align`: `"LEFT"` \| `"CENTER"` \| `"RIGHT"`; - `vertical_align`: `"TOP"` \| `"MIDDLE"` \| `"BOTTOM"`; - }; - `type`: `"alignment"`; - } - -> ## `AlignmentFieldType.alignmentDirection` -> -> **alignmentDirection**?: `"HORIZONTAL"` \| `"VERTICAL"` \| `"BOTH"` -> -> ## `AlignmentFieldType.default` -> -> **default**?: `object` -> -> > ### `default.horizontal_align` -> > -> > **horizontal\_align**?: `"LEFT"` \| `"CENTER"` \| `"RIGHT"` -> > -> > ### `default.vertical_align` -> > -> > **vertical\_align**?: `"TOP"` \| `"MIDDLE"` \| `"BOTTOM"` -> > -> > -> -> ## `AlignmentFieldType.type` -> -> **type**: `"alignment"` -> -> - -## Source - -fieldTypes.ts:54 diff --git a/docs/field-types/type-aliases/type-alias.AudioFieldType.md b/docs/field-types/type-aliases/type-alias.AudioFieldType.md deleted file mode 100644 index b6b75fe..0000000 --- a/docs/field-types/type-aliases/type-alias.AudioFieldType.md +++ /dev/null @@ -1,50 +0,0 @@ -[API](../index.md) > AudioFieldType - -# Type alias: AudioFieldType - -> **AudioFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `file_duration`: `number`; - `file_extension`: `string`; - `file_id`: `number`; - `file_url`: `string`; - `title`: `string`; - }; - `type`: `"audioplayer"`; - } - -> ## `AudioFieldType.default` -> -> **default**?: `object` -> -> > ### `default.file_duration` -> > -> > **file\_duration**?: `number` -> > -> > ### `default.file_extension` -> > -> > **file\_extension**?: `string` -> > -> > ### `default.file_id` -> > -> > **file\_id**?: `number` -> > -> > ### `default.file_url` -> > -> > **file\_url**?: `string` -> > -> > ### `default.title` -> > -> > **title**?: `string` -> > -> > -> -> ## `AudioFieldType.type` -> -> **type**: `"audioplayer"` -> -> - -## Source - -fieldTypes.ts:62 diff --git a/docs/field-types/type-aliases/type-alias.BackgroundImageFieldType.md b/docs/field-types/type-aliases/type-alias.BackgroundImageFieldType.md deleted file mode 100644 index d4581b5..0000000 --- a/docs/field-types/type-aliases/type-alias.BackgroundImageFieldType.md +++ /dev/null @@ -1,40 +0,0 @@ -[API](../index.md) > BackgroundImageFieldType - -# Type alias: BackgroundImageFieldType - -> **BackgroundImageFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `background_position`: `"TOP_LEFT"` \| `"TOP_CENTER"` \| `"TOP_RIGHT"` \| `"MIDDLE_LEFT"` \| `"MIDDLE_CENTER"` \| `"MIDDLE_RIGHT"` \| `"BOTTOM_LEFT"` \| `"BOTTOM_CENTER"` \| `"BOTTOM_RIGHT"`; - `background_size`: `"COVER"` \| `"CONTAIN"` \| `"AUTO"`; - `src`: `string`; - }; - `type`: `"backgroundimage"`; - } - -> ## `BackgroundImageFieldType.default` -> -> **default**?: `object` -> -> > ### `default.background_position` -> > -> > **background\_position**?: `"TOP_LEFT"` \| `"TOP_CENTER"` \| `"TOP_RIGHT"` \| `"MIDDLE_LEFT"` \| `"MIDDLE_CENTER"` \| `"MIDDLE_RIGHT"` \| `"BOTTOM_LEFT"` \| `"BOTTOM_CENTER"` \| `"BOTTOM_RIGHT"` -> > -> > ### `default.background_size` -> > -> > **background\_size**?: `"COVER"` \| `"CONTAIN"` \| `"AUTO"` -> > -> > ### `default.src` -> > -> > **src**?: `string` -> > -> > -> -> ## `BackgroundImageFieldType.type` -> -> **type**: `"backgroundimage"` -> -> - -## Source - -fieldTypes.ts:72 diff --git a/docs/field-types/type-aliases/type-alias.BaseField.md b/docs/field-types/type-aliases/type-alias.BaseField.md deleted file mode 100644 index 9122d03..0000000 --- a/docs/field-types/type-aliases/type-alias.BaseField.md +++ /dev/null @@ -1,153 +0,0 @@ -[API](../index.md) > BaseField - -# Type alias: BaseField - -> **BaseField**: `object` - -## Type declaration - -### `advancedVisibility` - -**advancedVisibility**?: [`AdvancedVisibility`](type-alias.AdvancedVisibility.md) - -*** - -### `displayWidth` - -**displayWidth**?: `string` - -*** - -### `helpText` - -**helpText**?: `string` - -*** - -### `id` - -**id**?: `string` - -*** - -### `inheritedValueDefaultValuePath` - -**inheritedValueDefaultValuePath**?: `string` - -*** - -### `inheritedValuePropertyValuePaths` - -**inheritedValuePropertyValuePaths**?: `object` - -*** - -### `inlineHelpText` - -**inlineHelpText**?: `string` \| `null` - -*** - -### `label` - -**label**: `string` - -*** - -### `locked` - -**locked**?: `boolean` - -*** - -### `name` - -**name**: `string` - -*** - -### `occurrence` - -**occurrence**?: `object` - -> #### `occurrence.default` -> -> **default**?: `number` \| `null` -> -> #### `occurrence.max` -> -> **max**?: `number` \| `null` -> -> #### `occurrence.min` -> -> **min**: `number` -> -> #### `occurrence.sorting_label_field` -> -> **sorting\_label\_field**?: `string` -> -> - -*** - -### `propertyAliasesPaths` - -**propertyAliasesPaths**?: `object` - -*** - -### `required` - -**required**?: `boolean` - -*** - -### `sortable` - -**sortable**?: `boolean` - -*** - -### `visibility` - -**visibility**?: `object` - -> #### `visibility.access` -> -> **access**?: \{ -> `gates`: `string`[]; -> `operator`: `"HAS_ALL"` \| `"HAS_ANY"` \| `"HAS_NONE"`; -> `scopes`: `string`[]; -> } \| `null` -> -> #### `visibility.controlling_field` -> -> **controlling\_field**?: `string` \| `null` -> -> #### `visibility.controlling_field_path` -> -> **controlling\_field\_path**?: `string` \| `null` -> -> #### `visibility.controlling_value_regex` -> -> **controlling\_value\_regex**?: `string` \| `null` -> -> #### `visibility.hidden_subfields` -> -> **hidden\_subfields**?: \{} \| `null` -> -> #### `visibility.operator` -> -> **operator**?: `"NOT_EQUAL"` \| `"EQUAL"` \| `"EMPTY"` \| `"NOT_EMPTY"` \| `"MATCHES_REGEX"` \| `null` -> -> - -*** - -### `visibilityRules` - -**visibilityRules**?: `"SIMPLE"` \| `"ADVANCED"` - -## Source - -fieldTypes.ts:3 diff --git a/docs/field-types/type-aliases/type-alias.BlogFieldType.md b/docs/field-types/type-aliases/type-alias.BlogFieldType.md deleted file mode 100644 index 7ca564f..0000000 --- a/docs/field-types/type-aliases/type-alias.BlogFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > BlogFieldType - -# Type alias: BlogFieldType - -> **BlogFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `number` \| `number`[]; - `placeholder`: `string`; - `type`: `"blog"`; - } - -> ## `BlogFieldType.default` -> -> **default**?: `number` \| `number`[] -> -> ## `BlogFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `BlogFieldType.type` -> -> **type**: `"blog"` -> -> - -## Source - -fieldTypes.ts:89 diff --git a/docs/field-types/type-aliases/type-alias.BooleanFieldType.md b/docs/field-types/type-aliases/type-alias.BooleanFieldType.md deleted file mode 100644 index e147da1..0000000 --- a/docs/field-types/type-aliases/type-alias.BooleanFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > BooleanFieldType - -# Type alias: BooleanFieldType - -> **BooleanFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `boolean`; - `display`: `"toggle"` \| `"checkbox"`; - `type`: `"boolean"`; - } - -> ## `BooleanFieldType.default` -> -> **default**?: `boolean` -> -> ## `BooleanFieldType.display` -> -> **display**?: `"toggle"` \| `"checkbox"` -> -> ## `BooleanFieldType.type` -> -> **type**: `"boolean"` -> -> - -## Source - -fieldTypes.ts:94 diff --git a/docs/field-types/type-aliases/type-alias.BorderFieldType.md b/docs/field-types/type-aliases/type-alias.BorderFieldType.md deleted file mode 100644 index 4b012cf..0000000 --- a/docs/field-types/type-aliases/type-alias.BorderFieldType.md +++ /dev/null @@ -1,68 +0,0 @@ -[API](../index.md) > BorderFieldType - -# Type alias: BorderFieldType - -> **BorderFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `allowCustomBorderSides`: `boolean`; - `default`: \{ - `border_radius`: \{ - `units`: [`CssUnit`](type-alias.CssUnit.md); - `value`: `number`; - }; - `bottom`: [`BorderSideType`](type-alias.BorderSideType.md); - `left`: [`BorderSideType`](type-alias.BorderSideType.md); - `right`: [`BorderSideType`](type-alias.BorderSideType.md); - `top`: [`BorderSideType`](type-alias.BorderSideType.md); - }; - `type`: `"border"`; - } - -> ## `BorderFieldType.allowCustomBorderSides` -> -> **allowCustomBorderSides**?: `boolean` -> -> ## `BorderFieldType.default` -> -> **default**?: `object` -> -> > ### `default.border_radius` -> > -> > **border\_radius**?: `object` -> > -> > > #### `border\_radius.units` -> > > -> > > **units**: [`CssUnit`](type-alias.CssUnit.md) -> > > -> > > #### `border\_radius.value` -> > > -> > > **value**: `number` -> > > -> > > -> > -> > ### `default.bottom` -> > -> > **bottom**?: [`BorderSideType`](type-alias.BorderSideType.md) -> > -> > ### `default.left` -> > -> > **left**?: [`BorderSideType`](type-alias.BorderSideType.md) -> > -> > ### `default.right` -> > -> > **right**?: [`BorderSideType`](type-alias.BorderSideType.md) -> > -> > ### `default.top` -> > -> > **top**?: [`BorderSideType`](type-alias.BorderSideType.md) -> > -> > -> -> ## `BorderFieldType.type` -> -> **type**: `"border"` -> -> - -## Source - -fieldTypes.ts:117 diff --git a/docs/field-types/type-aliases/type-alias.BorderSideType.md b/docs/field-types/type-aliases/type-alias.BorderSideType.md deleted file mode 100644 index e825f91..0000000 --- a/docs/field-types/type-aliases/type-alias.BorderSideType.md +++ /dev/null @@ -1,45 +0,0 @@ -[API](../index.md) > BorderSideType - -# Type alias: BorderSideType - -> **BorderSideType**: [`BaseField`](type-alias.BaseField.md) & \{ - `color`: `string`; - `opacity`: `number`; - `style`: `"none"` \| `"solid"` \| `"dashed"` \| `"double"` \| `"groove"` \| `"ridge"` \| `"inset"` \| `"outset"`; - `width`: \{ - `units`: [`CssUnit`](type-alias.CssUnit.md); - `value`: `number`; - }; - } - -> ## `BorderSideType.color` -> -> **color**?: `string` -> -> ## `BorderSideType.opacity` -> -> **opacity**?: `number` -> -> ## `BorderSideType.style` -> -> **style**?: `"none"` \| `"solid"` \| `"dashed"` \| `"double"` \| `"groove"` \| `"ridge"` \| `"inset"` \| `"outset"` -> -> ## `BorderSideType.width` -> -> **width**?: `object` -> -> > ### `width.units` -> > -> > **units**: [`CssUnit`](type-alias.CssUnit.md) -> > -> > ### `width.value` -> > -> > **value**: `number` -> > -> > -> -> - -## Source - -fieldTypes.ts:100 diff --git a/docs/field-types/type-aliases/type-alias.ChoiceFieldType.md b/docs/field-types/type-aliases/type-alias.ChoiceFieldType.md deleted file mode 100644 index 28c75af..0000000 --- a/docs/field-types/type-aliases/type-alias.ChoiceFieldType.md +++ /dev/null @@ -1,47 +0,0 @@ -[API](../index.md) > ChoiceFieldType - -# Type alias: ChoiceFieldType - -> **ChoiceFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `choices`: [`any`, `string`][]; - `default`: `string` \| `number` \| (`string` \| `number`)[]; - `display`: `"radio"` \| `"select"` \| `"checkbox"`; - `multiple`: `boolean`; - `placeholder`: `string`; - `reorderingEnabled`: `boolean`; - `type`: `"choice"`; - } - -> ## `ChoiceFieldType.choices` -> -> **choices**: [`any`, `string`][] -> -> ## `ChoiceFieldType.default` -> -> **default**?: `string` \| `number` \| (`string` \| `number`)[] -> -> ## `ChoiceFieldType.display` -> -> **display**?: `"radio"` \| `"select"` \| `"checkbox"` -> -> ## `ChoiceFieldType.multiple` -> -> **multiple**?: `boolean` -> -> ## `ChoiceFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `ChoiceFieldType.reorderingEnabled` -> -> **reorderingEnabled**?: `boolean` -> -> ## `ChoiceFieldType.type` -> -> **type**: `"choice"` -> -> - -## Source - -fieldTypes.ts:131 diff --git a/docs/field-types/type-aliases/type-alias.ColorFieldType.md b/docs/field-types/type-aliases/type-alias.ColorFieldType.md deleted file mode 100644 index 6a61667..0000000 --- a/docs/field-types/type-aliases/type-alias.ColorFieldType.md +++ /dev/null @@ -1,60 +0,0 @@ -[API](../index.md) > ColorFieldType - -# Type alias: ColorFieldType - -> **ColorFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `color`: `string`; - `css`: `string`; - `hex`: `string`; - `opacity`: `number`; - `rgb`: `string`; - `rgba`: `string`; - }; - `showOpacity`: `boolean`; - `type`: `"color"`; - } - -> ## `ColorFieldType.default` -> -> **default**?: `object` -> -> > ### `default.color` -> > -> > **color**?: `string` -> > -> > ### `default.css` -> > -> > **css**?: `string` -> > -> > ### `default.hex` -> > -> > **hex**?: `string` -> > -> > ### `default.opacity` -> > -> > **opacity**?: `number` -> > -> > ### `default.rgb` -> > -> > **rgb**?: `string` -> > -> > ### `default.rgba` -> > -> > **rgba**?: `string` -> > -> > -> -> ## `ColorFieldType.showOpacity` -> -> **showOpacity**?: `boolean` -> -> ## `ColorFieldType.type` -> -> **type**: `"color"` -> -> - -## Source - -fieldTypes.ts:140 diff --git a/docs/field-types/type-aliases/type-alias.CrmObjectFieldType.md b/docs/field-types/type-aliases/type-alias.CrmObjectFieldType.md deleted file mode 100644 index 9401a44..0000000 --- a/docs/field-types/type-aliases/type-alias.CrmObjectFieldType.md +++ /dev/null @@ -1,55 +0,0 @@ -[API](../index.md) > CrmObjectFieldType - -# Type alias: CrmObjectFieldType - -> **CrmObjectFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `id`: `number`; - }; - `displayFormat`: `string`; - `displayProperties`: `string`[]; - `objectType`: `string`; - `placeholder`: `string`; - `propertiesToFetch`: `string`[]; - `type`: `"crmobject"`; - } - -> ## `CrmObjectFieldType.default` -> -> **default**?: `object` -> -> > ### `default.id` -> > -> > **id**?: `number` -> > -> > -> -> ## `CrmObjectFieldType.displayFormat` -> -> **displayFormat**?: `string` -> -> ## `CrmObjectFieldType.displayProperties` -> -> **displayProperties**?: `string`[] -> -> ## `CrmObjectFieldType.objectType` -> -> **objectType**: `string` -> -> ## `CrmObjectFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `CrmObjectFieldType.propertiesToFetch` -> -> **propertiesToFetch**: `string`[] -> -> ## `CrmObjectFieldType.type` -> -> **type**: `"crmobject"` -> -> - -## Source - -fieldTypes.ts:152 diff --git a/docs/field-types/type-aliases/type-alias.CrmObjectPropertyFieldType.md b/docs/field-types/type-aliases/type-alias.CrmObjectPropertyFieldType.md deleted file mode 100644 index 60ac539..0000000 --- a/docs/field-types/type-aliases/type-alias.CrmObjectPropertyFieldType.md +++ /dev/null @@ -1,40 +0,0 @@ -[API](../index.md) > CrmObjectPropertyFieldType - -# Type alias: CrmObjectPropertyFieldType - -> **CrmObjectPropertyFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `property`: `string`; - }; - `objectType`: `string`; - `placeholder`: `string`; - `type`: `"crmobjectproperty"`; - } - -> ## `CrmObjectPropertyFieldType.default` -> -> **default**?: `object` -> -> > ### `default.property` -> > -> > **property**?: `string` -> > -> > -> -> ## `CrmObjectPropertyFieldType.objectType` -> -> **objectType**: `string` -> -> ## `CrmObjectPropertyFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `CrmObjectPropertyFieldType.type` -> -> **type**: `"crmobjectproperty"` -> -> - -## Source - -fieldTypes.ts:163 diff --git a/docs/field-types/type-aliases/type-alias.CssUnit.md b/docs/field-types/type-aliases/type-alias.CssUnit.md deleted file mode 100644 index eb6d1b7..0000000 --- a/docs/field-types/type-aliases/type-alias.CssUnit.md +++ /dev/null @@ -1,9 +0,0 @@ -[API](../index.md) > CssUnit - -# Type alias: CssUnit - -> **CssUnit**: `"px"` \| `"pt"` \| `"em"` \| `"rem"` \| `"%"` \| `"ex"` \| `"ch"` - -## Source - -fieldTypes.ts:99 diff --git a/docs/field-types/type-aliases/type-alias.CtaFieldType.md b/docs/field-types/type-aliases/type-alias.CtaFieldType.md deleted file mode 100644 index 12f7be9..0000000 --- a/docs/field-types/type-aliases/type-alias.CtaFieldType.md +++ /dev/null @@ -1,22 +0,0 @@ -[API](../index.md) > CtaFieldType - -# Type alias: CtaFieldType - -> **CtaFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string`; - `type`: `"cta"`; - } - -> ## `CtaFieldType.default` -> -> **default**?: `string` -> -> ## `CtaFieldType.type` -> -> **type**: `"cta"` -> -> - -## Source - -fieldTypes.ts:171 diff --git a/docs/field-types/type-aliases/type-alias.DateFieldType.md b/docs/field-types/type-aliases/type-alias.DateFieldType.md deleted file mode 100644 index b953878..0000000 --- a/docs/field-types/type-aliases/type-alias.DateFieldType.md +++ /dev/null @@ -1,22 +0,0 @@ -[API](../index.md) > DateFieldType - -# Type alias: DateFieldType - -> **DateFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `number`; - `type`: `"date"`; - } - -> ## `DateFieldType.default` -> -> **default**?: `number` -> -> ## `DateFieldType.type` -> -> **type**: `"date"` -> -> - -## Source - -fieldTypes.ts:175 diff --git a/docs/field-types/type-aliases/type-alias.DateTimeFieldType.md b/docs/field-types/type-aliases/type-alias.DateTimeFieldType.md deleted file mode 100644 index ffd5d63..0000000 --- a/docs/field-types/type-aliases/type-alias.DateTimeFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > DateTimeFieldType - -# Type alias: DateTimeFieldType - -> **DateTimeFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `number`; - `step`: `number`; - `type`: `"datetime"`; - } - -> ## `DateTimeFieldType.default` -> -> **default**?: `number` -> -> ## `DateTimeFieldType.step` -> -> **step**?: `number` -> -> ## `DateTimeFieldType.type` -> -> **type**: `"datetime"` -> -> - -## Source - -fieldTypes.ts:179 diff --git a/docs/field-types/type-aliases/type-alias.EmailFieldType.md b/docs/field-types/type-aliases/type-alias.EmailFieldType.md deleted file mode 100644 index 2c4a432..0000000 --- a/docs/field-types/type-aliases/type-alias.EmailFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > EmailFieldType - -# Type alias: EmailFieldType - -> **EmailFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `allowCustomEmailAddresses`: `boolean`; - `default`: `string`[]; - `type`: `"email"`; - } - -> ## `EmailFieldType.allowCustomEmailAddresses` -> -> **allowCustomEmailAddresses**?: `boolean` -> -> ## `EmailFieldType.default` -> -> **default**?: `string`[] -> -> ## `EmailFieldType.type` -> -> **type**: `"email"` -> -> - -## Source - -fieldTypes.ts:184 diff --git a/docs/field-types/type-aliases/type-alias.EmbedFieldType.md b/docs/field-types/type-aliases/type-alias.EmbedFieldType.md deleted file mode 100644 index e0c4460..0000000 --- a/docs/field-types/type-aliases/type-alias.EmbedFieldType.md +++ /dev/null @@ -1,100 +0,0 @@ -[API](../index.md) > EmbedFieldType - -# Type alias: EmbedFieldType - -> **EmbedFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `embed_type`: `string`; - `height`: `number`; - `max_height`: `number`; - `max_width`: `number`; - `media_bridge_object`: \{}; - `oembed_response`: \{}; - `oembed_string`: `string`; - `size_type`: `"auto"` \| `"auto_custom_max"` \| `"auto_full_width"` \| `"exact"`; - `source_type`: `"oembed"` \| `"html"` \| `"media_bridge"`; - `width`: `number`; - }; - `resizable`: `boolean`; - `showPreview`: `boolean`; - `supportedMediaBridgeProviders`: `number`[]; - `supportedOembedTypes`: (`"photo"` \| `"video"` \| `"link"` \| `"rich"`)[]; - `supportedSourceTypes`: (`"oembed"` \| `"html"` \| `"media_bridge"`)[]; - `type`: `"embed"`; - } - -> ## `EmbedFieldType.default` -> -> **default**?: `object` -> -> > ### `default.embed_type` -> > -> > **embed\_type**?: `string` -> > -> > ### `default.height` -> > -> > **height**?: `number` -> > -> > ### `default.max_height` -> > -> > **max\_height**?: `number` -> > -> > ### `default.max_width` -> > -> > **max\_width**?: `number` -> > -> > ### `default.media_bridge_object` -> > -> > **media\_bridge\_object**?: `object` -> > -> > ### `default.oembed_response` -> > -> > **oembed\_response**?: `object` -> > -> > ### `default.oembed_string` -> > -> > **oembed\_string**?: `string` -> > -> > ### `default.size_type` -> > -> > **size\_type**?: `"auto"` \| `"auto_custom_max"` \| `"auto_full_width"` \| `"exact"` -> > -> > ### `default.source_type` -> > -> > **source\_type**?: `"oembed"` \| `"html"` \| `"media_bridge"` -> > -> > ### `default.width` -> > -> > **width**?: `number` -> > -> > -> -> ## `EmbedFieldType.resizable` -> -> **resizable**?: `boolean` -> -> ## `EmbedFieldType.showPreview` -> -> **showPreview**?: `boolean` -> -> ## `EmbedFieldType.supportedMediaBridgeProviders` -> -> **supportedMediaBridgeProviders**: `number`[] -> -> ## `EmbedFieldType.supportedOembedTypes` -> -> **supportedOembedTypes**: (`"photo"` \| `"video"` \| `"link"` \| `"rich"`)[] -> -> ## `EmbedFieldType.supportedSourceTypes` -> -> **supportedSourceTypes**: (`"oembed"` \| `"html"` \| `"media_bridge"`)[] -> -> ## `EmbedFieldType.type` -> -> **type**: `"embed"` -> -> - -## Source - -fieldTypes.ts:189 diff --git a/docs/field-types/type-aliases/type-alias.Field.md b/docs/field-types/type-aliases/type-alias.Field.md deleted file mode 100644 index 6d8ff33..0000000 --- a/docs/field-types/type-aliases/type-alias.Field.md +++ /dev/null @@ -1,9 +0,0 @@ -[API](../index.md) > Field - -# Type alias: Field - -> **Field**: `CamelToSnakeCaseMap`\< `CamelCaseField` \> - -## Source - -fieldTypes.ts:636 diff --git a/docs/field-types/type-aliases/type-alias.FieldComponentProps.md b/docs/field-types/type-aliases/type-alias.FieldComponentProps.md deleted file mode 100644 index 9dc9834..0000000 --- a/docs/field-types/type-aliases/type-alias.FieldComponentProps.md +++ /dev/null @@ -1,17 +0,0 @@ -[API](../index.md) > FieldComponentProps - -# Type alias: FieldComponentProps`` - -> **FieldComponentProps**: <`T`> `AdaptChildren`\< `AdaptChildren`\< `Omit`\< `Extract`\< `CamelCaseField`, \{ - `type`: `T`; - } \>, `"type"` \> \> \> - -## Type parameters - -| Parameter | -| :------ | -| `T` *extends* [`FieldType`](type-alias.FieldType.md) | - -## Source - -fieldTypes.ts:655 diff --git a/docs/field-types/type-aliases/type-alias.FieldType.md b/docs/field-types/type-aliases/type-alias.FieldType.md deleted file mode 100644 index 0850051..0000000 --- a/docs/field-types/type-aliases/type-alias.FieldType.md +++ /dev/null @@ -1,9 +0,0 @@ -[API](../index.md) > FieldType - -# Type alias: FieldType - -> **FieldType**: `CamelCaseField`[`"type"`] - -## Source - -fieldTypes.ts:639 diff --git a/docs/field-types/type-aliases/type-alias.FileFieldType.md b/docs/field-types/type-aliases/type-alias.FileFieldType.md deleted file mode 100644 index f45b48f..0000000 --- a/docs/field-types/type-aliases/type-alias.FileFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > FileFieldType - -# Type alias: FileFieldType - -> **FileFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string`; - `picker`: `"file"` \| `"image"` \| `"video"` \| `"document"` \| `"audio"`; - `type`: `"file"`; - } - -> ## `FileFieldType.default` -> -> **default**?: `string` -> -> ## `FileFieldType.picker` -> -> **picker**: `"file"` \| `"image"` \| `"video"` \| `"document"` \| `"audio"` -> -> ## `FileFieldType.type` -> -> **type**: `"file"` -> -> - -## Source - -fieldTypes.ts:212 diff --git a/docs/field-types/type-aliases/type-alias.FollowUpEmailFieldType.md b/docs/field-types/type-aliases/type-alias.FollowUpEmailFieldType.md deleted file mode 100644 index 4714d76..0000000 --- a/docs/field-types/type-aliases/type-alias.FollowUpEmailFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > FollowUpEmailFieldType - -# Type alias: FollowUpEmailFieldType - -> **FollowUpEmailFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string`; - `placeholder`: `string`; - `type`: `"followupemail"`; - } - -> ## `FollowUpEmailFieldType.default` -> -> **default**?: `string` -> -> ## `FollowUpEmailFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `FollowUpEmailFieldType.type` -> -> **type**: `"followupemail"` -> -> - -## Source - -fieldTypes.ts:217 diff --git a/docs/field-types/type-aliases/type-alias.FontFieldType.md b/docs/field-types/type-aliases/type-alias.FontFieldType.md deleted file mode 100644 index c6b6ff7..0000000 --- a/docs/field-types/type-aliases/type-alias.FontFieldType.md +++ /dev/null @@ -1,88 +0,0 @@ -[API](../index.md) > FontFieldType - -# Type alias: FontFieldType - -> **FontFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `color`: `string`; - `fallback`: `string`; - `font`: `string`; - `font_set`: `"DEFAULT"` \| `"GOOGLE"` \| `"CUSTOM"`; - `google_font_variants`: `FontVariants`[]; - `size`: `number`; - `size_unit`: [`CssUnit`](type-alias.CssUnit.md); - `styles`: \{ - `key`: `string`; - `value`: `string`; - }; - `variant`: `string`; - }; - `loadExternalFonts`: `boolean`; - `type`: `"font"`; - } - -> ## `FontFieldType.default` -> -> **default**?: `object` -> -> > ### `default.color` -> > -> > **color**?: `string` -> > -> > ### `default.fallback` -> > -> > **fallback**?: `string` -> > -> > ### `default.font` -> > -> > **font**: `string` -> > -> > ### `default.font_set` -> > -> > **font\_set**?: `"DEFAULT"` \| `"GOOGLE"` \| `"CUSTOM"` -> > -> > ### `default.google_font_variants` -> > -> > **google\_font\_variants**?: `FontVariants`[] -> > -> > ### `default.size` -> > -> > **size**?: `number` -> > -> > ### `default.size_unit` -> > -> > **size\_unit**?: [`CssUnit`](type-alias.CssUnit.md) -> > -> > ### `default.styles` -> > -> > **styles**?: `object` -> > -> > > #### `styles.key` -> > > -> > > **key**: `string` -> > > -> > > #### `styles.value` -> > > -> > > **value**: `string` -> > > -> > > -> > -> > ### `default.variant` -> > -> > **variant**?: `string` -> > -> > -> -> ## `FontFieldType.loadExternalFonts` -> -> **loadExternalFonts**?: `boolean` -> -> ## `FontFieldType.type` -> -> **type**: `"font"` -> -> - -## Source - -fieldTypes.ts:241 diff --git a/docs/field-types/type-aliases/type-alias.FormFieldType.md b/docs/field-types/type-aliases/type-alias.FormFieldType.md deleted file mode 100644 index 14b5547..0000000 --- a/docs/field-types/type-aliases/type-alias.FormFieldType.md +++ /dev/null @@ -1,65 +0,0 @@ -[API](../index.md) > FormFieldType - -# Type alias: FormFieldType - -> **FormFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `allowInlineFormEditing`: `boolean`; - `default`: \{ - `form_id`: `string`; - `form_type`: `"HUBSPOT"` \| `"TICKET_FORM"`; - `message`: `string`; - `redirect_id`: `number`; - `redirect_url`: `string`; - `response_type`: `"inline"` \| `"redirect"`; - `workflow_id`: `number`[]; - }; - `type`: `"form"`; - } - -> ## `FormFieldType.allowInlineFormEditing` -> -> **allowInlineFormEditing**?: `boolean` -> -> ## `FormFieldType.default` -> -> **default**?: `object` -> -> > ### `default.form_id` -> > -> > **form\_id**?: `string` -> > -> > ### `default.form_type` -> > -> > **form\_type**?: `"HUBSPOT"` \| `"TICKET_FORM"` -> > -> > ### `default.message` -> > -> > **message**?: `string` -> > -> > ### `default.redirect_id` -> > -> > **redirect\_id**?: `number` -> > -> > ### `default.redirect_url` -> > -> > **redirect\_url**?: `string` -> > -> > ### `default.response_type` -> > -> > **response\_type**?: `"inline"` \| `"redirect"` -> > -> > ### `default.workflow_id` -> > -> > **workflow\_id**?: `number`[] -> > -> > -> -> ## `FormFieldType.type` -> -> **type**: `"form"` -> -> - -## Source - -fieldTypes.ts:256 diff --git a/docs/field-types/type-aliases/type-alias.GradientColorType.md b/docs/field-types/type-aliases/type-alias.GradientColorType.md deleted file mode 100644 index 7526165..0000000 --- a/docs/field-types/type-aliases/type-alias.GradientColorType.md +++ /dev/null @@ -1,40 +0,0 @@ -[API](../index.md) > GradientColorType - -# Type alias: GradientColorType - -> **GradientColorType**: [`BaseField`](type-alias.BaseField.md) & \{ - `color`: \{ - `a`: `number`; - `b`: `string`; - `g`: `string`; - `r`: `string`; - }; - } - -> ## `GradientColorType.color` -> -> **color**: `object` -> -> > ### `color.a` -> > -> > **a**: `number` -> > -> > ### `color.b` -> > -> > **b**: `string` -> > -> > ### `color.g` -> > -> > **g**: `string` -> > -> > ### `color.r` -> > -> > **r**: `string` -> > -> > -> -> - -## Source - -fieldTypes.ts:279 diff --git a/docs/field-types/type-aliases/type-alias.GradientFieldType.md b/docs/field-types/type-aliases/type-alias.GradientFieldType.md deleted file mode 100644 index 273220c..0000000 --- a/docs/field-types/type-aliases/type-alias.GradientFieldType.md +++ /dev/null @@ -1,48 +0,0 @@ -[API](../index.md) > GradientFieldType - -# Type alias: GradientFieldType - -> **GradientFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `color`: [`GradientColorType`](type-alias.GradientColorType.md)[]; - `side_or_corner`: \{ - `horizontalSide`: `"LEFT"` \| `"RIGHT"`; - `verticalSide`: `"TOP"` \| `"BOTTOM"`; - }; - }; - `type`: `"gradient"`; - } - -> ## `GradientFieldType.default` -> -> **default**?: `object` -> -> > ### `default.color` -> > -> > **color**?: [`GradientColorType`](type-alias.GradientColorType.md)[] -> > -> > ### `default.side_or_corner` -> > -> > **side\_or\_corner**?: `object` -> > -> > > #### `side\_or\_corner.horizontalSide` -> > > -> > > **horizontalSide**?: `"LEFT"` \| `"RIGHT"` -> > > -> > > #### `side\_or\_corner.verticalSide` -> > > -> > > **verticalSide**?: `"TOP"` \| `"BOTTOM"` -> > > -> > > -> > -> > -> -> ## `GradientFieldType.type` -> -> **type**: `"gradient"` -> -> - -## Source - -fieldTypes.ts:269 diff --git a/docs/field-types/type-aliases/type-alias.GroupFieldType.md b/docs/field-types/type-aliases/type-alias.GroupFieldType.md deleted file mode 100644 index 9a07c6a..0000000 --- a/docs/field-types/type-aliases/type-alias.GroupFieldType.md +++ /dev/null @@ -1,37 +0,0 @@ -[API](../index.md) > GroupFieldType - -# Type alias: GroupFieldType - -> **GroupFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `children`: [`Field`](type-alias.Field.md)[]; - `default`: [] \| \{}; - `expanded`: `boolean`; - `tab`: `"STYLE"`; - `type`: `"group"`; - } - -> ## `GroupFieldType.children` -> -> **children**?: [`Field`](type-alias.Field.md)[] -> -> ## `GroupFieldType.default` -> -> **default**?: [] \| \{} -> -> ## `GroupFieldType.expanded` -> -> **expanded**?: `boolean` -> -> ## `GroupFieldType.tab` -> -> **tab**?: `"STYLE"` -> -> ## `GroupFieldType.type` -> -> **type**: `"group"` -> -> - -## Source - -fieldTypes.ts:579 diff --git a/docs/field-types/type-aliases/type-alias.HtmlFieldType.md b/docs/field-types/type-aliases/type-alias.HtmlFieldType.md deleted file mode 100644 index c502b0c..0000000 --- a/docs/field-types/type-aliases/type-alias.HtmlFieldType.md +++ /dev/null @@ -1,22 +0,0 @@ -[API](../index.md) > HtmlFieldType - -# Type alias: HtmlFieldType - -> **HtmlFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string`; - `type`: `"html"`; - } - -> ## `HtmlFieldType.default` -> -> **default**?: `string` -> -> ## `HtmlFieldType.type` -> -> **type**: `"html"` -> -> - -## Source - -fieldTypes.ts:287 diff --git a/docs/field-types/type-aliases/type-alias.HubdbRowFieldType.md b/docs/field-types/type-aliases/type-alias.HubdbRowFieldType.md deleted file mode 100644 index 04ad4fd..0000000 --- a/docs/field-types/type-aliases/type-alias.HubdbRowFieldType.md +++ /dev/null @@ -1,55 +0,0 @@ -[API](../index.md) > HubDbRowFieldType - -# Type alias: HubDbRowFieldType - -> **HubDbRowFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `columnsToFetch`: `string`[]; - `default`: \{ - `id`: `number`; - }; - `displayColumns`: `string`[]; - `displayFormat`: `string`; - `placeholder`: `string`; - `tableNameOrId`: `string` \| `number`; - `type`: `"hubdbrow"`; - } - -> ## `HubDbRowFieldType.columnsToFetch` -> -> **columnsToFetch**: `string`[] -> -> ## `HubDbRowFieldType.default` -> -> **default**?: `object` -> -> > ### `default.id` -> > -> > **id**: `number` -> > -> > -> -> ## `HubDbRowFieldType.displayColumns` -> -> **displayColumns**?: `string`[] -> -> ## `HubDbRowFieldType.displayFormat` -> -> **displayFormat**?: `string` -> -> ## `HubDbRowFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `HubDbRowFieldType.tableNameOrId` -> -> **tableNameOrId**: `string` \| `number` -> -> ## `HubDbRowFieldType.type` -> -> **type**: `"hubdbrow"` -> -> - -## Source - -fieldTypes.ts:291 diff --git a/docs/field-types/type-aliases/type-alias.HubdbTableFieldType.md b/docs/field-types/type-aliases/type-alias.HubdbTableFieldType.md deleted file mode 100644 index e1e5c35..0000000 --- a/docs/field-types/type-aliases/type-alias.HubdbTableFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > HubDbTableFieldType - -# Type alias: HubDbTableFieldType - -> **HubDbTableFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string` \| `number`; - `placeholder`: `string`; - `type`: `"hubdbtable"`; - } - -> ## `HubDbTableFieldType.default` -> -> **default**?: `string` \| `number` -> -> ## `HubDbTableFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `HubDbTableFieldType.type` -> -> **type**: `"hubdbtable"` -> -> - -## Source - -fieldTypes.ts:302 diff --git a/docs/field-types/type-aliases/type-alias.HublFieldType.md b/docs/field-types/type-aliases/type-alias.HublFieldType.md deleted file mode 100644 index d724820..0000000 --- a/docs/field-types/type-aliases/type-alias.HublFieldType.md +++ /dev/null @@ -1,22 +0,0 @@ -[API](../index.md) > HublFieldType - -# Type alias: HublFieldType - -> **HublFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string`; - `type`: `"hubl"`; - } - -> ## `HublFieldType.default` -> -> **default**?: `string` -> -> ## `HublFieldType.type` -> -> **type**: `"hubl"` -> -> - -## Source - -fieldTypes.ts:307 diff --git a/docs/field-types/type-aliases/type-alias.IconFieldType.md b/docs/field-types/type-aliases/type-alias.IconFieldType.md deleted file mode 100644 index 394d823..0000000 --- a/docs/field-types/type-aliases/type-alias.IconFieldType.md +++ /dev/null @@ -1,45 +0,0 @@ -[API](../index.md) > IconFieldType - -# Type alias: IconFieldType - -> **IconFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `name`: `string`; - `type`: `"SOLID"` \| `"REGULAR"`; - `unicode`: `string`; - }; - `set`: `"fontawesome-5"` \| `"fontawesome-5.0.10"` \| `"fontawesome-5.14.0"`; - `type`: `"icon"`; - } - -> ## `IconFieldType.default` -> -> **default**?: `object` -> -> > ### `default.name` -> > -> > **name**?: `string` -> > -> > ### `default.type` -> > -> > **type**?: `"SOLID"` \| `"REGULAR"` -> > -> > ### `default.unicode` -> > -> > **unicode**?: `string` -> > -> > -> -> ## `IconFieldType.set` -> -> **set**?: `"fontawesome-5"` \| `"fontawesome-5.0.10"` \| `"fontawesome-5.14.0"` -> -> ## `IconFieldType.type` -> -> **type**: `"icon"` -> -> - -## Source - -fieldTypes.ts:311 diff --git a/docs/field-types/type-aliases/type-alias.ImageFieldType.md b/docs/field-types/type-aliases/type-alias.ImageFieldType.md deleted file mode 100644 index 2c42358..0000000 --- a/docs/field-types/type-aliases/type-alias.ImageFieldType.md +++ /dev/null @@ -1,80 +0,0 @@ -[API](../index.md) > ImageFieldType - -# Type alias: ImageFieldType - -> **ImageFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `alt`: `string`; - `height`: `number`; - `loading`: `"disabled"` \| `"eager"` \| `"lazy"`; - `max_height`: `number`; - `max_width`: `number`; - `size_type`: `"auto"` \| `"auto_custom_max"` \| `"auto_full_width"` \| `"exact"`; - `src`: `string`; - `width`: `number`; - }; - `resizable`: `boolean`; - `responsive`: `boolean`; - `showLoading`: `boolean`; - `type`: `"image"`; - } - -> ## `ImageFieldType.default` -> -> **default**?: `object` -> -> > ### `default.alt` -> > -> > **alt**?: `string` -> > -> > ### `default.height` -> > -> > **height**?: `number` -> > -> > ### `default.loading` -> > -> > **loading**?: `"disabled"` \| `"eager"` \| `"lazy"` -> > -> > ### `default.max_height` -> > -> > **max\_height**?: `number` -> > -> > ### `default.max_width` -> > -> > **max\_width**?: `number` -> > -> > ### `default.size_type` -> > -> > **size\_type**?: `"auto"` \| `"auto_custom_max"` \| `"auto_full_width"` \| `"exact"` -> > -> > ### `default.src` -> > -> > **src**: `string` -> > -> > ### `default.width` -> > -> > **width**?: `number` -> > -> > -> -> ## `ImageFieldType.resizable` -> -> **resizable**?: `boolean` -> -> ## `ImageFieldType.responsive` -> -> **responsive**?: `boolean` -> -> ## `ImageFieldType.showLoading` -> -> **showLoading**?: `boolean` -> -> ## `ImageFieldType.type` -> -> **type**: `"image"` -> -> - -## Source - -fieldTypes.ts:320 diff --git a/docs/field-types/type-aliases/type-alias.LinkFieldType.md b/docs/field-types/type-aliases/type-alias.LinkFieldType.md deleted file mode 100644 index 62e50fb..0000000 --- a/docs/field-types/type-aliases/type-alias.LinkFieldType.md +++ /dev/null @@ -1,83 +0,0 @@ -[API](../index.md) > LinkFieldType - -# Type alias: LinkFieldType - -> **LinkFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `no_follow`: `boolean`; - `open_in_new_tab`: `boolean`; - `sponsored`: `boolean`; - `url`: \{ - `content_id`: `number`; - `href`: `string`; - `type`: `UrlTypes`; - }; - `user_generated_content`: `boolean`; - }; - `placeholder`: `string`; - `showAdvancedRelOptions`: `boolean`; - `supportedTypes`: `UrlTypes`[]; - `type`: `"link"`; - } - -> ## `LinkFieldType.default` -> -> **default**?: `object` -> -> > ### `default.no_follow` -> > -> > **no\_follow**?: `boolean` -> > -> > ### `default.open_in_new_tab` -> > -> > **open\_in\_new\_tab**?: `boolean` -> > -> > ### `default.sponsored` -> > -> > **sponsored**?: `boolean` -> > -> > ### `default.url` -> > -> > **url**?: `object` -> > -> > > #### `url.content_id` -> > > -> > > **content\_id**: `number` -> > > -> > > #### `url.href` -> > > -> > > **href**: `string` -> > > -> > > #### `url.type` -> > > -> > > **type**: `UrlTypes` -> > > -> > > -> > -> > ### `default.user_generated_content` -> > -> > **user\_generated\_content**?: `boolean` -> > -> > -> -> ## `LinkFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `LinkFieldType.showAdvancedRelOptions` -> -> **showAdvancedRelOptions**?: `boolean` -> -> ## `LinkFieldType.supportedTypes` -> -> **supportedTypes**?: `UrlTypes`[] -> -> ## `LinkFieldType.type` -> -> **type**: `"link"` -> -> - -## Source - -fieldTypes.ts:336 diff --git a/docs/field-types/type-aliases/type-alias.LogoFieldType.md b/docs/field-types/type-aliases/type-alias.LogoFieldType.md deleted file mode 100644 index dd156ef..0000000 --- a/docs/field-types/type-aliases/type-alias.LogoFieldType.md +++ /dev/null @@ -1,65 +0,0 @@ -[API](../index.md) > LogoFieldType - -# Type alias: LogoFieldType - -> **LogoFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `alt`: `string`; - `height`: `number`; - `loading`: `string`; - `override_inherited_src`: `boolean`; - `src`: `string`; - `suppress_company_name`: `boolean`; - `width`: `number`; - }; - `showLoading`: `true`; - `type`: `"logo"`; - } - -> ## `LogoFieldType.default` -> -> **default**?: `object` -> -> > ### `default.alt` -> > -> > **alt**?: `string` -> > -> > ### `default.height` -> > -> > **height**?: `number` -> > -> > ### `default.loading` -> > -> > **loading**?: `string` -> > -> > ### `default.override_inherited_src` -> > -> > **override\_inherited\_src**?: `boolean` -> > -> > ### `default.src` -> > -> > **src**?: `string` -> > -> > ### `default.suppress_company_name` -> > -> > **suppress\_company\_name**?: `boolean` -> > -> > ### `default.width` -> > -> > **width**?: `number` -> > -> > -> -> ## `LogoFieldType.showLoading` -> -> **showLoading**: `true` -> -> ## `LogoFieldType.type` -> -> **type**: `"logo"` -> -> - -## Source - -fieldTypes.ts:353 diff --git a/docs/field-types/type-aliases/type-alias.MeetingFieldType.md b/docs/field-types/type-aliases/type-alias.MeetingFieldType.md deleted file mode 100644 index a89f14b..0000000 --- a/docs/field-types/type-aliases/type-alias.MeetingFieldType.md +++ /dev/null @@ -1,32 +0,0 @@ -[API](../index.md) > MeetingFieldType - -# Type alias: MeetingFieldType - -> **MeetingFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string`; - `embeddable`: `boolean`; - `placeholder`: `string`; - `type`: `"meeting"`; - } - -> ## `MeetingFieldType.default` -> -> **default**?: `string` -> -> ## `MeetingFieldType.embeddable` -> -> **embeddable**?: `boolean` -> -> ## `MeetingFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `MeetingFieldType.type` -> -> **type**: `"meeting"` -> -> - -## Source - -fieldTypes.ts:366 diff --git a/docs/field-types/type-aliases/type-alias.MenuFieldType.md b/docs/field-types/type-aliases/type-alias.MenuFieldType.md deleted file mode 100644 index 4781be9..0000000 --- a/docs/field-types/type-aliases/type-alias.MenuFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > MenuFieldType - -# Type alias: MenuFieldType - -> **MenuFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `number` \| `string`; - `placeholder`: `"string"`; - `type`: `"menu"`; - } - -> ## `MenuFieldType.default` -> -> **default**?: `number` \| `string` -> -> ## `MenuFieldType.placeholder` -> -> **placeholder**?: `"string"` -> -> ## `MenuFieldType.type` -> -> **type**: `"menu"` -> -> - -## Source - -fieldTypes.ts:372 diff --git a/docs/field-types/type-aliases/type-alias.NumberFieldType.md b/docs/field-types/type-aliases/type-alias.NumberFieldType.md deleted file mode 100644 index c2aa9b3..0000000 --- a/docs/field-types/type-aliases/type-alias.NumberFieldType.md +++ /dev/null @@ -1,62 +0,0 @@ -[API](../index.md) > NumberFieldType - -# Type alias: NumberFieldType - -> **NumberFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `number` \| `number`[] \| `null`; - `display`: `"text"` \| `"slider"`; - `format`: `"ANY"` \| `"INTEGER"`; - `max`: `number`; - `min`: `number`; - `placeholder`: `string`; - `prefix`: `string`; - `step`: `number`; - `suffix`: `string`; - `type`: `"number"`; - } - -> ## `NumberFieldType.default` -> -> **default**?: `number` \| `number`[] \| `null` -> -> ## `NumberFieldType.display` -> -> **display**?: `"text"` \| `"slider"` -> -> ## `NumberFieldType.format` -> -> **format**?: `"ANY"` \| `"INTEGER"` -> -> ## `NumberFieldType.max` -> -> **max**?: `number` -> -> ## `NumberFieldType.min` -> -> **min**?: `number` -> -> ## `NumberFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `NumberFieldType.prefix` -> -> **prefix**?: `string` -> -> ## `NumberFieldType.step` -> -> **step**?: `number` -> -> ## `NumberFieldType.suffix` -> -> **suffix**?: `string` -> -> ## `NumberFieldType.type` -> -> **type**: `"number"` -> -> - -## Source - -fieldTypes.ts:377 diff --git a/docs/field-types/type-aliases/type-alias.PageFieldType.md b/docs/field-types/type-aliases/type-alias.PageFieldType.md deleted file mode 100644 index 06c34b1..0000000 --- a/docs/field-types/type-aliases/type-alias.PageFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > PageFieldType - -# Type alias: PageFieldType - -> **PageFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `number` \| `number`[]; - `placeholder`: `string`; - `type`: `"page"`; - } - -> ## `PageFieldType.default` -> -> **default**?: `number` \| `number`[] -> -> ## `PageFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `PageFieldType.type` -> -> **type**: `"page"` -> -> - -## Source - -fieldTypes.ts:389 diff --git a/docs/field-types/type-aliases/type-alias.PaymentFieldType.md b/docs/field-types/type-aliases/type-alias.PaymentFieldType.md deleted file mode 100644 index cfb133c..0000000 --- a/docs/field-types/type-aliases/type-alias.PaymentFieldType.md +++ /dev/null @@ -1,30 +0,0 @@ -[API](../index.md) > PaymentFieldType - -# Type alias: PaymentFieldType - -> **PaymentFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `id`: `number`; - }; - `type`: `"payment"`; - } - -> ## `PaymentFieldType.default` -> -> **default**?: `object` -> -> > ### `default.id` -> > -> > **id**?: `number` -> > -> > -> -> ## `PaymentFieldType.type` -> -> **type**: `"payment"` -> -> - -## Source - -fieldTypes.ts:394 diff --git a/docs/field-types/type-aliases/type-alias.PodcastFieldType.md b/docs/field-types/type-aliases/type-alias.PodcastFieldType.md deleted file mode 100644 index fef18e2..0000000 --- a/docs/field-types/type-aliases/type-alias.PodcastFieldType.md +++ /dev/null @@ -1,35 +0,0 @@ -[API](../index.md) > PodcastFieldType - -# Type alias: PodcastFieldType - -> **PodcastFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `episode_id`: `number`; - `show_id`: `number`; - }; - `type`: `"podcast"`; - } - -> ## `PodcastFieldType.default` -> -> **default**?: `object` -> -> > ### `default.episode_id` -> > -> > **episode\_id**?: `number` -> > -> > ### `default.show_id` -> > -> > **show\_id**?: `number` -> > -> > -> -> ## `PodcastFieldType.type` -> -> **type**: `"podcast"` -> -> - -## Source - -fieldTypes.ts:400 diff --git a/docs/field-types/type-aliases/type-alias.RichTextFieldType.md b/docs/field-types/type-aliases/type-alias.RichTextFieldType.md deleted file mode 100644 index 9f881f1..0000000 --- a/docs/field-types/type-aliases/type-alias.RichTextFieldType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > RichTextFieldType - -# Type alias: RichTextFieldType - -> **RichTextFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string`; - `enabledFeatures`: `RichTextFeatures`[]; - `type`: `"richtext"`; - } - -> ## `RichTextFieldType.default` -> -> **default**?: `string` -> -> ## `RichTextFieldType.enabledFeatures` -> -> **enabledFeatures**?: `RichTextFeatures`[] -> -> ## `RichTextFieldType.type` -> -> **type**: `"richtext"` -> -> - -## Source - -fieldTypes.ts:447 diff --git a/docs/field-types/type-aliases/type-alias.SfdcCamapaignFieldType.md b/docs/field-types/type-aliases/type-alias.SfdcCamapaignFieldType.md deleted file mode 100644 index 20fee28..0000000 --- a/docs/field-types/type-aliases/type-alias.SfdcCamapaignFieldType.md +++ /dev/null @@ -1,22 +0,0 @@ -[API](../index.md) > SfdcCamapaignFieldType - -# Type alias: SfdcCamapaignFieldType - -> **SfdcCamapaignFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string`; - `type`: `"salesforcecampaign"`; - } - -> ## `SfdcCamapaignFieldType.default` -> -> **default**?: `string` -> -> ## `SfdcCamapaignFieldType.type` -> -> **type**: `"salesforcecampaign"` -> -> - -## Source - -fieldTypes.ts:452 diff --git a/docs/field-types/type-aliases/type-alias.SimpleMenuFieldType.md b/docs/field-types/type-aliases/type-alias.SimpleMenuFieldType.md deleted file mode 100644 index 614c54d..0000000 --- a/docs/field-types/type-aliases/type-alias.SimpleMenuFieldType.md +++ /dev/null @@ -1,22 +0,0 @@ -[API](../index.md) > SimpleMenuFieldType - -# Type alias: SimpleMenuFieldType - -> **SimpleMenuFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{}[]; - `type`: `"simplemenu"`; - } - -> ## `SimpleMenuFieldType.default` -> -> **default**?: \{}[] -> -> ## `SimpleMenuFieldType.type` -> -> **type**: `"simplemenu"` -> -> - -## Source - -fieldTypes.ts:456 diff --git a/docs/field-types/type-aliases/type-alias.SpacingFieldType.md b/docs/field-types/type-aliases/type-alias.SpacingFieldType.md deleted file mode 100644 index 59cc587..0000000 --- a/docs/field-types/type-aliases/type-alias.SpacingFieldType.md +++ /dev/null @@ -1,145 +0,0 @@ -[API](../index.md) > SpacingFieldType - -# Type alias: SpacingFieldType - -> **SpacingFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `margin`: \{ - `bottom`: [`SpacingValueType`](type-alias.SpacingValueType.md); - `left`: [`SpacingValueType`](type-alias.SpacingValueType.md); - `right`: [`SpacingValueType`](type-alias.SpacingValueType.md); - `top`: [`SpacingValueType`](type-alias.SpacingValueType.md); - }; - `padding`: \{ - `bottom`: [`SpacingValueType`](type-alias.SpacingValueType.md); - `left`: [`SpacingValueType`](type-alias.SpacingValueType.md); - `right`: [`SpacingValueType`](type-alias.SpacingValueType.md); - `top`: [`SpacingValueType`](type-alias.SpacingValueType.md); - }; - }; - `limits`: \{ - `margin`: \{ - `bottom`: [`SpacingLimitType`](type-alias.SpacingLimitType.md); - `left`: [`SpacingLimitType`](type-alias.SpacingLimitType.md); - `right`: [`SpacingLimitType`](type-alias.SpacingLimitType.md); - `top`: [`SpacingLimitType`](type-alias.SpacingLimitType.md); - }; - `padding`: \{ - `bottom`: [`SpacingLimitType`](type-alias.SpacingLimitType.md); - `left`: [`SpacingLimitType`](type-alias.SpacingLimitType.md); - `right`: [`SpacingLimitType`](type-alias.SpacingLimitType.md); - `top`: [`SpacingLimitType`](type-alias.SpacingLimitType.md); - }; - }; - `type`: `"spacing"`; - } - -> ## `SpacingFieldType.default` -> -> **default**?: `object` -> -> > ### `default.margin` -> > -> > **margin**?: `object` -> > -> > > #### `margin.bottom` -> > > -> > > **bottom**?: [`SpacingValueType`](type-alias.SpacingValueType.md) -> > > -> > > #### `margin.left` -> > > -> > > **left**?: [`SpacingValueType`](type-alias.SpacingValueType.md) -> > > -> > > #### `margin.right` -> > > -> > > **right**?: [`SpacingValueType`](type-alias.SpacingValueType.md) -> > > -> > > #### `margin.top` -> > > -> > > **top**?: [`SpacingValueType`](type-alias.SpacingValueType.md) -> > > -> > > -> > -> > ### `default.padding` -> > -> > **padding**?: `object` -> > -> > > #### `padding.bottom` -> > > -> > > **bottom**?: [`SpacingValueType`](type-alias.SpacingValueType.md) -> > > -> > > #### `padding.left` -> > > -> > > **left**?: [`SpacingValueType`](type-alias.SpacingValueType.md) -> > > -> > > #### `padding.right` -> > > -> > > **right**?: [`SpacingValueType`](type-alias.SpacingValueType.md) -> > > -> > > #### `padding.top` -> > > -> > > **top**?: [`SpacingValueType`](type-alias.SpacingValueType.md) -> > > -> > > -> > -> > -> -> ## `SpacingFieldType.limits` -> -> **limits**?: `object` -> -> > ### `limits.margin` -> > -> > **margin**: `object` -> > -> > > #### `margin.bottom` -> > > -> > > **bottom**?: [`SpacingLimitType`](type-alias.SpacingLimitType.md) -> > > -> > > #### `margin.left` -> > > -> > > **left**?: [`SpacingLimitType`](type-alias.SpacingLimitType.md) -> > > -> > > #### `margin.right` -> > > -> > > **right**?: [`SpacingLimitType`](type-alias.SpacingLimitType.md) -> > > -> > > #### `margin.top` -> > > -> > > **top**?: [`SpacingLimitType`](type-alias.SpacingLimitType.md) -> > > -> > > -> > -> > ### `limits.padding` -> > -> > **padding**: `object` -> > -> > > #### `padding.bottom` -> > > -> > > **bottom**?: [`SpacingLimitType`](type-alias.SpacingLimitType.md) -> > > -> > > #### `padding.left` -> > > -> > > **left**?: [`SpacingLimitType`](type-alias.SpacingLimitType.md) -> > > -> > > #### `padding.right` -> > > -> > > **right**?: [`SpacingLimitType`](type-alias.SpacingLimitType.md) -> > > -> > > #### `padding.top` -> > > -> > > **top**?: [`SpacingLimitType`](type-alias.SpacingLimitType.md) -> > > -> > > -> > -> > -> -> ## `SpacingFieldType.type` -> -> **type**: `"spacing"` -> -> - -## Source - -fieldTypes.ts:469 diff --git a/docs/field-types/type-aliases/type-alias.SpacingLimitType.md b/docs/field-types/type-aliases/type-alias.SpacingLimitType.md deleted file mode 100644 index 39983db..0000000 --- a/docs/field-types/type-aliases/type-alias.SpacingLimitType.md +++ /dev/null @@ -1,27 +0,0 @@ -[API](../index.md) > SpacingLimitType - -# Type alias: SpacingLimitType - -> **SpacingLimitType**: `object` - -## Type declaration - -### `max` - -**max**: `number` - -*** - -### `min` - -**min**: `number` - -*** - -### `units` - -**units**: [`CssUnit`](type-alias.CssUnit.md)[] - -## Source - -fieldTypes.ts:464 diff --git a/docs/field-types/type-aliases/type-alias.SpacingValueType.md b/docs/field-types/type-aliases/type-alias.SpacingValueType.md deleted file mode 100644 index f71f0fb..0000000 --- a/docs/field-types/type-aliases/type-alias.SpacingValueType.md +++ /dev/null @@ -1,21 +0,0 @@ -[API](../index.md) > SpacingValueType - -# Type alias: SpacingValueType - -> **SpacingValueType**: `object` - -## Type declaration - -### `units` - -**units**: [`CssUnit`](type-alias.CssUnit.md) - -*** - -### `value` - -**value**: `number` - -## Source - -fieldTypes.ts:460 diff --git a/docs/field-types/type-aliases/type-alias.SurveyFieldType.md b/docs/field-types/type-aliases/type-alias.SurveyFieldType.md deleted file mode 100644 index 5c8dc67..0000000 --- a/docs/field-types/type-aliases/type-alias.SurveyFieldType.md +++ /dev/null @@ -1,40 +0,0 @@ -[API](../index.md) > SurveyFieldType - -# Type alias: SurveyFieldType - -> **SurveyFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `id`: `string`; - `survey_type`: `"CES"` \| `"CSAT"` \| `"NPS"`; - }; - `placeholder`: `string`; - `type`: `"survey"`; - } - -> ## `SurveyFieldType.default` -> -> **default**?: `object` -> -> > ### `default.id` -> > -> > **id**?: `string` -> > -> > ### `default.survey_type` -> > -> > **survey\_type**?: `"CES"` \| `"CSAT"` \| `"NPS"` -> > -> > -> -> ## `SurveyFieldType.placeholder` -> -> **placeholder**?: `string` -> -> ## `SurveyFieldType.type` -> -> **type**: `"survey"` -> -> - -## Source - -fieldTypes.ts:500 diff --git a/docs/field-types/type-aliases/type-alias.TagFieldType.md b/docs/field-types/type-aliases/type-alias.TagFieldType.md deleted file mode 100644 index 0923439..0000000 --- a/docs/field-types/type-aliases/type-alias.TagFieldType.md +++ /dev/null @@ -1,35 +0,0 @@ -[API](../index.md) > TagFieldType - -# Type alias: TagFieldType - -> **TagFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `string` \| `number` \| \{ - `id`: `string`; - `name`: `string`; - `slug`: `string`; - }; - `tagValue`: `"SLUG"` \| `"NAME"` \| `"ID"` \| `"ALL"`; - `type`: `"tag"`; - } - -> ## `TagFieldType.default` -> -> **default**?: `string` \| `number` \| \{ -> `id`: `string`; -> `name`: `string`; -> `slug`: `string`; -> } -> -> ## `TagFieldType.tagValue` -> -> **tagValue**: `"SLUG"` \| `"NAME"` \| `"ID"` \| `"ALL"` -> -> ## `TagFieldType.type` -> -> **type**: `"tag"` -> -> - -## Source - -fieldTypes.ts:508 diff --git a/docs/field-types/type-aliases/type-alias.TextAlignmentFieldType.md b/docs/field-types/type-aliases/type-alias.TextAlignmentFieldType.md deleted file mode 100644 index 74d762a..0000000 --- a/docs/field-types/type-aliases/type-alias.TextAlignmentFieldType.md +++ /dev/null @@ -1,30 +0,0 @@ -[API](../index.md) > TextAlignmentFieldType - -# Type alias: TextAlignmentFieldType - -> **TextAlignmentFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `text_align`: `"LEFT"` \| `"CENTER"` \| `"RIGHT"` \| `"JUSTIFY"`; - }; - `type`: `"textalignment"`; - } - -> ## `TextAlignmentFieldType.default` -> -> **default**?: `object` -> -> > ### `default.text_align` -> > -> > **text\_align**?: `"LEFT"` \| `"CENTER"` \| `"RIGHT"` \| `"JUSTIFY"` -> > -> > -> -> ## `TextAlignmentFieldType.type` -> -> **type**: `"textalignment"` -> -> - -## Source - -fieldTypes.ts:527 diff --git a/docs/field-types/type-aliases/type-alias.TextFieldType.md b/docs/field-types/type-aliases/type-alias.TextFieldType.md deleted file mode 100644 index 50a29d4..0000000 --- a/docs/field-types/type-aliases/type-alias.TextFieldType.md +++ /dev/null @@ -1,37 +0,0 @@ -[API](../index.md) > TextFieldType - -# Type alias: TextFieldType - -> **TextFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `allowNewLine`: `boolean`; - `default`: `string`; - `showEmojiPicker`: `boolean`; - `type`: `"text"`; - `validationRegex`: `string`; - } - -> ## `TextFieldType.allowNewLine` -> -> **allowNewLine**?: `boolean` -> -> ## `TextFieldType.default` -> -> **default**?: `string` -> -> ## `TextFieldType.showEmojiPicker` -> -> **showEmojiPicker**?: `boolean` -> -> ## `TextFieldType.type` -> -> **type**: `"text"` -> -> ## `TextFieldType.validationRegex` -> -> **validationRegex**?: `string` -> -> - -## Source - -fieldTypes.ts:520 diff --git a/docs/field-types/type-aliases/type-alias.UrlFieldType.md b/docs/field-types/type-aliases/type-alias.UrlFieldType.md deleted file mode 100644 index 912c7fd..0000000 --- a/docs/field-types/type-aliases/type-alias.UrlFieldType.md +++ /dev/null @@ -1,50 +0,0 @@ -[API](../index.md) > UrlFieldType - -# Type alias: UrlFieldType - -> **UrlFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `content_id`: `number`; - `href`: `string`; - `supported_types`: `UrlTypes`[]; - `type`: `UrlTypes`; - }; - `supportedTypes`: `UrlTypes`[]; - `type`: `"url"`; - } - -> ## `UrlFieldType.default` -> -> **default**?: `object` -> -> > ### `default.content_id` -> > -> > **content\_id**?: `number` -> > -> > ### `default.href` -> > -> > **href**?: `string` -> > -> > ### `default.supported_types` -> > -> > **supported\_types**?: `UrlTypes`[] -> > -> > ### `default.type` -> > -> > **type**?: `UrlTypes` -> > -> > -> -> ## `UrlFieldType.supportedTypes` -> -> **supportedTypes**: `UrlTypes`[] -> -> ## `UrlFieldType.type` -> -> **type**: `"url"` -> -> - -## Source - -fieldTypes.ts:543 diff --git a/docs/field-types/type-aliases/type-alias.VideoFieldType.md b/docs/field-types/type-aliases/type-alias.VideoFieldType.md deleted file mode 100644 index 0b4e57e..0000000 --- a/docs/field-types/type-aliases/type-alias.VideoFieldType.md +++ /dev/null @@ -1,100 +0,0 @@ -[API](../index.md) > VideoFieldType - -# Type alias: VideoFieldType - -> **VideoFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: \{ - `autoplay`: `boolean`; - `conversion_asset`: `any`; - `height`: `number`; - `hide_controls`: `boolean`; - `loop_video`: `boolean`; - `max_height`: `number`; - `max_width`: `number`; - `mute_by_default`: `boolean`; - `player_id`: `number`; - `player_type`: `string`; - `size_type`: `"exact"` \| `"auto"` \| `"auto_custom_max"` \| `"auto_full_width"`; - `width`: `number`; - }; - `resizable`: `boolean`; - `showAdvancedOptions`: `boolean`; - `showPreview`: `boolean`; - `type`: `"videoplayer"`; - } - -> ## `VideoFieldType.default` -> -> **default**?: `object` -> -> > ### `default.autoplay` -> > -> > **autoplay**?: `boolean` -> > -> > ### `default.conversion_asset` -> > -> > **conversion\_asset**?: `any` -> > -> > ### `default.height` -> > -> > **height**?: `number` -> > -> > ### `default.hide_controls` -> > -> > **hide\_controls**?: `boolean` -> > -> > ### `default.loop_video` -> > -> > **loop\_video**?: `boolean` -> > -> > ### `default.max_height` -> > -> > **max\_height**?: `number` -> > -> > ### `default.max_width` -> > -> > **max\_width**?: `number` -> > -> > ### `default.mute_by_default` -> > -> > **mute\_by\_default**?: `boolean` -> > -> > ### `default.player_id` -> > -> > **player\_id**?: `number` -> > -> > ### `default.player_type` -> > -> > **player\_type**?: `string` -> > -> > ### `default.size_type` -> > -> > **size\_type**?: `"exact"` \| `"auto"` \| `"auto_custom_max"` \| `"auto_full_width"` -> > -> > ### `default.width` -> > -> > **width**?: `number` -> > -> > -> -> ## `VideoFieldType.resizable` -> -> **resizable**?: `boolean` -> -> ## `VideoFieldType.showAdvancedOptions` -> -> **showAdvancedOptions**?: `boolean` -> -> ## `VideoFieldType.showPreview` -> -> **showPreview**?: `boolean` -> -> ## `VideoFieldType.type` -> -> **type**: `"videoplayer"` -> -> - -## Source - -fieldTypes.ts:553 diff --git a/docs/field-types/type-aliases/type-alias.WorkflowFieldType.md b/docs/field-types/type-aliases/type-alias.WorkflowFieldType.md deleted file mode 100644 index ec35ae4..0000000 --- a/docs/field-types/type-aliases/type-alias.WorkflowFieldType.md +++ /dev/null @@ -1,22 +0,0 @@ -[API](../index.md) > WorkflowFieldType - -# Type alias: WorkflowFieldType - -> **WorkflowFieldType**: [`BaseField`](type-alias.BaseField.md) & \{ - `default`: `number`; - `type`: `"workflow"`; - } - -> ## `WorkflowFieldType.default` -> -> **default**?: `number` -> -> ## `WorkflowFieldType.type` -> -> **type**: `"workflow"` -> -> - -## Source - -fieldTypes.ts:574 diff --git a/docs/field-types/typedoc-sidebar.json b/docs/field-types/typedoc-sidebar.json deleted file mode 100644 index 7729a9d..0000000 --- a/docs/field-types/typedoc-sidebar.json +++ /dev/null @@ -1,332 +0,0 @@ -[ - { - "text": "AdvancedVisibility", - "link": "/../../field-types/type-aliases/type-alias.AdvancedVisibility.md", - "collapsed": true, - "items": [] - }, - { - "text": "AlignmentFieldType", - "link": "/../../field-types/type-aliases/type-alias.AlignmentFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "AudioFieldType", - "link": "/../../field-types/type-aliases/type-alias.AudioFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "BackgroundImageFieldType", - "link": "/../../field-types/type-aliases/type-alias.BackgroundImageFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "BaseField", - "link": "/../../field-types/type-aliases/type-alias.BaseField.md", - "collapsed": true, - "items": [] - }, - { - "text": "BlogFieldType", - "link": "/../../field-types/type-aliases/type-alias.BlogFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "BooleanFieldType", - "link": "/../../field-types/type-aliases/type-alias.BooleanFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "BorderFieldType", - "link": "/../../field-types/type-aliases/type-alias.BorderFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "BorderSideType", - "link": "/../../field-types/type-aliases/type-alias.BorderSideType.md", - "collapsed": true, - "items": [] - }, - { - "text": "ChoiceFieldType", - "link": "/../../field-types/type-aliases/type-alias.ChoiceFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "ColorFieldType", - "link": "/../../field-types/type-aliases/type-alias.ColorFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "CrmObjectFieldType", - "link": "/../../field-types/type-aliases/type-alias.CrmObjectFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "CrmObjectPropertyFieldType", - "link": "/../../field-types/type-aliases/type-alias.CrmObjectPropertyFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "CssUnit", - "link": "/../../field-types/type-aliases/type-alias.CssUnit.md", - "collapsed": true, - "items": [] - }, - { - "text": "CtaFieldType", - "link": "/../../field-types/type-aliases/type-alias.CtaFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "DateFieldType", - "link": "/../../field-types/type-aliases/type-alias.DateFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "DateTimeFieldType", - "link": "/../../field-types/type-aliases/type-alias.DateTimeFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "EmailFieldType", - "link": "/../../field-types/type-aliases/type-alias.EmailFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "EmbedFieldType", - "link": "/../../field-types/type-aliases/type-alias.EmbedFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "Field", - "link": "/../../field-types/type-aliases/type-alias.Field.md", - "collapsed": true, - "items": [] - }, - { - "text": "FieldComponentProps", - "link": "/../../field-types/type-aliases/type-alias.FieldComponentProps.md", - "collapsed": true, - "items": [] - }, - { - "text": "FieldType", - "link": "/../../field-types/type-aliases/type-alias.FieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "FileFieldType", - "link": "/../../field-types/type-aliases/type-alias.FileFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "FollowUpEmailFieldType", - "link": "/../../field-types/type-aliases/type-alias.FollowUpEmailFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "FontFieldType", - "link": "/../../field-types/type-aliases/type-alias.FontFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "FormFieldType", - "link": "/../../field-types/type-aliases/type-alias.FormFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "GradientColorType", - "link": "/../../field-types/type-aliases/type-alias.GradientColorType.md", - "collapsed": true, - "items": [] - }, - { - "text": "GradientFieldType", - "link": "/../../field-types/type-aliases/type-alias.GradientFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "GroupFieldType", - "link": "/../../field-types/type-aliases/type-alias.GroupFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "HtmlFieldType", - "link": "/../../field-types/type-aliases/type-alias.HtmlFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "HubDbRowFieldType", - "link": "/../../field-types/type-aliases/type-alias.HubdbRowFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "HubDbTableFieldType", - "link": "/../../field-types/type-aliases/type-alias.HubdbTableFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "HublFieldType", - "link": "/../../field-types/type-aliases/type-alias.HublFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "IconFieldType", - "link": "/../../field-types/type-aliases/type-alias.IconFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "ImageFieldType", - "link": "/../../field-types/type-aliases/type-alias.ImageFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "LinkFieldType", - "link": "/../../field-types/type-aliases/type-alias.LinkFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "LogoFieldType", - "link": "/../../field-types/type-aliases/type-alias.LogoFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "MeetingFieldType", - "link": "/../../field-types/type-aliases/type-alias.MeetingFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "MenuFieldType", - "link": "/../../field-types/type-aliases/type-alias.MenuFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "NumberFieldType", - "link": "/../../field-types/type-aliases/type-alias.NumberFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "PageFieldType", - "link": "/../../field-types/type-aliases/type-alias.PageFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "PaymentFieldType", - "link": "/../../field-types/type-aliases/type-alias.PaymentFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "RichTextFieldType", - "link": "/../../field-types/type-aliases/type-alias.RichTextFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "SfdcCamapaignFieldType", - "link": "/../../field-types/type-aliases/type-alias.SfdcCamapaignFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "SimpleMenuFieldType", - "link": "/../../field-types/type-aliases/type-alias.SimpleMenuFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "SpacingFieldType", - "link": "/../../field-types/type-aliases/type-alias.SpacingFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "SpacingLimitType", - "link": "/../../field-types/type-aliases/type-alias.SpacingLimitType.md", - "collapsed": true, - "items": [] - }, - { - "text": "SpacingValueType", - "link": "/../../field-types/type-aliases/type-alias.SpacingValueType.md", - "collapsed": true, - "items": [] - }, - { - "text": "SurveyFieldType", - "link": "/../../field-types/type-aliases/type-alias.SurveyFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "TagFieldType", - "link": "/../../field-types/type-aliases/type-alias.TagFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "TextAlignmentFieldType", - "link": "/../../field-types/type-aliases/type-alias.TextAlignmentFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "TextFieldType", - "link": "/../../field-types/type-aliases/type-alias.TextFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "UrlFieldType", - "link": "/../../field-types/type-aliases/type-alias.UrlFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "VideoFieldType", - "link": "/../../field-types/type-aliases/type-alias.VideoFieldType.md", - "collapsed": true, - "items": [] - }, - { - "text": "WorkflowFieldType", - "link": "/../../field-types/type-aliases/type-alias.WorkflowFieldType.md", - "collapsed": true, - "items": [] - } -] diff --git a/docs/index.md b/docs/index.md index cc58f41..573f396 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,46 +1 @@ ---- -next: - text: 'API Reference' - link: 'reference/project-structure' ---- - -CMS React slack channel: [\#cms-react](https://hubspotdev.slack.com/archives/C04AY1H2204) - -# Introduction - -## Welcome! - -Thank you for taking the time to explore this new direction for the HubSpot CMS! As always our goal is to solve for our customers so we welcome any and all feedback. Chat away in [\#cms-js-rendering](https://hubspotdev.slack.com/archives/C04AY1H2204) with other HubSpot developers who are pushing forward with React on the HubSpot CMS. - -The easiest way to get started is by following the [Hello World example guide](https://github.com/HubSpot/cms-react/tree/main/examples/hello-world). Once you've acquainted yourself with React modules and partials use the [API reference](https://github.hubspot.com/cms-react/reference/project-structure.html) to learn more. If you are new to JavaScript or React, please check out the “Learning links” execution in the [appendix](/appendix) below. - -## What are the new things? - -React modules and partials are new building blocks you can use to write React and JavaScript instead of HubL inside the HubSpot CMS. Note this doesn’t mean you will switch entirely away from HubL immediately, rather we want to provide a pathway to code React and render that on both on the server and client. JS modules and partials are built from React components and can directly be referenced via HubL tags in your templates. - -In addition to stitching server-rendered React components into the HTML generated by HubL, JS modules and partials support client-side interactivity with [islands](https://www.patterns.dev/posts/islands-architecture). Similar to the islands concept from Astro, Fresh, and others, you can add an `` inside your JS module or partial to establish a component that is rendered on both the server and client and is automatically code-split. In addition to allowing you to reuse JavaScript code between the server and browser, islands help you write fast websites by giving you precise control over what JavaScript is shipped to the browser and when it runs. - -## Benefits - -Using React instead of HubL comes with lots of benefits, including component composability, code reuse, broader community resources, and real access to JavaScript on the server. While this release is just a start, our hope is to make developing on the HubSpot CMS feel like modern web development. Plus we want to give you technologies that scale with you, all the way from simple static pages to complex interactive and dynamic web applications. - -Rendering React on the server means that there is far less of a technological divide between your code that serves the initial page HTML and your interactive browser code. Previously, as you created more complex and interactive pages, that would either lead to: - -- More and more client-side JavaScript that "blocked" and slowed down the page until it was all downloaded and executed -- Having to replicate or dually maintain UI logic across HubL and JavaScript in order to have server HTML that is immediately visible and can later interact to user input - -In other words, you often needed to choose between: - -- Accepting worse performance that comes from keeping your more complex module or component logic code only in the browser -- Accepting the complexity and maintenance burden that comes from splitting a module or component's logic across HubL and JavaScript - -However when server-side rendering (SSR) JavaScript, you no longer have to make that trade-off. You can code complex interactive components which either share code with or are directly rendered on the server themselves. When paired with the islands model, we believe you'll be able to more easily code web experiences that have good Core Web Vital scores (LCP, FID, CLS) even as your clients and organizations demand more and more. - -Additionally by building on top of JavaScript and an open source framework (React), you'll have better access to the wealth of tooling, libraries, example code, community answers, etc available in the broader ecosystem. That will make new developers get up to speed faster, enable you to create better experiences with less time and effort, and give you better and shinier toys to code with. For example, since JS modules and partials are built on top of Vite, you'll get things like ESM, TypeScript, JSX, CSS modules, and tree-shaking out of the box. - -## Features missing and caveats - -Note, React modules & partials are still in development and we are actively working on many things. Here is a list of some features that we are actively implementing but are not fully finished yet: - -- More performance optimizations -- Support for importing JS Modules into JS Partials +# Official documentation moved to [https://developers.hubspot.com](https://developers.hubspot.com/docs/guides/cms/quickstart/react-plus-hubl-quickstart) diff --git a/docs/reference.md b/docs/reference.md deleted file mode 100644 index 93bf706..0000000 --- a/docs/reference.md +++ /dev/null @@ -1,3 +0,0 @@ -# Documentation moved - -Documentation is now available at https://github.hubspot.com/cms-react/ diff --git a/docs/reference/build-healthchecks.md b/docs/reference/build-healthchecks.md deleted file mode 100644 index 9ee801e..0000000 --- a/docs/reference/build-healthchecks.md +++ /dev/null @@ -1,50 +0,0 @@ -# Build health checks - -To validiate and prevent unexpected production behavior, CMS React will automatically run a series of "health checks" at the end of your build. For now, those health checks are enabled but will not fail your build by default. - -Here are the specifc things the health checks look for: - - - For every React partial: - - Make sure the built partial code can be imported - - Make sure there is a default export _and_ that it is a React component (a function) - - - For every React module: - - Make sure the built module code can be imported - - Make sure there is a `Component` named export _and_ that it is a React component (a function) - - Make sure there is a `fields` named export _and_ it is a React element (`...`) or an array - - Make sure there is a `meta` named export _and_ it is a JavaScript object - - - For any island import (`?island`), client import (`?client`), or dynamic import (`import(...)`) linked from a React module or partial's code: - - Make sure that code can be imported - -
- -::: info -Currently only failed health checks are logged in the build output _only_ when strict health checks are enabled. In the future we will always output all successful and failed health checks to make it easier to now about failures _before_ enabling strict mode. -::: - -### ESM and Common JS "fun" - -In addition to verifing React modules and partial definitions, health checks also will uncover problematic ESM ↔ Common JS issues _before_ any code is deployed (what the heck? Learn more about [CJS vs ESM](https://yuzu.health/blog/cjs-vs-esm)). We built CMS React on top of [Vite](https://vitejs.dev/) with the intention of living in a modern JavaScript world, however that can lead to problems when depending on other packages that have misconfigured ESM exports. - -And particuarly bad are packages that advertise CJS exports (i.e. `package.json` `export`/`type` stuff) that actually have ESM `import` and `export` syntax in them (for example [`@mui/material@5.15.10`](https://publint.dev/@mui/material@5.15.10)). Because that can lead to situations where Vite's compiler outputs an import to that package's file in a `node_modules/...`, but when that code is run there will be a runtime syntax error. However, with build health checks we make sure to discover that problem at _build-time_ rather than by your visitors at runtime. - -Note, we are working toward making solving more of these kind of problems automatically. However, in the mean time build health checks with strict mode enabled are very helpful to prevent this problem from "sneaking" out to production. - -### Build health check configuration - -If you would like to explicitly configure your project's build health checks, you can do that inside of `cms-assets.json`: - -```json -// cms-assets.json -{ - "label": "My CMS project", - "buildConfig": { - "healthchecks": { - "enabled": true, // default is true - "strict": true // default is false (for now) - } - } -}; -``` - diff --git a/docs/reference/cms-components.md b/docs/reference/cms-components.md deleted file mode 100644 index 21c2acf..0000000 --- a/docs/reference/cms-components.md +++ /dev/null @@ -1,391 +0,0 @@ -# @hubspot/cms-components - -`@hubspot/cms-components` is a runtime library providing primitives to interact with CMS React features and other HubSpot data from your components. - -## Getters - -### `getHubID` - -`( ) => number` - -Returns the the current account ID (“Hub ID” or “portal ID”) for the page being rendered - -### `getIsDeployed` - -`( ) => boolean` - -Returns `true` for components rendered live for a deployed project and `false` when rendering in the dev server. - -### `getSecret` - -`(secretName: string) => string` - -Returns a value for a given secret key. The secret must be defined using `hs secrets` in the CLI and the key must be included in a `secretNames` array in your `cms-assets.json` configuration. To prevent accidentally leaking secrets, `getSecret()`: - - **Cannot** be called at the top-level of a module - - **Cannot** be called from inside an island - -In other words, `getSecert` _must be called from_ a React component function that is rendered on the server. And if you want to pass a secret to client-side code—which makes it available public "view-source" viewing—you must explicitly pass the secret string via an island prop. - -See the [Secrets section](./secrets) for more information on usage. - -## Hooks - -We provide a number of React hooks from the `@hubspot/cms-components` package to help write components that run on both the server and the browser. - -### `useAfterIslandHydration` - -`( ) => boolean` - -Will return `true` only after hydration is completed. More specifically it will: - -- Return `false` during the initial render on the server. -- Return `false` during the first render that happens inside the browser. -- Return `true` during any subsequent renders that happen after the component has been “mounted” in the browser. - -This hook is useful because React requires server-rendered HTML to match the initial client render. See the [Server/Client Rendering section](../appendix#server-side-client-side-rendering) in the appendix for more information. - -### `useIsServerRender` - -`( ) => boolean` - -Returns `true` while the component is being rendered on the server and `false` in the browser. Note, in most cases it is better to use `useAfterIslandHydration()`, since it makes it easier for your code to “do the right thing” for hydration. - -### `usePageUrl` - -`( ) => URL` - -Returns the current page [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL). Works on server and is reactive to changes to the URL on client. This can be useful when components need to react to URL changes, such as query params, while also supporting server rendering. To programmatically trigger non-navigation URL changes, use `pushHistoryState()` which is identical to `window.history.pushState()` but integrates with `usePageUrl()` to ensure it receives change events. - -### `useInlineHeadAsset` - -`(renderFunc: () => JSX.Element) => void` - -Provides an API to pass HTML to render in the ``. This is most useful for collecting CSS from CSS-in-JS libraries and including the emitted CSS in the initial page response. See [Styling](./styling) for more details. - -### `useSharedIslandState` - -```javascript -const [sharedState, updateSharedState, sharedStateID] = useSharedIslandState(); -``` - -Returns an object of state shared multiple islands and updater function. It works similarly to `useState`, but updating the state via `updateSharedState(newValue)` will "reach across" and update all of the other islands that also use `useSharedIslandState()`. Works in coordination with the `SharedIslandState` component. - -### `useSharedIslandReducer` - -```javascript -const [sharedState, dispatch] = useSharedIslandReducer(); -``` - -Returns an object of state shared multiple islands and a dispatch function. It works similarly to `useReducer`, but actions dispatched will "reach across" and update all of the other islands that also use `useSharedIslandReducer()`. Works in coordination with the `SharedIslandReducer` component. - -## Components - -### `` - -See the [Islands](./islands) section for details. - -### `` - -Defines the initial value for the shared state accessed in `useSharedIslandState()` by other islands in this JS module or partial. All islands that are are "wrapped" by `SharedIslandState` (i.e. are children or descendents of the children) will share a single state reference. Note, `SharedIslandState` must be rendered on the server and cannot be contained inside an island. - -```javascript - - … - -``` - -### `` - -Defines the reducer function and initial value for the shared reducer state accessed in `useSharedIslandReducer()` by other islands in this JS module or partial. All islands that are are "wrapped" by `SharedIslandReducer` (i.e. are children or descendents of the children) will share a single state reference and dispatch function. Note, `SharedIslandReducer` must be rendered on the server and cannot be contained inside an island and the reducer function passed in must imported with the `?client` suffix (which will automatically prepare code-split that function for the browser to grab it). - -```javascript -import reducerFuncReference from '../path/to/reducerFunc.js?client'; - - … - - -// reducerFunc.js -export default function reducerFunc(state, action) { - if (action.type === 'increment') { - state = { - ...state, - new: ‘state value’ - }; - } - - return state; -} -``` - -## Field Helper Components - -The following components are designed to be used with associated module field definitions. They cannot be used for non-field related use cases. - -If an associated field is not found at the provided `fieldPath` then the components will render null. - -### Icon - -#### @hubspot/cms-components/Icon - -The Icon component renders a SVG for a referenced Icon field. - -##### Props - -###### fieldPath - -type: `string` - -The path of the icon field to render - -Examples: - -- Top level `fieldPath="icon_field"` - -- Nested in a group: `fieldPath="group_field.icon_field"` - -- Repeater field: `fieldPath="icon_field[1]"` - -- Repeater group field: `fieldPath="group_field[0].icon_field"` - -###### iconPurpose - -type: `'SEMANTIC' | 'DECORATIVE'` - -default: `SEMANTIC` - -`SEMANTIC` will set the `role="img"` attribute on the svg, as well as `aria-labelledby` pointing to the [title](#title) element - -###### Title - -type: `string` - -If provided, will render a `` tag within the SVG for accessibilty to be described by `aria-labelledby` via [iconPurpose](#iconpurpose) - -###### iconStyle - -type: `'REGULAR' | 'SOLID' | 'LIGHT'` - -If provided, overrides the default icon style associated with the field. Not all icons have every style. Will only use the override if the icon style exists. - -###### SVG element attributes - -This component also accepts all valid attributes for an SVG element and will apply them, such as `id`, `style`, etc. - -##### Example Usage - -```javascript -import { Icon } from '@hubspot/cms-components'; - -export function Component() { - return <Icon fieldPath="icon_field" height={10} />; -} - -export const meta = { - label: `Icon Module`, -}; - -export const fields = [ - { - type: 'icon', - default: { - name: 'Alternate Level Up', - unicode: 'f3bf', - type: 'SOLID', - }, - icon_set: 'fontawesome-5.14.0', - label: 'Icon', - name: 'icon_field', - }, -]; -``` - -### RichText - -#### @hubspot/cms-components/RichText - -The RichText component handles inserting the RichText HTML into your DOM. - -##### Props - -###### fieldPath - -type: `string` - -The path of the Rich Text field to render - -###### tag - -The tag used as the wrapping element for the content. - -default: `div` - -###### Element attributes - -This component passes through all valid attributes to the wrapper tag and applies them, such as `id`, `style`, etc. - -##### Example Usage - -```javascript -import { RichText } from '@hubspot/cms-components'; - -export function Component() { - return <RichText fieldPath="richtext_field" tag="span" />; -} - -export const meta = { - label: `RichText Module`, -}; - -export const fields = [ - { - type: 'richtext', - label: 'Rich text', - name: 'richtext_field', - default: '<p><em><strong>Helllo, world!</strong></em></p>', - }, -]; -``` - -### Cta - -#### @hubspot/cms-components/Cta - -The Cta component inserts Cta HTML into the DOM. - -##### Props - -###### fieldPath - -type: `string` - -The path of the Cta field to render - -###### tag - -The tag used as the wrapping element for the content. - -default: `div` - -###### Element attributes - -This component passes through all valid attributes to the wrapper tag and applies them, such as `id`, `style`, etc. - -##### Example Usage - -```javascript -import { Cta } from '@hubspot/cms-components'; - -export function Component() { - return <Cta fieldPath="cta_field" />; -} - -export const meta = { - label: `CTA Module`, -}; - -export const fields = [ - { - type: 'cta', - label: 'CTA', - name: 'cta_field', - default: '13bcd0b3-5192-4570-baff-9a779df01bd8', - }, -]; -``` - -### Form - -#### @hubspot/cms-components/Form - -The Form field helper component inserts the HubL Form HTML into the DOM. - -##### Props - -###### fieldPath - -type: `string` - -The path of the Form field to render - -###### tag - -The tag used as the wrapping element for the content. - -default: `div` - -###### Element attributes - -This component passes through all valid attributes to the wrapper tag and applies them, such as `id`, `style`, etc. - -##### Example Usage - -```javascript -import { Form } from '@hubspot/cms-components'; - -export function Component() { - return <Form fieldPath="form_field" />; -} - -export const meta = { - label: `Form Module`, -}; - -export const fields = [ - { - type: 'form', - default: { - form_id: '56208269-add7-458d-b514-7f215e6ad98c', - message: 'Thanks for submitting the form.', - }, - label: 'Form', - name: 'form_field', - }, -]; -``` - -### Menu - -#### @hubspot/cms-components/Menu - -The Menu field helper component inserts the HubL menu HTML into the DOM. - -##### Props - -###### fieldPath - -type: `string` - -The path of the Menu field to render - -###### tag - -The tag used as the wrapping element for the content. - -default: `div` - -###### Element attributes - -This component passes through all valid attributes to the wrapper tag and applies them, such as `id`, `style`, etc. - -##### Example Usage - -```javascript -import { Menu } from '@hubspot/cms-components'; - -export function Component() { - return <Menu fieldPath="my_menu_field" />; -} - -export const meta = { - label: `Menu Module`, -}; - -export const fields = [ - { - type: 'menu', - default: 57978762829, - label: 'Menu', - name: 'my_menu_field', - }, -]; -``` diff --git a/docs/reference/cms-dev-server.md b/docs/reference/cms-dev-server.md deleted file mode 100644 index 2486bb7..0000000 --- a/docs/reference/cms-dev-server.md +++ /dev/null @@ -1,169 +0,0 @@ - -# @hubspot/cms-dev-server - -## Basic Usage - -`@hubspot/cms-dev-server` is a package that allows users to start an Express + Vite dev server enabling an auto-reloading local development workflow that is nearly identical to your deployed components. The `cms-dev-server` also enables rendering local versions of your components on live CMS pages to aid in development. - -Users can start the cms-dev-server by running `hs-cms-dev-server /path/to/components-directory` in a project that has `@hubspot/cms-dev-server` installed. - -For example, a CMS page with JS rendered components “https://cmssite.com/page" would be accessible by visiting one of: - -- http://cmssite.com.hslocal.net:3000/page -- http://cmssite.com.localhost:3000/page - -Or by visiting http://hslocal.net:3000/proxy and pasting in the page you want to proxy. - -Similar to how previewing a page from the page editor works, you can force the page to render with the context of a contact by passing an `email` parameter. For example `http://cmssite.com.hslocal.net:3000/page?email=bh@hubspot.com` will cause the contact object to be populated based on the email parameter value. - -You may also start the dev server with the `--ssl` option, which enables: - -- https://cmssite.com.hslocal.net:3000/page -- https://cmssite.com.localhost:3000/page - -## Routes - -When the CMS Dev Server for CMS React starts it will look at the directory structure and look for `partials` and `modules` within `components`. It will then dynamically create routes based on what it finds there. - -### Modules - -The CMS Dev Server offers two different rotes for your modules; `/preview/module/[module_name]` and `/module/[module_name]`. - -#### `/preview/module/[module_name]` - -You need to be "online" and "authenticated" to use this route. - -The `/preview/module/[module_name]` route does talk to the HubSpot backend and behaves similarly to viewing a module in the Design Previewer. - -Field values that are used rely on defaults as there is no module instance to pull from. There is no `fields` param available here for overrides. - -GraphQL data is derived on the BE and there is no query from the local server to the GraphQL service. - -`hublDataTemplate` is supported at this route, the assumed context is similar to that of the Design Previewer. - -`Icon`, `CTA`, and other `@hubspot/cms-component` Field helpers are supported at this route. - -#### `/module/[module_name]` - -The `/module/[module_name]` route is rendered entirely locally without talking to the HubSpot backend. - -You can work "offline" and "unauthenticated" at this route - with caveats for GraphQL. - -Field values that are used are derived entirely from the Field default values and from parameter level overrides. Param level overrides can be passed via `fields` param which expects stringified JSON of fieldValues that matches what is the passed fieldValues prop (matching the fields definition structure). - -GraphQL data in this context is fetched from your local machine using your local access token as the auth for the collector service. These queries are cached, but you can bust the cache with the `hsLocalQueryKey` query parameter. - -`hublDataTemplate` is not supported at this route. - -`hublParams` at this route will always be an empty object `{}`. - -`Icon`, `CTA`, and other `@hubspot/cms-component` Field helpers are not supported at this route. - -### Partials - -The CMS Dev Server offer a route for partials; `/partial/[partial_file_name]`. - -Partials are very thin and do not support GraphQL or `hublDataTemplate`. In the context of the dev server `hublParameters` will always be and empty object `{}`. - -## Proxying Private Pages - -Making use of the CMS React local dev with proxied pages is powerful. It allows you to make changed to your React modules locally and see how they will look within the context of a page. This is no less true for pages that are private via a password or other means. - -### Proxied User View - -Visit a private page and login with the configured method. Once authenticated Once there add `hslocal.net:3000` or `localhost:3000` to your root domain just as you would with proxying a public page. This will allow you to develop your React modules locally in the context of an authenticated live page. - -When proxying a private page, if you provide an email parameter e.g. `https://mydomain.hslocal.net:3000/private-page?email=bh@hubspot.com` that email's user will be used for the `request_contact` HubL variable. This can be passed to React with the [`hublDataTemplate`](./js-modules#hublDataTemplate) feature. - -### Proxied Preview - -Visit the page as a "preview". You can do this from the page editor by clicking the "Preview" button and then "Open in a new tab". Once there add `hslocal.net:3000` or `localhost:3000` to your root domain. This will allow you to do local development on a private pages. Further if you pass an `email` param it will use the associated contact as context for viewing the page. Your URL in this case wil look like `http://my-domain.com.localhost:3000/private-page-path?hs_preview=[preview_key]&email=bh@hubspot.com`. - -## Storybook - -`cms-dev-server` includes a [Storybook](https://storybook.js.org/) integration. Pass a `--storybook` option when starting the server to start a Storybook instance alongside the built-in dev server. You may then add `.stories.jsx` files alongside your components to build stories for testing or development. At the root http://hslocal.net:3000 page there should be a link to the Storybook UI for your project. -To make building stories for HubSpot modules easier, `cms-dev-server` provides helpers to auto-generate `argTypes` based on module fields. See the [GraphQL and Storybook](https://github.com/HubSpot/cms-react/tree/main/examples/graphql-storybook/gql-storybook-project/gql-storybook-app) example project for usage of `moduleStory()`. -Storybook is built with client components in mind, so components that cross island boundaries can have unexpected lifecycle behavior when rendered in a story. Because server-only components never make it to the browser, they cannot be hot reloaded and a full re-render is necessary to update the server response. To fully emulate hybrid rendering in Storybook at the cost of hot module reloading, you may use `moduleStoryWithIsland()` in your story in place of `moduleStory()`. - -## Fields Type Generation - -If you are using Typescript in your CMS React project, you can make use of the `--generateFieldsTypes` argument of the dev server. This command will watch for changes to the fields object that is exported from module file and create a `.types.ts` file inside of the directory of the module. You can then import this module directly into your module component and use it in the generic `ModuleProps<T>` type. As an example, if this is your `fields.jsx` file: - -```tsx -// components/modules/MyModule/fields.tsx - -export const fields = ( - <ModuleFields> - <ChoiceField - label="Choice Test" - name="choice" - display="select" - choices={[ - ["choice1", "One"], - ["choice2", "Two"], - ]} - default="choice1" - /> - <NumberField label="Display on each blog post" name="numberField" /> - <FieldGroup name="defaultGroup" label="Default text" locked> - <TextField - label="Text Field One" - name="textFieldOne" - default="Text Field" - /> - <TextField label="Text Field Two" name="textFieldTwo" /> - <NumberField label="Number Field" name="numberField" /> - </FieldGroup> - </ModuleFields> -); -``` - -Running `hs-cms-dev-server [path-to-project] --generateFieldsTypes` will generate a `modules/MyModule/fields.types.ts` file with a default exported type `MyModuleFieldsType`. The above `fields.tsx` will generate this file: - -```ts -// modules/MyModule/fields.types.ts - -// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -// Removing the above comment will disable type generation for this module -// This file was created by @hubspot/cms-dev-server, for more information see https://github.hubspot.com/cms-react/reference/js-modules.html#module-fields -import { type DefaultValues, type ChoiceFieldType, type NumberFieldType, type TextFieldType, type GroupFieldType, type Override } from "@hubspot/cms-components/fields"; -type MyModuleFieldsType = DefaultValues<{ - choice: Required<ChoiceFieldType>; - numberField: NumberFieldType; - defaultGroup: Override<GroupFieldType, { - children: { - textFieldOne: Required<TextFieldType>; - textFieldTwo: TextFieldType; - numberField: NumberFieldType; - }; - }>; -}>; -export default MyModuleFieldsType; -``` - - -Then, you can import and use the type in your component as follows: - -```tsx -// components/modules/MyModule/index.tsx - -import { ModuleProps } from '@hubspot/cms-components'; -import MyModule from './fields.types'; - -export const Component = ({ - fieldValues, - hublParameters = {}, -}: ModuleProps<MyModule>) => { - const number = fieldValues.numberField; - // ^?const number: number | number[] | null | undefined - // Note that can be undefined because no default set - - const choice = fieldValues.choice; - // ^?const choice: string | number | (string | number)[] - - const text = fieldValues.defaultGroup.textFieldOne - // ^?const text: string | null -} -``` - -Note that the generated types file will be overwritten every time there is an update made to the fields object. To disable this behaviour, remove the `THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.` comment at the top of the file. diff --git a/docs/reference/data-fetching.md b/docs/reference/data-fetching.md deleted file mode 100644 index 00564ad..0000000 --- a/docs/reference/data-fetching.md +++ /dev/null @@ -1,189 +0,0 @@ -# Data Fetching - -Getting content and data into your React modules partials can take many forms as the sources are varied and nuanced. - -## Server Side - -### GraphQL - -GraphQL (pro/enterprise) currently exposes the following internal HubSpot data: - -* HubDB -* CRM Objects -* Blog -* *Coming Soon* - Knowlege Base - -Visit https://app.hubspot.com/graphiql/[portal-id] to explore your schema. - -In an ideal world the HubSpot GraphQL integration would be the go to for getting all of your HubSpot content into React components. Currently however, GraphQL only supports what is listed above - refer to the [GraphQL](./js-modules#graphql) documentation. There are some key advantages to using the GraphQL integration with React modules. - -- Co-located Query and Component -- One single Query for needed associations e.g. contact->company -- Tight coupling with prerendering: updates to the query or relevant data will update any pages containing the query - -### hublParameters - -At the template level you can pass information accessed in the HubL context to your React Module. Within your react component you can access this information via `props.hublParameters`. - -```handlebars -{% module "contact_profile" - path="@projects/contact-profile-project/contact-profile-app/components/modules/ContactProfile", - firstName="{{contact.firstname}}", - lastName="{{contact.lastname}}", - email="{{contact.email}}" %} -``` - -And then on the React side: - -```jsx -// contact-profile-project/contact-profile-app/components/modules/ContactProfile/index.jsx -export const Component = (props) => { - return ( - <div> - <span>{props.hublParameters.firstName}</span> - <span>{props.hublParameters.lastName}</span> - <span>{props.hublParameters.email}</span> - </div> - ) -} -``` - -Whether you are passing data via the HubL tags or querying via GraphQL these solutions account only for reading data, not for creating or updating data in your HubSpot portal. React modules and partials today don't offer any new avenues for manipulating your HubSpot Data. - -### hublDataTemplate - -`hublParameters` does not work for cases where modules are added to the page by a marketer via DnD. For this use case there `hublDataTemplate` can be leveraged. See [hublDataTemplate](./js-modules#hublDataTemplate) for more information - -### Server Data Fetching with getServerSideProps - -"Server Data Fetching" (pro/enterprise) allows developers to export a function `getServerSideProps` from their CMS React Module definition. `getServerSideProps` must return an object with a `serverSideProps` property and a `cacheConfig` property which configures caching of the module. In the React component the information returned in `serverSideProps` can be accessed via `props.serverSideProps`. - -#### Dependency Helpers - -In Data Fetching scenarios, you often need to fetch specific data based on various dependencies such as URLs, query parameters, or the HubSpot Contact object. The utility functions `withModuleProps`, `withUrlPath`, `withUrlAndQuery`, and `withContact` help wrap your data-fetching functions and automatically inject relevant dependencies (with TypeScript types). These helpers ensure that your module has the necessary context to fetch and process data effectively. - -##### `withModuleProps` - -**Purpose:** -Wraps a function to provide module properties without any additional dependencies. Access to `fieldValues`, `hublData`, `dataQueryResult` etc is available. - -**Usage:** - -```typescript -import { withModuleProps } from 'path/to/helpers'; - -const fetchData = (props: ModulePropsWithoutSSP) => { - // Your data fetching logic -}; - -export const getServerSideProps = withModuleProps(fetchData); -``` - -##### `withUrlPath` - -**Purpose:** -Wraps a function to provide the module properties along with a URL without query parameters. Everything that was present in `withModuleProps`, plus the page URL without the query parameters. Caching at the module level is partly based on the props and dependencies used in data fetching. Specifying you only need the URL and not the Query can optimize that caching as it will not create new cache records for every query param variation. - -**Usage:** - -```typescript -import { withUrlPath } from 'path/to/helpers'; - -const fetchData = (props: ModulePropsWithoutSSP, { url }: { url: URLWithoutQuery }) => { - // Your data fetching logic -}; - -export const getServerSideProps = withUrlPath(fetchData); -``` - -##### `withUrlAndQuery` - -**Purpose:** -Wraps a function to provide the module properties along with a URL including query parameters. Building on `withUrlPath`, the passed extra dependency will have the query parameters as well. As stated above a new cache record will be created for each permutation the url with query for this module. - -**Usage:** - -```typescript -import { withUrlAndQuery } from 'path/to/helpers'; - -const fetchData = (props: ModulePropsWithoutSSP, { url }: { url: URL }) => { - // Your data fetching logic -}; - -export const getServerSideProps = withUrlAndQuery(fetchData); -``` - -##### `withContact` - -**Purpose:** -Wraps a function to provide the module properties along with a URL (with query parameters) and a contact. This will pass the url, with the query parameters, and the HubSpot Contact object. - -**Usage:** - -```typescript -import { withContact } from 'path/to/helpers'; - -const fetchData = (props: ModulePropsWithoutSSP, { url, contact }: { url: URL; contact: Contact }) => { - // Your data fetching logic -}; - -export const getServerSideProps = withContact(fetchData); -``` - -#### How It Works - -Each of these helper functions wraps your data-fetching function and injects the relevant dependencies based on the type of data you need to fetch. This process ensures that your function has the necessary context and dependencies to operate correctly, streamlining your data-fetching logic and maintaining consistency across your modules. - -For example, when you use `withUrlPath`, the wrapped function will receive a URL without query parameters, making it easy to fetch data based on the path alone. Similarly, `withContact` ensures that your function has access to both the URL, query, and contact information, allowing for more complex data-fetching scenarios. - -#### Caching - -Under the hood, the use of `getServerSideProps` introduces a new architecture which creates a cache between our edge CDN and data center where we render the React Modules. This caching strategy is outside our current [prerendering strategy](https://developers.hubspot.com/docs/cms/developer-reference/cdn/prerendering). This means that other parts of the page beside the module can be statically prerendered and the module itself can always be dynamic or cached by caching rules the developer defines. We have set a default 10 second cache (`Cache-control: max-age=10`) for these Data Fetching modules. - -Cache "keys" are based on the following: - -* Project Build Number -* Module Props - * This includes fieldValues, hublData, dataQueryResult etc.. -* Injected dependency values - * For example if `withUrlPath` is used a unique cache key will be created each time the module is rendered within a page of a new URL path. - -Knowing this, if you hadn't made changes to any data flowing into the module, but still wanted to bust the cache, a new project build would suffice. - -The `caching` property that is returned from `getServerSideProps` currently has one property `cacheControl`. This represents the `Cache-Control` header, and the properties can be any of the standard directives. - -```typescript -import { withModuleProps } from 'path/to/helpers'; - -const fetchData = async (props: ModulePropsWithoutSSP) => { - // Your data fetching logic - const results = await fetch(...).then(response => response.json()) - - return { - serverSideProps: { - results - }, - caching: { - cacheControl: { - maxAge: 60 - } - } - } -}; - -export const getServerSideProps = withModuleProps(fetchData); -``` - -In the above example the module will be cached for 60 seconds, and any request after that will trigger a re-cache. - -In local development the module is rendered on the developers machine, and so no caching is at play. - -## Client Side - -### HubSpot Data - -As was the case without CMS React components, you can make use of public APIs to fetch your HubSpot data from the browser. While these new components don't offer any HubSpot specific tools for data fetching on the client, we think the introduction of [Islands](./islands) will allow for more optimized and ergonomic client side data fetching. Relative to updating your HubSpot data - the recommended path would still be to implement a [Serverless Function](https://developers.hubspot.com/docs/cms/data/serverless-functions) that is responsible for securely making calls to HubSpot APIs. The serverless function would then expose an endpoint to respond to requests to from the client. - -### External Content - -Similar to the client side HubSpot Content scenario there is no real "change" in in terms of what is possible for fetching data on the client. diff --git a/docs/reference/dependencies.md b/docs/reference/dependencies.md deleted file mode 100644 index cde1e9e..0000000 --- a/docs/reference/dependencies.md +++ /dev/null @@ -1,5 +0,0 @@ -# Third-party dependencies - -JS modules and JS partials can depend on public third-party NPM dependencies inside and outside of Islands. Dependency code will only be bundled and sent to the client if it is referenced from an Island. You can specify a package and version in the `dependencies` field of your `package.json` within your asset package that will be used in the project build. Note that the build process runs a `production` installation of dependencies, so `devDependencies` will not be included. - -If you use parts of our API from `@hubspot/cms-components` such as `Island`, you can specify a `dependencies` version to use in your build. If no [semver range](https://github.com/npm/node-semver#versions) is included in the version, a `^` range will be added to ensure future builds pick up patch releases to `@hubspot/cms-components` without breaking changes. diff --git a/docs/reference/islands.md b/docs/reference/islands.md deleted file mode 100644 index 810ebcb..0000000 --- a/docs/reference/islands.md +++ /dev/null @@ -1,70 +0,0 @@ -# Islands - -```js -import Island from '@hubspot/cms-components'; -``` - -To use an interactive React component in a page—any component that responds to user input or has state—you need to wrap it with an `<Island>`. - -- Here’s how you do that: When importing the component, add `?island` to the end of the import specifier -- Render the Island component from `@hubspot/cms-components`, and pass `InteractiveComponent` from the result of the `?island` import as the `module` prop -- Any serializable props (no functions) can be passed to `Island` and will be received by the component passed to module (`InteractiveComponent` will receive `someProp` when it renders both on the server and client) - -```javascript -import { useState } from 'react'; -import Island from '@hubspot/cms-components'; -import InteractiveComponent from '../InteractiveComponent?island'; - -export default function MyPartial() { - let [count, setCount] = useState(0); - - return ( - <div> - <p> - This content outside of `InteractiveComponent` is server-rendered only - </p> - - {/* - This Island wrapper will auto code-split - InteractiveComponent for you, render it on the server, - and set it up to hydrate in the browser. - */} - <Island module={InteractiveComponent} defaultCount={42} /> - </div> - ); -} -``` - -```javascript -import { useState } from 'react'; - -export default function InteractiveComponent({ defaultCount }) { - let [count, setCount] = useState(defaultCount); - - /* - Note, this click handler will only work if - InteractiveComponent was called from inside an <Island>. - Otherwise the static server HTML returned will be a button - that does nothing when you try to click it. - */ - return <button onClick={() => setCount(count + 1)}>Click me!</button>; -} -``` - -## Island props - -Name | Type | Default | Description --- | -- | -- | -- -<span>**clientOnly**</span> | `boolean` | `false` | When set to `true` the Island won’t be rendered on the server. This can be useful for components that rely on logic/libraries that can only run in the browser. -<span>**hydrateOn**</span> | `"load" \| "visible" \| "idle"` | `"load"` | When rendering a page with Islands on the server, the output includes a script to initialize Islands on the client. Hydrating means downloading and initializing the Island component code, so using these different hydration types strategically to defer some of that work can help boost initial page load performance! See [Hydration Types](#hydration-types) below for more information. -<span>**id**</span> | `string` | - | By default we generate a unique ID string for your island such as `island-123456`. But if you wish to provide your own island ID, you can use this prop. -<span>**module**</span> | `React.Component` | - | Please keep in mind that the component passed in as the value of this prop must include the `?island` suffix as a part of the import RUL. Refer to the `InteractiveComponent` example at the top of the docs. -<span>**wrapperTag**</span> | `string `| `"div"` | The string provided must be a valid HTML element tag (e.g. 'span', 'article', 'section', etc). -<span>**wrapperClassName**</span> | `string` | - | This props gets passed through to the wrapping element around the island. Refer to the `wrapperTag` prop for how to customize which HTML element is used as the wrapping element. -<span>**wrapperStyle**</span> | `CSSProperties` | - | The `CSSProperties` provided will be applied inline to the `wrapperTag` of the island. -<span>**Wrapper**</span> | `React.Component` | - | This prop allows you to provide a custom context provider that will wrap the React tree of your island component. This is particularly useful for integrating with [CSS-in-JS libraries](https://github.hubspot.com/cms-react/reference/styling.html#styled-components), such as styled-components, or other context providers that need to encapsulate the component's subtree for applying styles or context values. Please remember that when using the `Wrapper` prop you **must import the component passed with a `?client` suffix** to make sure it can be bundled for the client. - -### [Hydration types](#hydration-types) -The default behavior of the island initialization script is to eagerly hydrate all Islands as soon as possible, i.e., on `load`, but there are other strategies available when hydrating components: -- For islands with the `idle` hydration type we use [requestIdleCallback](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback), allowing the hydration to be deferred. This is good for lower priority components, allowing client resources to be used first on higher priority. -- For Islands with the `visible` hydration type we don’t hydrate until the element is visible on screen by using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). This mode is good for components that aren't visible to the user immediately, e.g., if they are further down a long page. diff --git a/docs/reference/js-modules.md b/docs/reference/js-modules.md deleted file mode 100644 index bac33e1..0000000 --- a/docs/reference/js-modules.md +++ /dev/null @@ -1,305 +0,0 @@ -# JS Modules - -A JS module is just like a [traditional HubL module](https://developers.hubspot.com/docs/cms/building-blocks/modules), in that they have fields, can be edited in the page editor, and can be dragged into Drag and Drop areas, but its HTML is generated by a React component instead of HubL and its fields are generated by JSX instead of JSON. JS Modules must be located in the `components/modules/` subdirectory of the JavaScript project component. JS modules are referenced in HubL like so: - -``` -{% module "todos" - path="@projects/hello-world-project/cms-assets/components/modules/TodoList" -%} -``` - - - -## Directory Structure Requirements - -A JS Module file can live at either of the following paths, using the directory or file name as the module name: - -`/components/modules/ExampleModule/index.js` - -``` -js-package/ -└── components/ - └── modules/ - └── ExampleModule/ - └── index.jsx -``` - -`/components/modules/ExampleModule.jsx` - -``` -js-package/ -└── components/ - └── modules/ - └── ExampleModule.jsx -``` - -Regardless of the path you chose, the file (i.e. either `ExampleModule/index.jsx` or `ExampleModule.jsx`) must contain the following named exports: - -- `Component`: A React component to be rendered. It may contain islands -- `meta`: A JavaScript object, equivalent to the `meta.json` [in CMS modules](https://developers.hubspot.com/docs/cms/building-blocks/modules/configuration#meta-json) -- `fields`: A JSX tree using components from `@hubspot/cms-components/fields` to define [module fields](#module-fields) or a traditional [JavaScript fields object](https://developers.hubspot.com/docs/cms/building-blocks/module-theme-fields) -Note that you may use re-exports, for example: - -``` -// Directory Structure -js-package/ -└── components/ - └── modules/ - └── ExampleModule/ - ├── ExampleModuleFields.jsx - ├── ExampleModuleComponent.jsx - ├── ExampleModuleMeta.js - └── index.js -``` - -```javascript -// index.js -/* - Note: index.js re-exports ExampleModuleFields.jsx, - ExampleModuleMeta.js, and ExampleModuleComponent.jsx as named - exports - */ -export { default as Component } from './ExampleModuleComponent.js; -export { fields } from './ExampleModuleFields.js; -export { meta } from './ExampleModuleMeta.js; -``` - -## Module Fields - -Fields can be expressed as a JSX tree using field components from `@hubspot/cms-components/fields` . These are the same [module fields](https://developers.hubspot.com/docs/cms/building-blocks/modules#fields-json) that a developer has access to today. They also include TypeScript definitions, so developers can benefit from autocomplete and validation when defining fields. [Here](../field-types/) are the TypeDocs of all the exported Field Types. - -You may still express field definitions as an array of JavaScript objects identical to the traditional [JSON structure](https://developers.hubspot.com/docs/cms/building-blocks/module-theme-fields) within a HubL module, exporting in the same way as `fields`. - - -### Building fields with JSX - -As an alternative to JSON, JS module fields are written using JSX. We believe the JSX field syntax is easier to read than JSON fields. It also allows you to dynamically generate fields, share field logic between modules, and create custom abstractions around field definitions. For example, here is a `FullNameField` custom field component that abstracts out a group of 2 or 3 text fields: - -```javascript -import { - ModuleFields, - TextField, - FieldGroup, - BooleanField -} from '@hubspot/cms-components/fields'; - -const FullNameField = ({ includeMiddleName = false }) => ( - <FieldGroup - name="full_name" - label="Full Name" -> - <TextField - name="given_name" - label="Given Name" - default="HubSpot" - required={true} - /> - {includeMiddleName && ( - <TextField - name="middle_name" - label="Middle Name" - default="" - /> - )} - <TextField - name="family_name" - label="Family Name" - default="Developer" - /> - </FieldGroup> -); - - -export const fields = ( - <ModuleFields> - <TextField - name="example_field" - label="Example Text Field" - default="Placeholder text" /> - - <FieldGroup name="group_of_fields" label="Field Group"> - <BooleanField - name="child_boolean_field" - label="Child Boolean Field" - default={true} - /> - <TextField - name="child_text_field" - label="Child Text Field" - default="Child Field" - /> - </FieldGroup> - - - {/Using the custom field component alongside other fields*/} - <FullNameField includeMiddleName={false}> - </ModuleFields> -); -``` - -It's important to note that the root component of the `fields` export is required to be `ModuleFields`. Addtionally we are making use of `FieldGroup` which is a component type that creates a [Field Group](https://developers.hubspot.com/docs/cms/building-blocks/module-theme-fields-overview#field-groups) that includes the nested fields. - -In the `FullNameField` React component for the module fields defined above, props will have the following shape: - -```javascript -{ - example_field: "Placeholder text", - group_of_fields: { - child_boolean_field: true, - child_text_field: "Child Field" - }, - full_name: { - given_name: "HubSpot", - family_name: "Developer", - } -} -``` - -Note that the default was used to fill in the value field once it was passed. This is because module values are passed from the server, so if someone changes the value of a field in the page editor, the new value will be passed to your module. But in our current case where no page-level field value is set, the server passes the default value to your props. - -#### RepeatedFieldGroup - -In addition to `ModuleFields` and `FieldGroup`, another special component type from `@hubspot/cms-components/fields` is `RepeatedFieldGroup`. It creates a repeater and is used like so: - -```javascript -export const fields = ( - <ModuleFields> - <RepeatedFieldGroup - name="default_todos" - label="Default Todos" - occurrence={{ - min: 1, - max: 500, - default: 1, - }} - default={[ - { - text: 'Todo Test 1a', - completed: false - },{ - text: 'Todo Test 2', - completed: true - }, - ]} - > - <TextField - label="Todo title" - name="text" - default="Todo..." - required - /> - <BooleanField label="Todo Completed" name="completed" default={false} /> - </RepeatedFieldGroup> - </ModuleFields> -) - -``` - -### Using Field Values - -Field values are passed as props to the Component export of your module. For example, to use the field structure from the previous example inside of your JS module’s component you can: - -```javascript -export const Component = ({ fieldValues }) => { - return ( - <ul> - <li>{fieldValues.example_field}</li> - <li>{fieldValues.group_of_fields.child_text_field}</li> - </ul> - ); -}; -``` - -## GraphQL - -Like in HubL modules, you can bind a GraphQL data query to a JS module. Adding a named `query` export to a module will provide the query result to render in the component props as `dataQueryResult`. You can import and re-export a `.graphql` query file or a JavaScript expression that evaluates to a GraphQL query (e.g. with [`gql-query-builder`](https://www.npmjs.com/package/gql-query-builder)). The result will be available via a `dataQueryResult` prop in the module component. - -```javascript -// index.js - -import ModuleComponent from './ModuleComponent.js'; -import ModuleFields from './ModuleFields.js'; -import ModuleMeta from './ModuleMeta.js'; -import myQuery from './myQuery.graphql'; - -// This component will receive the query result via `dataQueryResult` -export const Component = ModuleComponent; - -export const meta = ModuleMeta; - -export const fields = ModuleFields; - -export const query = myQuery; -``` - -And accessing the data in `ModuleComponent`: - -```jsx -//ModuleComponent.jsx - -export default function ModuleComponent(props) { - return ( - <div> - <span> - {props.dataQueryResult.data.CRM.contact_collection.items[0].firstname} - </span> - <span> - {props.dataQueryResult.data.CRM.contact_collection.items[0].lastname} - </span> - </div> - ) -} -``` - -The GraphQL HubSpot integration currently supports querying data from HubDB and Custom Objects. To explore your portal's GraphQL data schema and for help with writing queries check out our [GraphiQL implementation](http://app.hubspot.com/l/graphiql) - -Using GraphQL in this way will connect any module and subsequent down stream pages to updates to the query and upstream data. This is has implications for prerendering in that updates to data sources referenced from the query will cause the page to re-prerender. - -## hublDataTemplate - -To automatically attach and pass through HubL context variables to your React modules you can use the `hublDataTemplate` API. - -Export a string via `hublDataTemplate` from your module: -`export const hublDataTemplate = "..."` - -In this string, set the `hublData` variable: -`{% set hublData = "Hello from HubL!" %}` - -Full example: - -``` -export const hublDataTemplate = `{% set hublData = "Hello from HubL!" %}` -``` - -Any valid HubL may go into this template, including HubL [functions/filters](https://developers.hubspot.com/docs/cms/hubl/functions), referencing the fields on your module, etc. - -This will come through on your React module as a top level prop, `hublData`. - -```javascript -import ModuleFields from './ModuleFields.js'; -import ModuleMeta from './ModuleMeta.js'; - -export function Component(props) { - return ( - <div> - <div>My total posts: {props.hublData.totalBlogPostCount}</div> - <a href={props.hublData.blogAllPostsUrl}>View all posts</a> - </div> - ) -} - -export const meta = ModuleMeta; - -export const fields = ModuleFields; - -export const hublDataTemplate = ` - {% set blogId = module.blog_field %} - {% set hublData = { - "totalBlogPostCount": blog_total_post_count(blogId), - "blogAllPostsUrl": blog_all_posts_url(blogId) - } - %} -` -``` - -While developing modules in `cms-dev-server`, prepend `preview` to any `hslocal.net:3000/module/...` routes, e.g. `hslocal.net:3000/preview/module/...`, to have your local hublDataTemplate string resolved. diff --git a/docs/reference/js-partials.md b/docs/reference/js-partials.md deleted file mode 100644 index d104471..0000000 --- a/docs/reference/js-partials.md +++ /dev/null @@ -1,37 +0,0 @@ -# JS Partials - -Similar to [global partials](https://developers.hubspot.com/docs/cms/building-blocks/global-content#global-partials-vs-global-modules), JavaScript partials are “slices” of your page that can be replaced with React. These can be used globally within HubL. Partials must be located in the `components/partials/` subdirectory of the JavaScript project component. For instance, if you have a file `components/partials/Header.jsx`, which default exports a React component, then you can include it in your project HubL like so: - -``` -{% js_partial - path="@projects/project-folder/js-package/components/partials/Header.jsx" - pageTitle="My page" -%} -``` - -Any parameters passed to `js_partial` alongside the `path` will be available within the React component as props. - -## Directory Structure Requirements - -A JS Partial file can live at either of the following paths, using the directory or file name as the partial name: - -`/components/partials/ExamplePartial/index.js` - -``` -js-package/ -└── components/ - └── partials/ - └── ExamplePartial/ - └── index.jsx -``` - -`/components/partials/ExamplePartial.jsx` - -``` -js-package/ -└── components/ - └── partials/ - └── ExamplePartial.jsx -``` - -Regardless of the path you chose, the file (i.e. either `ExamplePartial/index.jsx` or `ExamplePartial.jsx`) must contain a default export of your component. diff --git a/docs/reference/prerendering.md b/docs/reference/prerendering.md deleted file mode 100644 index af07a29..0000000 --- a/docs/reference/prerendering.md +++ /dev/null @@ -1,3 +0,0 @@ -# Prerendering - -JS modules and JS partials will be prerendered by default as part of the overall CMS page logic to prerender providing a faster load time for static content. JS partials that are passed [prerender-incompatible HubL values](https://developers.hubspot.com/docs/cms/developer-reference/cdn/prerendering#incompatible-hubl-variables) will not be prerendered, since the HubL referencing it will disqualify it from prerendering. See the [prerendering documentation](https://developers.hubspot.com/docs/cms/developer-reference/cdn/prerendering) for more information. diff --git a/docs/reference/project-structure.md b/docs/reference/project-structure.md deleted file mode 100644 index 4be701f..0000000 --- a/docs/reference/project-structure.md +++ /dev/null @@ -1,34 +0,0 @@ -# Project Structure - -This is the top-level structure to be used for JS rendering projects: - -``` -project-folder/ -│ -├── js-package/ -│ ├── components/ -│ │ ├── partials/ -│ │ └── modules/ -│ ├── cms-assets.json -│ └── package.json -│ -├── … optionally other project components … -│ -└── hsproject.json -``` - -A `hsproject.json` file must be inside the root of your project folder in order for `hs project upload` to recognize your project. A `cms-assets.json` file must be inside of your JavaScript asset package subfolder so that the project build can recognize and correctly build your JS components. - -CMS React components introduce the “CMS assets” project component alongside private apps, CRM extensions, and serverless functions. To learn more about HubSpot projects, you can check out the [projects beta documentation](https://developers.hubspot.com/docs/platform/build-and-deploy-using-hubspot-projects). - -:::info Note -The linked documentation notes that "Create a project (BETA)" is available for "Sales Hub" and "Service Hub" enterprise. CMS React components are available for all tiers and therefore so is use of the Projects system to support them. -::: - -Building and deploying is straightforward. A project can be uploaded for build and deploy with the `hs project upload` command. The command can be run in the root of a project with no argument or a directory path can be passed i.e. `hs project upload`. - -The command will kick off a build for your project. If you have "auto deploy" configured for the project it will deploy the build if successful. Projects that are not configured for "auto deploy" can be deployed via the command line with `hs project deploy`. More info is available with `hs project --help`. - -Project information is available in the HubSpot app at [app.hubspot.com/l/developer-projects](https://app.hubspot.com/l/developer-projects). Clicking into a project will give you history of project activity with previous builds and deploys. Clicking "View all activity" will given a list of all previous builds and deploys. You can deploy an old build of a project by clicking "View details" of a build from the project activity view. From the project build view you can click "deploy this build" to deploy that specific build into production. - -The examples in this repo have both a "CMS Assets" project component and a "HubL Theme" within them. This illustrates one way a developer might organize code, but a "HubL Theme" and a "CMS Asset Project Component" are currently two decoupled concepts in HubSpot. The top-level configuration in each example is added for convenience to get started, especially the scripts in the `package.json`. diff --git a/docs/reference/secrets.md b/docs/reference/secrets.md deleted file mode 100644 index c601662..0000000 --- a/docs/reference/secrets.md +++ /dev/null @@ -1,41 +0,0 @@ -# Secrets - -CMS React components integrate with the same secrets store used by [HubSpot serverless functions](https://developers.hubspot.com/docs/cms/data/serverless-functions#secrets) to receive sensitive data. - -To start using secrets, store secret values using `hs secrets add` in the HubSpot CLI, then add the names of secrets used by your components to a `secretNames` array in your `cms-assets.json` config. For example: - -```js -// cms-assets.json -{ - "label": "My CMS project", - "secretNames": ["TEST_SECRET"] -} -``` - -To access the secret, `@hubspot/cms-components` exports a `getSecret()` function to return a given secret's value. To prevent accidentally leaking secrets, `getSecret()` can only be called from component code executed on the server and not from the browser (i.e. within an island). If a secret value isn't sensitive and you need to access it in island components, you may call `getSecret()` outside the island and pass the value down via a prop. - -```javascript -import { getSecret } from '@hubspot/cms-components'; -// ... - -// in a React component outside of an island -export function Component(props) { - const mySecretValue = getSecret('TEST_SECRET'); - - return <OtherComponent secret={mySecretValue} >; -}; - -// Note, this code will fail since it is not called from within a component's render function (or from a utiliity function called from the component's render function) -// const SECRET_NO_WORK = getSecret('secrets-dont-work-at-module-top-level'); -``` - -## Secrets in local development - -To make secrets available with local development via `@hubspot/cms-dev-server`, create a `.env` file to define secret values for local use only. Keys in this file need to be prefixed with `HS_` to be recognized by the dev server as secrets, for example: - -``` -// .env -HS_TEST_SECRET=localsecretvalue -``` - -This secret will be accessible locally by `getSecret('TEST_SECRET')`. diff --git a/docs/reference/serverless.md b/docs/reference/serverless.md deleted file mode 100644 index ef25659..0000000 --- a/docs/reference/serverless.md +++ /dev/null @@ -1,33 +0,0 @@ -# HubSpot Serverless Functions with CMS React Modules - -## Introduction - -HubSpot provides two different types of serverless functions: [CMS Serverless Functions](https://developers.hubspot.com/docs/cms/data/serverless-functions/reference) and [Developer Platform Serverless Functions](https://developers.hubspot.com/docs/platform/serverless-functions). While they are similar in many ways, there are some key differences between them. This documentation will help you understand these differences and guide you on how to use them effectively with CMS React Modules. - -## CMS Serverless Functions - -CMS Serverless Functions were specifically designed to work with the HubSpot CMS. They are tightly integrated with the CMS. You deploy them via the CLI to the Design Manager and can edit them locally or in the Design Manager - -### Limitations to CMS Serverless Functions - -- CMS Serverless functions do not allow you to add your own dependencies i.e. 3rd party packages. - -- Because Developer Platform Serverless functions are defined within a "Private App" they inherit the scopes assigned to that Private App. That level of granular control is not available with CMS Serverless Functions. They rely on storing a personal access token in hs secrets which is then referenced in the serverless function. - -## Developer Platform Serverless Functions - -Developer Platform Serverless Functions, on the other hand, are part of the broader HubSpot Developer Platform. They are built on projects, the same system that CMS React is built on. Thus a developer may have a single project with a CMS React component as well as a Private App with a serverless function. - -Please see an example of a CMS React component along side a Developer Platform Serverless functions here [https://github.com/HubSpot/cms-react/examples/serverless](https://github.com/HubSpot/cms-react/tree/main/examples/serverless) - -Looking forward the Developer Platform will offer one system to learn across CRM, CMS, and other parts of Hubspot. Serverless function capabilities can be more easily upgraded overtime by HubSpot due to being tied into the Projects versioning system. Unlocking a better developer experience, security, etc. A unified system for managing secrets. Private apps could also be shared between website and UI Extensions. - -### Limitations with Developer Platform Functions - -- Currently there is no access to logs for Developer Platform Endpoint functions. - -## How to Decide Which To Use - -Ultimately we are going to provide a migration path for CMS Serverless Functions to the Developer Platform Serverless functions. At this current moment the limitation on logging may give a CMS Developer pause for using these functions. It is for that reason that we suggest CMS Developers continue to use the CMS Serverless Functions until such time that logging is fully supported in the Developer Platform Serverless Functions. - -However, if a developer finds the convenience of a single build system, and access to the 3rd party deps outweighs that limitation the upside will be that they will be ahead of the game in terms of any migrations that might be required. diff --git a/docs/reference/static-assets.md b/docs/reference/static-assets.md deleted file mode 100644 index ae65d04..0000000 --- a/docs/reference/static-assets.md +++ /dev/null @@ -1,13 +0,0 @@ -# Static Assets - -Static asset in your modules with common extensions will resolve to public URLs automatically: - -```javascript -import myImage from './myImage.png'; - -export default function MyComponent() { - return <img src={myImage} />; -} -``` - -See [Vite’s static asset documentation](https://vitejs.dev/guide/assets.html) for more information. diff --git a/docs/reference/styling.md b/docs/reference/styling.md deleted file mode 100644 index f32da91..0000000 --- a/docs/reference/styling.md +++ /dev/null @@ -1,137 +0,0 @@ -# Styling - -Refer to the [styling example project](https://github.com/HubSpot/cms-react/tree/main/styling/styling-project/styling-app) for working examples of supported methods of styling your components, including a number of major styling libraries. - -## Tailwind - -You can configure [Tailwind](https://tailwindcss.com/) for your components by doing the following: - -- Add a dependency to `tailwindcss` to your `package.json` -- Add a PostCSS configuration file to your project subcomponent including tailwind as a plugin -- Refer to a Tailwind config in that plugin with any Tailwind-specific configuration -- Import a CSS file in your top level component with the base Tailwind layer directives - -See the `TailwindPartial` component and the relevant configuration in the example for more detail. - -## styled-components - -You can use [`styled-components`](https://styled-components.com) in your project by doing the following: - -- Add a `dependency` on `styled-components` to your `package.json` -- Create a registry component using the styled-components [server side rendering](https://styled-components.com/docs/advanced#server-side-rendering) API along with [`useInlineHeadAsset()`](./cms-components#useinlineheadasset) and wrap the components you intend to style in it. The example includes a `StyledComponentsRegistry.jsx` you can use. -- For each Island usage, you must wrap each subtree in a registry to capture styles when rendering on the server. To make this easier you may use the `Wrapper` prop on the `Island` component to wrap the contents without needing to edit the island components themselves. Note that This prop also lets you configure this once by replacing all instances of `<Island />` with a `<StyledIsland />` that looks something like: - -::: warning Important -when using the `Wrapper` prop **you must import the component passed with a `?client` suffix** to make sure it can be bundled for the client. -::: - -```javascript -import { Island } from '@hubspot/cms-components'; -import StyledComponentsRegistry from './StyledComponentsRegistry?client'; - -export default function StyledIsland(props) { - return <Island {...props} Wrapper={StyledComponentsRegistry} /> -} -``` - -- You can now `import styled from 'styled-components';` and use it to style your components. - -## styled-jsx - -Steps to use `styled-jsx` are: - -- Add a dependency on `styled-jsx` to your `package.json` -- Create a registry component using the [server side rendering](https://github.com/vercel/styled-jsx#server-side-rendering) API and [`useInlineHeadAsset()`](./cms-components#useinlineheadasset). The example includes a `StyledJSXRegistry.jsx` to refer to or use. -- The registry component for `styled-jsx` must also be wrapped on any `Island` usage to prevent hydration mismatches or missing styles on initial load. Note that `styled-jsx`'s implementation depends on `useId()` hooks in a way that can cause mismatches if not properly configured. See the `StyledJSXIsland.jsx` implementation from the example for an easier pattern of replacing all direct `<Island />` usage. -- You can now use `styled-jsx` to style your components, including ``<style jsx>{` /* CSS here */ `}</style>`` patterns. - -## CSS Modules - -You can use [CSS Modules](https://github.com/css-modules/css-modules) within any React components by importing a file ending in .module.css, which will return a CSS module object: - -```css -/example.module.css */ - -.red { - color: red; -} - -/How to have global—non-namespaced—styles in CSS modules */ -:global(html) { - border: 6px solid SteelBlue; -} -``` - -```javascript -import classes from './example.module.css'; - -export default function MyComponent() { - return <div className={classes.red}>red text</div>; -} -``` - -When you important a CSS modules file from inside a React component: - -- A `<style>` tag will automatically be inserted into the page for you when the component is server-rendered OR when it is dynamically rendered on in the browser -- Those styles will automatically be namespaced so they don’t interfere with anything else on the page - -Note, you can also import regular CSS files into your React components. But their selectors will not be automatically namespaced. - -### Dynamic styles based on props - -If you need to dynamically adjust styles based on props, here are some options: - -- If you have some conditional style that is either on or off, then you can have a className that the React component code conditionally renders in your JSX. -- However if you have some dynamic style that is not a toggle but rather a specific color or number that you need to apply to your styles then you can: - - Define CSS custom properties in your CSS or CSS modules code and inject new CSS custom property values via React - - Use React to set inline styles on the specific part of the module HTML needed - -Here’s a hypothetical example of all three of those techniques in action: - -```css -/example2.module.css */ - -.fancy-module-wrapper {} - -.purple-border { - border: 2px solid rebeccapurple; -} - -.second-text { - color: var(--second-text-color, mediumvioletred); -} -``` - -```javascript -import styles from './example2.module.css'; - -export default function FancierComponent(props) { - const { hasPurpleBorder, paddingPx, customSecondTextColor } = props; - - // Example: toggling styles via a prop - const classes = [styles['fancy-module-wrapper']]; - if (hasPurpleBorder) { - classes.push(styles['purple-border']); - } - - // Example: using inline style attribute (with React's style syntax) - const inlineStyles = { padding: paddingPx }; - - // Example: setting a CSS custom property value that's picked up by other CSS - const inlineAndCustomPropertyStyles = { - ...inlineStyles, - '--second-text-color': customSecondTextColor, - }; - - return ( - <div className={classes.join(' ')} style={inlineAndCustomPropertyStyles}> - <p>First text</p> - <p className={styles['second-text']}>Second text</p> - </div> - ); -} -``` - -## Other CSS-in-JS libraries - -Other CSS-in-JS libraries that provide a server side rendering API and don't depend on a Babel plugin can be used within HubSpot projects. The same registry pattern described above can be generalized for other libraries to emit CSS to include as part of the server render. The registry will need to be included as a `Wrapper` on any `<Island />` usage as well if there are styles within the island. diff --git a/docs/reference/testing.md b/docs/reference/testing.md deleted file mode 100644 index b6975b1..0000000 --- a/docs/reference/testing.md +++ /dev/null @@ -1,24 +0,0 @@ -# Testing - -React components are easy to unit test with [Vitest](https://vitest.dev/) and [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/). - -To add tests to your own project, start by adding those packages as dev dependencies, as well as `@vitejs/plugin-react` (for React support) - -For Vitest to work properly with your React components add a vitest.config.js in your package root. - -```javascript -import { defineConfig } from 'vitest/config'; -import react from '@vitejs/plugin-react'; - -export default defineConfig({ - plugins: [react()], -}); -``` - -When writing a test file that uses React Testing Library to render components or referencing any browser-specific APIs, [add this to the top of the file](https://vitest.dev/guide/environment.html#test-environment): - -```javascript -// @vitest-environment jsdom -``` - -This enables React Testing Library’s [`render`](https://testing-library.com/docs/react-testing-library/api/#render) function to work. From 38057b1d934392d685577cc11ce2aaf18ef9f002 Mon Sep 17 00:00:00 2001 From: Jon Miller <jonmiller@hubspot.com> Date: Mon, 21 Apr 2025 15:13:35 -0500 Subject: [PATCH 3/6] refactor readme --- README.md | 75 +++++++++++++++++++++++-------------------------------- 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index fac732e..423ee2f 100644 --- a/README.md +++ b/README.md @@ -1,63 +1,50 @@ # HubSpot CMS React -## Documentation - -Check out an expanded documentation page at <a href="https://developers.hubspot.com/docs/guides/cms/react/overview" target="_blank">https://developers.hubspot.com/docs/guides/cms/react/overview</a> - -## Welcome! - -Thank you for taking the time to learn about HubSpot CMS React. As always our goal is to solve for our customers so we welcome any and all feedback. Chat away in [\#cms-react](https://hubspotdev.slack.com/archives/C04AY1H2204) with other HubSpot developers who are pushing forward with developing with React on the Hubspot CMS. If you do not have access to the developer slack, you can request access [here](https://developers.hubspot.com/slack). - -## Can I use React modules on my CMS account? - -Yes! Working with React modules can be used with all tiers of the CMS, including free. - -## Examples -In this repository is example usage of some of key features of React modules. These examples are are best understood alongside our official <a href="https://developers.hubspot.com/docs/guides/cms/react/overview" target="_blank">docs</a>. You can quickly try things out without any local setup by [opening this repo in Codesandbox.io](https://codesandbox.io/p/sandbox/stoic-pateu-g20chg?file=%2Fcms-react%2FREADME.md). +A collection of CMS React examples for building on the HubSpot CMS. +## Table of Contents -### [Getting Started](examples/getting-started) +- [Overview](#overview) +- [Documentation](#documentation) +- [Examples](#examples) +- [Contributing](#contributing) +- [Support](#support) -The "Getting Started" example is the most up to date example of CMS React basics. It illustrates the definition and development of Modules with React, uses 3rd party dependencies, islands, and CSS Modules. +--- -### [Hello World](examples/hello-world) +## Overview -**NOTE:** this is an older example, and [Getting Started](getting-started) is a better first example +This repo demonstrates how to build React modules and "islands" for the HubSpot CMS. You'll find step-by-step examples, best practices, and customizable boilerplates to get you up and running quickly. -The "Hello World" example combines partials, modules, islands and CSS modules for styling to show a more cohesive yet straightforward example of how CMS React components and APIs work together. - -### [Styling](examples/styling) - -In this example, we take a look at three different approaches to styling React components. This is not an exhaustive list and there are many ways that styles can be organized and implemented. - -### [Islands](examples/islands) - -Islands are a key concept for React modules in HubSpot. In addition to stitching server-rendered React components into the HTML generated by HubL, JS modules and partials support client-side interactivity with islands. Similar to the islands concept from [Astro](https://astro.build/), [Fresh](https://fresh.deno.dev/), and others, you can add an `<Island />` inside your JS module or partial to automatically code-split and render a component on both the server and client. In addition to allowing you to reuse JavaScript code between the server and browser, islands help you write performant websites by giving you precise control over what JavaScript is shipped to the browser and when it runs. - -### [Graphql + Storybook](examples/graphql-storybook) +## Documentation -GraphQL is the future for querying HubSpot data in your CMS pages. As part of JS Modules, a developer can export a GraphQL query string and the Module's root component will then be passed the query result. Additionally we show how a Module that uses GraphQL can be developed using our Storybook integration. This integration will automatically understand the field types of a module and generate controls for a Storybook story. +- Official HubSpot CMS React guide: + https://developers.hubspot.com/docs/guides/cms/react/overview -### [Todo MVC](examples/todo-mvc) +## Examples +Each folder under `examples/` is a standalone example focused on a specific use case or feature. If you are just getting started with CMS React, the following examples are the best places to start: -It seems with every new FE technology on the web comes an implemetation of TodoMVC. We didn't want to be left out and ported a recent version that made use of React and React hooks to work as a JS Module with Islands. Additionally there is an example of our `sharedIslandReducer` which provides a redux like interface for sharing state across islands. +- **[getting-started-project-theme](examples/getting-started-project-theme)** + Building a CMS theme with React and Projects +- **[getting-started](examples/getting-started)** + Building a standalone Project with React modules that can be used across CMS themes +--- -### [Default React modules](default-react-modules) +## Contributing -This directory contains a copy of all of our internal default React modules. As React modules do not appear in the Design manager, we made them available within this public repository so you can make your own copy and edit as you like. The modules you find in this directory are synced up with our internal code to ensure we keep them up to date. +We welcome bug reports and PRs to update or add new examples: -#### What if I don't see a default React module in this repo but that is available for use within Hubspot? -Some default React modules contain code that is internal to Hubspot and thus cannot be used in a general way by external developers. If you are are seeking to utilize one of these modules, or otherwise get a better sense of how it works, please reach out to a developer advocate for more information. +1. Fork this repo +2. Create a feature branch (`git checkout -b my-new-example`) +3. Commit your changes (`git commit -m "Add amazing example"`) +4. Open a PR -### [React module boilerplate](react-module-boilerplate) +--- -If you'd like to get started with your own React module or one of our defaults, we have provided a boilerplate project for you to pick up and get started right away. This boilerplate comes complete with a Sample module so you can test working with this repo with only a few steps on your part. In order to get working with this boilerplate you simply have to: +## Support -- Become familiar with working with our CLI, if you are not already, with our [Hubspot CLI documentation](https://developers.hubspot.com/docs/cms/guides/getting-started) -- Run `hs init` and select your portal. -- Within the react-module-boilerplate/src run `yarn deploy` or `npm deploy`, which is a helper script we offer which runs the `hs project upload` CLI command. -- You will be prompted to create this project in your portal. Confirm and the project will be created. -- Wait a few moments for the deploy to finish. You can view the projects within your portal at `https://app.hubspot.com/developer-projects/{YOUR_PORTAL_ID}` +Chat with the community on Slack: +https://hubspotdev.slack.com/archives/C04AY1H2204 -Once the module is uploaded you should be able to see it when you go to edit a page, adding it like any other modules. +--- From 0eaf4534fe8031c0330e7178f27dda1caa6e7e70 Mon Sep 17 00:00:00 2001 From: Jon Miller <jonmiller@hubspot.com> Date: Mon, 21 Apr 2025 15:16:29 -0500 Subject: [PATCH 4/6] add npx script reference --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 423ee2f..100392b 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ Each folder under `examples/` is a standalone example focused on a specific use - **[getting-started](examples/getting-started)** Building a standalone Project with React modules that can be used across CMS themes +If you want to bootstrap a new Project with CMS React you can run `npx @hubspot/create-cms-theme@latest` which will create a Project starting point for you to build upon. [Learn More](https://www.npmjs.com/package/@hubspot/create-cms-theme) + --- ## Contributing From 9996068c2441d9c1e7c448020f74fbc9338ec22a Mon Sep 17 00:00:00 2001 From: Jon Miller <jonmiller@hubspot.com> Date: Mon, 21 Apr 2025 15:25:11 -0500 Subject: [PATCH 5/6] update nav items --- docs/.vitepress/config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts index 782610e..bc3589f 100644 --- a/docs/.vitepress/config.ts +++ b/docs/.vitepress/config.ts @@ -1,5 +1,4 @@ import { defineConfig } from 'vitepress'; -import fieldTypesSidebar from '../field-types/typedoc-sidebar.json'; // https://vitepress.dev/reference/site-config export default defineConfig({ @@ -9,6 +8,8 @@ export default defineConfig({ themeConfig: { // https://vitepress.dev/reference/default-theme-config nav: [ + { text: 'Official Docs', link: 'https://developers.hubspot.com/docs/guides/cms/react/overview' }, + { text: 'Examples', link: 'https://github.com/HubSpot/cms-react/tree/main/examples' }, { text: 'Release Log', link: 'release-log' }, ], }, From 4c185d63e7877f2b813f3c975c8a4c653bbe7e9c Mon Sep 17 00:00:00 2001 From: Jon Miller <jonmiller@hubspot.com> Date: Mon, 21 Apr 2025 16:02:53 -0500 Subject: [PATCH 6/6] update slack community link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 100392b..0fae4ba 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,6 @@ We welcome bug reports and PRs to update or add new examples: ## Support Chat with the community on Slack: -https://hubspotdev.slack.com/archives/C04AY1H2204 +https://developers.hubspot.com/docs/getting-started/slack/developer-slack ---