Skip to content

Commit 92a7b9f

Browse files
committed
Initial commit
0 parents  commit 92a7b9f

15 files changed

+3059
-0
lines changed

.eslintignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
node_modules
2+
**/.next/**
3+
**/_next/**
4+
next-env.d.ts
5+
next.config.js

.eslintrc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": ["next", "next/core-web-vitals", "prettier"]
3+
}

.gitignore

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
node_modules
2+
lib
3+
examples
4+
build
5+
test
6+
src/**.js
7+
*.log

.husky/post-commit

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
. "$(dirname "$0")/_/husky.sh"
3+
4+
npm run post-commit

.husky/pre-commit

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/bin/sh
2+
. "$(dirname "$0")/_/husky.sh"
3+
4+
npm run pre-commit

.prettierrc

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"printWidth": 100,
3+
"semi": true,
4+
"trailingComma": "all"
5+
}

LICENSE

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
MIT License
2+
3+
Copyright (c) 2022 Roman Zhuravlov
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Hubspot Forms for Next.js
2+
3+
[![npm (scoped)](https://img.shields.io/npm/v/next-hubspot?style=flat-square)](https://www.npmjs.com/package/next-hubspot)
4+
[![Bundle Size](https://img.shields.io/bundlephobia/min/next-hubspot?style=flat-square)](https://bundlephobia.com/result?p=next-hubspot)
5+
![License](https://img.shields.io/npm/l/next-hubspot?style=flat-square)
6+
7+
Embed HubSpot forms into your Next.js application using hooks.
8+
9+
## Install
10+
11+
```
12+
$ npm install --save next-hubspot
13+
```
14+
15+
```
16+
$ yarn add next-hubspot
17+
```
18+
19+
## Getting Started
20+
21+
Wrap your application with `HubspotProvider`. This will add [Hubspot script](https://js.hsforms.net/forms/v2.js) to your document.
22+
23+
```TSX
24+
import { HubspotProvider } from 'next-hubspot';
25+
26+
const MyApp = ({ Component, pageProps }) => (
27+
<HubspotProvider>
28+
<Component {...pageProps} />
29+
</HubspotProvider>
30+
)
31+
32+
```
33+
34+
## Usage
35+
36+
```TSX
37+
import { useHubspotForm } from 'next-hubspot';
38+
39+
const HubspotForm = () => {
40+
const { loaded, error, formCreated } = useHubspotForm({
41+
portalId: 'XXXXXXX',
42+
formId: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
43+
target: 'husbpot-form-wrapper'
44+
});
45+
46+
return (
47+
<div id="husbpot-form-wrapper" />
48+
)
49+
}
50+
51+
```

package.json

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"name": "next-hubspot",
3+
"version": "0.0.1",
4+
"description": "Hubspot forms in Next.js with no headache",
5+
"repository": "https://github.com/snelsi/next-hubspot",
6+
"license": "MIT",
7+
"keywords": [
8+
"hubspot",
9+
"next",
10+
"next.js",
11+
"react",
12+
"form",
13+
"hook"
14+
],
15+
"main": "./lib/cjs/index.js",
16+
"module": "./lib/esm/index.js",
17+
"types": "./lib/esm/index.d.ts",
18+
"files": [
19+
"/lib"
20+
],
21+
"scripts": {
22+
"build": "yarn build:esm && yarn build:cjs",
23+
"build:esm": "tsc",
24+
"build:cjs": "tsc --module commonjs --outDir lib/cjs",
25+
"prettier": "prettier --write .",
26+
"lint": "eslint",
27+
"lint-fix": "eslint --fix",
28+
"fix": "npm run prettier && npm run lint-fix",
29+
"pre-commit": "npm run lint && lint-staged",
30+
"post-commit": "git update-index --again"
31+
},
32+
"peerDependencies": {
33+
"react": ">=16.8.0",
34+
"react-dom": ">=16.8.0",
35+
"next": ">=11.0.0"
36+
},
37+
"engines": {
38+
"node": ">=12.22.0"
39+
},
40+
"dependencies": {
41+
"react": "^18.0.0",
42+
"react-dom": "^18.0.0",
43+
"next": "^12.1.5"
44+
},
45+
"devDependencies": {
46+
"@types/react": "^18.0.6",
47+
"@types/react-dom": "^18.0.2",
48+
"@typescript-eslint/eslint-plugin": "^5.20.0",
49+
"@typescript-eslint/parser": "^5.20.0",
50+
"eslint": "^8.14.0",
51+
"eslint-config-next": "^12.1.5",
52+
"eslint-config-prettier": "^8.5.0",
53+
"husky": "^7.0.4",
54+
"lint-staged": "^12.4.0",
55+
"prettier": "^2.6.2",
56+
"pretty-quick": "^3.1.3",
57+
"typescript": "^4.6.3"
58+
},
59+
"lint-staged": {
60+
"**/*.{js,jsx,ts,tsx}": [
61+
"pretty-quick --staged"
62+
]
63+
}
64+
}

