UNPKG

react-klasha

Version:

This is an reactJS library for implementing klasha payment gateway

249 lines (248 loc) 8.05 kB
/** * Waits for a component to be ready for * both custom element and non-custom element builds. * If non-custom element build, el.componentOnReady * will be used. * For custom element builds, we wait a frame * so that the inner contents of the component * have a chance to render. * * Use this utility rather than calling * el.componentOnReady yourself. */ export const componentOnReady = (el, callback) => { if (el.componentOnReady) { el.componentOnReady().then((resolvedEl) => callback(resolvedEl)); } else { raf(() => callback(el)); } }; /** * Elements inside of web components sometimes need to inherit global attributes * set on the host. For example, the inner input in `ion-input` should inherit * the `title` attribute that developers set directly on `ion-input`. This * helper function should be called in componentWillLoad and assigned to a variable * that is later used in the render function. * * This does not need to be reactive as changing attributes on the host element * does not trigger a re-render. */ export const inheritAttributes = (el, attributes = []) => { const attributeObject = {}; attributes.forEach(attr => { if (el.hasAttribute(attr)) { const value = el.getAttribute(attr); if (value !== null) { attributeObject[attr] = el.getAttribute(attr); } el.removeAttribute(attr); } }); return attributeObject; }; export const addEventListener = (el, eventName, callback, opts) => { if (typeof window !== 'undefined') { const win = window; const config = win && win.Ionic && win.Ionic.config; if (config) { const ael = config.get('_ael'); if (ael) { return ael(el, eventName, callback, opts); } else if (config._ael) { return config._ael(el, eventName, callback, opts); } } } return el.addEventListener(eventName, callback, opts); }; export const removeEventListener = (el, eventName, callback, opts) => { if (typeof window !== 'undefined') { const win = window; const config = win && win.Ionic && win.Ionic.config; if (config) { const rel = config.get('_rel'); if (rel) { return rel(el, eventName, callback, opts); } else if (config._rel) { return config._rel(el, eventName, callback, opts); } } } return el.removeEventListener(eventName, callback, opts); }; /** * Gets the root context of a shadow dom element * On newer browsers this will be the shadowRoot, * but for older browser this may just be the * element itself. * * Useful for whenever you need to explicitly * do "myElement.shadowRoot!.querySelector(...)". */ export const getElementRoot = (el, fallback = el) => { return el.shadowRoot || fallback; }; /** * Patched version of requestAnimationFrame that avoids ngzone * Use only when you know ngzone should not run */ export const raf = (h) => { if (typeof __zone_symbol__requestAnimationFrame === 'function') { return __zone_symbol__requestAnimationFrame(h); } if (typeof requestAnimationFrame === 'function') { return requestAnimationFrame(h); } return setTimeout(h); }; export const hasShadowDom = (el) => { return !!el.shadowRoot && !!el.attachShadow; }; export const findItemLabel = (componentEl) => { const itemEl = componentEl.closest('ion-item'); if (itemEl) { return itemEl.querySelector('ion-label'); } return null; }; /** * This method is used for Ionic's input components that use Shadow DOM. In * order to properly label the inputs to work with screen readers, we need * to get the text content of the label outside of the shadow root and pass * it to the input inside of the shadow root. * * Referencing label elements by id from outside of the component is * impossible due to the shadow boundary, read more here: * https://developer.salesforce.com/blogs/2020/01/accessibility-for-web-components.html * * @param componentEl The shadow element that needs the aria label * @param inputId The unique identifier for the input */ export const getAriaLabel = (componentEl, inputId) => { let labelText; // If the user provides their own label via the aria-labelledby attr // we should use that instead of looking for an ion-label const labelledBy = componentEl.getAttribute('aria-labelledby'); // Grab the id off of the component in case they are using // a custom label using the label element const componentId = componentEl.id; let labelId = labelledBy !== null && labelledBy.trim() !== '' ? labelledBy : inputId + '-lbl'; let label = labelledBy !== null && labelledBy.trim() !== '' ? document.getElementById(labelledBy) : findItemLabel(componentEl); if (label) { if (labelledBy === null) { label.id = labelId; } labelText = label.textContent; label.setAttribute('aria-hidden', 'true'); // if there is no label, check to see if the user has provided // one by setting an id on the component and using the label element } else if (componentId.trim() !== '') { label = document.querySelector(`label[for="${componentId}"]`); if (label) { if (label.id !== '') { labelId = label.id; } else { label.id = labelId = `${componentId}-lbl`; } labelText = label.textContent; } } return { label, labelId, labelText }; }; /** * This method is used to add a hidden input to a host element that contains * a Shadow DOM. It does not add the input inside of the Shadow root which * allows it to be picked up inside of forms. It should contain the same * values as the host element. * * @param always Add a hidden input even if the container does not use Shadow * @param container The element where the input will be added * @param name The name of the input * @param value The value of the input * @param disabled If true, the input is disabled */ export const renderHiddenInput = (always, container, name, value, disabled) => { if (always || hasShadowDom(container)) { let input = container.querySelector('input.aux-input'); if (!input) { input = container.ownerDocument.createElement('input'); input.type = 'hidden'; input.classList.add('aux-input'); container.appendChild(input); } input.disabled = disabled; input.name = name; input.value = value || ''; } }; export const clamp = (min, n, max) => { return Math.max(min, Math.min(n, max)); }; export const assert = (actual, reason) => { if (!actual) { const message = 'ASSERT: ' + reason; console.error(message); debugger; // tslint:disable-line throw new Error(message); } }; export const now = (ev) => { return ev.timeStamp || Date.now(); }; export const pointerCoord = (ev) => { // get X coordinates for either a mouse click // or a touch depending on the given event if (ev) { const changedTouches = ev.changedTouches; if (changedTouches && changedTouches.length > 0) { const touch = changedTouches[0]; return { x: touch.clientX, y: touch.clientY }; } if (ev.pageX !== undefined) { return { x: ev.pageX, y: ev.pageY }; } } return { x: 0, y: 0 }; }; /** * @hidden * Given a side, return if it should be on the end * based on the value of dir * @param side the side * @param isRTL whether the application dir is rtl */ export const isEndSide = (side) => { const isRTL = document.dir === 'rtl'; switch (side) { case 'start': return isRTL; case 'end': return !isRTL; default: throw new Error(`"${side}" is not a valid value for [side]. Use "start" or "end" instead.`); } }; export const deferEvent = (event) => { return debounceEvent(event, 0); }; export const debounceEvent = (event, wait) => { const original = event._original || event; return { _original: event, emit: debounce(original.emit.bind(original), wait) }; }; export const debounce = (func, wait = 0) => { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(func, wait, ...args); }; };