diff --git a/CHANGELOG.md b/CHANGELOG.md index c80fc20..4660ebb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +## [9.2.5] 2023-01-18 + +### Fixed + +- Fixed a bug that would cause rich text editor to fail validation (or break while validating) for complex links + ## [9.2.4] 2023-01-04 ### Fixed diff --git a/package-lock.json b/package-lock.json index 6e3f47a..8455e0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@perimetre/ui", - "version": "9.2.4", + "version": "9.2.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@perimetre/ui", - "version": "9.2.4", + "version": "9.2.5", "license": "MIT", "dependencies": { "@babel/core": "^7.12.13", diff --git a/package.json b/package.json index f6efc08..87e9a1d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@perimetre/ui", "description": "A component library made by @perimetre", - "version": "9.2.4", + "version": "9.2.5", "repository": { "type": "git", "url": "git+https://github.com/perimetre/ui.git" diff --git a/src/components/WYSIWYGInput/Toolbar/Options/Hyperlink.tsx b/src/components/WYSIWYGInput/Toolbar/Options/Hyperlink.tsx index fb6638c..c888ea1 100644 --- a/src/components/WYSIWYGInput/Toolbar/Options/Hyperlink.tsx +++ b/src/components/WYSIWYGInput/Toolbar/Options/Hyperlink.tsx @@ -10,6 +10,12 @@ import { Dropdown } from '../../../Dropdown'; import { TextInput } from '../../../TextInput'; import { WYSIWYGTranslations } from '../../translations'; +/** + * Ref: https://stackoverflow.com/a/65810131 + */ +const URL = + /^((https?|ftp):\/\/)?(www.)?(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i; + type HyperlinkProps = { /** * The translation object @@ -106,14 +112,10 @@ export const Hyperlink: React.FC = ({ translations, isActive, ed // This is useful because the user can delete a link by not typing anything // So we only validate if the user has typed something, or else the user wouldn't be able // To continue with no text - link && link.length > 0 - ? schema - .matches( - /((https?):\/\/)?(www.)?[a-z0-9-]+(\.[a-z]{2,}){1,3}(#?\/?[a-zA-Z0-9#-]+)*\/?(\?[a-zA-Z0-9-_]+=[a-zA-Z0-9-%]+&?)?$/, - translations.linkErrorLabel - ) - .required() - : schema + // + // We are using a custom regex to validate the url instead of yup.url() + // because yup validator is too strict and won't accept urls starting only with www. + link && link.length > 0 ? schema.matches(URL, translations.linkErrorLabel).required() : schema ) .label(translations.linkInputLabel) }),