mirror of
https://github.com/IgnatZakalinsky/home-works.git
synced 2025-12-17 12:31:15 +00:00
hw6
This commit is contained in:
@@ -15,7 +15,6 @@ type SuperInputTextPropsType = Omit<DefaultInputPropsType, 'type'> & { // и +
|
|||||||
|
|
||||||
const SuperInputText: React.FC<SuperInputTextPropsType> = (
|
const SuperInputText: React.FC<SuperInputTextPropsType> = (
|
||||||
{
|
{
|
||||||
// type, // достаём и игнорируем чтоб нельзя было задать другой тип инпута
|
|
||||||
onChange, onChangeText,
|
onChange, onChangeText,
|
||||||
onKeyPress, onEnter,
|
onKeyPress, onEnter,
|
||||||
error,
|
error,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react'
|
|||||||
|
|
||||||
const Error404 = () => {
|
const Error404 = () => {
|
||||||
return (
|
return (
|
||||||
<div id={'page-404'}>
|
<div id={'hw5-page-404'}>
|
||||||
<div>404</div>
|
<div>404</div>
|
||||||
<div>Page not found!</div>
|
<div>Page not found!</div>
|
||||||
<div>—ฅ/ᐠ.̫ .ᐟ\ฅ—</div>
|
<div>—ฅ/ᐠ.̫ .ᐟ\ฅ—</div>
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import HW6 from '../../hw06/HW6'
|
||||||
|
|
||||||
function Junior() {
|
function Junior() {
|
||||||
return (
|
return (
|
||||||
<div id={'hw5-page-junior'}>
|
<div id={'hw5-page-junior'}>
|
||||||
junior page
|
junior page
|
||||||
{/*<HW6/>*/}
|
<HW6/>
|
||||||
{/*<HW7/>*/}
|
{/*<HW7/>*/}
|
||||||
{/*<HW8/>*/}
|
{/*<HW8/>*/}
|
||||||
{/*<HW9/>*/}
|
{/*<HW9/>*/}
|
||||||
|
|||||||
44
src/s2-homeworks/hw06/HW6.tsx
Normal file
44
src/s2-homeworks/hw06/HW6.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import React, {useState} from 'react'
|
||||||
|
import SuperEditableSpan from './common/c4-SuperEditableSpan/SuperEditableSpan'
|
||||||
|
import {restoreState, saveState} from './localStorage/localStorage'
|
||||||
|
import s2 from '../../s1-main/App.module.css'
|
||||||
|
import SuperButton from '../hw04/common/c2-SuperButton/SuperButton'
|
||||||
|
|
||||||
|
const HW6 = () => {
|
||||||
|
const [value, setValue] = useState<string>('')
|
||||||
|
|
||||||
|
const save = () => {
|
||||||
|
saveState<string>('hw6-editable-span-value', value)
|
||||||
|
}
|
||||||
|
const restore = () => { // делают студенты
|
||||||
|
setValue(restoreState<string>('hw6-editable-span-value', ''))
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div id={'hw6'} className={s2.hw}>
|
||||||
|
<hr/>
|
||||||
|
{/*можно убрать этот тег*/}
|
||||||
|
|
||||||
|
<div className={s2.hwTitle}>homeworks 6</div>
|
||||||
|
|
||||||
|
{/*should work (должно работать)*/}
|
||||||
|
<div>
|
||||||
|
<SuperEditableSpan
|
||||||
|
id={'hw6-spanable-input'}
|
||||||
|
value={value}
|
||||||
|
onChangeText={setValue}
|
||||||
|
spanProps={{children: value ? undefined : 'enter text...', id: 'hw6-editable-span'}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<SuperButton id={'hw6-save'} onClick={save}>save to ls</SuperButton>
|
||||||
|
<SuperButton id={'hw6-restore'} onClick={restore}>get from ls</SuperButton>
|
||||||
|
|
||||||
|
<hr/>
|
||||||
|
{/*можно убрать этот тег*/}
|
||||||
|
<hr/>
|
||||||
|
{/*можно убрать этот тег*/}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HW6
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
.span {
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
height: 31px;
|
||||||
|
padding-top: 10px;
|
||||||
|
|
||||||
|
cursor: pointer;
|
||||||
|
color: #77aaff;
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import React, {DetailedHTMLProps, InputHTMLAttributes, HTMLAttributes, useState} from 'react'
|
||||||
|
import s from './SuperEditableSpan.module.css'
|
||||||
|
import SuperInputText from '../../../hw04/common/c1-SuperInputText/SuperInputText'
|
||||||
|
|
||||||
|
// тип пропсов обычного инпута
|
||||||
|
type DefaultInputPropsType = DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>
|
||||||
|
// тип пропсов обычного спана
|
||||||
|
type DefaultSpanPropsType = DetailedHTMLProps<HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>
|
||||||
|
|
||||||
|
// здесь мы говорим что у нашего инпута будут такие же пропсы как у обычного инпута, кроме type
|
||||||
|
// (чтоб не писать value: string, onChange: ...; они уже все описаны в DefaultInputPropsType)
|
||||||
|
type SuperEditableSpanType = Omit<DefaultInputPropsType, 'type'> & { // и + ещё пропсы которых нет в стандартном инпуте
|
||||||
|
onChangeText?: (value: string) => void
|
||||||
|
onEnter?: () => void
|
||||||
|
error?: string
|
||||||
|
|
||||||
|
spanProps?: DefaultSpanPropsType // пропсы для спана
|
||||||
|
}
|
||||||
|
|
||||||
|
const SuperEditableSpan: React.FC<SuperEditableSpanType> = (
|
||||||
|
{
|
||||||
|
autoFocus,
|
||||||
|
onBlur,
|
||||||
|
onEnter,
|
||||||
|
spanProps,
|
||||||
|
|
||||||
|
...restProps// все остальные пропсы попадут в объект restProps
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
const [editMode, setEditMode] = useState<boolean>(false)
|
||||||
|
const {children, onDoubleClick, className, ...restSpanProps} = spanProps || {}
|
||||||
|
|
||||||
|
const onEnterCallback = () => {
|
||||||
|
setEditMode(false) // выключить editMode при нажатии Enter // делают студенты
|
||||||
|
|
||||||
|
onEnter?.()
|
||||||
|
}
|
||||||
|
const onBlurCallback = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||||
|
setEditMode(false) // выключить editMode при нажатии за пределами инпута // делают студенты
|
||||||
|
|
||||||
|
onBlur?.(e)
|
||||||
|
}
|
||||||
|
const onDoubleClickCallBack = (e: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
|
||||||
|
setEditMode(true) // включить editMode при двойном клике // делают студенты
|
||||||
|
|
||||||
|
onDoubleClick?.(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
const spanClassName = `${s.span} ${className ? className : ''}`
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{editMode
|
||||||
|
? (
|
||||||
|
<SuperInputText
|
||||||
|
autoFocus={autoFocus || true}
|
||||||
|
onBlur={onBlurCallback}
|
||||||
|
onEnter={onEnterCallback}
|
||||||
|
|
||||||
|
{...restProps} // отдаём инпуту остальные пропсы если они есть (value например там внутри)
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<span
|
||||||
|
onDoubleClick={onDoubleClickCallBack}
|
||||||
|
className={spanClassName}
|
||||||
|
|
||||||
|
{...restSpanProps}
|
||||||
|
>
|
||||||
|
{/*если нет захардкодженного текста для спана, то значение инпута*/}
|
||||||
|
✎ {children || restProps.value}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SuperEditableSpan
|
||||||
27
src/s2-homeworks/hw06/localStorage/localStorage.ts
Normal file
27
src/s2-homeworks/hw06/localStorage/localStorage.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// вот вам функция для сохранения объектов в память браузера
|
||||||
|
// (данные в этом хранилище сохраняться даже при перезагрузке компа):
|
||||||
|
export function saveState<T>(key: string, state: T) {
|
||||||
|
const stateAsString = JSON.stringify(state)
|
||||||
|
localStorage.setItem(key, stateAsString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// и вот вам функция для получения сохранённого объекта в памяти браузера:
|
||||||
|
export function restoreState<T>(key: string, defaultState: T) {
|
||||||
|
let state = defaultState
|
||||||
|
const stateAsString = localStorage.getItem(key)
|
||||||
|
if (stateAsString !== null) state = JSON.parse(stateAsString) as T
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------------------------------------------
|
||||||
|
// пример использования:
|
||||||
|
type StateType = {
|
||||||
|
x: string
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
|
||||||
|
// сохраняем объект типа StateType в ячейке 'test'
|
||||||
|
saveState<StateType>('test', {x: 'A', y: 1})
|
||||||
|
|
||||||
|
// получем в переменную state объект из ячейки 'test' или дэфолтный объект если ячейка пуста
|
||||||
|
const state: StateType = restoreState<StateType>('test', {x: '', y: 0})
|
||||||
Reference in New Issue
Block a user