mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Formula UI redesign
Summary: Redesigning column type section to make it more user-friendly. Introducing column behavior concept. Column can be either: - Empty Formula Column: initial state (user can convert to Formula/Data Column) - Data Column: non formula column with or without trigger (with option to add trigger, or convert to formula) - Formula Column: pure formula column, with an option to convert to data column with a trigger. Test Plan: Existing tests. Reviewers: dsagal Reviewed By: dsagal Differential Revision: https://phab.getgrist.com/D3092
This commit is contained in:
@@ -38,6 +38,7 @@ export type IconName = "ChartArea" |
|
||||
"Copy" |
|
||||
"CrossBig" |
|
||||
"CrossSmall" |
|
||||
"Database" |
|
||||
"Dots" |
|
||||
"Download" |
|
||||
"DragDrop" |
|
||||
@@ -79,6 +80,7 @@ export type IconName = "ChartArea" |
|
||||
"Repl" |
|
||||
"ResizePanel" |
|
||||
"RightAlign" |
|
||||
"Script" |
|
||||
"Search" |
|
||||
"Settings" |
|
||||
"Share" |
|
||||
@@ -133,6 +135,7 @@ export const IconList: IconName[] = ["ChartArea",
|
||||
"Copy",
|
||||
"CrossBig",
|
||||
"CrossSmall",
|
||||
"Database",
|
||||
"Dots",
|
||||
"Download",
|
||||
"DragDrop",
|
||||
@@ -174,6 +177,7 @@ export const IconList: IconName[] = ["ChartArea",
|
||||
"Repl",
|
||||
"ResizePanel",
|
||||
"RightAlign",
|
||||
"Script",
|
||||
"Search",
|
||||
"Settings",
|
||||
"Share",
|
||||
|
||||
@@ -100,6 +100,16 @@ export const bigBasicButtonLink = tbind(button, null, {link: true, large: true})
|
||||
export const primaryButtonLink = tbind(button, null, {link: true, primary: true});
|
||||
export const bigPrimaryButtonLink = tbind(button, null, {link: true, large: true, primary: true});
|
||||
|
||||
// Button that looks like a link (have no background and no border).
|
||||
export const textButton = styled(cssButton, `
|
||||
border: none;
|
||||
padding: 0px;
|
||||
background-color: inherit !important;
|
||||
&:disabled {
|
||||
color: ${colors.inactiveCursor};
|
||||
}
|
||||
`);
|
||||
|
||||
const cssButtonLink = styled('a', `
|
||||
display: inline-block;
|
||||
&, &:hover, &:focus {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import {Command} from 'app/client/components/commands';
|
||||
import {NeedUpgradeError, reportError} from 'app/client/models/errors';
|
||||
import {colors, testId, vars} from 'app/client/ui2018/cssVars';
|
||||
import {cssSelectBtn} from 'app/client/ui2018/select';
|
||||
import {IconName} from 'app/client/ui2018/IconList';
|
||||
import {icon} from 'app/client/ui2018/icons';
|
||||
import {commonUrls} from 'app/common/gristUrls';
|
||||
import {Computed, dom, DomElementArg, DomElementMethod, MaybeObsArray, MutableObsArray, Observable,
|
||||
styled} from 'grainjs';
|
||||
import { Command } from 'app/client/components/commands';
|
||||
import { NeedUpgradeError, reportError } from 'app/client/models/errors';
|
||||
import { cssCheckboxSquare, cssLabel, cssLabelText } from 'app/client/ui2018/checkbox';
|
||||
import { colors, testId, vars } from 'app/client/ui2018/cssVars';
|
||||
import { IconName } from 'app/client/ui2018/IconList';
|
||||
import { icon } from 'app/client/ui2018/icons';
|
||||
import { cssSelectBtn } from 'app/client/ui2018/select';
|
||||
import { commonUrls } from 'app/common/gristUrls';
|
||||
import { BindableValue, Computed, dom, DomElementArg, DomElementMethod, IDomArgs,
|
||||
MaybeObsArray, MutableObsArray, Observable, styled } from 'grainjs';
|
||||
import * as weasel from 'popweasel';
|
||||
import {cssCheckboxSquare, cssLabel, cssLabelText} from 'app/client/ui2018/checkbox';
|
||||
|
||||
export interface IOptionFull<T> {
|
||||
value: T;
|
||||
@@ -304,6 +304,71 @@ export function autocomplete(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates simple (not reactive) static menu that looks like a select-box.
|
||||
* Primary usage is for menus, where you want to control how the options and a default
|
||||
* label will look. Label is not updated or changed when one of the option is clicked, for those
|
||||
* use cases use a select component.
|
||||
* Icons are optional, can use custom elements instead of labels and options.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* selectMenu(selectTitle("Title", "Script"), () => [
|
||||
* selectOption(() => ..., "Option1", "Database"),
|
||||
* selectOption(() => ..., "Option2", "Script"),
|
||||
* ]);
|
||||
*
|
||||
* // Control disabled state (if the menu will be opened or not)
|
||||
*
|
||||
* const disabled = observable(false);
|
||||
* selectMenu(selectTitle("Title", "Script"), () => [
|
||||
* selectOption(() => ..., "Option1", "Database"),
|
||||
* selectOption(() => ..., "Option2", "Script"),
|
||||
* ], disabled);
|
||||
*
|
||||
*/
|
||||
export function selectMenu(
|
||||
label: DomElementArg,
|
||||
items: () => DomElementArg[],
|
||||
...args: IDomArgs<HTMLDivElement>
|
||||
) {
|
||||
return cssSelectBtn(
|
||||
label,
|
||||
icon('Dropdown'),
|
||||
menu(
|
||||
items,
|
||||
{
|
||||
...weasel.defaultMenuOptions,
|
||||
menuCssClass: cssSelectMenuElem.className + ' grist-floating-menu',
|
||||
stretchToSelector : `.${cssSelectBtn.className}`,
|
||||
trigger : [(triggerElem, ctl) => {
|
||||
const isDisabled = () => triggerElem.classList.contains('disabled');
|
||||
dom.onElem(triggerElem, 'click', () => isDisabled() || ctl.toggle());
|
||||
dom.onKeyElem(triggerElem as HTMLElement, 'keydown', {
|
||||
ArrowDown: () => isDisabled() || ctl.open(),
|
||||
ArrowUp: () => isDisabled() || ctl.open()
|
||||
});
|
||||
}]
|
||||
},
|
||||
),
|
||||
...args,
|
||||
);
|
||||
}
|
||||
|
||||
export function selectTitle(label: BindableValue<string>, iconName?: BindableValue<IconName>) {
|
||||
return cssOptionRow(
|
||||
iconName ? dom.domComputed(iconName, (name) => cssOptionRowIcon(name)) : null,
|
||||
dom.text(label)
|
||||
);
|
||||
}
|
||||
|
||||
export function selectOption(
|
||||
action: (item: HTMLElement) => void,
|
||||
label: BindableValue<string>,
|
||||
iconName?: BindableValue<IconName>) {
|
||||
return menuItem(action, selectTitle(label, iconName));
|
||||
}
|
||||
|
||||
export const menuSubHeader = styled('div', `
|
||||
font-size: ${vars.xsmallFontSize};
|
||||
text-transform: uppercase;
|
||||
@@ -404,13 +469,13 @@ const cssOptionIcon = styled(icon, `
|
||||
margin: -3px 8px 0 2px;
|
||||
`);
|
||||
|
||||
const cssOptionRow = styled('span', `
|
||||
export const cssOptionRow = styled('span', `
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
`);
|
||||
|
||||
const cssOptionRowIcon = styled(cssOptionIcon, `
|
||||
export const cssOptionRowIcon = styled(cssOptionIcon, `
|
||||
margin: 0 8px 0 0;
|
||||
flex: none;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user