Skip to content

Commit

Permalink
feat(NOJIRA-123): Initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
mathio committed Nov 19, 2023
1 parent 92dd907 commit 8c94cc7
Show file tree
Hide file tree
Showing 37 changed files with 7,560 additions and 0 deletions.
13 changes: 13 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# EditorConfig is awesome: http://EditorConfig.org

# top-most EditorConfig file
root = true

[*]
max_line_length=120
end_of_line=lf
charset=utf-8
trim_trailing_whitespace=true
insert_final_newline=true
indent_style=space
indent_size=2
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
dist/
3 changes: 3 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: ['@typeform/eslint-config', 'prettier', 'plugin:prettier/recommended'],
}
59 changes: 59 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# OSX and ide's folder attributes
.DS_Store
Thumbs.db
.cache
.project
.settings
.tmproj
*.esproj
nbproject
*.sublime-project
*.sublime-workspace
*.sublime-*
jsconfig.json
.vscode
.idea
.env

# common node files and folders
# https://github.com/github/gitignore/blob/master/Node.gitignore
lib-cov
*.seed
*.log
*.csv
*.dat
*.out
*.pid
*.gz

pids
logs
results

build/Release # Compiled binary addons (http://nodejs.org/api/addons.html)

# always-ignore extensions
*.diff
*.err
*.orig
*.rej
*.swo
*.swp
*.vi
*~
*.sass-cache

# project specific
.next
node_modules
build
build-aws
types
dist

# tests
**/e2e/screenshots
**/cypress/screenshots
**/cypress/videos
**/cypress/fixtures
packages/embed/vrt.json
7 changes: 7 additions & 0 deletions .huskyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"hooks": {
"pre-commit": "yarn lint && yarn build",
"pre-push": "yarn test",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# override registry since this is a public repo
@typeform:registry=https://registry.yarnpkg.com
7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"printWidth": 120
}
112 changes: 112 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,115 @@

Integrate Typeform Admin UI in your web app - as an iframe or a popup.

## Usage

As HTML button:

```html
<button data-tf-embed-admin data-tf-embed-admin-callback="handleSelect">select typeform</button>
<script src="dist/button.js"></script>
<script>
// you still need to implement the callback in JavaScript
function handleSelect(action, formId) {
console.log(`you have selected form with id ${formId}`)
}
</script>
```

Or using JavaScript:

```html
<button onclick="selectTypeform()">select form</button>
<script src="dist/button.js"></script>
<script>
const callback = (action, formId) => {
console.log(`you have selected form with id ${formId}`)
}
const selectTypeform = () => {
window.tfEmbedAdmin.open({ callback, type: 'iframe' })
}
</script>
```

## Options

| name | type | description | default value |
| -------- | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
| type | `"iframe" \| "popup"` | Open embed admin in popup (default) or iframe. **Note:** If you want to implement iframe, please [contant us to get your domain whitelisted](https://www.typeform.com/help/contact/360000510012/). | `"popup"` |
| action | `"select" \| "edit"` | Action to perform. If you want to "edit" you also need to pass form ID as `payload` | `"select"` |
| payload | string | Form ID, required for "edit" action. | `undefined` |
| appName | string | Application name | `window.location.hostname` |
| callback | (action: string, formId: string) => void | Method to be called when a form is selected or edited in Typeform Admin UI. | `undefined` |

You can pass options as object to the `open` method:

```javascript
window.tfEmbedAdmin.open({
type: 'iframe',
action: 'edit',
payload: myTypeformId,
appName: 'my-app',
callback: (action, id) => console.log(`action: ${action}, form id: ${id}`),
})
```

Or you can pass them as attributes to the HTML button with `data-tf-embed-admin-*` prefix:

```html
<button
data-tf-embed-admin
data-tf-embed-admin-type="iframe"
data-tf-embed-admin-action="edit"
data-tf-embed-admin-payload="123456"
data-tf-embed-admin-app-name="my-app"
data-tf-embed-admin-callback="embedAdminCallback"
>
edit typeform
</button>
<script>
function embedAdminCallback() {
// callback fucntion needs to be available on global scope (window)
}
</script>
```

## Demo

Run:

```shell
yarn start
```

Demo implementation of the library will be served at http://localhost:9090

Or [open the demo in CodeSandbox](https://codesandbox.io/s/github/Typeform/button), directly in your browser.

## Development

Requiremenets:

- node >= 18
- yarn

Install dependencies:

```shell
yarn
```

For local development run:

```shell
yarn watch
```

or with demo:

```shell
yarn start
```

## Helo and Contribution

Feel free to [open a Github Issue with your question](https://github.com/Typeform/button/issues) or [submit a pull request](https://github.com/Typeform/button/pulls).
14 changes: 14 additions & 0 deletions commitlint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'scope-empty': [1, 'never'],
'scope-case': [2, 'always', 'uppercase'],
'subject-case': [2, 'always', 'sentencecase'],
},
parserPreset: {
parserOpts: {
headerPattern: /^([a-z]+)(\(\w{2,}-\d{1,}\))?: (\S+)/,
headerCorrespondence: ['type', 'scope', 'subject'],
},
},
}
113 changes: 113 additions & 0 deletions demo/embed.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Typeform Button Demo</title>
<style>
* {
margin: 0;
padding: 0;
}
body {
padding: 20px;
}
h1 {
margin: 10px 0 20px 0;
}
button {
padding: 5px 10px;
cursor: pointer;
}
ul#typeforms {
list-style: none;
display: flex;
flex-direction: row;
}
ul#typeforms li {
width: 300px;
margin: 0 20px 20px 0;
}
ul#typeforms li img {
max-width: 300px;
}
</style>
</head>
<body>
<h1>Typeform Button Demo - with Embed SDK</h1>

