[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 2\nend_of_line = lf\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n"
  },
  {
    "path": ".gitignore",
    "content": "\n# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\nnode_modules\n\n# builds\nbuild\n.rpt2_cache\ndist\n\n# misc\n.DS_Store\n.env\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\ntypings\nexample\n\n.idea\n.vscode"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## 4.4.0\n\n- Added `className` option to `InlineWidget` component.\n- Removed SMS prefill option since it is no longer supported by Calendly.\n\nhttps://github.com/tcampb/react-calendly/issues/194\nhttps://github.com/tcampb/react-calendly/issues/186\n\n\n## 4.3.1\n\n- Added `onPageHeightResize` option to `useCalendlyEventListener` hook. This function is called when the Calendly scheduling page's height changes. The event payload includes the new height in pixels.\n\nhttps://github.com/tcampb/react-calendly/issues/174\nhttps://github.com/tcampb/react-calendly/issues/137\nhttps://github.com/tcampb/react-calendly/issues/133\nhttps://github.com/tcampb/react-calendly/issues/15\nhttps://github.com/tcampb/react-calendly/issues/145\n\n## 4.3.0\n\n- Added `smsReminderNumber` prefill option (https://github.com/tcampb/react-calendly/pull/171).\n\n## 4.2.1\n\n- Removes unused sourcemaps (https://github.com/tcampb/react-calendly/issues/169).\n\n## 4.2.0\n- All components now include an optional `LoadingSpinner` prop. This prop is a React component that will be rendered while the Calendly iframe is loading; the default Calendly loading spinner will be displayed if this property is not provided.\n\n## 4.1.1\n- `PopupWidget`, `PopupModal`, and `PopupButton` components will throw an error when opened without a `rootElement` prop (https://github.com/tcampb/react-calendly/issues/143).\n\n## 4.1.0\n\n- Added `salesforce_uuid` prefill option (https://github.com/tcampb/react-calendly/pull/128).\n\n## 4.0.1\n\n- Fixed issue that caused the `email` and `guests` prefill options to not be properly encoded (https://github.com/tcampb/react-calendly/issues/116).\n\n## 4.0.0\n\n- Replaced `CalendlyEventListener` component with `useCalendlyEventListener` hook (https://github.com/tcampb/react-calendly/issues/45).\n- Updated `react` & `react-dom` peer dependency versions; `react-calendly@4.0.0` now requires react and react-dom version >=16.8.\n\n## 3.0.3\n\n- Supports new React 18 types (https://github.com/tcampb/react-calendly/pull/111).\n- Allows closing modal with an overlay click (https://github.com/tcampb/react-calendly/pull/110).\n\n## 3.0.2\n\n- Adds React v18 support (https://github.com/tcampb/react-calendly/issues/106).\n\n## 3.0.1\n\n- Fixes uri encoding bug (https://github.com/tcampb/react-calendly/pull/102).\n\n## 3.0.0\n\n- Removes Calendly widget script dependency (https://assets.calendly.com/assets/external/widget.js).\n- Removes `openPopupWidget` and `closePopupWidget` functions (replaced by `PopupModal` component).\n- Adds `PopupModal` component.\n\n## 2.2.3\n\n- [#96] Added title attribute to the Calendly scheduling page iframe.\n\n## 2.2.2\n\n- [#88] Fixed bug that caused the loading spinner to remain on the page even after the Calendly widget had finished loading.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2020 Tyler Campbell\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# react-calendly\n[Calendly integration](https://help.calendly.com/hc/en-us/articles/223147027-Embed-options-overview) for React apps\n\n[![NPM](https://img.shields.io/npm/v/react-calendly.svg)](https://www.npmjs.com/package/react-calendly) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) [![](https://raw.githubusercontent.com/storybooks/brand/master/badge/badge-storybook.svg)](https://tcampb.github.io/react-calendly)\n\n---\n\n<p>\n  <strong>Are you looking to fully customize your React booking page?</strong><br/>\n  <span>Ship a React booking page you control - with https://components.calforce.pro and <a href=\"https://github.com/tcampb/react-calendly-scheduler\">react-calendly-scheduler</a></span>\n</p>\n\n---\n\n<img width=\"1402\" alt=\"react-calendly\" src=\"https://user-images.githubusercontent.com/33756113/128376592-3cef4ef7-5c8b-4a07-a360-d83da17fff1d.png\">\n\n## Installation\n\nDepending on the package manager you are using for your project, use `npm install` or `yarn add` to include react-calendly in your react app.\n\n```bash\nnpm install --save react-calendly\n```\n\n```bash\nyarn add react-calendly\n```\n\n## Documentation\n\n- [Basic Usage](#basic-usage)\n- [Advanced Usage](#advanced-usage)\n- [Frequently Asked Questions](#faq)\n\n### Basic Usage\n\nEnsure that React has been included into your page or component. Then, you can import any of the following components from the \"react-calendly\" package:\n\n- [InlineWidget](#inlinewidget)\n- [PopupWidget](#popupwidget)\n- [PopupButton](#popupbutton)\n- [useCalendlyEventListener](#usecalendlyeventlistener)\n\n#### InlineWidget\n\n```jsx\nimport React from \"react\";\nimport { InlineWidget } from \"react-calendly\";\n\nconst App = () => {\n  return (\n    <div className=\"App\">\n      <InlineWidget url=\"https://calendly.com/your_scheduling_page\" />\n    </div>\n  );\n};\n\nexport default App;\n```\n\n#### PopupWidget\n\n```jsx\nimport React from \"react\";\nimport { PopupWidget } from \"react-calendly\";\n\nconst App = () => {\n  return (\n    <div className=\"App\">\n      <PopupWidget\n        url=\"https://calendly.com/your_scheduling_page\"\n        /*\n         * react-calendly uses React's Portal feature (https://reactjs.org/docs/portals.html) to render the popup modal. As a result, you'll need to\n         * specify the rootElement property to ensure that the modal is inserted into the correct domNode.\n         */\n        rootElement={document.getElementById(\"root\")}\n        text=\"Click here to schedule!\"\n        textColor=\"#ffffff\"\n        color=\"#00a2ff\"\n      />\n    </div>\n  );\n};\n\nexport default App;\n```\n\n#### PopupButton\n\n```jsx\nimport React from \"react\";\nimport { PopupButton } from \"react-calendly\";\n\nconst App = () => {\n  return (\n    <div className=\"App\">\n      <PopupButton\n        url=\"https://calendly.com/your_scheduling_page\"\n        /*\n         * react-calendly uses React's Portal feature (https://reactjs.org/docs/portals.html) to render the popup modal. As a result, you'll need to\n         * specify the rootElement property to ensure that the modal is inserted into the correct domNode.\n         */\n        rootElement={document.getElementById(\"root\")}\n        text=\"Click here to schedule!\"\n      />\n    </div>\n  );\n};\n\nexport default App;\n```\n\n#### useCalendlyEventListener\n\n```jsx\nimport React from \"react\";\nimport { useCalendlyEventListener, InlineWidget } from \"react-calendly\";\n\nconst App = () => {\n  useCalendlyEventListener({\n    onProfilePageViewed: () => console.log(\"onProfilePageViewed\"),\n    onDateAndTimeSelected: () => console.log(\"onDateAndTimeSelected\"),\n    onEventTypeViewed: () => console.log(\"onEventTypeViewed\"),\n    onEventScheduled: (e) => console.log(e.data.payload),\n    onPageHeightResize: (e) => console.log(e.data.payload.height),\n  });\n\n  return (\n    <div className=\"App\">\n      <InlineWidget url=\"https://calendly.com/your_scheduling_page\" />\n    </div>\n  );\n};\n\nexport default App;\n```\n\n### Advanced Usage\n\nYou can also take advantage of using optional props on the component(s) such as including a defined height, color customization options (available on Pro plan only), utm parameters, pre-filling custom questions, etc. Here are the optional props you can use with the inline embed:\n\n#### Inline Embed Height\n\n```jsx\nstyles={{\n  height: '1000px'\n}}\n```\n\n#### Page Settings\n\n```jsx\npageSettings={{\n  backgroundColor: 'ffffff',\n  hideEventTypeDetails: false,\n  hideLandingPageDetails: false,\n  primaryColor: '00a2ff',\n  textColor: '4d5055'\n}}\n```\n\n#### Prefill Values\n\n```jsx\nprefill={{\n  email: 'test@test.com',\n  firstName: 'Jon',\n  lastName: 'Snow',\n  name: 'Jon Snow',\n  guests: [\n    'janedoe@example.com',\n    'johndoe@example.com'\n  ],\n  customAnswers: {\n    a1: 'a1',\n    a2: 'a2',\n    a3: 'a3',\n    a4: 'a4',\n    a5: 'a5',\n    a6: 'a6',\n    a7: 'a7',\n    a8: 'a8',\n    a9: 'a9',\n    a10: 'a10'\n  },\n  date: new Date(Date.now() + 86400000)\n}}\n```\n\n#### UTM Parameters\n\n```jsx\nutm={{\n  utmCampaign: 'Spring Sale 2019',\n  utmContent: 'Shoe and Shirts',\n  utmMedium: 'Ad',\n  utmSource: 'Facebook',\n  utmTerm: 'Spring'\n}}\n```\n\n## FAQ\n\n#### Why are my page settings not working?\n\nFor the page settings to work, you'll need to pass in a `url` prop that is associated with a Calendly account on the [Pro plan](https://calendly.com/pages/pricing).\n\n#### How do I create a custom button that triggers a pop-up scheduler?\n\n```tsx\nimport { PopupModal } from \"react-calendly\";\n\nclass CustomButtonExample extends React.Component {\n  constructor(props) {\n    super(props);\n\n    this.state = {\n      isOpen: false,\n    };\n  }\n\n  render() {\n    return (\n      <div>\n        <button\n          style={{ display: \"block\", margin: \"0 auto\" }}\n          onClick={() => this.setState({ isOpen: true })}\n        >\n          Custom Button\n        </button>\n        <PopupModal\n          url=\"https://calendly.com/acmesales\"\n          pageSettings={this.props.pageSettings}\n          utm={this.props.utm}\n          prefill={this.props.prefill}\n          onModalClose={() => this.setState({ isOpen: false })}\n          open={this.state.isOpen}\n          /*\n           * react-calendly uses React's Portal feature (https://reactjs.org/docs/portals.html) to render the popup modal. As a result, you'll need to\n           * specify the rootElement property to ensure that the modal is inserted into the correct domNode.\n           */\n          rootElement={document.getElementById(\"root\")}\n        />\n      </div>\n    );\n  }\n}\n```\n\n#### How can I access the event details when an event is scheduled?\n\nThe [useCalendlyEventListener](https://tcampb.github.io/react-calendly/?path=/story/components--usecalendlyeventlistener) `onEventScheduled` prop receives an event with the following data structure:\n\n```javascript\n{\n  event: \"calendly.event_scheduled\",\n  payload: {\n    event: {\n      uri: \"https://calendly.com/api/v2/scheduled_events/AAAAAAAAAAAAAA\"\n    },\n    invitee: {\n      uri: \"https://calendly.com/api/v2/scheduled_events/AAAAAAAAAAAAAA/invitees/AAAAAAAAAAAAAA\"\n    }\n  }\n}\n```\n\nIf you are using [Calendly's v2 api](https://developer.calendly.com/docs/api-docs/docs/A-API-Getting-Started.md) you can reference the event/invitee URIs included in the event payload to retrieve additional information about the event and/or invitee record.\n\n- [Scheduled Event Schema](https://developer.calendly.com/api-docs/e2f95ebd44914-get-event)\n- [Invitee Schema](https://developer.calendly.com/api-docs/8305c0ccfac70-get-event-invitee)\n\n#### Can I use react-calendly with Nextjs?\n\nYes, see https://github.com/tcampb/react-calendly/issues/105 for additional details.\n\n## Additional Resources\n\n[Embed options overview](https://help.calendly.com/hc/en-us/articles/223147027-Embed-options-overview)\n\n[Advanced embed options](https://help.calendly.com/hc/en-us/articles/360020052833-Advanced-embed-options)\n\n[Common embed questions](https://help.calendly.com/hc/en-us/articles/360019861794-Common-embed-questions)\n\n## License\n\nMIT © [tcampb](https://github.com/tcampb)\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"react-calendly\",\n  \"version\": \"4.4.0\",\n  \"description\": \"Calendly integration for React apps\",\n  \"author\": \"tcampb\",\n  \"license\": \"MIT\",\n  \"repository\": \"tcampb/react-calendly\",\n  \"main\": \"dist/index.js\",\n  \"typings\": \"typings/index.d.ts\",\n  \"module\": \"dist/index.es.js\",\n  \"jsnext:main\": \"dist/index.es.js\",\n  \"engines\": {\n    \"node\": \">=8\",\n    \"npm\": \">=5\"\n  },\n  \"keywords\": [\n    \"react\",\n    \"calendly\",\n    \"component\"\n  ],\n  \"scripts\": {\n    \"build\": \"rollup -c && tsc --emitDeclarationOnly\",\n    \"start\": \"rollup -c -w\",\n    \"prepare\": \"npm run build\"\n  },\n  \"peerDependencies\": {\n    \"react\": \">=16.8.0\",\n    \"react-dom\": \">=16.8.0\"\n  },\n  \"devDependencies\": {\n    \"@rollup/plugin-typescript\": \"^11.1.4\",\n    \"@types/react\": \"^16.8.0\",\n    \"@types/react-dom\": \"^16.8.0\",\n    \"prettier\": \"2.0.2\",\n    \"react\": \"^16.8.0\",\n    \"react-dom\": \"^16.8.0\",\n    \"rollup\": \"^3.29.4\",\n    \"typescript\": \"^4.0.5\",\n    \"@rollup/plugin-commonjs\": \"^25.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.2.1\",\n    \"rollup-plugin-peer-deps-external\": \"^2.2.4\",\n    \"rollup-plugin-postcss\": \"^4.0.2\",\n    \"tslib\": \"^2.6.2\"\n  },\n  \"files\": [\n    \"dist\",\n    \"typings\"\n  ]\n}\n"
  },
  {
    "path": "rollup.config.js",
    "content": "const typescript = require(\"@rollup/plugin-typescript\");\nconst commonjs = require('@rollup/plugin-commonjs')\nconst pkg = require(\"./package.json\")\nconst postcss = require('rollup-plugin-postcss');\nconst external = require('rollup-plugin-peer-deps-external');\n\nmodule.exports = {\n  input: \"src/index.tsx\",\n  output: [\n    {\n      file: pkg.main,\n      format: \"cjs\",\n      exports: \"named\"\n    },\n    {\n      file: pkg.module,\n      format: \"es\",\n      exports: \"named\"\n    },\n  ],\n  plugins: [external(), postcss(), typescript(), commonjs()],\n};\n"
  },
  {
    "path": "src/calendly-widget.css",
    "content": "/*\n  code is extracted from Calendly's embed stylesheet: https://assets.calendly.com/assets/external/widget.css\n*/\n\n.calendly-inline-widget,\n.calendly-inline-widget *,\n.calendly-badge-widget,\n.calendly-badge-widget *,\n.calendly-overlay,\n.calendly-overlay * {\n  font-size: 16px;\n  line-height: 1.2em;\n}\n\n.calendly-inline-widget {\n  min-width: 320px;\n  height: 630px;\n}\n\n.calendly-inline-widget iframe,\n.calendly-badge-widget iframe,\n.calendly-overlay iframe {\n  display: inline;\n  width: 100%;\n  height: 100%;\n}\n\n.calendly-popup-content {\n  position: relative;\n}\n\n.calendly-popup-content.calendly-mobile {\n  -webkit-overflow-scrolling: touch;\n  overflow-y: auto;\n}\n\n.calendly-overlay {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  overflow: hidden;\n  z-index: 9999;\n  background-color: #a5a5a5;\n  background-color: rgba(31, 31, 31, 0.4);\n}\n\n.calendly-overlay .calendly-close-overlay {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n}\n\n.calendly-overlay .calendly-popup {\n  box-sizing: border-box;\n  position: absolute;\n  top: 50%;\n  left: 50%;\n  -webkit-transform: translateY(-50%) translateX(-50%);\n  transform: translateY(-50%) translateX(-50%);\n  width: 80%;\n  min-width: 900px;\n  max-width: 1000px;\n  height: 90%;\n  max-height: 680px;\n}\n\n@media (max-width: 975px) {\n  .calendly-overlay .calendly-popup {\n    position: fixed;\n    top: 50px;\n    left: 0;\n    right: 0;\n    bottom: 0;\n    -webkit-transform: none;\n    transform: none;\n    width: 100%;\n    height: auto;\n    min-width: 0;\n    max-height: none;\n  }\n}\n\n.calendly-overlay .calendly-popup .calendly-popup-content {\n  height: 100%;\n}\n\n.calendly-overlay .calendly-popup-close {\n  position: absolute;\n  top: 25px;\n  right: 25px;\n  color: #fff;\n  width: 19px;\n  height: 19px;\n  cursor: pointer;\n  background: url(https://assets.calendly.com/assets/external/close-icon.svg)\n    no-repeat;\n  background-size: contain;\n}\n\n@media (max-width: 975px) {\n  .calendly-overlay .calendly-popup-close {\n    top: 15px;\n    right: 15px;\n  }\n}\n\n.calendly-badge-widget {\n  position: fixed;\n  right: 20px;\n  bottom: 15px;\n  z-index: 9998;\n}\n\n.calendly-badge-widget .calendly-badge-content {\n  display: table-cell;\n  width: auto;\n  height: 45px;\n  padding: 0 30px;\n  border-radius: 25px;\n  box-shadow: rgba(0, 0, 0, 0.25) 0 2px 5px;\n  font-family: sans-serif;\n  text-align: center;\n  vertical-align: middle;\n  font-weight: bold;\n  font-size: 14px;\n  color: #fff;\n  cursor: pointer;\n}\n\n.calendly-badge-widget .calendly-badge-content.calendly-white {\n  color: #666a73;\n}\n\n.calendly-badge-widget .calendly-badge-content span {\n  display: block;\n  font-size: 12px;\n}\n\n.calendly-spinner {\n  position: absolute;\n  top: 50%;\n  left: 0;\n  right: 0;\n  -webkit-transform: translateY(-50%);\n  transform: translateY(-50%);\n  text-align: center;\n  z-index: -1;\n}\n\n.calendly-spinner > div {\n  display: inline-block;\n  width: 18px;\n  height: 18px;\n  background-color: #e1e1e1;\n  border-radius: 50%;\n  vertical-align: middle;\n  -webkit-animation: calendly-bouncedelay 1.4s infinite ease-in-out;\n  animation: calendly-bouncedelay 1.4s infinite ease-in-out;\n  -webkit-animation-fill-mode: both;\n  animation-fill-mode: both;\n}\n\n.calendly-spinner .calendly-bounce1 {\n  -webkit-animation-delay: -0.32s;\n  animation-delay: -0.32s;\n}\n\n.calendly-spinner .calendly-bounce2 {\n  -webkit-animation-delay: -0.16s;\n  animation-delay: -0.16s;\n}\n\n@-webkit-keyframes calendly-bouncedelay {\n  0%,\n  80%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n\n  40% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n\n@keyframes calendly-bouncedelay {\n  0%,\n  80%,\n  100% {\n    -webkit-transform: scale(0);\n    transform: scale(0);\n  }\n\n  40% {\n    -webkit-transform: scale(1);\n    transform: scale(1);\n  }\n}\n"
  },
  {
    "path": "src/calendly.tsx",
    "content": "import { sanitizePageSettingsProps } from \"./helpers/propHelpers\";\n\ntype Optional<T extends object> = {\n  [P in keyof T]?: T[P];\n};\n\nexport type Prefill = Optional<{\n  name: string;\n  email: string;\n  firstName: string;\n  lastName: string;\n  location: string;\n  guests: string[];\n  customAnswers: Optional<{\n    a1: string;\n    a2: string;\n    a3: string;\n    a4: string;\n    a5: string;\n    a6: string;\n    a7: string;\n    a8: string;\n    a9: string;\n    a10: string;\n  }>;\n  date: Date;\n}>;\n\nexport enum CalendlyEvent {\n  PROFILE_PAGE_VIEWED = \"calendly.profile_page_viewed\",\n  EVENT_TYPE_VIEWED = \"calendly.event_type_viewed\",\n  DATE_AND_TIME_SELECTED = \"calendly.date_and_time_selected\",\n  EVENT_SCHEDULED = \"calendly.event_scheduled\",\n  PAGE_HEIGHT = \"calendly.page_height\",\n}\n\nexport type Utm = Optional<{\n  utmCampaign: string;\n  utmSource: string;\n  utmMedium: string;\n  utmContent: string;\n  utmTerm: string;\n  salesforce_uuid: string;\n}>;\n\n/**\n * @description The default title is Calendly Scheduling Page\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title}\n */\nexport type IframeTitle = string;\n\n/**\n * @description LoadingSpinner is a React component that will be displayed while the Calendly iframe is loading. If no component is provided, the default Calendly loading spinner will be used.\n */\nexport type LoadingSpinner = React.FunctionComponent;\n\nexport type PageSettings = Optional<{\n  /**\n   * @description Use this setting to hide your profile picture, name, event duration, location, and description when Calendly is embedded. This will help reduce duplicate information that you may already have on your web page.\n   * @see {@link https://help.calendly.com/hc/en-us/articles/360020052833-Advanced-embed-options#2} for further information.\n   */\n  hideLandingPageDetails: boolean;\n  /**\n   * @description Use this setting to hide your profile picture, name, event duration, location, and description when Calendly is embedded. This will help reduce duplicate information that you may already have on your web page.\n   * @see {@link https://help.calendly.com/hc/en-us/articles/360020052833-Advanced-embed-options#2} for further information.\n   */\n  hideEventTypeDetails: boolean;\n  /**\n   * @description This setting is only available for Calendly users on the Pro plan. Use this setting to change your Calendly scheduling page's background color.\n   * @example 00a2ff\n   * @see {@link https://help.calendly.com/hc/en-us/articles/223147027-Embed-options-overview#3} for further information.\n   */\n  backgroundColor: string;\n  /**\n   * @description This setting is only available for Calendly users on the Pro plan. Use this setting to change your Calendly scheduling page's text color.\n   * @example ffffff\n   * @see {@link https://help.calendly.com/hc/en-us/articles/223147027-Embed-options-overview#3} for further information.\n   */\n  textColor: string;\n  /**\n   * @description This setting is only available for Calendly users on the Pro plan. Use this setting to change your Calendly scheduling page's primary color.\n   * @example 4d5055\n   * @see {@link https://help.calendly.com/hc/en-us/articles/223147027-Embed-options-overview#3} for further information.\n   */\n  primaryColor: string;\n  /**\n   * @description The General Data Protection Regulation governs data protection in the EU and EEA. Certain Calendly integrations require access to cookies with user information. If you do not embed the GDPR banner, users in those areas will not have the ability to give their consent in order to access integrations such as Google Analytics, Facebook Pixel, PayPal, and Stripe.\n   * @see {@link https://help.calendly.com/hc/en-us/articles/360007385493-Cookie-FAQs} for further information.\n   */\n  hideGdprBanner: boolean;\n}>;\n\nexport const formatCalendlyUrl = ({\n  url,\n  prefill = {},\n  pageSettings = {},\n  utm = {},\n  embedType,\n}: {\n  url: string;\n  prefill?: Prefill;\n  pageSettings?: PageSettings;\n  utm?: Utm;\n  embedType?: \"Inline\" | \"PopupWidget\" | \"PopupButton\";\n}) => {\n  const sanitizedPageSettings = sanitizePageSettingsProps(pageSettings);\n\n  const {\n    backgroundColor,\n    hideEventTypeDetails,\n    hideLandingPageDetails,\n    primaryColor,\n    textColor,\n    hideGdprBanner,\n  } = sanitizedPageSettings;\n\n  const {\n    customAnswers,\n    date,\n    email,\n    firstName,\n    guests,\n    lastName,\n    location,\n    name,\n  } = prefill;\n\n  const {\n    utmCampaign,\n    utmContent,\n    utmMedium,\n    utmSource,\n    utmTerm,\n    salesforce_uuid,\n  } = utm;\n\n  const queryStringIndex = url.indexOf(\"?\");\n  const hasQueryString = queryStringIndex > -1;\n  const queryString = url.slice(queryStringIndex + 1);\n  const baseUrl = hasQueryString ? url.slice(0, queryStringIndex) : url;\n\n  const updatedQueryString = [\n    hasQueryString ? queryString : null,\n    backgroundColor ? `background_color=${backgroundColor}` : null,\n    hideEventTypeDetails ? `hide_event_type_details=1` : null,\n    hideLandingPageDetails ? `hide_landing_page_details=1` : null,\n    primaryColor ? `primary_color=${primaryColor}` : null,\n    textColor ? `text_color=${textColor}` : null,\n    hideGdprBanner ? `hide_gdpr_banner=1` : null,\n    name ? `name=${encodeURIComponent(name)}` : null,\n    location ? `location=${encodeURIComponent(location)}` : null,\n    firstName ? `first_name=${encodeURIComponent(firstName)}` : null,\n    lastName ? `last_name=${encodeURIComponent(lastName)}` : null,\n    guests ? `guests=${guests.map(encodeURIComponent).join(\",\")}` : null,\n    email ? `email=${encodeURIComponent(email)}` : null,\n    date && date instanceof Date ? `date=${formatDate(date)}` : null,\n    utmCampaign ? `utm_campaign=${encodeURIComponent(utmCampaign)}` : null,\n    utmContent ? `utm_content=${encodeURIComponent(utmContent)}` : null,\n    utmMedium ? `utm_medium=${encodeURIComponent(utmMedium)}` : null,\n    utmSource ? `utm_source=${encodeURIComponent(utmSource)}` : null,\n    utmTerm ? `utm_term=${encodeURIComponent(utmTerm)}` : null,\n    salesforce_uuid\n      ? `salesforce_uuid=${encodeURIComponent(salesforce_uuid)}`\n      : null,\n    embedType ? `embed_type=${embedType}` : null,\n    /*\n     * https://github.com/tcampb/react-calendly/pull/31\n     * embed_domain must be defined to receive messages from the Calendly iframe.\n     */\n    `embed_domain=1`,\n  ]\n    .concat(customAnswers ? formatCustomAnswers(customAnswers) : [])\n    .filter((item) => item !== null)\n    .join(\"&\");\n\n  return `${baseUrl}?${updatedQueryString}`;\n};\n\nconst formatDate = (d: Date) => {\n  const month = d.getMonth() + 1;\n  const day = d.getDate();\n  const year = d.getFullYear();\n\n  return [\n    year,\n    month < 10 ? `0${month}` : month,\n    day < 10 ? `0${day}` : day,\n  ].join(\"-\");\n};\n\nconst CUSTOM_ANSWER_PATTERN = /^a\\d{1,2}$/;\nconst formatCustomAnswers = (customAnswers: object) => {\n  const customAnswersFiltered = Object.keys(customAnswers).filter((key) =>\n    key.match(CUSTOM_ANSWER_PATTERN)\n  );\n\n  if (!customAnswersFiltered.length) return [];\n\n  return customAnswersFiltered.map(\n    (key) => `${key}=${encodeURIComponent(customAnswers[key])}`\n  );\n};\n"
  },
  {
    "path": "src/components/InlineWidget/InlineWidget.tsx",
    "content": "import * as React from \"react\";\nimport \"../../calendly-widget.css\";\nimport {\n  PageSettings,\n  Prefill,\n  Utm,\n  IframeTitle,\n  formatCalendlyUrl,\n  LoadingSpinner,\n} from \"../../calendly\";\nimport CalendlyLoadingSpinner from \"../LoadingSpinner/LoadingSpinner\";\n\nexport interface Props {\n  url: string;\n  prefill?: Prefill;\n  utm?: Utm;\n  styles?: React.CSSProperties | undefined;\n  pageSettings?: PageSettings;\n  iframeTitle?: IframeTitle;\n  LoadingSpinner?: LoadingSpinner;\n  className?: string;\n}\n\nconst defaultClassName = \"calendly-inline-widget\";\n\nclass InlineWidget extends React.Component<Props, { isLoading: boolean }> {\n  constructor(props: Props) {\n    super(props);\n\n    this.state = {\n      isLoading: true,\n    };\n\n    this.onLoad = this.onLoad.bind(this);\n  }\n\n  private onLoad() {\n    this.setState({\n      isLoading: false,\n    });\n  }\n\n  render() {\n    const src = formatCalendlyUrl({\n      url: this.props.url,\n      pageSettings: this.props.pageSettings,\n      prefill: this.props.prefill,\n      utm: this.props.utm,\n      embedType: \"Inline\",\n    });\n    const LoadingSpinner = this.props.LoadingSpinner || CalendlyLoadingSpinner;\n\n    return (\n      <div\n        className={this.props.className || defaultClassName}\n        style={this.props.styles || {}}\n      >\n        {this.state.isLoading && <LoadingSpinner />}\n        <iframe\n          width=\"100%\"\n          height=\"100%\"\n          frameBorder=\"0\"\n          title={this.props.iframeTitle || \"Calendly Scheduling Page\"}\n          onLoad={this.onLoad}\n          src={src}\n        ></iframe>\n      </div>\n    );\n  }\n}\n\nexport default InlineWidget;\n"
  },
  {
    "path": "src/components/LoadingSpinner/LoadingSpinner.tsx",
    "content": "import * as React from \"react\";\nimport \"../../calendly-widget.css\";\n\nclass LoadingSpinner extends React.Component {\n  render() {\n    return (\n      <div className=\"calendly-spinner\">\n        <div className=\"calendly-bounce1\"></div>\n        <div className=\"calendly-bounce2\"></div>\n        <div className=\"calendly-bounce3\"></div>\n      </div>\n    );\n  }\n}\n\nexport default LoadingSpinner;\n"
  },
  {
    "path": "src/components/PopupButton/PopupButton.tsx",
    "content": "import * as React from \"react\";\nimport \"../../calendly-widget.css\";\nimport { PageSettings, Prefill, Utm, IframeTitle, LoadingSpinner } from \"../../calendly\";\nimport Modal from \"../PopupModal/Modal\";\n\nexport interface Props {\n  url: string;\n  text: string;\n  rootElement: HTMLElement;\n  prefill?: Prefill;\n  utm?: Utm;\n  pageSettings?: PageSettings;\n  styles?: React.CSSProperties | undefined;\n  className?: string;\n  iframeTitle?: IframeTitle;\n  LoadingSpinner?: LoadingSpinner;\n}\n\nclass PopupButton extends React.Component<Props, { isOpen: boolean }> {\n  constructor(props: Props) {\n    super(props);\n\n    this.state = {\n      isOpen: false,\n    };\n\n    this.onClick = this.onClick.bind(this);\n    this.onClose = this.onClose.bind(this);\n  }\n\n  onClick(e: React.SyntheticEvent) {\n    e.preventDefault();\n    this.setState({\n      isOpen: true,\n    });\n  }\n\n  onClose(e: React.SyntheticEvent) {\n    e.stopPropagation();\n\n    this.setState({\n      isOpen: false,\n    });\n  }\n\n  render() {\n    return (\n      <>\n        <button\n          onClick={this.onClick}\n          style={this.props.styles || {}}\n          className={this.props.className || \"\"}\n        >\n          {this.props.text}\n        </button>\n        <Modal\n          {...this.props}\n          open={this.state.isOpen}\n          onModalClose={this.onClose}\n          rootElement={this.props.rootElement}\n        />\n      </>\n    );\n  }\n}\n\nexport default PopupButton;\n"
  },
  {
    "path": "src/components/PopupModal/Modal.tsx",
    "content": "import * as React from \"react\";\nimport * as ReactDom from \"react-dom\";\nimport { LoadingSpinner } from \"../../calendly\";\nimport ModalContent, { Props as ModalContentProps } from \"./ModalContent\";\n\ninterface Props extends ModalContentProps {\n  onModalClose: (e: React.MouseEvent<HTMLElement>) => void;\n  open: boolean;\n  rootElement: HTMLElement;\n  LoadingSpinner?: LoadingSpinner;\n}\n\nexport default (props: Props) => {\n  if (!props.open) return null;\n\n  if (!props.rootElement) {\n    throw new Error('[react-calendly]: PopupModal rootElement property cannot be undefined')\n  }\n\n  return ReactDom.createPortal(\n    <div className=\"calendly-overlay\">\n      <div\n        onClick={props.onModalClose}\n        className=\"calendly-close-overlay\"\n      ></div>\n      <div className=\"calendly-popup\">\n        <div className=\"calendly-popup-content\">\n          <ModalContent {...props} />\n        </div>\n      </div>\n      <button\n        className=\"calendly-popup-close\"\n        onClick={props.onModalClose}\n        aria-label=\"Close modal\"\n        style={{\n          display: \"block\",\n          border: \"none\",\n          padding: 0,\n        }}\n      ></button>\n    </div>,\n    props.rootElement\n  );\n};\n"
  },
  {
    "path": "src/components/PopupModal/ModalContent.tsx",
    "content": "import * as React from \"react\";\nimport \"../../calendly-widget.css\";\nimport {\n  PageSettings,\n  Prefill,\n  Utm,\n  IframeTitle,\n  formatCalendlyUrl,\n  LoadingSpinner,\n} from \"../../calendly\";\nimport CalendlyLoadingSpinner from \"../LoadingSpinner/LoadingSpinner\";\n\nexport interface Props {\n  url: string;\n  prefill?: Prefill;\n  utm?: Utm;\n  pageSettings?: PageSettings;\n  iframeTitle?: IframeTitle;\n  LoadingSpinner?: LoadingSpinner;\n}\n\nclass ModalContent extends React.Component<Props, { isLoading: boolean }> {\n  constructor(props: Props) {\n    super(props);\n\n    this.state = {\n      isLoading: true,\n    };\n\n    this.onLoad = this.onLoad.bind(this);\n  }\n\n  private onLoad() {\n    this.setState({\n      isLoading: false,\n    });\n  }\n\n  render() {\n    const src = formatCalendlyUrl({\n      url: this.props.url,\n      pageSettings: this.props.pageSettings,\n      prefill: this.props.prefill,\n      utm: this.props.utm,\n      embedType: \"Inline\",\n    });\n    const LoadingSpinner = this.props.LoadingSpinner || CalendlyLoadingSpinner;\n\n    return (\n      <>\n        {this.state.isLoading && <LoadingSpinner />}\n        <iframe\n          width=\"100%\"\n          height=\"100%\"\n          frameBorder=\"0\"\n          title={this.props.iframeTitle || \"Calendly Scheduling Page\"}\n          onLoad={this.onLoad}\n          src={src}\n        ></iframe>\n      </>\n    );\n  }\n}\n\nexport default ModalContent;\n"
  },
  {
    "path": "src/components/PopupWidget/PopupWidget.tsx",
    "content": "import * as React from \"react\";\nimport \"../../calendly-widget.css\";\nimport { PageSettings, Prefill, Utm, IframeTitle, LoadingSpinner } from \"../../calendly\";\nimport Modal from \"../PopupModal/Modal\";\n\nexport interface Props {\n  url: string;\n  text: string;\n  rootElement: HTMLElement;\n  color?: string;\n  textColor?: string;\n  branding?: boolean;\n  prefill?: Prefill;\n  utm?: Utm;\n  pageSettings?: PageSettings;\n  iframeTitle?: IframeTitle;\n  LoadingSpinner?: LoadingSpinner;\n}\n\nclass PopupWidget extends React.Component<Props, { isOpen: boolean }> {\n  constructor(props: Props) {\n    super(props);\n\n    this.state = {\n      isOpen: false,\n    };\n\n    this.onClick = this.onClick.bind(this);\n    this.onClose = this.onClose.bind(this);\n  }\n\n  onClick() {\n    this.setState({\n      isOpen: true,\n    });\n  }\n\n  onClose(e: React.SyntheticEvent) {\n    e.stopPropagation();\n\n    this.setState({\n      isOpen: false,\n    });\n  }\n\n  render() {\n    return (\n      <div className=\"calendly-badge-widget\" onClick={this.onClick}>\n        <div\n          className=\"calendly-badge-content\"\n          style={{\n            background: this.props.color || \"#00a2ff\",\n            color: this.props.textColor || \"#ffffff\",\n          }}\n        >\n          {this.props.text || \"Schedule time with me\"}\n          {this.props.branding && <span>powered by Calendly</span>}\n        </div>\n        <Modal\n          {...this.props}\n          open={this.state.isOpen}\n          onModalClose={this.onClose}\n          rootElement={this.props.rootElement}\n        />\n      </div>\n    );\n  }\n}\n\nexport default PopupWidget;\n"
  },
  {
    "path": "src/components/hooks/useCalendlyEventListener.ts",
    "content": "import * as React from \"react\";\nimport { CalendlyEvent } from \"../../calendly\";\n\nexport type DateAndTimeSelectedEvent = MessageEvent<{\n  event: CalendlyEvent.DATE_AND_TIME_SELECTED;\n  payload: {};\n}>;\n\nexport type EventScheduledEvent = MessageEvent<{\n  event: CalendlyEvent.EVENT_SCHEDULED;\n  payload: {\n    event: {\n      /**\n       * @description Canonical reference (unique identifier) to the event that was scheduled.\n       * @example https://calendly.com/api/v2/scheduled_events/AAAAAAAAAAAAAA\n       * @see {@link https://developer.calendly.com/docs/api-docs/reference/calendly-api/openapi.yaml/paths/~1scheduled_events~1%7Buuid%7D/get} for further information.\n       */\n      uri: string;\n    };\n    invitee: {\n      /**\n       * @description Canonical reference (unique identifier) for the invitee who scheduled the event.\n       * @example https://calendly.com/api/v2/scheduled_events/AAAAAAAAAAAAAA/invitees/AAAAAAAAAAAAAA\n       * @see {@link https://developer.calendly.com/docs/api-docs/reference/calendly-api/openapi.yaml/paths/~1scheduled_events~1%7Bevent_uuid%7D~1invitees~1%7Binvitee_uuid%7D/get} for further information.\n       */\n      uri: string;\n    };\n  };\n}>;\n\nexport type EventTypeViewedEvent = MessageEvent<{\n  event: CalendlyEvent.EVENT_TYPE_VIEWED;\n  payload: {};\n}>;\n\nexport type ProfilePageViewedEvent = MessageEvent<{\n  event: CalendlyEvent.PROFILE_PAGE_VIEWED;\n  payload: {};\n}>;\n\nexport type PageHeightResizeEvent = MessageEvent<{\n  event: CalendlyEvent.PAGE_HEIGHT;\n  payload: {\n    /**\n       * @description The height of the Calendly scheduling page in pixels.\n       * @example 1200px\n       */\n    height: string;\n  };\n}>;\n\nexport type CalendlyEventHandlers = {\n  onDateAndTimeSelected?: (e: DateAndTimeSelectedEvent) => any;\n  onEventScheduled?: (e: EventScheduledEvent) => any;\n  onEventTypeViewed?: (e: EventTypeViewedEvent) => any;\n  onProfilePageViewed?: (e: ProfilePageViewedEvent) => any;\n  onPageHeightResize?: (e: PageHeightResizeEvent) => any;\n};\n\nconst EVENT_NAME = \"message\";\n\nexport default function useCalendlyEventListener(\n  eventHandlers: CalendlyEventHandlers\n) {\n  const {\n    onDateAndTimeSelected,\n    onEventScheduled,\n    onEventTypeViewed,\n    onProfilePageViewed,\n    onPageHeightResize\n  } = eventHandlers || {};\n\n  React.useEffect(() => {\n    const onMessage = (e: MessageEvent) => {\n      const eventName = e.data.event;\n\n      if (eventName === CalendlyEvent.DATE_AND_TIME_SELECTED) {\n        onDateAndTimeSelected && onDateAndTimeSelected(e);\n      } else if (eventName === CalendlyEvent.EVENT_SCHEDULED) {\n        onEventScheduled && onEventScheduled(e);\n      } else if (eventName === CalendlyEvent.EVENT_TYPE_VIEWED) {\n        onEventTypeViewed && onEventTypeViewed(e);\n      } else if (eventName === CalendlyEvent.PROFILE_PAGE_VIEWED) {\n        onProfilePageViewed && onProfilePageViewed(e);\n      } else if (eventName === CalendlyEvent.PAGE_HEIGHT) {\n        onPageHeightResize && onPageHeightResize(e);\n      }\n    };\n\n    window.addEventListener(EVENT_NAME, onMessage);\n\n    return function cleanup() {\n      window.removeEventListener(EVENT_NAME, onMessage);\n    };\n  }, [eventHandlers]);\n}\n"
  },
  {
    "path": "src/helpers/propHelpers.ts",
    "content": "import { PageSettings } from \"../calendly\";\n\nfunction sanitizeColorString(str: string): string {\n  if (str.charAt(0) === \"#\") {\n    return str.slice(1);\n  }\n  return str;\n}\n\nexport function sanitizePageSettingsProps(\n  props: PageSettings\n) {\n  if (props?.primaryColor) {\n    props.primaryColor = sanitizeColorString(props.primaryColor);\n  }\n\n  if (props?.textColor) {\n    props.textColor = sanitizeColorString(props.textColor);\n  }\n\n  if (props?.backgroundColor) {\n    props.backgroundColor = sanitizeColorString(props.backgroundColor);\n  }\n\n  return props;\n}\n"
  },
  {
    "path": "src/index.tsx",
    "content": "import InlineWidget from \"./components/InlineWidget/InlineWidget\";\nimport PopupButton from \"./components/PopupButton/PopupButton\";\nimport PopupWidget from \"./components/PopupWidget/PopupWidget\";\nimport PopupModal from \"./components/PopupModal/Modal\";\nimport useCalendlyEventListener from \"./components/hooks/useCalendlyEventListener\";\nimport type {\n  DateAndTimeSelectedEvent,\n  EventScheduledEvent,\n  EventTypeViewedEvent,\n  ProfilePageViewedEvent,\n} from \"./components/hooks/useCalendlyEventListener\";\n\nexport { InlineWidget };\nexport { PopupButton };\nexport { PopupWidget };\nexport { PopupModal };\nexport { useCalendlyEventListener };\nexport {\n  DateAndTimeSelectedEvent,\n  EventScheduledEvent,\n  EventTypeViewedEvent,\n  ProfilePageViewedEvent,\n};\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"outDir\": \"build\",\n    \"module\": \"esnext\",\n    \"target\": \"es5\",\n    \"lib\": [\"es6\", \"dom\", \"es2016\", \"es2017\"],\n    \"sourceMap\": true,\n    \"allowJs\": false,\n    \"jsx\": \"react\",\n    \"declaration\": true,\n    \"declarationDir\": \"typings\",\n    \"moduleResolution\": \"node\",\n    \"forceConsistentCasingInFileNames\": true,\n    \"noImplicitReturns\": true,\n    \"noImplicitThis\": true,\n    \"noImplicitAny\": true,\n    \"strictNullChecks\": true,\n    \"suppressImplicitAnyIndexErrors\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true\n  },\n  \"include\": [\"src\"],\n  \"exclude\": [\n    \"node_modules\",\n    \"build\",\n    \"dist\",\n    \"rollup.config.js\",\n    \"**/*.stories.tsx\"\n  ]\n}\n"
  }
]