From 096c06c2da66b7f0ba98e4554ae1f20b1b589f4d Mon Sep 17 00:00:00 2001 From: kc-leung Date: Thu, 12 May 2022 15:34:54 -0400 Subject: [PATCH 1/7] editable-title - replace with borderless textfield --- src/view/title-bar/editable-title.js | 83 ++++++++++++++-------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/src/view/title-bar/editable-title.js b/src/view/title-bar/editable-title.js index c4c1a8f4f..1da7712fd 100644 --- a/src/view/title-bar/editable-title.js +++ b/src/view/title-bar/editable-title.js @@ -29,63 +29,41 @@ const commonClasses = { }, } -const useStyles = (mode) => makeStyles( - mode === modes.EDITOR - ? { - title: { - display: 'flex', - alignItems: 'center', - color: getTailwindConfigColor('secondary-600'), - fontWeight: 700, - background: getTailwindConfigColor('secondary-100'), - fontSize: '0.875rem', - padding: '0.2rem 0.4rem', - paddingLeft: '0.6rem', - cursor: 'default', - }, - ...commonClasses, - } - : { - title: { - color: getTailwindConfigColor('primary-500'), - fontSize: '1.125rem', - fontWeight: 700, - }, - ...commonClasses, - } +const useStyles = () => makeStyles( + { + title: { + color: getTailwindConfigColor('primary-500'), + fontSize: '1.125rem', + fontWeight: 700, + }, + ...commonClasses, + }, ) +const textFieldClasses = Object.freeze({ + container: 'bg-secondary-100', + input: 'mb-0 text-sm text-secondary-600' +}) + const EditableTitle = () => { const userUpdate = useStoreActions((actions) => actions.userUpdate) const isLoading = useStoreState((state) => state.isLoading) const title = useStoreState((state) => state.title) const mode = useStoreState((state) => state.ui.mode) - const classes = useStyles(mode) + const classes = useStyles() const [editing, setEditing] = useState(false) const [tentativeTitle, setTentativeTitle] = useState(title) + useEffect(() => { setTentativeTitle(title) }, [title]) - const renderEditButton = ( - setEditing(true)} - endIcon={} - /> - ) const renderTitle = ( -
+
{isLoading ? '...' : title} - { - (mode === modes.QL || mode === modes.EDITOR) && - renderEditButton - }
) @@ -94,7 +72,7 @@ const EditableTitle = () => { return (
{ - editing + mode === modes.EDITOR ?
{ @@ -106,7 +84,7 @@ const EditableTitle = () => { setEditing(false) }} > - { setTentativeTitle(title) setEditing(false) }} + /> */} + setTentativeTitle(v)} + onFocus={(e) => { + e.nativeEvent.preventDefault() + e.nativeEvent.stopPropagation() + setEditing(true) + }} + onBlur={(e) => { + e.nativeEvent.preventDefault() + e.nativeEvent.stopPropagation() + updateTitle(e.target.value) + setTentativeTitle(title) + setEditing(false) + }} + deleteButton={editing} /> - : <> + : + <> {renderTitle} } From 18fa8399ca5c01ced331db04f072a30d4722c387 Mon Sep 17 00:00:00 2001 From: kc-leung Date: Thu, 12 May 2022 17:09:44 -0400 Subject: [PATCH 2/7] editable-title - auto width on input --- src/view/title-bar/editable-title.js | 101 +++++++++++++-------------- 1 file changed, 47 insertions(+), 54 deletions(-) diff --git a/src/view/title-bar/editable-title.js b/src/view/title-bar/editable-title.js index 1da7712fd..2ff647112 100644 --- a/src/view/title-bar/editable-title.js +++ b/src/view/title-bar/editable-title.js @@ -1,9 +1,9 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useRef } from 'react' -import { Icons, TextField, makeStyles, getTailwindConfigColor } from '@eqworks/lumen-labs' +import { TextField, makeStyles, getTailwindConfigColor } from '@eqworks/lumen-labs' import { useStoreState, useStoreActions } from '../../store' -import CustomButton from '../../components/custom-button' + import modes from '../../constants/modes' @@ -42,7 +42,7 @@ const useStyles = () => makeStyles( const textFieldClasses = Object.freeze({ container: 'bg-secondary-100', - input: 'mb-0 text-sm text-secondary-600' + input: 'mb-0 text-sm text-secondary-600', }) const EditableTitle = () => { @@ -56,71 +56,64 @@ const EditableTitle = () => { const [editing, setEditing] = useState(false) const [tentativeTitle, setTentativeTitle] = useState(title) + const textfieldRef = useRef(null) + useEffect(() => { setTentativeTitle(title) }, [title]) - const renderTitle = (
{isLoading ? '...' : title}
) + const renderTextfield = () => { + if (textfieldRef.current) { + let el = textfieldRef.current.childNodes[0][0] + el.style.width = `${(el.value.length + 1) * 8}px` + } + + return ( + setTentativeTitle(v)} + onFocus={(e) => { + e.preventDefault() + e.stopPropagation() + e.nativeEvent.preventDefault() + e.nativeEvent.stopPropagation() + setEditing(true) + }} + onBlur={(e) => { + e.preventDefault() + e.stopPropagation() + e.nativeEvent.preventDefault() + e.nativeEvent.stopPropagation() + updateTitle(e.target.value) + setEditing(false) + }} + deleteButton={editing} + /> + ) + } + const updateTitle = title => userUpdate({ title }) return ( -
+
{ mode === modes.EDITOR - ?
{ - e.preventDefault() - e.stopPropagation() - e.nativeEvent.preventDefault() - e.nativeEvent.stopPropagation() - updateTitle(e.target.children[0].children[0].value) - setEditing(false) - }} - > - {/* setTentativeTitle(v)} - onSubmit={(e) => { - e.nativeEvent.preventDefault() - e.nativeEvent.stopPropagation() - }} - onBlur={(e) => { - updateTitle(e.target.value) - setTentativeTitle(title) - setEditing(false) - }} - /> */} - setTentativeTitle(v)} - onFocus={(e) => { - e.nativeEvent.preventDefault() - e.nativeEvent.stopPropagation() - setEditing(true) - }} - onBlur={(e) => { - e.nativeEvent.preventDefault() - e.nativeEvent.stopPropagation() - updateTitle(e.target.value) - setTentativeTitle(title) - setEditing(false) - }} - deleteButton={editing} - /> - - : + ? + <> + {renderTextfield()} + + : <> {renderTitle} From 06d765e2eaa39197845e8d07204fd139cd98c4ac Mon Sep 17 00:00:00 2001 From: kc-leung Date: Tue, 24 May 2022 14:29:07 -0400 Subject: [PATCH 3/7] editable-title - fix title auto width & add onDelete update --- src/view/title-bar/editable-title.js | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/view/title-bar/editable-title.js b/src/view/title-bar/editable-title.js index 2ff647112..7f752d23f 100644 --- a/src/view/title-bar/editable-title.js +++ b/src/view/title-bar/editable-title.js @@ -3,7 +3,6 @@ import React, { useState, useEffect, useRef } from 'react' import { TextField, makeStyles, getTailwindConfigColor } from '@eqworks/lumen-labs' import { useStoreState, useStoreActions } from '../../store' - import modes from '../../constants/modes' @@ -71,7 +70,7 @@ const EditableTitle = () => { const renderTextfield = () => { if (textfieldRef.current) { let el = textfieldRef.current.childNodes[0][0] - el.style.width = `${(el.value.length + 1) * 8}px` + el.style.width = `${(el.value.length + 2) * 8}px` } return ( @@ -79,7 +78,16 @@ const EditableTitle = () => { variant='borderless' classes={textFieldClasses} value={tentativeTitle} - onChange={(v) => setTentativeTitle(v)} + onChange={(v) => { + setTentativeTitle(v) + }} + onBlur={(e) => { + e.preventDefault() + e.stopPropagation() + e.nativeEvent.preventDefault() + e.nativeEvent.stopPropagation() + setEditing(false) + }} onFocus={(e) => { e.preventDefault() e.stopPropagation() @@ -87,15 +95,14 @@ const EditableTitle = () => { e.nativeEvent.stopPropagation() setEditing(true) }} - onBlur={(e) => { + deleteButton={editing} + onDelete={(e) => { e.preventDefault() e.stopPropagation() e.nativeEvent.preventDefault() e.nativeEvent.stopPropagation() - updateTitle(e.target.value) - setEditing(false) + updateTitle('') }} - deleteButton={editing} /> ) } From ff66d96f51f7b412c62c61af1513d2a3f9ab1504 Mon Sep 17 00:00:00 2001 From: kc-leung Date: Wed, 25 May 2022 14:23:04 -0400 Subject: [PATCH 4/7] editable-title - fix title styling yarn lint --fix --- src/view/title-bar/editable-title.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/view/title-bar/editable-title.js b/src/view/title-bar/editable-title.js index 7f752d23f..1c3627b58 100644 --- a/src/view/title-bar/editable-title.js +++ b/src/view/title-bar/editable-title.js @@ -12,6 +12,10 @@ const commonClasses = { alignItems: 'center', margin: '0 0.6rem', display: 'flex', + + '& .textfield-container': { + backgroundColor: getTailwindConfigColor('secondary-100'), + }, }, button: { marginLeft: '0.4rem', @@ -40,8 +44,9 @@ const useStyles = () => makeStyles( ) const textFieldClasses = Object.freeze({ - container: 'bg-secondary-100', - input: 'mb-0 text-sm text-secondary-600', + container: 'textfield-container', + root: 'focus-within:border-primary-500', + input: 'mb-0 text-sm focus:text-secondary-900', }) const EditableTitle = () => { From b927ac00160a4bae53ffcbb4e3819d712458d6d0 Mon Sep 17 00:00:00 2001 From: kc-leung Date: Mon, 22 Aug 2022 15:53:07 -0400 Subject: [PATCH 5/7] editable-table - add getTextSize string manipulation --- src/util/string-manipulation.js | 54 ++++++++++++++++++++++++++++ src/view/title-bar/editable-title.js | 4 ++- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/util/string-manipulation.js b/src/util/string-manipulation.js index 6afde59e5..6b635e81d 100644 --- a/src/util/string-manipulation.js +++ b/src/util/string-manipulation.js @@ -76,3 +76,57 @@ export const truncateString = (fullStr, strLen, separator = ' ... ') => { * @returns { string } - capitalized string */ export const capitalize = s => (s?.[0]?.toUpperCase() + s?.slice(1)) || '' + +// "vendored" from https://github.com/mdevils/html-entities/blob/68a1a96/src/xml-entities.ts +const decodeXML = (str) => { + const ALPHA_INDEX = { + '<': '<', + '>': '>', + '"': '"', + '&apos': '\'', + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': '\'', + '&': '&', + } + if (!str || !str.length) { + return '' + } + return str.replace(/&#?[0-9a-zA-Z]+;?/g, (s) => { + if (s.charAt(1) === '#') { + const code = s.charAt(2).toLowerCase() === 'x' ? + parseInt(s.substr(3), 16) : + parseInt(s.substr(2)) + + if (isNaN(code) || code < -32768 || code > 65535) { + return '' + } + return String.fromCharCode(code) + } + return ALPHA_INDEX[s] || s + }) +} + +/** + * https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/50813259#50813259 + * getTextSize - calculates a rendered text width and height in rem + * @param { string } text - a text string + * @param { number || string } fontWeight - text's font weight + * @param { number } fontSize - text's font size in pixels + * @param { string } fontFamily - text's font family + * @returns { object } - the width and height of the rendered text in rem + */ +export const getTextSize = (text, fontWeight, fontSize, fontFamily) => { + let font = `${fontWeight} ${fontSize}px ${fontFamily}` + let canvas = document.createElement('canvas') + let context = canvas.getContext('2d') + context.font = font + let metrics = typeof text === 'number' + ? context.measureText(text) + : context.measureText(decodeXML(text)) + return { + width: metrics.width, + } +} \ No newline at end of file diff --git a/src/view/title-bar/editable-title.js b/src/view/title-bar/editable-title.js index 1c3627b58..00daf0014 100644 --- a/src/view/title-bar/editable-title.js +++ b/src/view/title-bar/editable-title.js @@ -4,6 +4,7 @@ import { TextField, makeStyles, getTailwindConfigColor } from '@eqworks/lumen-la import { useStoreState, useStoreActions } from '../../store' import modes from '../../constants/modes' +import { getTextSize } from '../../util/string-manipulation' const commonClasses = { @@ -75,7 +76,8 @@ const EditableTitle = () => { const renderTextfield = () => { if (textfieldRef.current) { let el = textfieldRef.current.childNodes[0][0] - el.style.width = `${(el.value.length + 2) * 8}px` + el.style.width = `${getTextSize(el.value, 700, 16, 'Open Sans').width}px` + // console.log(getTextSize(el.value, 700, 20, 'Open Sans')) } return ( From 281324a315dae1f0f8a94b31267d4b75047bd840 Mon Sep 17 00:00:00 2001 From: kc-leung Date: Tue, 23 Aug 2022 16:37:26 -0400 Subject: [PATCH 6/7] editable-title - rebase and on focus styling fix --- src/util/string-manipulation.js | 2 +- src/view/title-bar/editable-title.js | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/util/string-manipulation.js b/src/util/string-manipulation.js index 6b635e81d..8a7ffc69c 100644 --- a/src/util/string-manipulation.js +++ b/src/util/string-manipulation.js @@ -129,4 +129,4 @@ export const getTextSize = (text, fontWeight, fontSize, fontFamily) => { return { width: metrics.width, } -} \ No newline at end of file +} diff --git a/src/view/title-bar/editable-title.js b/src/view/title-bar/editable-title.js index 00daf0014..c37a4a4a6 100644 --- a/src/view/title-bar/editable-title.js +++ b/src/view/title-bar/editable-title.js @@ -16,6 +16,16 @@ const commonClasses = { '& .textfield-container': { backgroundColor: getTailwindConfigColor('secondary-100'), + + '& .textfield-root': { + outlineWidth: 0, + outlineColor: 'transparent', + borderTop: 0, + }, + + '& .textfield-root:focus-within': { + borderColor: getTailwindConfigColor('primary-500'), + }, }, }, button: { @@ -46,8 +56,8 @@ const useStyles = () => makeStyles( const textFieldClasses = Object.freeze({ container: 'textfield-container', - root: 'focus-within:border-primary-500', - input: 'mb-0 text-sm focus:text-secondary-900', + root: 'textfield-root', + input: 'textfield-input mb-0 text-sm focus:text-secondary-900', }) const EditableTitle = () => { @@ -76,8 +86,8 @@ const EditableTitle = () => { const renderTextfield = () => { if (textfieldRef.current) { let el = textfieldRef.current.childNodes[0][0] - el.style.width = `${getTextSize(el.value, 700, 16, 'Open Sans').width}px` - // console.log(getTextSize(el.value, 700, 20, 'Open Sans')) + const lengthSize = el.value.length > 12 ? 14 : 16 + el.style.width = `${getTextSize(el.value, 700, lengthSize, 'Open Sans').width}px` } return ( From 34d9d8fdaf9f78a5bbd87113ee0fb341c271c086 Mon Sep 17 00:00:00 2001 From: kc-leung Date: Wed, 24 Aug 2022 10:19:36 -0400 Subject: [PATCH 7/7] editable-title - set font-family for input field editable-title - fix outline on focus for input field --- src/view/title-bar/editable-title.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/view/title-bar/editable-title.js b/src/view/title-bar/editable-title.js index c37a4a4a6..6d435113a 100644 --- a/src/view/title-bar/editable-title.js +++ b/src/view/title-bar/editable-title.js @@ -18,9 +18,13 @@ const commonClasses = { backgroundColor: getTailwindConfigColor('secondary-100'), '& .textfield-root': { - outlineWidth: 0, - outlineColor: 'transparent', borderTop: 0, + + '& .textfield-input': { + fontFamily: 'Open Sans', + outlineWidth: 0, + outlineColor: 'transparent', + }, }, '& .textfield-root:focus-within': {