(core) Forms improvements

Summary:
Forms improvements and following new design
- New headers
- New UI
- New right panel options

Test Plan: Tests updated

Reviewers: georgegevoian, dsagal

Reviewed By: georgegevoian

Subscribers: dsagal, paulfitz

Differential Revision: https://phab.getgrist.com/D4158
This commit is contained in:
Jarosław Sadziński
2024-01-18 18:23:50 +01:00
parent b82209b458
commit 0aad09a4ed
55 changed files with 3468 additions and 1410 deletions

View File

@@ -49,11 +49,13 @@ export type IconName = "ChartArea" |
"Chat" |
"Code" |
"Collapse" |
"Columns" |
"Convert" |
"Copy" |
"CrossBig" |
"CrossSmall" |
"Database" |
"Desktop" |
"Dots" |
"Download" |
"DragDrop" |
@@ -94,6 +96,7 @@ export type IconName = "ChartArea" |
"Message" |
"Minimize" |
"Minus" |
"Mobile" |
"MobileChat" |
"MobileChat2" |
"NewNotification" |
@@ -102,6 +105,7 @@ export type IconName = "ChartArea" |
"Page" |
"PanelLeft" |
"PanelRight" |
"Paragraph" |
"Pencil" |
"PinBig" |
"PinSmall" |
@@ -123,6 +127,8 @@ export type IconName = "ChartArea" |
"Robot" |
"Script" |
"Search" |
"Section" |
"Separator" |
"Settings" |
"Share" |
"Sort" |
@@ -198,11 +204,13 @@ export const IconList: IconName[] = ["ChartArea",
"Chat",
"Code",
"Collapse",
"Columns",
"Convert",
"Copy",
"CrossBig",
"CrossSmall",
"Database",
"Desktop",
"Dots",
"Download",
"DragDrop",
@@ -243,6 +251,7 @@ export const IconList: IconName[] = ["ChartArea",
"Message",
"Minimize",
"Minus",
"Mobile",
"MobileChat",
"MobileChat2",
"NewNotification",
@@ -251,6 +260,7 @@ export const IconList: IconName[] = ["ChartArea",
"Page",
"PanelLeft",
"PanelRight",
"Paragraph",
"Pencil",
"PinBig",
"PinSmall",
@@ -272,6 +282,8 @@ export const IconList: IconName[] = ["ChartArea",
"Robot",
"Script",
"Search",
"Section",
"Separator",
"Settings",
"Share",
"Sort",

View File

@@ -110,6 +110,7 @@ export const cssLabelText = styled('span', `
font-weight: initial; /* negate bootstrap */
overflow: hidden;
text-overflow: ellipsis;
line-height: 16px;
`);
type CheckboxArg = DomArg<HTMLInputElement>;

View File

@@ -132,7 +132,7 @@ export function menuItemSubmenu(
}
/**
* Subheader as a menu item.
* Header with a submenu (used in collapsed menus scenarios).
*/
export function menuSubHeaderMenu(
submenu: weasel.MenuCreateFunc,
@@ -557,7 +557,7 @@ export const menuItem = styled(weasel.menuItem, menuItemStyle);
export const menuItemLink = styled(weasel.menuItemLink, menuItemStyle);
// when element name is, to long, it will be trimmed with ellipsis ("...")
// when element name is too long, it will be trimmed with ellipsis ("...")
export function menuItemTrimmed(
action: (item: HTMLElement, ev: Event) => void, label: string, ...args: DomElementArg[]) {
return menuItem(action, cssEllipsisLabel(label), ...args);
@@ -584,7 +584,7 @@ export function menuItemCmd(
typeof label === 'string'
? dom('span', label, testId('cmd-name'))
: dom('div', label(), testId('cmd-name')),
cmd.humanKeys.length ? cssCmdKey(cmd.humanKeys[0]) : null,
cmd.humanKeys?.length ? cssCmdKey(cmd.humanKeys[0]) : null,
cssMenuItemCmd.cls(''), // overrides some menu item styles
...args
);
@@ -826,3 +826,52 @@ const cssMenuSearchInput = styled('input', `
color: ${theme.inputPlaceholderFg};
}
`);
type MenuDefinition = Array<MenuItem>;
interface MenuItem {
label?: string;
header?: string;
action?: string | (() => void);
disabled?: boolean;
icon?: IconName;
shortcut?: string;
submenu?: MenuDefinition;
maxSubmenu?: number;
type?: 'header' | 'separator' | 'item'; // default to item.
}
export function buildMenu(definition: MenuDefinition, onclick?: (action: string) => any) {
function *buildMenuItems(current: MenuDefinition): IterableIterator<Element> {
for (const item of current) {
const isHeader = item.type === 'header' || item.header;
// If this is header with submenu.
if (isHeader && item.submenu) {
yield menuSubHeaderMenu(() => [...buildMenuItems(item.submenu!)], {}, item.header ?? item.label);
continue;
} else if (isHeader) {
yield menuSubHeader(item.header ?? item.label);
continue;
}
// Not a header, so it's an item or a separator.
if (item.type === 'separator') {
yield menuDivider();
continue;
}
// If this is an item with submenu.
if (item.submenu) {
yield menuItemSubmenu(() => [...buildMenuItems(item.submenu!)], {}, item.label);
continue;
}
// Not a submenu, so it's a regular item.
const action = typeof item.action === 'function' ? item.action : () => onclick?.(item.action as string);
yield menuItem(action, item.icon && menuIcon(item.icon), item.label, item.shortcut && cssCmdKey(item.shortcut));
}
}
return menu((ctl) => [...buildMenuItems(definition)], {});
}