UNPKG

@dialpad/dialtone

Version:

Dialpad's Dialtone design system monorepo

1 lines 22.4 kB
{"version":3,"file":"index.cjs","names":["DEFAULT_VALIDATION_MESSAGE_TYPE","VALIDATION_MESSAGE_TYPES","Comment","Text","configVue2StyleClassAttrs"],"sources":["../../../common/utils/index.js"],"sourcesContent":["import {\n DEFAULT_PREFIX,\n DEFAULT_VALIDATION_MESSAGE_TYPE,\n VALIDATION_MESSAGE_TYPES,\n} from '../constants/index.js';\nimport {\n configVue2StyleClassAttrs,\n} from '../config';\nimport {\n h,\n Comment,\n Text,\n} from 'vue';\n\nlet UNIQUE_ID_COUNTER = 0;\nlet TIMER;\n\n// selector to find focusable not hidden inputs\nconst FOCUSABLE_SELECTOR_NOT_HIDDEN = 'input:not([type=hidden]):not(:disabled)';\n// selector to find focusable not disables elements\nconst FOCUSABLE_SELECTOR_NOT_DISABLED = 'select:not(:disabled),textarea:not(:disabled),button:not(:disabled)';\n// // selector to find focusable not hidden and disabled elements\nconst FOCUSABLE_SELECTOR_NOT_HIDDEN_DISABLED = `${FOCUSABLE_SELECTOR_NOT_HIDDEN},${FOCUSABLE_SELECTOR_NOT_DISABLED}`;\n// selector to find focusable elements\nconst FOCUSABLE_SELECTOR = `a,frame,iframe,${FOCUSABLE_SELECTOR_NOT_HIDDEN_DISABLED},*[tabindex]`;\n\nconst scheduler = typeof setImmediate === 'function' ? setImmediate : setTimeout;\n\nexport function getUniqueString (prefix = DEFAULT_PREFIX) {\n return `${prefix}${UNIQUE_ID_COUNTER++}`;\n}\n\n/**\n * Returns a random element from array\n * @param array - the array to return a random element from\n * @param {string} seed - use a string to seed the randomization, so it returns the same element each time\n * based on that string.\n * @returns {*} - the random element\n */\nexport function getRandomElement (array, seed) {\n if (seed) {\n const hash = javaHashCode(seed);\n return array[Math.abs(hash) % array.length];\n } else {\n return array[getRandomInt(array.length)];\n }\n}\n\n/**\n * Returns a hash code for a string.\n * (Compatible to Java's String.hashCode())\n * We use this algo to be in sync with android.\n *\n * The hash code for a string object is computed as\n * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]\n * using number arithmetic, where s[i] is the i th character\n * of the given string, n is the length of the string,\n * and ^ indicates exponentiation.\n * (The hash value of the empty string is zero.)\n *\n * @param {string} str a string\n * @return {number} a hash code value for the given string.\n */\nexport function javaHashCode (str) {\n let h;\n for (let i = 0; i < str.length; i++) {\n h = Math.imul(31, h) + str.charCodeAt(i) | 0;\n }\n\n return h;\n}\n\n/**\n * Generate a random integer\n * @param {number} max - max range of integer to generate\n * @returns {number} randomly generated integer between 0 and max\n */\nexport function getRandomInt (max) {\n return Math.floor(Math.random() * max);\n}\n\nexport function formatMessages (messages) {\n if (!messages) {\n return [];\n }\n\n return messages.map(message => {\n if (typeof message === 'string') {\n return {\n message,\n type: DEFAULT_VALIDATION_MESSAGE_TYPE,\n };\n }\n\n return message;\n });\n}\n\nexport function filterFormattedMessages (formattedMessages) {\n const validationState = getValidationState(formattedMessages);\n\n if (!formattedMessages || !validationState) {\n return [];\n }\n\n return formattedMessages.filter(message => !!message.message && message.type === validationState);\n}\n\n/*\n * The priority order of message types is as flows: 'error' > 'warning' > 'success'.\n * If any message of type 'error' is present in messages, the input state is considered\n * to be 'error', then 'warning' and lastly 'success'.\n */\nexport function getValidationState (formattedMessages) {\n if (!formattedMessages) {\n return null;\n }\n\n if (hasFormattedMessageOfType(formattedMessages, VALIDATION_MESSAGE_TYPES.ERROR)) {\n return VALIDATION_MESSAGE_TYPES.ERROR;\n }\n if (hasFormattedMessageOfType(formattedMessages, VALIDATION_MESSAGE_TYPES.WARNING)) {\n return VALIDATION_MESSAGE_TYPES.WARNING;\n }\n if (hasFormattedMessageOfType(formattedMessages, VALIDATION_MESSAGE_TYPES.SUCCESS)) {\n return VALIDATION_MESSAGE_TYPES.SUCCESS;\n }\n\n return null;\n}\n\nexport function hasFormattedMessageOfType (formattedMessages, messageType) {\n if (!formattedMessages || !messageType) {\n return false;\n }\n\n return formattedMessages.some(message => message?.type === messageType);\n}\n\nexport function findFirstFocusableNode (element) {\n return element?.querySelector(FOCUSABLE_SELECTOR);\n}\n\n/* html-fragment component:\n * To render html without wrapping in another element as when using v-html.\n * props: html\n */\nexport const htmlFragment = (props) => {\n return h('div', { innerHTML: props.html });\n};\n\nexport const flushPromises = () => {\n return new Promise((resolve) => {\n scheduler(resolve);\n });\n};\n\n/*\n It is very cumbersome to check if a slot is empty in vue 3. Copied this method from the following thread\n https://github.com/vuejs/core/issues/4733. There is an RFC to fix this but not yet being worked on.\n https://github.com/vuejs/rfcs/discussions/453\n*/\nexport function hasSlotContent (slot, slotProps = {}) {\n if (!slot) return false;\n\n\n return slot(slotProps).some((vnode) => {\n if (vnode.type === Comment) return false;\n\n if (Array.isArray(vnode.children) && !vnode.children.length) return false;\n\n return (\n vnode.type !== Text ||\n (typeof vnode.children === 'string' && vnode.children.trim() !== '')\n );\n });\n}\n\n/**\n * Transform a string from kebab-case to PascalCase\n * @param string\n * @returns {string}\n */\nexport const kebabCaseToPascalCase = (string) => {\n return string?.toLowerCase()\n .split('-')\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join('');\n};\n\n/**\n * Transform a string from PascalCase to kebab-case\n * @param string\n * @returns {string}\n */\nexport const pascalCaseToKebabCase = (string) => {\n return string\n .replace(/\\.?([A-Z0-9]+)/g, (x, y) => '-' + y.toLowerCase())\n .replace(/^-/, '');\n};\n\n/**\n * Extracts Vue event listeners from attributes object\n * @param {Object} attrs - The attributes object to extract listeners from\n * @returns {Object} Object containing only Vue event listeners (keys matching on[A-Z])\n */\nexport const extractVueListeners = (attrs) => {\n const listeners = Object.entries(attrs)\n .filter(([key]) => key.match(/on[A-Z]/));\n return Object.fromEntries(listeners);\n};\n\n/**\n * Extracts non-listener attributes from attributes object\n * @param {Object} attrs - The attributes object to extract non-listeners from\n * @returns {Object} Object containing only non-listener attributes (keys not matching on[A-Z])\n */\nexport const extractNonListeners = (attrs) => {\n const nonListeners = Object.entries(attrs)\n .filter(([key]) => !key.match(/on[A-Z]/));\n return Object.fromEntries(nonListeners);\n};\n\n/**\n * $el works very differently than in vue 2, if the first node in the template is a text node\n * such as a comment it will return that instead of the first actual element. This function\n * will recursively return the first element in the template instead of the first node.\n * @param el\n * @returns {HTMLElement} The first element in the template\n */\nexport const returnFirstEl = (el) => {\n if (el?.nodeType === Node.ELEMENT_NODE) {\n return el;\n } else if (!el?.nodeType) {\n return null;\n } else {\n return returnFirstEl(el?.nextSibling);\n }\n};\n\n/**\n Only will apply changes if the config option configVue2StyleClassAttrs is set to true. It is false by default.\n\n Removes the class and style attributes from the $attrs. This is useful for vue 2 to vue 3 migration\n purposes so we don't cause breaking changes due to INSTANCE_ATTRS_CLASS_STYLE\n https://v3-migration.vuejs.org/breaking-changes/attrs-includes-class-style\n\n Remove the class and style attributes from the v-bind like so so v-bind=\"removeClassStyleAttrs($attrs)\",\n and then apply them to the root element manually via:\n\n :class=\"$attrs.class\"\n :style=\"$attrs.style\"\n*/\nexport function removeClassStyleAttrs (attrs) {\n if (!configVue2StyleClassAttrs) return attrs;\n const listeners = Object.entries(attrs)\n .filter(([key]) => !['class', 'style'].includes(key));\n return Object.fromEntries(listeners);\n}\n\n/**\n This should be applied to the root element on components using inheritAttrs: false.\n This will add the class and style attributes back to the root element if configVue2StyleClassAttrs\n is enabled.\n*/\nexport function addClassStyleAttrs (attrs) {\n if (!configVue2StyleClassAttrs) return {};\n return {\n class: attrs.class,\n style: attrs.style,\n };\n}\n\n/*\n* Set's a global timer to debounce the execution of a function.\n* @param { object } func - the function that is going to be called after timeout\n* @param { number } [timeout=300] timeout\n* */\nexport function debounce (func, timeout = 300) {\n clearTimeout(TIMER);\n TIMER = setTimeout(func, timeout);\n}\n\n/**\n * Checks if the element is out of the viewport\n * https://gomakethings.com/how-to-check-if-any-part-of-an-element-is-out-of-the-viewport-with-vanilla-js/\n * @param {HTMLElement} element The element to check\n * @return {Object} A set of booleans for each side of the element\n */\n\nexport function isOutOfViewPort (element) {\n const bounding = element.getBoundingClientRect();\n\n const isOut = {\n top: bounding.top < 0,\n left: bounding.left < 0,\n bottom: bounding.bottom > (window.innerHeight || document.documentElement.clientHeight),\n right: bounding.right > (window.innerWidth || document.documentElement.clientWidth),\n };\n isOut.any = Object.values(isOut).some(val => val);\n isOut.all = Object.values(isOut).every(val => val);\n return isOut;\n}\n\n// match valid characters for a domain name followed by a dot, e.g. \"dialpad.\"\nconst domainNameRegex = /(?:(?:[^\\s!@#$%^&*()_=+[\\]{}\\\\|;:'\",.<>/?]+)\\.)/;\n\n// match valid TLDs for a hostname (outdated list from ~2017)\nconst tldRegerx = new RegExp(\n '(?:' +\n 'com|ru|org|net|de|jp|uk|br|it|pl|fr|in|au|ir|info|nl|cn|es|cz|kr|ca|eu|ua|co|gr|' +\n 'za|ro|biz|ch|se|tw|mx|vn|hu|be|tr|at|dk|tv|me|ar|sk|no|us|fi|id|cl|xyz|io|pt|by|' +\n 'il|ie|nz|kz|hk|lt|cc|my|sg|club|bg|edu|рф|pk|su|top|th|hr|rs|pe|pro|si|az|lv|pw|' +\n 'ae|ph|online|ng|ee|ws|ve|cat' +\n ')',\n);\n\n// match valid IPv4 addresses, e.g. \"192.158.1.38\"\nconst ipv4Regex = new RegExp(\n '(?:(?:[0-9]|[1-9]\\\\d|1\\\\d{2}|2[0-4]\\\\d|25[0-5])\\\\.){3}' +\n '(?:[0-9]|[1-9]\\\\d|1\\\\d{2}|2[0-4]\\\\d|25[0-5])',\n);\n\n// match hostnames OR IPv4 addresses, e.g. \"dialpad.com\" or \"192.158.1.38\"\nconst hostnameOrIpRegex = new RegExp(\n '(?:' +\n [\n [\n domainNameRegex.source,\n tldRegerx.source,\n ].join('+'),\n ipv4Regex.source,\n ].join('|') +\n ')',\n);\n\n// match URL paths, e.g. \"/news\"\nconst urlPathRegex = /(?:(?:[;/][^#?<>\\s]*)?)/;\n\n// match URL queries and fragments, e.g. \"?cache=1&new=true\" or \"#heading1\"\nconst urlQueryOrFragmentRegex = /(?:(?:\\?[^#<>\\s]+)?(?:#[^<>\\s]+)?)/;\n\n// match complete hostnames or IPv4 addresses without a protocol and with optional\n// URL paths, queries and fragments e.g. \"dialpad.com/news?cache=1#heading1\"\nconst urlWithoutProtocolRegex = new RegExp(\n '\\\\b' +\n [\n hostnameOrIpRegex.source,\n urlPathRegex.source,\n urlQueryOrFragmentRegex.source,\n '(?!\\\\w)',\n ].join('+'),\n);\n\n// match complete hostnames with protocols and optional URL paths, queries and fragments,\n// e.g. \"ws://localhost:9011\" or \"https://dialpad.com/news?cache=1#heading1\"\nconst urlWithProtocolRegex = /\\b[a-z\\d.-]+:\\/\\/[^<>\\s]+/;\n\n// match email addresses with an optional \"mailto:\" prefix and URL queries, e.g.\n// \"hey@dialpad.com\" or \"mailto:hey@dialpad.com?subject=Hi&body=Hey%20there\"\nconst emailAddressRegex = new RegExp(\n '(?:mailto:)?' +\n '[a-z0-9!#$%&\\'*+/=?^_`{|}~-]+(?:\\\\.[a-z0-9!#$%&\\'*+/=?^_`{|}~-]+)*@' +\n [\n hostnameOrIpRegex.source,\n urlQueryOrFragmentRegex.source,\n ].join('+') +\n '(?!\\\\w)',\n);\n\n/**\n * Match phone numbers, e.g. \"765-8813\", \"(778) 765-8813\" or \"+17787658813\".\n * @param {number} minLength\n * @param {number} maxLength\n * @returns {RegExp}\n */\nexport function getPhoneNumberRegex (minLength = 7, maxLength = 15) {\n // Some older browser versions don't support lookbehind, so provide a RegExp\n // version without it. It fails just one test case, so IMO it's still good\n // enough to use. https://caniuse.com/js-regexp-lookbehind\n try {\n return new RegExp(\n '(?:^|(?<=\\\\W))' +\n '(?![\\\\s\\\\-])\\\\+?(?:[0-9()\\\\- \\\\t]' +\n `{${minLength},${maxLength}}` +\n ')(?=\\\\b)(?=\\\\W(?=\\\\W|$)|\\\\s|$)',\n );\n } catch {\n // eslint-disable-next-line no-console\n console.warn('This browser doesn\\'t support regex lookahead/lookbehind');\n }\n\n return new RegExp(\n '(?![\\\\s\\\\-])\\\\+?(?:[0-9()\\\\- \\\\t]' +\n `{${minLength},${maxLength}}` +\n ')(?=\\\\b)(?=\\\\W(?=\\\\W|$)|\\\\s|$)',\n );\n}\n\nconst phoneNumberRegex = getPhoneNumberRegex();\n\n// match all link types\nexport const linkRegex = new RegExp(\n [\n urlWithoutProtocolRegex.source,\n urlWithProtocolRegex.source,\n emailAddressRegex.source,\n phoneNumberRegex.source,\n ].join('|'),\n 'gi',\n);\n\n/**\n * Check if a string is a phone number. Validates only exact matches.\n * @param {string|number} input\n * @returns {boolean}\n */\nexport function isPhoneNumber (input) {\n if (!input || (!['string', 'number'].includes(typeof input))) return false;\n input = input.toString();\n return phoneNumberRegex.exec(input)?.[0] === input;\n}\n\n/**\n * Check if a string is an URL. Validates only exact matches.\n * @param {string} input\n * @returns {boolean}\n */\nexport function isURL (input) {\n if (!input || typeof input !== 'string') return false;\n return urlWithoutProtocolRegex.exec(input)?.[0] === input ||\n urlWithProtocolRegex.exec(input)?.[0] === input;\n}\n\n/**\n * Check if a string is an email address. Validates only exact matches.\n * @param {string} input\n * @returns {boolean}\n */\nexport function isEmailAddress (input) {\n if (!input || typeof input !== 'string') return false;\n return emailAddressRegex.exec(input)?.[0] === input;\n}\n\n/**\n * Concatenate a string removing null or undefined elements\n * avoiding parsing them as string with template strings\n * @param {Array} elements\n * @returns {String}\n */\nexport function safeConcatStrings (elements) {\n return elements.filter(str => !!str).join(', ');\n}\n\n/**\n * Locale safe function to capitalize the first letter of a string.\n * @param {string} str the string to capitalize the first letter of\n * @param {string} locale a string representing the locale to be used. Defaults to 'en-US'\n * @returns The passed in string with the first letter capitalized\n */\nexport function capitalizeFirstLetter (str, locale = 'en-US') {\n return str.replace(/^\\p{CWU}/u, char => char.toLocaleUpperCase(locale));\n}\n\n/**\n * Warns if the component is not mounted properly. Useful for tests.\n * @param {HTMLElement} componentRef - the component reference\n * @param {string} componentName - the component name\n */\n\nexport function warnIfUnmounted (componentRef, componentName) {\n if (typeof process === 'undefined') return;\n if (process.env.NODE_ENV !== 'test') return;\n if (!componentRef || !(componentRef instanceof HTMLElement) || !document?.body) return;\n if (!document.body.contains(componentRef)) {\n console.warn(`The ${componentName} component is not attached to the document body. This may cause issues.`);\n }\n}\n\n/**\n * checks whether the dt-scrollbar is being used on the root element.\n * @param rootElement {HTMLElement}\n * @returns {boolean}\n */\nfunction isDtScrollbarInUse (rootElement = document.documentElement) {\n if (rootElement.hasAttribute('data-overlayscrollbars')) {\n return true;\n }\n return false;\n}\n\n/**\n * This will disable scrolling on the root element regardless of whether you are using dt-scrollbar or not.\n * @param rootElement {HTMLElement}\n */\nexport function disableRootScrolling (rootElement = document.documentElement) {\n if (isDtScrollbarInUse(rootElement)) {\n rootElement.classList.add('d-scrollbar-disabled');\n } else {\n rootElement.classList.add('d-of-hidden');\n }\n}\n\n/**\n * This will enable scrolling on the root element regardless of whether you are using dt-scrollbar or not.\n * @param rootElement {HTMLElement}\n */\nexport function enableRootScrolling (rootElement = document.documentElement) {\n if (isDtScrollbarInUse(rootElement)) {\n rootElement.classList.remove('d-scrollbar-disabled');\n } else {\n rootElement.classList.remove('d-of-hidden');\n }\n}\n\n/**\n * This will take a text string e.g \"accessibility-mac\"\n * and convert it to our Fluent Key standard format \"ACCESSIBILITY_MAC\"\n * @param text\n * @returns {string}\n */\nexport function toFluentKeyString (text) {\n return text\n .replaceAll(/[ -]/g, '_')\n .replaceAll(/\\W/g, '')\n .toUpperCase();\n}\n\nexport default {\n getUniqueString,\n getRandomElement,\n getRandomInt,\n formatMessages,\n filterFormattedMessages,\n hasFormattedMessageOfType,\n getValidationState,\n htmlFragment,\n flushPromises,\n kebabCaseToPascalCase,\n extractVueListeners,\n extractNonListeners,\n removeClassStyleAttrs,\n addClassStyleAttrs,\n returnFirstEl,\n debounce,\n isOutOfViewPort,\n getPhoneNumberRegex,\n linkRegex,\n isEmailAddress,\n isPhoneNumber,\n isURL,\n safeConcatStrings,\n capitalizeFirstLetter,\n disableRootScrolling,\n enableRootScrolling,\n};\n"],"mappings":"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"}