From 28b6410dbb7a127c1f4454db68933c4a35e6db61 Mon Sep 17 00:00:00 2001 From: Matti Nannt Date: Tue, 18 Oct 2022 12:24:17 +0200 Subject: [PATCH] Feature/add react lib to monorepo #107 (#115) * add changesets * add react-app to monorepo --- .changeset/README.md | 8 + .changeset/config.json | 11 + .changeset/twelve-carpets-eat.md | 5 + .env.docker | 17 + .env.example | 3 + .github/workflows/release.yml | 40 + README.md | 5 + apps/web/package.json | 15 +- package.json | 4 +- packages/database/package.json | 1 + packages/eslint-config-custom/package.json | 3 +- packages/prettier-config/package.json | 2 +- packages/snoopforms-react/.gitignore | 7 + packages/snoopforms-react/LICENSE | 21 + packages/snoopforms-react/README.md | 63 + packages/snoopforms-react/package.json | 89 + packages/snoopforms-react/postcss.config.js | 7 + .../src/components/Elements/Cards.tsx | 126 + .../src/components/Elements/Checkbox.tsx | 105 + .../src/components/Elements/Email.tsx | 76 + .../src/components/Elements/Number.tsx | 70 + .../src/components/Elements/Phone.tsx | 71 + .../src/components/Elements/Radio.tsx | 82 + .../src/components/Elements/Submit.tsx | 22 + .../src/components/Elements/Text.tsx | 71 + .../src/components/Elements/Textarea.tsx | 64 + .../src/components/Elements/Website.tsx | 76 + .../SnoopElement/SnoopElement.stories.tsx | 34 + .../components/SnoopElement/SnoopElement.tsx | 188 + .../src/components/SnoopForm/SnoopForm.tsx | 138 + .../src/components/SnoopPage/SnoopPage.tsx | 100 + packages/snoopforms-react/src/index.ts | 3 + packages/snoopforms-react/src/lib/elements.ts | 40 + packages/snoopforms-react/src/lib/utils.ts | 3 + packages/snoopforms-react/src/styles.css | 3 + packages/snoopforms-react/src/types.ts | 14 + packages/snoopforms-react/tailwind.config.js | 7 + packages/snoopforms-react/tsconfig.json | 5 + packages/tailwind-config/package.json | 2 +- packages/tsconfig/nextjs.json | 2 +- packages/tsconfig/package.json | 2 +- packages/tsconfig/react-library.json | 4 +- packages/ui/package.json | 3 +- pnpm-lock.yaml | 10582 +++++++++++++++- 44 files changed, 12014 insertions(+), 180 deletions(-) create mode 100644 .changeset/README.md create mode 100644 .changeset/config.json create mode 100644 .changeset/twelve-carpets-eat.md create mode 100644 .github/workflows/release.yml create mode 100644 packages/snoopforms-react/.gitignore create mode 100644 packages/snoopforms-react/LICENSE create mode 100644 packages/snoopforms-react/README.md create mode 100644 packages/snoopforms-react/package.json create mode 100644 packages/snoopforms-react/postcss.config.js create mode 100644 packages/snoopforms-react/src/components/Elements/Cards.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Checkbox.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Email.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Number.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Phone.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Radio.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Submit.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Text.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Textarea.tsx create mode 100644 packages/snoopforms-react/src/components/Elements/Website.tsx create mode 100644 packages/snoopforms-react/src/components/SnoopElement/SnoopElement.stories.tsx create mode 100644 packages/snoopforms-react/src/components/SnoopElement/SnoopElement.tsx create mode 100644 packages/snoopforms-react/src/components/SnoopForm/SnoopForm.tsx create mode 100644 packages/snoopforms-react/src/components/SnoopPage/SnoopPage.tsx create mode 100644 packages/snoopforms-react/src/index.ts create mode 100644 packages/snoopforms-react/src/lib/elements.ts create mode 100644 packages/snoopforms-react/src/lib/utils.ts create mode 100644 packages/snoopforms-react/src/styles.css create mode 100644 packages/snoopforms-react/src/types.ts create mode 100644 packages/snoopforms-react/tailwind.config.js create mode 100644 packages/snoopforms-react/tsconfig.json diff --git a/.changeset/README.md b/.changeset/README.md new file mode 100644 index 0000000000..e5b6d8d6a6 --- /dev/null +++ b/.changeset/README.md @@ -0,0 +1,8 @@ +# Changesets + +Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works +with multi-package repos, or single-package repos to help you version and publish your code. You can +find the full documentation for it [in our repository](https://github.com/changesets/changesets) + +We have a quick list of common questions to get you started engaging with this project in +[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) diff --git a/.changeset/config.json b/.changeset/config.json new file mode 100644 index 0000000000..7fcf97338c --- /dev/null +++ b/.changeset/config.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://unpkg.com/@changesets/config@2.2.0/schema.json", + "changelog": "@changesets/cli/changelog", + "commit": false, + "fixed": [], + "linked": [], + "access": "restricted", + "baseBranch": "main", + "updateInternalDependencies": "patch", + "ignore": [] +} diff --git a/.changeset/twelve-carpets-eat.md b/.changeset/twelve-carpets-eat.md new file mode 100644 index 0000000000..0495834c3c --- /dev/null +++ b/.changeset/twelve-carpets-eat.md @@ -0,0 +1,5 @@ +--- +"@snoopforms/react": patch +--- + +Move react library to monorepo diff --git a/.env.docker b/.env.docker index 7e3ac78687..4f0838e366 100644 --- a/.env.docker +++ b/.env.docker @@ -11,9 +11,12 @@ NEXTAUTH_SECRET=RANDOM_STRING NEXTAUTH_URL=http://localhost:3000 +<<<<<<< HEAD # This should always be localhost:3000 (or whatever port your app is running on) NEXTAUTH_URL_INTERNAL=http://localhost:3000 +======= +>>>>>>> 7ab8b81 (add basic react package) DATABASE_URL='postgresql://postgres:postgres@postgres:5432/snoopforms?schema=public' ################ @@ -42,6 +45,7 @@ DATABASE_URL='postgresql://postgres:postgres@postgres:5432/snoopforms?schema=pub ##################### # Email Verification. If you enable Email Verification you have to setup SMTP-Settings, too. +<<<<<<< HEAD NEXT_PUBLIC_EMAIL_VERIFICATION_DISABLED=1 # Password Reset. If you enable Password Reset functionality you have to setup SMTP-Settings, too. @@ -49,15 +53,28 @@ NEXT_PUBLIC_PASSWORD_RESET_DISABLED=1 # Signup. Disable the ability for new users to create an account. # NEXT_PUBLIC_SIGNUP_DISABLED=1 +======= +EMAIL_VERIFICATION_DISABLED=1 + +# Password Reset. If you enable Password Reset functionality you have to setup SMTP-Settings, too. +PASSWORD_RESET_DISABLED=1 +>>>>>>> 7ab8b81 (add basic react package) ####################### # Additional Options # ####################### +<<<<<<< HEAD # NEXT_PUBLIC_TERMS_URL=https://www.example.com/terms # NEXT_PUBLIC_PRIVACY_URL=https://www.example.com/privacy # NEXT_PUBLIC_IMPRINT_URL=https://www.example.com/imprint # NEXT_PUBLIC_PRIVACY_URL=https://www.example.com/enduserPrivacy +======= +# TERMS_URL=https://www.example.com/terms +# PRIVACY_URL=https://www.example.com/privacy +# PUBLIC_IMPRINT_URL=https://www.example.com/imprint +# PUBLIC_PRIVACY_URL=https://www.example.com/enduserPrivacy +>>>>>>> 7ab8b81 (add basic react package) ###################### # Posthog Tracking # diff --git a/.env.example b/.env.example index 524066b646..d393f3f25e 100644 --- a/.env.example +++ b/.env.example @@ -12,9 +12,12 @@ NEXTAUTH_SECRET=RANDOM_STRING # Set this to your public-facing URL, e.g., https://example.com NEXTAUTH_URL=http://localhost:3000 +<<<<<<< HEAD # This should always be localhost:3000 (or whatever port your app is running on) NEXTAUTH_URL_INTERNAL=http://localhost:3000 +======= +>>>>>>> 7ab8b81 (add basic react package) DATABASE_URL='postgresql://postgres:postgres@localhost:5432/snoopforms?schema=public' # For Docker Compose Production Setup use this Database URL: # DATABASE_URL='postgresql://postgres:postgres@postgres:5432/snoopforms?schema=public' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..1555c3c63a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,40 @@ +name: Release + +on: + push: + branches: + - main + +concurrency: ${{ github.workflow }}-${{ github.ref }} + +jobs: + release: + name: Release + runs-on: ubuntu-latest + env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: ${{ secrets.TURBO_TEAM }} + steps: + - name: Checkout Repo + uses: actions/checkout@v2 + + - name: Setup Node.js 16.x + uses: actions/setup-node@v2 + with: + node-version: 16.x + + - name: Install pnpm + uses: pnpm/action-setup@v2.2.2 + + - name: Install Dependencies + run: pnpm install + + - name: Create Release Pull Request or Publish to npm + id: changesets + uses: changesets/action@v1 + with: + # This expects you to have a script called release which does a build for your packages and calls changeset publish + publish: pnpm release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/README.md b/README.md index b1e71fe76b..a03304b83b 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,12 @@ git clone https://github.com/formbricks/snoopforms.git && cd snoopforms ``` +<<<<<<< HEAD Create a `.env` file based on `.env.docker` and change all fields according to your setup. This file comes with a basic setup and snoopForms works without making any changes to the file. To enable email sending functionality you need to configure the SMTP settings in the `.env` file. If you configured your email credentials, you can also comment the following lines to enable email verification (`# NEXT_PUBLIC_EMAIL_VERIFICATION_DISABLED=1`) and password reset (`# NEXT_PUBLIC_EMAIL_VERIFICATION_DISABLED=1`). +======= +Create a `.env` file based on `.env.docker` and change all fields according to your setup. This file comes with a basic setup and snoopForms works without making any changes to the file. To enable email sending functionality you need to configure the SMTP settings in the `.env` file. If you configured your email credentials, you can also comment the following lines to enable email verification (`# EMAIL_VERIFICATION_DISABLED=1`) and password reset (`# PASSWORD_RESET_DISABLED=1`). + +> > > > > > > 7ab8b81 (add basic react package) Copy the `.env.docker` file to `.env` and edit it with an editor of your choice if needed. diff --git a/apps/web/package.json b/apps/web/package.json index 99053bddb8..ae777c336a 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -8,13 +8,16 @@ "start": "next start", "lint": "next lint" }, + "overrides": { + "@types/react": "^18.0.21" + }, "dependencies": { "@editorjs/editorjs": "^2.25.0", "@editorjs/header": "^2.6.2", "@editorjs/paragraph": "^2.8.0", "@headlessui/react": "^1.7.3", "@heroicons/react": "^2.0.12", - "@snoopforms/react": "^0.3.5", + "@snoopforms/react": "workspace:*", "bcryptjs": "^2.4.3", "chart.js": "^3.9.1", "crypto": "^1.0.1", @@ -25,13 +28,13 @@ "json2csv": "^5.0.7", "jsonwebtoken": "^8.5.1", "next": "12.3.1", - "next-auth": "^4.13.0", + "next-auth": "^4.14.0", "nextjs-cors": "^2.1.1", "nodemailer": "^6.8.0", "react": "18.2.0", "react-chartjs-2": "^4.3.1", "react-dom": "18.2.0", - "react-icons": "^4.4.0", + "react-icons": "^4.6.0", "react-loader-spinner": "^5.3.4", "react-toastify": "^9.0.8", "sanitize-html": "^2.7.2", @@ -45,13 +48,13 @@ "@tailwindcss/line-clamp": "^0.4.2", "@tailwindcss/typography": "^0.5.7", "@types/bcryptjs": "^2.4.2", - "@types/node": "18.8.3", - "@types/react": "^17.0.37", + "@types/node": "18.11.0", + "@types/react": "^18.0.21", "autoprefixer": "^10.4.12", "database": "workspace:*", "eslint": "8.25.0", "eslint-config-custom": "workspace:*", - "postcss": "^8.4.17", + "postcss": "^8.4.18", "tailwind-config": "workspace:*", "tailwindcss": "^3.1.8", "ts-node": "^10.9.1", diff --git a/package.json b/package.json index 71229c3ee8..0ef8c10a52 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,11 @@ "dev": "turbo run dev --parallel", "format": "prettier --write \"**/*.{ts,tsx,md}\"", "generate": "turbo run generate", - "lint": "turbo run lint" + "lint": "turbo run lint", + "release": "turbo run build --filter=web^... && changeset publish" }, "devDependencies": { + "@changesets/cli": "^2.22.0", "prettier": "latest", "tsx": "^3.7.1", "turbo": "latest" diff --git a/packages/database/package.json b/packages/database/package.json index fec084a15e..98285e8a05 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -1,6 +1,7 @@ { "name": "database", "version": "1.0.0", + "private": true, "license": "MIT", "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/packages/eslint-config-custom/package.json b/packages/eslint-config-custom/package.json index 32df8d8c6b..a5bcf67e6d 100644 --- a/packages/eslint-config-custom/package.json +++ b/packages/eslint-config-custom/package.json @@ -1,6 +1,7 @@ { "name": "eslint-config-custom", - "version": "0.0.0", + "version": "1.0.0", + "private": true, "main": "index.js", "license": "MIT", "dependencies": { diff --git a/packages/prettier-config/package.json b/packages/prettier-config/package.json index 008f1b0983..25087d60be 100644 --- a/packages/prettier-config/package.json +++ b/packages/prettier-config/package.json @@ -1,6 +1,6 @@ { "name": "prettier-config", - "version": "0.0.0", + "version": "1.0.0", "private": true, "license": "MIT", "publishConfig": { diff --git a/packages/snoopforms-react/.gitignore b/packages/snoopforms-react/.gitignore new file mode 100644 index 0000000000..9982fde9bc --- /dev/null +++ b/packages/snoopforms-react/.gitignore @@ -0,0 +1,7 @@ +*.log +.DS_Store +node_modules +.cache +dist +.parcel-cache +.idea/ diff --git a/packages/snoopforms-react/LICENSE b/packages/snoopforms-react/LICENSE new file mode 100644 index 0000000000..ce4ff29ae5 --- /dev/null +++ b/packages/snoopforms-react/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Matthias Nannt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/packages/snoopforms-react/README.md b/packages/snoopforms-react/README.md new file mode 100644 index 0000000000..88db2acf77 --- /dev/null +++ b/packages/snoopforms-react/README.md @@ -0,0 +1,63 @@ +# snoopForms React Library + +React Library with form- & survey-elements for the snoopForms platform + +[![npm package](https://img.shields.io/badge/npm%20i-@snoopforms/react)](https://www.npmjs.com/package/@snoopforms/react) [![version number](https://img.shields.io/npm/v/@snoopforms/react?color=green&label=version)](https://github.com/snoopforms/react/releases) [![Actions Status](https://github.com/snoopForms/snoopforms-react/workflows/Test/badge.svg)](https://github.com/snoopForms/snoopforms-react/actions) [![License](https://img.shields.io/github/license/snoopforms/snoopforms-react)](https://github.com/snoopForms/snoopforms-react/blob/main/LICENSE) + +
+ +> :warning: **Note**: This repository is still in an early stage of development. We love the open source community and want to show what we are working on early. We will update this readme with more information once it is safe to use. Until then, feel free to share your thoughts, contact us, and contribute if you'd like. + +## Installation + +``` +npm install @snoopforms/react +``` + +## How to use it 🤓 + +Use the SnoopForm components to build your form easily. + +- `SnoopForm:` Use the `SnoopForm` wrapper to make the connection to the SnoopForm Data-Platform. +- `SnoopPage:` Use `SnoopPage` to tell the Form where you need an new page. The SnoopForms library will only show the current page to the user. That way you can build long, more complex forms or a Typeform-like form-view, where the page changes after every question. +- `SnoopElement:` You can choose your `SnoopElement` from a wide range of pre-coded components, including text, email, checkboxes, radio-buttons, and many more. + +## Example + +```jsx + + + + + + + + + + + +