<!-- embed SDK -->
<link rel="stylesheet" href="//embed.typeform.com/next/css/popup.css" />
<script src="//embed.typeform.com/next/embed.js"></script>

<!-- typeform button -->
<script src="dist/button.js"></script>

<!-- custom script -->
<script>
const fetchTypeformDetails = async (formId) => {
const result = await fetch(
`https://form.typeform.com/oembed?url=${encodeURIComponent(`https://form.typeform.com/to/${formId}`)}`
)
if (!result.ok) {
return {}
}
const data = await result.json()
const { title, author_url: url, thumbnail_url: image } = data || {}
return { title, url, image: image?.href ?? image }
}
const onSelect = async (action, formId) => {
console.log('selected form:', formId)

const { title, image } = await fetchTypeformDetails(formId)

const container = document.createElement('li')

const heading = document.createElement('h2')
heading.innerText = title
container.append(heading)

const thumbnail = document.createElement('img')
thumbnail.src = image
container.append(thumbnail)

const viewButton = document.createElement('button')
viewButton.onclick = () => {
window.tf.createPopup(formId).open()
}
viewButton.innerText = 'View'
container.append(viewButton)

const editButton = document.createElement('button')
editButton.onclick = () => editTypeform(formId)
editButton.innerText = 'Edit'
container.append(editButton)

const removeButton = document.createElement('button')
removeButton.onclick = () => {
if (window.confirm('Do you want to remove this typeform from the list?')) {
container.remove()
}
}
removeButton.innerText = 'Remove'
container.append(removeButton)

document.querySelector('#typeforms').append(container)
}
const onEdit = (action, formId) => {}
const selectTypeform = () => {
window.tfEmbedAdmin.open({ callback: onSelect, type: 'iframe' })
}
const editTypeform = (payload) => {
window.tfEmbedAdmin.open({
callback: onEdit,
type: 'iframe',
action: 'edit',
payload,
})
}
</script>
<button onclick="selectTypeform()">select form</button>
<ul id="typeforms"></ul>
</body>
</html>
27 changes: 27 additions & 0 deletions demo/iframe-html.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Typeform Button Demo</title>
</head>
<body>
<h1>Typeform Button Demo - Iframe HTML</h1>
<button data-tf-embed-admin data-tf-embed-admin-type="iframe" data-tf-embed-admin-callback="handleSelect">
select typeform
</button>
<ul id="typeforms"></ul>
<script src="dist/button.js"></script>
<script>
function handleEdit(action, formId) {
console.log(`form ${formId} was edited`)
}
function handleSelect(action, formId) {
console.log(action, formId)
const editButton = `<button data-tf-embed-admin data-tf-embed-admin-type="iframe" data-tf-embed-admin-action="edit" data-tf-embed-admin-payload="${formId}" data-tf-embed-admin-callback="handleEdit">edit</button>`
document.querySelector('#typeforms').innerHTML += `<li>${formId} ${editButton}</li>`
window.tfEmbedAdmin.reload()
}
</script>
</body>
</html>
Loading

0 comments on commit 8c94cc7

Please sign in to comment.