Add growing textarea component
This commit is contained in:
commit
9cbef1d0b7
|
@ -77,10 +77,9 @@
|
||||||
|
|
||||||
.titleInput,
|
.titleInput,
|
||||||
.subtitleInput {
|
.subtitleInput {
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
|
line-height: 1.1;
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
|
|
||||||
&::placeholder {
|
&::placeholder {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
|
@ -93,6 +92,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Grow input
|
||||||
|
|
||||||
.editSettings,
|
.editSettings,
|
||||||
.edit {
|
.edit {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { useSession } from '../../context/session'
|
||||||
import { Modal } from '../Nav/Modal'
|
import { Modal } from '../Nav/Modal'
|
||||||
import { hideModal, showModal } from '../../stores/ui'
|
import { hideModal, showModal } from '../../stores/ui'
|
||||||
import { imageProxy } from '../../utils/imageProxy'
|
import { imageProxy } from '../../utils/imageProxy'
|
||||||
|
import { GrowingTextarea } from '../_shared/GrowingTextarea'
|
||||||
|
|
||||||
type EditViewProps = {
|
type EditViewProps = {
|
||||||
shout: Shout
|
shout: Shout
|
||||||
|
@ -73,11 +74,10 @@ export const EditView = (props: EditViewProps) => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleTitleInputChange = (e) => {
|
const handleTitleInputChange = (value) => {
|
||||||
const title = e.currentTarget.value
|
setForm('title', value)
|
||||||
setForm('title', title)
|
|
||||||
|
|
||||||
if (title) {
|
if (value) {
|
||||||
setFormErrors('title', '')
|
setFormErrors('title', '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,30 +139,21 @@ export const EditView = (props: EditViewProps) => {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<div class={styles.inputContainer}>
|
<div class={styles.inputContainer}>
|
||||||
<input
|
<GrowingTextarea
|
||||||
|
value={(value) => handleTitleInputChange(value)}
|
||||||
class={styles.titleInput}
|
class={styles.titleInput}
|
||||||
type="text"
|
|
||||||
name="title"
|
|
||||||
id="title"
|
|
||||||
placeholder={t('Header')}
|
placeholder={t('Header')}
|
||||||
autocomplete="off"
|
initialValue={form.title}
|
||||||
value={form.title}
|
|
||||||
onInput={handleTitleInputChange}
|
|
||||||
/>
|
/>
|
||||||
<Show when={formErrors.title}>
|
<Show when={formErrors.title}>
|
||||||
<div class={styles.validationError}>{formErrors.title}</div>
|
<div class={styles.validationError}>{formErrors.title}</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
<GrowingTextarea
|
||||||
<input
|
value={(value) => setForm('subtitle', value)}
|
||||||
class={styles.subtitleInput}
|
class={styles.subtitleInput}
|
||||||
type="text"
|
|
||||||
name="subtitle"
|
|
||||||
id="subtitle"
|
|
||||||
autocomplete="off"
|
|
||||||
placeholder={t('Subheader')}
|
placeholder={t('Subheader')}
|
||||||
value={form.subtitle}
|
initialValue={form.subtitle}
|
||||||
onChange={(e) => setForm('subtitle', e.currentTarget.value)}
|
|
||||||
/>
|
/>
|
||||||
<Editor
|
<Editor
|
||||||
shoutId={props.shout.id}
|
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