Thanks a lot for your time and insights 🙏

+
+
+``` + +## Contribute 🙏 + +Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. diff --git a/packages/snoopforms-react/package.json b/packages/snoopforms-react/package.json new file mode 100644 index 0000000000..517f0fa225 --- /dev/null +++ b/packages/snoopforms-react/package.json @@ -0,0 +1,89 @@ +{ + "version": "0.3.5", + "name": "@snoopforms/react", + "author": "snoopForms ", + "description": "React library with form- & survey-elements for the snoopForms platform", + "homepage": "https://snoopforms.com", + "keywords": [ + "react", + "forms", + "snoop", + "snoopforms", + "checkbox", + "survey" + ], + "license": "MIT", + "main": "dist/index.js", + "typings": "dist/index.d.ts", + "files": [ + "dist", + "src" + ], + "engines": { + "node": ">=10" + }, + "scripts": { + "build": "tsup src/index.ts --format esm,cjs --dts --external react && tailwindcss -i ./src/styles.css -o ./dist/styles.css", + "dev": "concurrently \"tsup src/index.ts --format esm,cjs --dts --external react --watch\" \"tailwindcss -i ./src/styles.css -o ./dist/styles.css --watch\"", + "clean": "rm -rf dist", + "size": "size-limit", + "analyze": "size-limit --why", + "build-tailwind": "cross-env NODE_ENV=production npx tailwindcss -i ./tailwind.css -o ./dist/styles.css --minify" + }, + "peerDependencies": { + "react": ">=16" + }, + "husky": { + "hooks": { + "pre-commit": "tsdx lint" + } + }, + "prettier": { + "printWidth": 80, + "semi": true, + "singleQuote": true, + "trailingComma": "es5" + }, + "module": "dist/react.esm.js", + "size-limit": [ + { + "path": "dist/react.cjs.production.min.js", + "limit": "10 KB" + }, + { + "path": "dist/react.esm.js", + "limit": "10 KB" + } + ], + "devDependencies": { + "@babel/core": "^7.19.3", + "@size-limit/preset-small-lib": "^8.1.0", + "@storybook/addon-essentials": "^6.5.12", + "@storybook/addon-info": "^5.3.21", + "@storybook/addon-links": "^6.5.12", + "@storybook/addon-postcss": "^2.0.0", + "@storybook/addons": "^6.5.12", + "@storybook/react": "^6.5.12", + "@tailwindcss/forms": "^0.5.3", + "@types/react": "^18.0.21", + "@types/react-dom": "^18.0.6", + "autoprefixer": "^10.4.12", + "babel-loader": "^8.2.5", + "cross-env": "^7.0.3", + "eslint-config-custom": "workspace:*", + "husky": "^8.0.1", + "postcss": "^8.4.18", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-is": "^18.2.0", + "size-limit": "^8.1.0", + "tailwind-config": "workspace:*", + "tailwindcss": "^3.1.8", + "tslib": "^2.4.0", + "tsconfig": "workspace:*", + "typescript": "^4.8.4" + }, + "dependencies": { + "@headlessui/react": "^1.7.3" + } +} diff --git a/packages/snoopforms-react/postcss.config.js b/packages/snoopforms-react/postcss.config.js new file mode 100644 index 0000000000..1e8c8dc86a --- /dev/null +++ b/packages/snoopforms-react/postcss.config.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: { + tailwindcss: { + content: ['./src/**/*.{js,jsx,ts,tsx}', './stories/*'], + }, + }, +}; diff --git a/packages/snoopforms-react/src/components/Elements/Cards.tsx b/packages/snoopforms-react/src/components/Elements/Cards.tsx new file mode 100644 index 0000000000..b18a442a87 --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Cards.tsx @@ -0,0 +1,126 @@ +import { RadioGroup } from '@headlessui/react'; +import React, { FC, useContext, useEffect, useState } from 'react'; +import { getOptionValue, setSubmissionValue } from '../../lib/elements'; +import { classNamesConcat } from '../../lib/utils'; +import { ClassNames, Option } from '../../types'; +import { + SubmissionContext, + SubmitHandlerContext, +} from '../SnoopForm/SnoopForm'; +import { PageContext } from '../SnoopPage/SnoopPage'; + +interface Props { + name: string; + label?: string; + help?: string; + cols?: number; + autoSubmit?: boolean; + options: (Option | string)[]; + placeholder?: string; + classNames: ClassNames; + required?: boolean; +} + +export const Cards: FC = ({ + name, + label, + help, + cols, + autoSubmit, + options, + classNames, +}) => { + const { submission, setSubmission }: any = useContext(SubmissionContext); + const handleSubmit = useContext(SubmitHandlerContext); + const pageName = useContext(PageContext); + const [triggerSubmit, setTriggerSubmit] = useState(false); + + useEffect(() => { + if (triggerSubmit) { + handleSubmit(pageName); + setTriggerSubmit(false); + } + }, [triggerSubmit]); + + return ( +
+ {label && ( + + )} + { + setSubmissionValue(getOptionValue(v), pageName, name, setSubmission); + if (autoSubmit) { + // trigger submit at next rerender to await setSubmissionValue() + setTriggerSubmit(true); + } + }} + className="mt-2" + > + + Choose an option + +
+ {options.map((option) => ( + + classNamesConcat( + 'cursor-pointer focus:outline-none', + active ? 'ring-2 ring-offset-2 ring-gray-500' : '', + checked + ? 'bg-gray-600 border-transparent text-white hover:bg-gray-700' + : 'bg-white border-gray-200 text-gray-900 hover:bg-gray-50', + 'border rounded-md py-3 px-3 flex items-center justify-center text-sm font-medium uppercase sm:flex-1' + ) + } + > + + {getOptionValue(option)} + + + ))} +
+
+ {help && ( +

+ {help} +

+ )} +
+ ); +}; diff --git a/packages/snoopforms-react/src/components/Elements/Checkbox.tsx b/packages/snoopforms-react/src/components/Elements/Checkbox.tsx new file mode 100644 index 0000000000..46e13f81f7 --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Checkbox.tsx @@ -0,0 +1,105 @@ +import React, { FC, useContext, useEffect, useState } from 'react'; +import { setSubmissionValue } from '../../lib/elements'; +import { ClassNames } from '../../types'; +import { SubmissionContext } from '../SnoopForm/SnoopForm'; +import { PageContext } from '../SnoopPage/SnoopPage'; + +interface Option { + label: string; + value: string; +} + +interface Props { + name: string; + label?: string; + help?: string; + options: (Option | string)[]; + placeholder?: string; + classNames: ClassNames; + required?: boolean; +} + +export const Checkbox: FC = ({ + name, + label, + help, + options, + classNames, +}) => { + const [checked, setChecked] = useState([]); + const { setSubmission }: any = useContext(SubmissionContext); + const pageName = useContext(PageContext); + + useEffect(() => { + setSubmissionValue(checked, pageName, name, setSubmission); + }, [checked]); + + return ( +
+ {label && ( + + )} +
+ {options.map((option) => ( +
+
+ { + const newChecked: string[] = [...checked]; + const value = + typeof option === 'object' ? option.value : option; + if (e.target.checked) { + newChecked.push(value); + } else { + const idx = newChecked.findIndex((v) => v === value); + if (idx >= 0) { + newChecked.splice(idx, 1); + } + } + setChecked(newChecked); + setSubmissionValue(newChecked, pageName, name, setSubmission); + }} + /> +
+
+ +
+
+ ))} +
+ {help && ( +

+ {help} +

+ )} +
+ ); +}; diff --git a/packages/snoopforms-react/src/components/Elements/Email.tsx b/packages/snoopforms-react/src/components/Elements/Email.tsx new file mode 100644 index 0000000000..657ae2dc60 --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Email.tsx @@ -0,0 +1,76 @@ +import React, { FC, useContext } from 'react'; +import { setSubmissionValue } from '../../lib/elements'; +import { classNamesConcat } from '../../lib/utils'; +import { ClassNames } from '../../types'; +import { SubmissionContext } from '../SnoopForm/SnoopForm'; +import { PageContext } from '../SnoopPage/SnoopPage'; + +interface Props { + name: string; + label?: string; + help?: string; + Icon?: React.ReactNode; + placeholder?: string; + classNames: ClassNames; + required: boolean; +} + +export const Email: FC = ({ + name, + label, + help, + Icon, + classNames, + placeholder, + required, +}) => { + const { setSubmission } = useContext(SubmissionContext); + const pageName = useContext(PageContext); + return ( +
+ {label && ( + + )} +
+ {Icon && ( +
+
{Icon}
+
+ )} + + + e.target.setCustomValidity('please enter a valid email address') + } + onInput={(e: any) => e.target.setCustomValidity('')} + name={name} + id={`input-${name}`} + className={classNamesConcat( + Icon ? 'pl-10' : '', + classNames.element || + 'block w-full border-gray-300 rounded-md focus:ring-slate-500 focus:border-slate-500 sm:text-sm' + )} + placeholder={placeholder} + onChange={(e) => + setSubmissionValue(e.target.value, pageName, name, setSubmission) + } + required={required} + /> +
+ {help && ( +

+ {help} +

+ )} +
+ ); +}; diff --git a/packages/snoopforms-react/src/components/Elements/Number.tsx b/packages/snoopforms-react/src/components/Elements/Number.tsx new file mode 100644 index 0000000000..b343b0f0cf --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Number.tsx @@ -0,0 +1,70 @@ +import React, { FC, useContext } from 'react'; +import { setSubmissionValue } from '../../lib/elements'; +import { classNamesConcat } from '../../lib/utils'; +import { ClassNames } from '../../types'; +import { SubmissionContext } from '../SnoopForm/SnoopForm'; +import { PageContext } from '../SnoopPage/SnoopPage'; + +interface Props { + name: string; + label?: string; + help?: string; + Icon?: React.ReactNode; + placeholder?: string; + classNames: ClassNames; + required: boolean; +} + +export const Number: FC = ({ + name, + label, + help, + Icon, + classNames, + placeholder, + required, +}) => { + const { setSubmission } = useContext(SubmissionContext); + const pageName = useContext(PageContext); + return ( +
+ {label && ( + + )} +
+ {Icon && ( +
+
{Icon}
+
+ )} + + setSubmissionValue(e.target.value, pageName, name, setSubmission) + } + required={required} + /> +
+ {help && ( +

+ {help} +

+ )} +
+ ); +}; diff --git a/packages/snoopforms-react/src/components/Elements/Phone.tsx b/packages/snoopforms-react/src/components/Elements/Phone.tsx new file mode 100644 index 0000000000..0475250986 --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Phone.tsx @@ -0,0 +1,71 @@ +import React, { FC, useContext } from 'react'; +import { setSubmissionValue } from '../../lib/elements'; +import { classNamesConcat } from '../../lib/utils'; +import { ClassNames } from '../../types'; +import { SubmissionContext } from '../SnoopForm/SnoopForm'; +import { PageContext } from '../SnoopPage/SnoopPage'; + +interface Props { + name: string; + label?: string; + help?: string; + Icon?: React.ReactNode; + placeholder?: string; + classNames: ClassNames; + required: boolean; +} + +export const Phone: FC = ({ + name, + label, + help, + Icon, + classNames, + placeholder, + required, +}) => { + const { setSubmission } = useContext(SubmissionContext); + const pageName = useContext(PageContext); + return ( +
+ {label && ( + + )} +
+ {Icon && ( +
+
{Icon}
+
+ )} + + + setSubmissionValue(e.target.value, pageName, name, setSubmission) + } + required={required} + /> +
+ {help && ( +

+ {help} +

+ )} +
+ ); +}; diff --git a/packages/snoopforms-react/src/components/Elements/Radio.tsx b/packages/snoopforms-react/src/components/Elements/Radio.tsx new file mode 100644 index 0000000000..43b307db7a --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Radio.tsx @@ -0,0 +1,82 @@ +import React, { FC, useContext } from 'react'; +import { getOptionValue, setSubmissionValue } from '../../lib/elements'; +import { ClassNames, Option } from '../../types'; +import { SubmissionContext } from '../SnoopForm/SnoopForm'; +import { PageContext } from '../SnoopPage/SnoopPage'; + +interface Props { + name: string; + label?: string; + help?: string; + options: (Option | string)[]; + placeholder?: string; + classNames: ClassNames; + required?: boolean; +} + +export const Radio: FC = ({ + name, + label, + help, + options, + classNames, +}) => { + const { setSubmission }: any = useContext(SubmissionContext); + const pageName = useContext(PageContext); + + return ( +
+ {label && ( + + )} +
+ Please choose an option +
+ {options.map((option) => ( +
+ + setSubmissionValue( + getOptionValue(option), + pageName, + name, + setSubmission + ) + } + /> + +
+ ))} +
+
+ {help && ( +

+ {help} +

+ )} +
+ ); +}; diff --git a/packages/snoopforms-react/src/components/Elements/Submit.tsx b/packages/snoopforms-react/src/components/Elements/Submit.tsx new file mode 100644 index 0000000000..907e29a8d9 --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Submit.tsx @@ -0,0 +1,22 @@ +import React, { FC } from 'react'; +import { classNamesConcat } from '../../lib/utils'; +import { ClassNames } from '../../types'; + +interface Props { + label?: string; + classNames?: ClassNames; +} + +export const Submit: FC = ({ classNames, label }) => { + return ( + + ); +}; diff --git a/packages/snoopforms-react/src/components/Elements/Text.tsx b/packages/snoopforms-react/src/components/Elements/Text.tsx new file mode 100644 index 0000000000..197898126f --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Text.tsx @@ -0,0 +1,71 @@ +import React, { FC, useContext } from 'react'; +import { setSubmissionValue } from '../../lib/elements'; +import { classNamesConcat } from '../../lib/utils'; +import { ClassNames } from '../../types'; +import { SubmissionContext } from '../SnoopForm/SnoopForm'; +import { PageContext } from '../SnoopPage/SnoopPage'; + +interface Props { + name: string; + label?: string; + help?: string; + Icon?: React.ReactNode; + placeholder?: string; + classNames: ClassNames; + required: boolean; +} + +export const Text: FC = ({ + name, + label, + help, + Icon, + classNames, + placeholder, + required, +}) => { + const { setSubmission } = useContext(SubmissionContext); + const pageName = useContext(PageContext); + return ( +
+ {label && ( + + )} +
+ {Icon && ( +
+
{Icon}
+
+ )} + + + setSubmissionValue(e.target.value, pageName, name, setSubmission) + } + required={required} + /> +
+ {help && ( +

+ {help} +

+ )} +
+ ); +}; diff --git a/packages/snoopforms-react/src/components/Elements/Textarea.tsx b/packages/snoopforms-react/src/components/Elements/Textarea.tsx new file mode 100644 index 0000000000..86edecfcfd --- /dev/null +++ b/packages/snoopforms-react/src/components/Elements/Textarea.tsx @@ -0,0 +1,64 @@ +import React, { FC, useContext } from 'react'; +import { setSubmissionValue } from '../../lib/elements'; +import { SubmissionContext } from '../SnoopForm/SnoopForm'; +import { PageContext } from '../SnoopPage/SnoopPage'; +import { ClassNames } from '../../types'; +import { classNamesConcat } from '../../lib/utils'; + +interface Props { + name: string; + label?: string; + help?: string; + placeholder?: string; + rows?: number; + classNames: ClassNames; + required: boolean; +} + +export const Textarea: FC = ({ + name, + label, + help, + classNames, + placeholder, + rows, + required, +}) => { + const { setSubmission } = useContext(SubmissionContext); + const pageName = useContext(PageContext); + return ( +
+ {label && ( + + )} +
+