diff --git a/demo/client/components/richText/elements/Button/Button/index.scss b/demo/client/components/richText/elements/Button/Button/index.scss index 75d7917cc0..f1b6402d32 100644 --- a/demo/client/components/richText/elements/Button/Button/index.scss +++ b/demo/client/components/richText/elements/Button/Button/index.scss @@ -17,10 +17,11 @@ &__header { width: 100%; + margin-bottom: $baseline; display: flex; justify-content: space-between; - h4 { + h3 { margin: 0; } diff --git a/src/client/components/elements/Button/index.js b/src/client/components/elements/Button/index.js index d659a23a44..021ae3770e 100644 --- a/src/client/components/elements/Button/index.js +++ b/src/client/components/elements/Button/index.js @@ -79,7 +79,7 @@ const Button = (props) => { function handleClick(event) { if (type !== 'submit' && onClick) event.preventDefault(); - if (onClick) onClick(); + if (onClick) onClick(event); } const buttonProps = { diff --git a/src/client/components/elements/Button/index.scss b/src/client/components/elements/Button/index.scss index e9f8525043..afaa090d90 100644 --- a/src/client/components/elements/Button/index.scss +++ b/src/client/components/elements/Button/index.scss @@ -92,6 +92,15 @@ &--style-none { padding: 0; margin: 0; + border-radius: 0; + + &:focus { + opacity: .8; + } + + &:active { + opacity: .7; + } } &--round { @@ -155,6 +164,8 @@ @include color-svg($color-dark-gray); background: $color-light-gray; } + + outline: none; } &:active { diff --git a/src/client/components/elements/Nav/index.scss b/src/client/components/elements/Nav/index.scss index 40d78604d6..a2fa174fc0 100644 --- a/src/client/components/elements/Nav/index.scss +++ b/src/client/components/elements/Nav/index.scss @@ -82,6 +82,15 @@ padding: base(.125) 0; display: flex; text-decoration: none; + + &:focus { + box-shadow: none; + font-weight: 600; + } + + &:active { + font-weight: normal; + } } nav { diff --git a/src/client/components/elements/Popup/index.js b/src/client/components/elements/Popup/index.js index 554820a3a0..0fa432b791 100644 --- a/src/client/components/elements/Popup/index.js +++ b/src/client/components/elements/Popup/index.js @@ -12,12 +12,12 @@ const baseClass = 'popup'; const Popup = (props) => { const { - render, align, size, color, button, buttonType, children, showOnHover, horizontalAlign, + render, align, size, color, button, buttonType, children, showOnHover, horizontalAlign, initActive, } = props; const buttonRef = useRef(null); const contentRef = useRef(null); - const [active, setActive] = useState(false); + const [active, setActive] = useState(initActive); const [verticalAlign, setVerticalAlign] = useState('top'); const [forceHorizontalAlign, setForceHorizontalAlign] = useState(null); @@ -143,6 +143,7 @@ Popup.defaultProps = { button: undefined, showOnHover: false, horizontalAlign: 'left', + initActive: false, }; Popup.propTypes = { @@ -155,6 +156,7 @@ Popup.propTypes = { buttonType: PropTypes.oneOf(['default', 'custom']), button: PropTypes.node, showOnHover: PropTypes.bool, + initActive: PropTypes.bool, }; export default Popup; diff --git a/src/client/components/elements/Popup/index.scss b/src/client/components/elements/Popup/index.scss index 33997a9dab..21c791294b 100644 --- a/src/client/components/elements/Popup/index.scss +++ b/src/client/components/elements/Popup/index.scss @@ -25,7 +25,8 @@ } &__scroll { - padding: base(1); + padding: $baseline; + padding-right: calc(var(--scrollbar-width) + #{$baseline}); overflow-y: auto; width: calc(100% + var(--scrollbar-width)); white-space: nowrap; diff --git a/src/client/components/forms/Error/index.js b/src/client/components/forms/Error/index.js index b770189686..44ff492fd2 100644 --- a/src/client/components/forms/Error/index.js +++ b/src/client/components/forms/Error/index.js @@ -2,6 +2,8 @@ import React from 'react'; import PropTypes from 'prop-types'; import Tooltip from '../../elements/Tooltip'; +import './index.scss'; + const Error = (props) => { const { showError, message } = props; diff --git a/src/client/components/forms/Error/index.scss b/src/client/components/forms/Error/index.scss index b21c850377..5c7ba8172a 100644 --- a/src/client/components/forms/Error/index.scss +++ b/src/client/components/forms/Error/index.scss @@ -1,14 +1,13 @@ @import '../../../scss/styles'; -.field-error { - .tooltip { - left: auto; - right: base(.5); - transform: none; - background-color: $error; +.error-message { + left: auto; + right: base(.5); + transform: none; + background-color: $color-red; - span { - border-top-color: $error; - } + span { + border-top-color: $color-red; } } + diff --git a/src/client/components/forms/field-types/RichText/RichText.js b/src/client/components/forms/field-types/RichText/RichText.js index 061e3afec7..4fb92e7671 100644 --- a/src/client/components/forms/field-types/RichText/RichText.js +++ b/src/client/components/forms/field-types/RichText/RichText.js @@ -14,15 +14,12 @@ import elementTypes from './elements'; import toggleLeaf from './leaves/toggle'; import hotkeys from './hotkeys'; import enablePlugins from './enablePlugins'; +import defaultValue from '../../../../../fields/richText/defaultValue'; import mergeCustomFunctions from './mergeCustomFunctions'; import './index.scss'; -const defaultValue = [{ - children: [{ text: '' }], -}]; - const defaultElements = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'link']; const defaultLeaves = ['bold', 'italic', 'underline', 'strikethrough', 'code']; diff --git a/src/client/components/forms/field-types/RichText/elements/link/index.js b/src/client/components/forms/field-types/RichText/elements/link/index.js index dffbe7e0aa..95d13c9b4b 100644 --- a/src/client/components/forms/field-types/RichText/elements/link/index.js +++ b/src/client/components/forms/field-types/RichText/elements/link/index.js @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { Fragment, useEffect, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import { ReactEditor, useSlate } from 'slate-react'; import { Transforms } from 'slate'; @@ -8,8 +8,8 @@ import LinkIcon from '../../../../../icons/Link'; import Portal from '../../../../../utilities/Portal'; import Popup from '../../../../../elements/Popup'; import Button from '../../../../../elements/Button'; -import Chevron from '../../../../../icons/Chevron'; import Check from '../../../../../icons/Check'; +import Error from '../../../../Error'; import './index.scss'; @@ -20,6 +20,7 @@ const Link = ({ attributes, children, element }) => { const linkRef = useRef(); const [left, setLeft] = useState(0); const [top, setTop] = useState(0); + const [error, setError] = useState(false); const [width, setWidth] = useState(0); const [height, setHeight] = useState(0); const [url, setURL] = useState(element.url); @@ -62,32 +63,67 @@ const Link = ({ attributes, children, element }) => { }} > } size="small" color="dark" horizontalAlign="center" - > -
- setURL(e.target.value)} - /> - -
- -
+ render={({ close }) => ( + +
+ { + const { value } = e.target; + + if (value && error) { + setError(false); + } + + setURL(value); + }} + onKeyDown={(e) => { + if (e.key === 'Enter') { + close(); + } + }} + /> +
+ +
+ )} + /> {children} diff --git a/src/client/components/forms/field-types/RichText/elements/link/index.scss b/src/client/components/forms/field-types/RichText/elements/link/index.scss index aceb1a1671..102db16992 100644 --- a/src/client/components/forms/field-types/RichText/elements/link/index.scss +++ b/src/client/components/forms/field-types/RichText/elements/link/index.scss @@ -9,6 +9,10 @@ position: absolute; z-index: $z-modal; cursor: pointer; + + .tooltip { + bottom: 80%; + } } .rich-text-link__button { @@ -19,7 +23,59 @@ left: 0; } +.rich-text-link__url-wrap { + position: relative; + width: 100%; + margin-bottom: base(.5); +} + +.rich-text-link__confirm { + position: absolute; + right: base(.5); + top: 50%; + transform: translateY(-50%); + + svg { + @include color-svg(white); + transform: rotate(-90deg); + } +} + .rich-text-link__url { @include formInput; - width: base(12); + min-width: base(12); + width: 100%; + background: rgba($color-background-gray, .1); + border: 0; + color: white; +} + +.rich-text-link__new-tab { + svg { + @include color-svg(white); + background-color: rgba(white, .1); + margin-right: base(.5); + } + + path { + opacity: 0; + } + + &:hover { + path { + opacity: .2; + } + } + + &--checked { + path { + opacity: 1; + } + + &:hover { + path { + opacity: .8; + } + } + } } diff --git a/src/client/components/forms/field-types/RichText/index.scss b/src/client/components/forms/field-types/RichText/index.scss index 6041208f8f..e532784e67 100644 --- a/src/client/components/forms/field-types/RichText/index.scss +++ b/src/client/components/forms/field-types/RichText/index.scss @@ -13,8 +13,10 @@ } &__editor { - min-height: 150px; + min-height: base(10); padding: base(.5); + max-height: base(20); + overflow-y: scroll; p, h1, diff --git a/src/client/scss/app.scss b/src/client/scss/app.scss index 4370c1842f..2ba9d8b231 100644 --- a/src/client/scss/app.scss +++ b/src/client/scss/app.scss @@ -93,6 +93,16 @@ ul, ol { a { color: $color-dark-gray; + + &:focus { + opacity: .8; + outline: none; + } + + &:active { + opacity: .7; + outline: none; + } } svg { diff --git a/src/client/scss/vars.scss b/src/client/scss/vars.scss index fd18a4760a..4440d6bbc3 100644 --- a/src/client/scss/vars.scss +++ b/src/client/scss/vars.scss @@ -42,6 +42,7 @@ $color-background-gray : #F3F3F3; $color-red : #ff6f76; $color-yellow : #FDFFA4; $color-green : #B2FFD6; +$color-purple : #F3DDF3; ////////////////////////////// // STYLES diff --git a/src/fields/richText/defaultValue.js b/src/fields/richText/defaultValue.js new file mode 100644 index 0000000000..cc7d0f9f66 --- /dev/null +++ b/src/fields/richText/defaultValue.js @@ -0,0 +1,3 @@ +export default [{ + children: [{ text: '' }], +}]; diff --git a/src/fields/validations.js b/src/fields/validations.js index 2d2f3095f9..018d33f7f2 100644 --- a/src/fields/validations.js +++ b/src/fields/validations.js @@ -1,3 +1,5 @@ +const defaultRichTextValue = require('./richText/defaultValue'); + const defaultMessage = 'This field is required.'; const optionsToValidatorMap = { @@ -92,15 +94,9 @@ const optionsToValidatorMap = { return true; }, richText: (value, options) => { - //! Need better way to share an empty text node - //! it is used here and in field-types/RichText - const emptyRichTextNode = [{ - children: [{ text: '' }], - }]; - if (options.required) { - const blankSlateJSNode = JSON.stringify(emptyRichTextNode); - if (value && JSON.stringify(value) !== blankSlateJSNode) return true; + const stringifiedDefaultValue = JSON.stringify(defaultRichTextValue); + if (value && JSON.stringify(value) !== stringifiedDefaultValue) return true; return 'This field is required.'; }