src/HubspotProvider.tsx

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import React, {
2+
createContext,
3+
useContext,
4+
useCallback,
5+
useEffect,
6+
useMemo,
7+
useState,
8+
useDebugValue,
9+
} from "react";
10+
import Script, { ScriptProps } from "next/script";
11+
12+
interface HubspotContextProps {
13+
/** Is Hubspot script loaded */
14+
readonly loaded: boolean;
15+
/** Is Hubspot failed to load */
16+
readonly error: boolean;
17+
}
18+
19+
const HubspotContext = createContext<HubspotContextProps>({
20+
loaded: false,
21+
error: false,
22+
});
23+
24+
const useHubspotContext = () => {
25+
const values = useContext(HubspotContext);
26+
useDebugValue(`Hubspot Script: ${values?.loaded ? "Loaded" : "Not Loaded"}`);
27+
useDebugValue(`Failed to load Script: ${values?.error ? "Yes" : "No"}`);
28+
return values;
29+
};
30+
31+
interface HubspotProviderProps extends Partial<ScriptProps> {
32+
children?: React.ReactNode;
33+
}
34+
35+
/** Loads Hubspot script to the document and syncs loading state between forms on the page */
36+
const HubspotProvider: React.FC<HubspotProviderProps> = ({
37+
children,
38+
src = "https://js.hsforms.net/forms/v2.js",
39+
strategy = "afterInteractive",
40+
onLoad: passedOnLoad,
41+
onError: passedOnError,
42+
...props
43+
}) => {
44+
const [loaded, setLoaded] = useState(false);
45+
const [error, setError] = useState(false);
46+
47+
// Reset state when script src is changed
48+
useEffect(() => {
49+
setLoaded(false);
50+
setError(false);
51+
}, [src]);
52+
53+
// Handle script load
54+
const onLoad = useCallback(
55+
(e: any) => {
56+
setLoaded(true);
57+
passedOnLoad?.(e);
58+
},
59+
[passedOnLoad],
60+
);
61+
62+
// Handle script error
63+
const onError = useCallback(
64+
(e: any) => {
65+
setError(true);
66+
passedOnError?.(e);
67+
},
68+
[passedOnError],
69+
);
70+
71+
// Prevent unnecessary rerenders
72+
const value = useMemo(() => ({ loaded, error }), [loaded, error]);
73+
74+
return (
75+
<HubspotContext.Provider value={value}>
76+
{children}
77+
<Script src={src} strategy={strategy} onLoad={onLoad} onError={onError} {...props} />
78+
</HubspotContext.Provider>
79+
);
80+
};
81+
82+
export { HubspotContext, useHubspotContext, HubspotProvider };
83+
export type { HubspotContextProps, HubspotProviderProps };

0 commit comments

Comments
 (0)