Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add BorderPanel & adjust the styling of ColorPicker #445

Merged
merged 9 commits into from
Nov 14, 2023
Merged
Prev Previous commit
Next Next commit
refactor: simplify the implementation of Menu & CustomLabel
  • Loading branch information
jikkai committed Nov 14, 2023
commit 0220ede16d4b3ac992da5f6d97adb48ec293acae
30 changes: 30 additions & 0 deletions packages/base-sheets/src/commands/commands/set-border-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,36 @@ function forEach(range: IRange, action: (row: number, column: number) => void):
}
}

enum BorderCommandType {
POSITION,
STYLE,
COLOR,
}

export type ISetBorderStylingCommand = {
value: BorderType;
type: BorderCommandType.POSITION;
} & {
value: BorderStyleTypes;
type: BorderCommandType.STYLE;
} & {
value: string;
type: BorderCommandType.COLOR;
};
export const SetBorderBasicCommand: ICommand<ISetBorderStylingCommand> = {
id: 'sheet.command.set-border-basic',
type: CommandType.COMMAND,
handler: async (accessor: IAccessor, params: ISetBorderStylingCommand) => {
// if (!params.value) return false;
// const commandService = accessor.get(ICommandService);
// const borderManager = accessor.get(BorderStyleManagerService);
// borderManager.setType(params.value);
// return commandService.executeCommand(SetBorderCommand.id);
console.log(params);
return true;
},
};

