{"version":3,"sources":["webpack:///./src/core/api/services/ApiService.ts","webpack:///./src/hooks/useIntersectionObserver.ts","webpack:///./src/hooks/useInView.ts","webpack:///./src/stories/Components/Forms/Checkbox/Checkbox.styles.ts","webpack:///./src/stories/Components/Forms/Checkbox/Checkbox.tsx","webpack:///./src/helpers/recaptcha.ts","webpack:///./src/stories/Components/Forms/Recaptcha/Recaptcha.styles.ts","webpack:///./src/stories/Components/Forms/Recaptcha/Recaptcha.tsx","webpack:///./src/hooks/useRecaptcha.ts","webpack:///./src/helpers/srOnly.ts"],"names":["ApiService","request","url","this","getUrl","headers","Headers","Accept","isMultipartFormData","delete","requestOptions","method","cache","body","getBody","files","keepalive","keepAlive","undefined","cors","mode","credentials","fetch","response","status","Error","statusText","json","data","slug","controller","length","isStorybook","isSSR","window","location","host","port","process","API_URL","baseUrl","params","querystring","stringify","formData","FormData","append","JSON","index","file","useIntersectionObserver","callback","options","observerRef","useRef","rootRef","elementRef","useEffect","current","IntersectionObserver","root","observe","disconnect","useInView","reverse","isEditMode","useState","inView","setInView","entries","isIntersecting","Input","styled","input","srOnly","Label","label","brand","white","rgba","grey","grey55","primary","base","Checkbox","value","onKeyDown","e","key","toLowerCase","preventDefault","onClick","noop","props","React","createElement","Fragment","S","type","checked","onChange","htmlLabel","htmlFor","id","required","dangerouslySetInnerHTML","__html","load","Promise","resolve","reject","grecaptcha","script","document","onRecaptchaLoad","src","head","appendChild","error","initialise","element","sitekey","ready","widgetId","render","reset","RecaptchaStyles","Container","div","Recaptcha","shouldLoad","siteKey","threshold","ref","recaptcha","recaptchaState","setRecaptchaState","verifyCallback","doAsync","useRecaptcha","token","css"],"mappings":"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","file":"16-9b4f9d100f6db26c4a2d.js","sourcesContent":["import { isSSR } from '@helpers/ssr';\r\nimport querystring from 'querystring';\r\nclass ApiService {\r\n async request(request) {\r\n // Get the url\r\n const url = this.getUrl(request);\r\n // Headers\r\n const headers = new Headers({\r\n 'Content-Type': 'application/json; charset=utf-8',\r\n Accept: 'application/json',\r\n });\r\n if (request.isMultipartFormData === true) {\r\n headers.delete('Content-Type');\r\n }\r\n // construct a request\r\n const requestOptions = {\r\n method: request.method,\r\n headers,\r\n cache: 'default',\r\n body: this.getBody(request, request.files),\r\n keepalive: request.keepAlive ?? false,\r\n };\r\n if (request.cors === undefined || request.cors === true) {\r\n requestOptions.mode = 'cors';\r\n requestOptions.credentials = 'include';\r\n }\r\n // await the response\r\n const response = await fetch(url, requestOptions);\r\n if (response.status === 500) {\r\n throw Error(`${response.status}: ${response.statusText}`);\r\n }\r\n const data = (await response.json());\r\n return data;\r\n }\r\n async safeRequest(request) {\r\n try {\r\n const response = await this.request(request);\r\n return response;\r\n }\r\n catch {\r\n return null;\r\n }\r\n }\r\n getUrl(request) {\r\n let url = `/${request.slug}`;\r\n if (request.controller && request.controller.length > 0) {\r\n url = `/api/${request.controller}/${request.slug}`;\r\n }\r\n let isStorybook = false;\r\n if (!isSSR()) {\r\n if ((window.location.host === 'styleguide.groundforce.netcprev.co.uk' ||\r\n window.location.port === '4000' ||\r\n window.location.port === '4001') &&\r\n process.env.API_URL) {\r\n isStorybook = true;\r\n }\r\n }\r\n if (request.baseUrl) {\r\n url = `${request.baseUrl}${url}`;\r\n }\r\n else if (isStorybook) {\r\n url = `${process.env.API_URL}${url}`;\r\n }\r\n if ((request.method === 'GET' || request.method === 'DELETE') && request.params) {\r\n url += '?';\r\n url += querystring.stringify({ ...request.params });\r\n }\r\n return url;\r\n }\r\n getBody(request, files) {\r\n if (request.method === 'GET') {\r\n return null;\r\n }\r\n if (request.isMultipartFormData === true) {\r\n const formData = new FormData();\r\n formData.append('params', JSON.stringify(request.params));\r\n if (files && files.length > 0) {\r\n for (let index = 0; index < files.length; index++) {\r\n const file = files[index];\r\n formData.append(`files-${index}`, file);\r\n }\r\n }\r\n return formData;\r\n }\r\n return JSON.stringify(request.params);\r\n }\r\n}\r\nexport default new ApiService();\r\n","import { useEffect, useRef } from 'react';\r\n/**\r\n * Use the IntersectionObserver to track visibility of an element in the viewport.\r\n * @param {IntersectionObserverCallback} callback\r\n * @param {IntersectionObserverInit} options\r\n * @returns {UseIntersectionObserverReturn}\r\n */\r\nfunction useIntersectionObserver(callback, options = {}) {\r\n const observerRef = useRef(null);\r\n const rootRef = useRef(null);\r\n const elementRef = useRef(null);\r\n useEffect(() => {\r\n if (!elementRef.current) {\r\n return undefined;\r\n }\r\n observerRef.current = new IntersectionObserver(callback, {\r\n root: rootRef.current,\r\n ...options,\r\n });\r\n observerRef.current.observe(elementRef.current);\r\n return () => {\r\n if (observerRef.current === null) {\r\n return;\r\n }\r\n observerRef.current.disconnect();\r\n };\r\n }, [callback, options]);\r\n return { elementRef, observerRef, rootRef };\r\n}\r\nexport default useIntersectionObserver;\r\n","import { useState } from 'react';\r\nimport useIntersectionObserver from './useIntersectionObserver';\r\nexport function useInView(options, reverse = false, isEditMode = false) {\r\n const [inView, setInView] = useState(false);\r\n const { elementRef } = useIntersectionObserver((entries) => {\r\n if (entries[0].isIntersecting) {\r\n setInView(true);\r\n }\r\n else if (reverse === true) {\r\n setInView(false);\r\n }\r\n }, options);\r\n return [elementRef, isEditMode ? true : inView];\r\n}\r\n","import brand from '@helpers/brand';\r\nimport srOnly from '@helpers/srOnly';\r\nimport { rgba } from 'polished';\r\nimport styled from 'styled-components';\r\nconst Input = styled.input `\r\n ${srOnly}\r\n`;\r\nconst Label = styled.label `\r\n position: relative;\r\n padding-left: 28px;\r\n user-select: none;\r\n\r\n &::before,\r\n &::after {\r\n content: '';\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n border-radius: 3px;\r\n height: 20px;\r\n width: 20px;\r\n transition: all 0.1s;\r\n }\r\n\r\n &::before {\r\n display: inline-flex;\r\n background: ${brand.white};\r\n border: 1px solid ${rgba(brand.grey.grey55, 0.75)};\r\n place-content: center;\r\n place-items: center;\r\n text-align: center;\r\n }\r\n\r\n &::after {\r\n display: inline-flex;\r\n background: ${brand.primary.base};\r\n background-clip: content-box;\r\n border: 1px solid ${rgba(brand.grey.grey55, 0.75)};\r\n border-radius: 3px;\r\n padding: 3px;\r\n place-content: center;\r\n place-items: center;\r\n text-align: center;\r\n opacity: 0;\r\n width: 14px;\r\n height: 14px;\r\n }\r\n\r\n ${Input}:checked + &::after {\r\n opacity: 1;\r\n }\r\n`;\r\nexport default {\r\n Input,\r\n Label,\r\n};\r\n","import React from 'react';\r\nimport S from './Checkbox.styles';\r\nimport noop from 'lodash/noop';\r\nconst Checkbox = ({ value, onKeyDown = (e) => {\r\n if (e.key.toLowerCase() === 'enter') {\r\n e.preventDefault(); // Stops weird behaviour\r\n }\r\n}, onClick = () => noop(), ...props }) => {\r\n const onChange = (e) => {\r\n if (props.onChange) {\r\n props.onChange(e);\r\n }\r\n };\r\n return (React.createElement(React.Fragment, null,\r\n React.createElement(S.Input, { ...props, type: \"checkbox\", checked: value, onChange: (e) => onChange(e), onKeyDown: onKeyDown }),\r\n !props.htmlLabel && (React.createElement(S.Label, { onClick: () => onClick && onClick(!value), htmlFor: props.id },\r\n props.label,\r\n \" \",\r\n props.required ? React.createElement(\"span\", null, \"*\") : null)),\r\n !!props.htmlLabel && (React.createElement(S.Label, { onClick: () => onClick && onClick(!value), htmlFor: props.id, dangerouslySetInnerHTML: { __html: props.label } }, props.required ? React.createElement(\"span\", null, \"*\") : null))));\r\n};\r\nexport default Checkbox;\r\n","import { isSSR } from '@helpers/ssr';\r\nfunction load() {\r\n const promise = new Promise((resolve, reject) => {\r\n if (isSSR() || typeof window.grecaptcha !== 'undefined') {\r\n return resolve();\r\n }\r\n try {\r\n const script = document.createElement('script');\r\n window.onRecaptchaLoad = function onRecaptchaLoad() {\r\n resolve();\r\n };\r\n script.src = 'https://www.google.com/recaptcha/api.js?onload=onRecaptchaLoad&render=explicit';\r\n document.head.appendChild(script);\r\n }\r\n catch (error) {\r\n reject(error);\r\n }\r\n });\r\n return promise;\r\n}\r\nfunction initialise(element, sitekey, callback) {\r\n const promise = new Promise((resolve, reject) => {\r\n if (typeof window.grecaptcha === 'undefined') {\r\n return reject(`\"window.grecaptcha\" is undefined, ensure the recaptcha script has been loaded.`);\r\n }\r\n window.grecaptcha.ready(() => {\r\n const widgetId = window.grecaptcha.render(element, {\r\n sitekey: sitekey,\r\n callback: callback,\r\n 'expired-callback': () => {\r\n window.grecaptcha.reset('recaptcha-container');\r\n },\r\n 'error-callback': reject,\r\n });\r\n resolve(widgetId);\r\n });\r\n });\r\n return promise;\r\n}\r\nfunction reset(widgetId) {\r\n const promise = new Promise((resolve, reject) => {\r\n if (typeof window.grecaptcha === 'undefined') {\r\n return reject(`\"window.grecaptcha\" is undefined, ensure the recaptcha script has been loaded.`);\r\n }\r\n window.grecaptcha.ready(() => {\r\n window.grecaptcha.reset(widgetId);\r\n resolve();\r\n });\r\n });\r\n return promise;\r\n}\r\nexport { initialise, load, reset };\r\n","import styled from 'styled-components';\r\nconst Container = styled.div ``;\r\nconst Recaptcha = styled.div ``;\r\nconst RecaptchaStyles = {\r\n Container,\r\n Recaptcha,\r\n};\r\nexport default RecaptchaStyles;\r\n","import { useInView } from '@hooks/useInView';\r\nimport { useRecaptcha } from '@hooks/useRecaptcha';\r\nimport * as React from 'react';\r\nimport S from './Recaptcha.styles';\r\nconst Recaptcha = ({ shouldLoad, siteKey, onChange }) => {\r\n const [ref, inView] = useInView({ threshold: 1 });\r\n const recaptcha = useRecaptcha({\r\n shouldLoad: inView ? shouldLoad : false,\r\n siteKey: siteKey,\r\n verifyCallback: (token) => {\r\n onChange(token);\r\n },\r\n });\r\n return React.createElement(S.Container, { ref: ref }, inView && React.createElement(S.Recaptcha, { ref: recaptcha.ref }));\r\n};\r\nexport default React.memo(Recaptcha);\r\n","import * as recaptcha from '@helpers/recaptcha';\r\nimport * as React from 'react';\r\nexport function useRecaptcha(params) {\r\n const ref = React.useRef(null);\r\n const [recaptchaState, setRecaptchaState] = React.useState({ widgetId: '' });\r\n // Handle initialisation of recaptcha.\r\n React.useEffect(() => {\r\n doAsync();\r\n async function doAsync() {\r\n // Defer until we should load, and ref is set.\r\n if (!ref.current || !params.shouldLoad) {\r\n return;\r\n }\r\n // Load recaptcha script.\r\n await recaptcha.load();\r\n // Initialise the recaptcha widget and store widget id in state.\r\n const widgetId = await recaptcha.initialise(ref.current, params.siteKey, params.verifyCallback);\r\n setRecaptchaState({ widgetId });\r\n }\r\n }, [params.shouldLoad]);\r\n // Create callback function based on current widget id.\r\n const reset = React.useCallback(async () => {\r\n await recaptcha.reset(recaptchaState.widgetId);\r\n }, [recaptchaState.widgetId]);\r\n return { ...recaptchaState, ref, reset };\r\n}\r\n","import { css } from 'styled-components';\r\n/**\r\n * Show only for screen readers.\r\n * @description Sourced from https://gist.github.com/ffoodd/000b59f431e3e64e4ce1a24d5bb36034\r\n */\r\nconst srOnly = css `\r\n border: 0 !important;\r\n clip: rect(1px, 1px, 1px, 1px) !important;\r\n -webkit-clip-path: inset(50%) !important;\r\n clip-path: inset(50%) !important;\r\n height: 1px !important;\r\n margin: -1px !important;\r\n overflow: hidden !important;\r\n padding: 0 !important;\r\n position: absolute !important;\r\n width: 1px !important;\r\n white-space: nowrap !important;\r\n`;\r\nexport default srOnly;\r\n"],"sourceRoot":""}