2023-03-01 15:21:19 +00:00
|
|
|
import {makeT} from 'app/client/lib/localization';
|
2023-08-28 09:16:17 +00:00
|
|
|
import {KoSaveableObservable} from 'app/client/models/modelUtil';
|
2023-04-19 10:17:22 +00:00
|
|
|
import {autoGrow} from 'app/client/ui/forms';
|
2023-12-12 09:58:20 +00:00
|
|
|
import {textarea, textInput} from 'app/client/ui/inputs';
|
2023-03-01 15:21:19 +00:00
|
|
|
import {cssLabel, cssRow} from 'app/client/ui/RightPanelStyles';
|
|
|
|
import {testId, theme} from 'app/client/ui2018/cssVars';
|
2023-08-28 09:16:17 +00:00
|
|
|
import {CursorPos} from 'app/plugin/GristAPI';
|
2023-12-12 09:58:20 +00:00
|
|
|
import {dom, DomArg, fromKo, MultiHolder, styled} from 'grainjs';
|
2023-03-01 15:21:19 +00:00
|
|
|
|
2023-05-12 13:08:28 +00:00
|
|
|
const t = makeT('DescriptionConfig');
|
2023-03-01 15:21:19 +00:00
|
|
|
|
|
|
|
export function buildDescriptionConfig(
|
2023-12-12 09:58:20 +00:00
|
|
|
owner: MultiHolder,
|
|
|
|
description: KoSaveableObservable<string>,
|
|
|
|
options: {
|
|
|
|
cursor: ko.Computed<CursorPos>,
|
|
|
|
testPrefix: string,
|
|
|
|
},
|
|
|
|
) {
|
2023-03-01 15:21:19 +00:00
|
|
|
|
2023-12-12 09:58:20 +00:00
|
|
|
// We will listen to cursor position and force a blur event on
|
|
|
|
// the text input, which will trigger save before the column observable
|
|
|
|
// will change its value.
|
|
|
|
// Otherwise, blur will be invoked after column change and save handler will
|
|
|
|
// update a different column.
|
|
|
|
let editor: HTMLTextAreaElement | undefined;
|
|
|
|
owner.autoDispose(
|
|
|
|
options.cursor.subscribe(() => {
|
|
|
|
editor?.blur();
|
|
|
|
})
|
|
|
|
);
|
2023-03-01 15:21:19 +00:00
|
|
|
|
2023-12-12 09:58:20 +00:00
|
|
|
return [
|
|
|
|
cssLabel(t("DESCRIPTION")),
|
|
|
|
cssRow(
|
|
|
|
editor = cssTextArea(fromKo(description),
|
|
|
|
{ onInput: false },
|
|
|
|
{ rows: '3' },
|
|
|
|
dom.on('blur', async (e, elem) => {
|
|
|
|
await description.saveOnly(elem.value);
|
|
|
|
}),
|
|
|
|
testId(`${options.testPrefix}-description`),
|
|
|
|
autoGrow(fromKo(description))
|
|
|
|
)
|
|
|
|
),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A generic version of buildDescriptionConfig that can be used for any text input.
|
|
|
|
*/
|
|
|
|
export function buildTextInput(
|
|
|
|
owner: MultiHolder,
|
|
|
|
options: {
|
|
|
|
value: KoSaveableObservable<any>,
|
|
|
|
cursor: ko.Computed<CursorPos>,
|
|
|
|
label: string,
|
|
|
|
placeholder?: ko.Computed<string>,
|
|
|
|
},
|
|
|
|
...args: DomArg[]
|
|
|
|
) {
|
|
|
|
owner.autoDispose(
|
|
|
|
options.cursor.subscribe(() => {
|
|
|
|
options.value.save().catch(reportError);
|
|
|
|
})
|
|
|
|
);
|
|
|
|
return [
|
|
|
|
cssLabel(options.label),
|
|
|
|
cssRow(
|
|
|
|
cssTextInput(fromKo(options.value),
|
|
|
|
dom.on('blur', () => {
|
|
|
|
return options.value.save();
|
|
|
|
}),
|
|
|
|
dom.prop('placeholder', options.placeholder || ''),
|
|
|
|
...args
|
2023-03-01 15:21:19 +00:00
|
|
|
),
|
2023-12-12 09:58:20 +00:00
|
|
|
),
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
const cssTextInput = styled(textInput, `
|
|
|
|
color: ${theme.inputFg};
|
|
|
|
background-color: ${theme.mainPanelBg};
|
|
|
|
border: 1px solid ${theme.inputBorder};
|
|
|
|
width: 100%;
|
|
|
|
outline: none;
|
|
|
|
border-radius: 3px;
|
|
|
|
height: 28px;
|
|
|
|
border-radius: 3px;
|
|
|
|
padding: 0px 6px;
|
|
|
|
&::placeholder {
|
|
|
|
color: ${theme.inputPlaceholderFg};
|
|
|
|
}
|
|
|
|
|
|
|
|
&[readonly] {
|
|
|
|
background-color: ${theme.inputDisabledBg};
|
|
|
|
color: ${theme.inputDisabledFg};
|
2023-03-01 15:21:19 +00:00
|
|
|
}
|
2023-12-12 09:58:20 +00:00
|
|
|
`);
|
2023-03-01 15:21:19 +00:00
|
|
|
|
|
|
|
const cssTextArea = styled(textarea, `
|
|
|
|
color: ${theme.inputFg};
|
|
|
|
background-color: ${theme.mainPanelBg};
|
|
|
|
border: 1px solid ${theme.inputBorder};
|
|
|
|
width: 100%;
|
|
|
|
outline: none;
|
|
|
|
border-radius: 3px;
|
|
|
|
padding: 3px 7px;
|
2023-04-19 10:17:22 +00:00
|
|
|
min-height: calc(3em * 1.5);
|
2023-09-21 16:57:58 +00:00
|
|
|
resize: none;
|
2023-03-01 15:21:19 +00:00
|
|
|
|
|
|
|
&::placeholder {
|
|
|
|
color: ${theme.inputPlaceholderFg};
|
|
|
|
}
|
|
|
|
|
|
|
|
&[readonly] {
|
|
|
|
background-color: ${theme.inputDisabledBg};
|
|
|
|
color: ${theme.inputDisabledFg};
|
|
|
|
}
|
|
|
|
`);
|