export interface ISetBorderPositionCommandParams {
value: BorderType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { RemoveColCommand, RemoveRowCommand } from '../commands/commands/remove-
import { RemoveSheetCommand } from '../commands/commands/remove-sheet.command';
import { RemoveWorksheetMergeCommand } from '../commands/commands/remove-worksheet-merge.command';
import {
SetBorderBasicCommand,
SetBorderColorCommand,
SetBorderCommand,
SetBorderPositionCommand,
Expand Down Expand Up @@ -158,6 +159,7 @@ export class BasicWorksheetController extends Disposable implements IDisposable
ResetBackgroundColorCommand,
ResetTextColorCommand,
SetBackgroundColorCommand,
SetBorderBasicCommand,
SetBorderColorCommand,
SetBorderCommand,
SetBorderPositionCommand,
Expand Down
1 change: 1 addition & 0 deletions packages/base-sheets/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export type {
ISetBorderStyleCommandParams,
} from './commands/commands/set-border-command';
export {
SetBorderBasicCommand,
SetBorderColorCommand,
SetBorderCommand,
SetBorderPositionCommand,
Expand Down
7 changes: 6 additions & 1 deletion packages/base-ui/src/components/custom-label/CustomLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ export function CustomLabel(props: ICustomLabelProps): JSX.Element | null {
const labelName = isStringLabel ? label : label?.name;

const CustomComponent = componentManager.get(labelName);
CustomComponent && nodes.push(<CustomComponent key={index++} {...customProps} />);

if (CustomComponent) {
nodes.push(<CustomComponent key={index++} {...customProps} />);
} else {
nodes.push(<span key={index++}>{localeService.t(labelName)}</span>);
}
}
if (title) {
nodes.push(<span key={index++}>{localeService.t(title)}</span>);
Expand Down
81 changes: 29 additions & 52 deletions packages/base-ui/src/components/menu/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,14 @@ import {
} from '@univerjs/design';
import { MoreSingle } from '@univerjs/icons';
import { useDependency } from '@wendellhu/redi/react-bindings';
import clsx from 'clsx';
import React, { useState } from 'react';
import { useState } from 'react';
import { isObservable, of } from 'rxjs';

import { ComponentManager } from '../../Common';
import {
ICustomComponentOption,
IDisplayMenuItem,
IMenuButtonItem,
IMenuItem,
IMenuSelectorItem,
isValueOptions,
IValueOption,
MenuGroup,
MenuItemDefaultValueType,
Expand All @@ -36,7 +32,7 @@ export interface IBaseMenuProps {
menuType?: string | string[];

value?: string | number;
options?: Array<IValueOption | ICustomComponentOption>;
options?: IValueOption[];

onOptionSelect?: (option: IValueOption) => void;
}
Expand Down Expand Up @@ -103,48 +99,32 @@ function MenuWrapper(props: IBaseMenuProps) {
function MenuOptionsWrapper(props: IBaseMenuProps) {
const { options, value, onOptionSelect, parentKey } = props;

const componentManager = useDependency(ComponentManager);
return options?.map((option: IValueOption, index: number) => {
const key = `${parentKey}-${option.label ?? option.id}-${index}`;

return options?.map((option: IValueOption | ICustomComponentOption, index: number) => {
const isValueOption = isValueOptions(option);
const key = `${parentKey}-${isValueOption ? option.label : option.id}-${index}`;
const onChange = (v: string | number) => {
onOptionSelect?.({ value: v, label: option?.label });
};

if (isValueOption) {
return (
<DesignMenuItem
key={key}
eventKey={key}
onClick={() => {
onOptionSelect?.({
...option,
});
}}
>
<span className={styles.menuItemContent}>
<CustomLabel
selected={String(value) === String(option.value)} // use √ for select
value={String(option.value)}
label={option.label}
title={typeof option.label === 'string' ? option.label : ''}
icon={option.icon}
/>
</span>
</DesignMenuItem>
);
}
const handleClick = () => {
if (typeof option.value === 'undefined') return;

const CustomComponent = componentManager.get(option.id) as React.ComponentType<any>;
onOptionSelect?.({
...option,
});
};

return (
<DesignMenuItem key={key} eventKey={key} className={clsx(styles.menuItemCustom)}>
<CustomComponent
onValueChange={(v: string | number) => {
onOptionSelect?.({
value: v,
label: option.id,
});
}}
/>
<DesignMenuItem key={key} eventKey={key} onClick={handleClick}>
<span className={styles.menuItemContent}>
<CustomLabel
selected={typeof value !== 'undefined' && value === option.value}
value={option.value}
label={option.label}
icon={option.icon}
onChange={onChange}
/>
</span>
</DesignMenuItem>
);
});
Expand Down Expand Up @@ -204,13 +184,9 @@ function MenuItem({ menuItem, onClick }: IMenuItemProps) {
const renderSelectorType = () => {
const item = menuItem as IDisplayMenuItem<IMenuSelectorItem>;

let selections: Array<IValueOption | ICustomComponentOption>;
let selections: IValueOption[];
if (isObservable(item.selections)) {
selections = useObservable<Array<IValueOption | ICustomComponentOption>>(
item.selections || of([]),
[],
true
);
selections = useObservable<IValueOption[]>(item.selections || of([]), [], true);
} else {
selections = item.selections || [];
}
Expand Down Expand Up @@ -241,7 +217,7 @@ function MenuItem({ menuItem, onClick }: IMenuItemProps) {
menuType={item.id}
options={selections}
onOptionSelect={(v) => {
onClick({ value: v.value, id: item.id }); // border style don't trigger hide menu, set show true
onClick({ value: v.value, id: item.id });
}}
/>
)}
Expand All @@ -255,9 +231,9 @@ function MenuItem({ menuItem, onClick }: IMenuItemProps) {
<CustomLabel
title={item.title}
value={inputValue}
onChange={onChange}
icon={item.icon}
label={item.label}
onChange={onChange}
/>
{item.shortcut && ` (${item.shortcut})`}
</span>
Expand All @@ -267,6 +243,7 @@ function MenuItem({ menuItem, onClick }: IMenuItemProps) {

const renderSubItemsType = () => {
const item = menuItem as IDisplayMenuItem<IMenuSelectorItem>;
console.log(item);

return (
<DesignSubMenu
Expand All @@ -275,7 +252,7 @@ function MenuItem({ menuItem, onClick }: IMenuItemProps) {
popupOffset={[18, 0]}
title={
<span className={styles.menuItemContent}>
<CustomLabel title={item.title} value={item.title} icon={item.icon} label={item.label} />
<CustomLabel title={item.title} icon={item.icon} label={item.label} onChange={onChange} />
</span>
}
expandIcon={<MoreSingle className={styles.menuItemMoreIcon} />}
Expand Down
3 changes: 0 additions & 3 deletions packages/base-ui/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,12 @@ export {
export { DesktopDialogService } from './services/dialog/desktop-dialog.service';
export { IDialogService } from './services/dialog/dialog.service';
export {
type ICustomComponentOption,
type ICustomComponentProps,
type IDisplayMenuItem,
type IMenuButtonItem,
type IMenuItem,
type IMenuItemFactory,
type IMenuSelectorItem,
isCustomComponentOption,
isValueOptions,
type IValueOption,
MenuGroup,
MenuItemType,
Expand Down
19 changes: 2 additions & 17 deletions packages/base-ui/src/services/menu/menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export interface IMenuButtonItem<V = undefined> extends IMenuItemBase<V> {
}

export interface IValueOption {
value: string | number;
value?: string | number;
label:
| string
| {
Expand All @@ -92,24 +92,11 @@ export interface IValueOption {
id?: string; // command id
}

export function isValueOptions(v: IValueOption | ICustomComponentOption): v is IValueOption {
return typeof (v as IValueOption).value !== 'undefined';
}

export interface ICustomComponentOption {
id: string;
disabled?: boolean;
}

export interface ICustomComponentProps<T> {
value: T;
onChange: (v: T) => void;
}

export function isCustomComponentOption(v: IValueOption | ICustomComponentOption): v is ICustomComponentOption {
return typeof (v as ICustomComponentOption).id !== 'undefined';
}

export interface IMenuSelectorItem<V = MenuItemDefaultValueType> extends IMenuItemBase<V> {
type: MenuItemType.SELECTOR | MenuItemType.SUBITEMS;

Expand All @@ -118,9 +105,7 @@ export interface IMenuSelectorItem<V = MenuItemDefaultValueType> extends IMenuIt
// 一个是一个特殊组件,比如 color picker,选中后直接使用其 value 触发 command
// 一个是其他 menu 的 id,直接渲染成其他的 menu
/** Options or IDs of registered components. */
selections?:
| Array<IValueOption | ICustomComponentOption>
| Observable<Array<IValueOption | ICustomComponentOption>>;
selections?: IValueOption[] | Observable<IValueOption[]>;
}

export function isMenuSelectorItem<T extends MenuItemDefaultValueType>(v: IMenuItem): v is IMenuSelectorItem<T> {
Expand Down
6 changes: 3 additions & 3 deletions packages/design/src/components/color-picker/ColorPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export interface IColorPickerProps {

onClick?: (color: string, e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;

onValueChange?: (value: string) => void;
onChange?: (value: string) => void;
}

enum ColorPickerMode {
Expand All @@ -19,7 +19,7 @@ enum ColorPickerMode {
}

export function ColorPicker(props: IColorPickerProps) {
const { onValueChange } = props;
const { onChange } = props;

const [mode, setMode] = useState<ColorPickerMode>(ColorPickerMode.PRESET);

Expand All @@ -32,7 +32,7 @@ export function ColorPicker(props: IColorPickerProps) {
function handleChange(color: Color | string) {
const value = (typeof color === 'string' ? color : color.toHexString()) ?? '';

onValueChange && onValueChange(value);
onChange?.(value);
}

function handleToggleMode(e: React.MouseEvent) {
Expand Down
Loading