gristlabs_grist-core/app/client/components/Forms/Paragraph.ts
Jarosław Sadziński a424450cbe (core) Forms feature
Summary:
A new widget type Forms. For now hidden behind GRIST_EXPERIMENTAL_PLUGINS().
This diff contains all the core moving parts as a serves as a base to extend this functionality
further.

Test Plan: New test added

Reviewers: georgegevoian

Reviewed By: georgegevoian

Subscribers: paulfitz

Differential Revision: https://phab.getgrist.com/D4130
2023-12-20 13:23:12 +01:00

95 lines
2.6 KiB
TypeScript

import * as css from './styles';
import {BoxModel, RenderContext} from 'app/client/components/Forms/Model';
import {textarea} from 'app/client/ui/inputs';
import {theme} from 'app/client/ui2018/cssVars';
import {Computed, dom, Observable, styled} from 'grainjs';
export class ParagraphModel extends BoxModel {
public edit = Observable.create(this, false);
public render(context: RenderContext) {
const box = this;
context.overlay.set(false);
const editMode = box.edit;
let element: HTMLElement;
const text = this.prop('text', '**Lorem** _ipsum_ dolor') as Observable<string|undefined>;
const properText = Computed.create(this, (use) => {
const savedText = use(text);
if (!savedText) { return ''; }
if (typeof savedText !== 'string') { return ''; }
return savedText;
});
properText.onWrite((val) => {
if (typeof val !== 'string') { return; }
text.set(val);
this.parent?.save().catch(reportError);
});
box.edit.addListener((val) => {
if (!val) { return; }
setTimeout(() => element.focus(), 0);
});
return css.cssStaticText(
css.markdown(use => use(properText) || '', dom.cls('_preview'), dom.hide(editMode)),
dom.maybe(use => !use(properText) && !use(editMode), () => cssEmpty('(empty)')),
dom.on('dblclick', () => {
editMode.set(true);
}),
css.cssStaticText.cls('-edit', editMode),
dom.maybe(editMode, () => [
cssTextArea(properText, {},
(el) => {
element = el;
},
dom.onKeyDown({
Enter$: (ev) => {
// if shift ignore
if (ev.shiftKey) {
return;
}
ev.stopPropagation();
ev.preventDefault();
editMode.set(false);
},
Escape$: (ev) => {
ev.stopPropagation();
ev.preventDefault();
editMode.set(false);
}
}),
dom.on('blur', () => {
editMode.set(false);
}),
),
])
);
}
}
const cssTextArea = styled(textarea, `
color: ${theme.inputFg};
background-color: ${theme.mainPanelBg};
border: 0px;
width: 100%;
padding: 3px 6px;
outline: none;
max-height: 300px;
min-height: calc(3em * 1.5);
resize: none;
border-radius: 3px;
&::placeholder {
color: ${theme.inputPlaceholderFg};
}
&[readonly] {
background-color: ${theme.inputDisabledBg};
color: ${theme.inputDisabledFg};
}
`);
const cssEmpty = styled('div', `
color: ${theme.inputPlaceholderFg};
font-style: italic;
`);