Add growing textarea component
This commit is contained in:
commit
9cbef1d0b7
|
@ -77,10 +77,9 @@
|
|||
|
||||
.titleInput,
|
||||
.subtitleInput {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
padding: 0;
|
||||
font-size: 36px;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 1.2rem;
|
||||
|
||||
&::placeholder {
|
||||
opacity: 0.3;
|
||||
|
@ -93,6 +92,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
//Grow input
|
||||
|
||||
.editSettings,
|
||||
.edit {
|
||||
display: none;
|
||||
|
|
|
@ -14,6 +14,7 @@ import { useSession } from '../../context/session'
|
|||
import { Modal } from '../Nav/Modal'
|
||||
import { hideModal, showModal } from '../../stores/ui'
|
||||
import { imageProxy } from '../../utils/imageProxy'
|
||||
import { GrowingTextarea } from '../_shared/GrowingTextarea'
|
||||
|
||||
type EditViewProps = {
|
||||
shout: Shout
|
||||
|
@ -73,11 +74,10 @@ export const EditView = (props: EditViewProps) => {
|
|||
})
|
||||
})
|
||||
|
||||
const handleTitleInputChange = (e) => {
|
||||
const title = e.currentTarget.value
|
||||
setForm('title', title)
|
||||
const handleTitleInputChange = (value) => {
|
||||
setForm('title', value)
|
||||
|
||||
if (title) {
|
||||
if (value) {
|
||||
setFormErrors('title', '')
|
||||
}
|
||||
}
|
||||
|
@ -139,30 +139,21 @@ export const EditView = (props: EditViewProps) => {
|
|||
})}
|
||||
>
|
||||
<div class={styles.inputContainer}>
|
||||
<input
|
||||
<GrowingTextarea
|
||||
value={(value) => handleTitleInputChange(value)}
|
||||
class={styles.titleInput}
|
||||
type="text"
|
||||
name="title"
|
||||
id="title"
|
||||
placeholder={t('Header')}
|
||||
autocomplete="off"
|
||||
value={form.title}
|
||||
onInput={handleTitleInputChange}
|
||||
initialValue={form.title}
|
||||
/>
|
||||
<Show when={formErrors.title}>
|
||||
<div class={styles.validationError}>{formErrors.title}</div>
|
||||
</Show>
|
||||
</div>
|
||||
|
||||
<input
|
||||
<GrowingTextarea
|
||||
value={(value) => setForm('subtitle', value)}
|
||||
class={styles.subtitleInput}
|
||||
type="text"
|
||||
name="subtitle"
|
||||
id="subtitle"
|
||||
autocomplete="off"
|
||||
placeholder={t('Subheader')}
|
||||
value={form.subtitle}
|
||||
onChange={(e) => setForm('subtitle', e.currentTarget.value)}
|
||||
initialValue={form.subtitle}
|
||||
/>
|
||||
<Editor
|
||||
shoutId={props.shout.id}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
.GrowingTextarea {
|
||||
display: block;
|
||||
width: 100%;
|
||||
|
||||
.growWrap {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
|
||||
&::after {
|
||||
content: attr(data-replicated-value);
|
||||
visibility: hidden;
|
||||
transition: height 0.3s linear;
|
||||
}
|
||||
|
||||
.textInput {
|
||||
margin-bottom: 0;
|
||||
border: none;
|
||||
resize: none;
|
||||
overflow: hidden;
|
||||
&::placeholder {
|
||||
color: #858585;
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:focus-visible,
|
||||
&:active {
|
||||
border: none;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&::after,
|
||||
& .textInput {
|
||||
/* Identical styling required!! */
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
44
src/components/_shared/GrowingTextarea/GrowingTextarea.tsx
Normal file
44
src/components/_shared/GrowingTextarea/GrowingTextarea.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { clsx } from 'clsx'
|
||||
import styles from './GrowingTextarea.module.scss'
|
||||
import { createEffect, createSignal } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
class?: string
|
||||
placeholder: string
|
||||
initialValue?: string
|
||||
value: (string) => void
|
||||
}
|
||||
|
||||
export const GrowingTextarea = (props: Props) => {
|
||||
const [value, setValue] = createSignal('')
|
||||
const handleChangeValue = (event) => {
|
||||
setValue(event.target.value)
|
||||
props.value(event.target.value)
|
||||
}
|
||||
|
||||
const handleKeyDown = async (event) => {
|
||||
if (event.key === 'Enter' && event.shiftKey) {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === 'Enter' && !event.shiftKey && value()?.trim().length > 0) {
|
||||
event.preventDefault()
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={clsx(styles.GrowingTextarea)}>
|
||||
<div class={clsx(styles.growWrap, props.class)} data-replicated-value={value()}>
|
||||
<textarea
|
||||
rows={1}
|
||||
autocomplete="off"
|
||||
class={clsx(styles.textInput, props.class)}
|
||||
value={props.initialValue}
|
||||
onKeyDown={handleKeyDown}
|
||||
onInput={(event) => handleChangeValue(event)}
|
||||
placeholder={props.placeholder}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
1
src/components/_shared/GrowingTextarea/index.ts
Normal file
1
src/components/_shared/GrowingTextarea/index.ts
Normal file
|
@ -0,0 +1 @@
|
|||
export { GrowingTextarea } from './GrowingTextarea'
|
Loading…
Reference in New Issue
Block a user