diff --git a/demo/scripts/controlsV2/demoButtons/darkModeButton.ts b/demo/scripts/controlsV2/demoButtons/darkModeButton.ts index 32f773e8039..00d03c1a5d7 100644 --- a/demo/scripts/controlsV2/demoButtons/darkModeButton.ts +++ b/demo/scripts/controlsV2/demoButtons/darkModeButton.ts @@ -21,4 +21,9 @@ export const darkModeButton: RibbonButton = { MainPane.getInstance().toggleDarkMode(); return true; }, + commandBarProperties: { + buttonStyles: { + icon: { paddingBottom: '10px' }, + }, + }, }; diff --git a/demo/scripts/controlsV2/demoButtons/exportContentButton.ts b/demo/scripts/controlsV2/demoButtons/exportContentButton.ts index 44807386d04..8cf6371219a 100644 --- a/demo/scripts/controlsV2/demoButtons/exportContentButton.ts +++ b/demo/scripts/controlsV2/demoButtons/exportContentButton.ts @@ -19,4 +19,9 @@ export const exportContentButton: RibbonButton = { const html = exportContent(editor); win.document.write(editor.getTrustedHTMLHandler()(html)); }, + commandBarProperties: { + buttonStyles: { + icon: { paddingBottom: '10px' }, + }, + }, }; diff --git a/demo/scripts/controlsV2/demoButtons/popoutButton.ts b/demo/scripts/controlsV2/demoButtons/popoutButton.ts index 5814cdafd60..98b214ed413 100644 --- a/demo/scripts/controlsV2/demoButtons/popoutButton.ts +++ b/demo/scripts/controlsV2/demoButtons/popoutButton.ts @@ -17,4 +17,9 @@ export const popoutButton: RibbonButton = { onClick: _ => { MainPane.getInstance().popout(); }, + commandBarProperties: { + buttonStyles: { + icon: { paddingBottom: '10px' }, + }, + }, }; diff --git a/demo/scripts/controlsV2/demoButtons/tableEditButtons.ts b/demo/scripts/controlsV2/demoButtons/tableEditButtons.ts index fe0bc42df27..fc7c937416e 100644 --- a/demo/scripts/controlsV2/demoButtons/tableEditButtons.ts +++ b/demo/scripts/controlsV2/demoButtons/tableEditButtons.ts @@ -84,7 +84,7 @@ export const tableMergeButton: RibbonButton< 'ribbonButtonTableMerge' | TableEditMergeMenuItemStringKey > = { key: 'ribbonButtonTableMerge', - iconName: 'TableComputed', + iconName: '', unlocalizedText: 'Merge', isDisabled: formatState => !formatState.isInTable, dropDownMenu: { @@ -102,13 +102,16 @@ export const tableMergeButton: RibbonButton< editTable(editor, TableEditOperationMap[key]); } }, + commandBarProperties: { + iconOnly: false, + }, }; export const tableSplitButton: RibbonButton< 'ribbonButtonTableSplit' | TableEditSplitMenuItemStringKey > = { key: 'ribbonButtonTableSplit', - iconName: 'TableComputed', + iconName: '', unlocalizedText: 'Split', isDisabled: formatState => !formatState.isInTable, dropDownMenu: { @@ -122,13 +125,16 @@ export const tableSplitButton: RibbonButton< editTable(editor, TableEditOperationMap[key]); } }, + commandBarProperties: { + iconOnly: false, + }, }; export const tableAlignCellButton: RibbonButton< 'ribbonButtonTableAlignCell' | TableEditAlignMenuItemStringKey > = { key: 'ribbonButtonTableAlignCell', - iconName: 'TableComputed', + iconName: '', unlocalizedText: 'Align table cell', isDisabled: formatState => !formatState.isInTable, dropDownMenu: { @@ -147,13 +153,16 @@ export const tableAlignCellButton: RibbonButton< editTable(editor, TableEditOperationMap[key]); } }, + commandBarProperties: { + iconOnly: false, + }, }; export const tableAlignTableButton: RibbonButton< 'ribbonButtonTableAlignTable' | TableEditAlignTableMenuItemStringKey > = { key: 'ribbonButtonTableAlignTable', - iconName: 'TableComputed', + iconName: '', unlocalizedText: 'Align table', isDisabled: formatState => !formatState.isInTable, dropDownMenu: { @@ -168,4 +177,7 @@ export const tableAlignTableButton: RibbonButton< editTable(editor, TableEditOperationMap[key]); } }, + commandBarProperties: { + iconOnly: false, + }, }; diff --git a/demo/scripts/controlsV2/demoButtons/zoomButton.ts b/demo/scripts/controlsV2/demoButtons/zoomButton.ts index ecfa48d4c96..ceaf11bb688 100644 --- a/demo/scripts/controlsV2/demoButtons/zoomButton.ts +++ b/demo/scripts/controlsV2/demoButtons/zoomButton.ts @@ -41,4 +41,10 @@ export const zoomButton: RibbonButton = { editor.triggerEvent('zoomChanged', { newZoomScale: zoomScale }); }, + commandBarProperties: { + buttonStyles: { + icon: { paddingBottom: '10px' }, + menuIcon: { paddingBottom: '10px' }, + }, + }, }; diff --git a/demo/scripts/controlsV2/mainPane/MainPane.scss b/demo/scripts/controlsV2/mainPane/MainPane.scss index 1739df86547..88b2240b212 100644 --- a/demo/scripts/controlsV2/mainPane/MainPane.scss +++ b/demo/scripts/controlsV2/mainPane/MainPane.scss @@ -12,6 +12,13 @@ overflow-x: hidden; } +.menuTab { + border-radius: 30% 30% 0 0; + background-color: $primaryLighter; + color: white; + font-weight: bold; +} + .body { flex: 1 1 auto; position: relative; diff --git a/demo/scripts/controlsV2/mainPane/MainPane.tsx b/demo/scripts/controlsV2/mainPane/MainPane.tsx index df358269189..2cc9cd9a796 100644 --- a/demo/scripts/controlsV2/mainPane/MainPane.tsx +++ b/demo/scripts/controlsV2/mainPane/MainPane.tsx @@ -3,25 +3,31 @@ import * as ReactDOM from 'react-dom'; import SampleEntityPlugin from '../plugins/SampleEntityPlugin'; import { ApiPlaygroundPlugin } from '../sidePane/apiPlayground/ApiPlaygroundPlugin'; import { Border, ContentModelDocument, EditorOptions } from 'roosterjs-content-model-types'; -import { buttons, buttonsWithPopout } from './ribbonButtons'; import { Colors, EditorPlugin, IEditor, Snapshots } from 'roosterjs-content-model-types'; import { ContentModelPanePlugin } from '../sidePane/contentModel/ContentModelPanePlugin'; import { createEmojiPlugin } from '../roosterjsReact/emoji'; -import { createFormatPainterButton } from '../demoButtons/formatPainterButton'; import { createImageEditMenuProvider } from '../roosterjsReact/contextMenu/menus/createImageEditMenuProvider'; import { createLegacyPlugins } from '../plugins/createLegacyPlugins'; import { createListEditMenuProvider } from '../roosterjsReact/contextMenu/menus/createListEditMenuProvider'; import { createPasteOptionPlugin } from '../roosterjsReact/pasteOptions'; import { createRibbonPlugin, Ribbon, RibbonButton, RibbonPlugin } from '../roosterjsReact/ribbon'; +import { darkModeButton } from '../demoButtons/darkModeButton'; import { Editor } from 'roosterjs-content-model-core'; import { EditorAdapter } from 'roosterjs-editor-adapter'; import { EditorOptionsPlugin } from '../sidePane/editorOptions/EditorOptionsPlugin'; import { EventViewPlugin } from '../sidePane/eventViewer/EventViewPlugin'; +import { exportContentButton } from '../demoButtons/exportContentButton'; import { FormatPainterPlugin } from '../plugins/FormatPainterPlugin'; import { FormatStatePlugin } from '../sidePane/formatState/FormatStatePlugin'; +import { getButtons } from '../tabs/ribbonButtons'; import { getDarkColor } from 'roosterjs-color-utils'; +import { getPresetModelById } from '../sidePane/presets/allPresets/allPresets'; +import { getTabs, tabNames } from '../tabs/getTabs'; import { getTheme } from '../theme/themes'; import { OptionState } from '../sidePane/editorOptions/OptionState'; +import { popoutButton } from '../demoButtons/popoutButton'; +import { PresetPlugin } from '../sidePane/presets/PresetPlugin'; +import { redoButton } from '../roosterjsReact/ribbon/buttons/redoButton'; import { registerWindowForCss, unregisterWindowForCss } from '../../utils/cssMonitor'; import { Rooster } from '../roosterjsReact/rooster'; import { SidePane } from '../sidePane/SidePane'; @@ -30,8 +36,10 @@ import { SnapshotPlugin } from '../sidePane/snapshot/SnapshotPlugin'; import { ThemeProvider } from '@fluentui/react/lib/Theme'; import { TitleBar } from '../titleBar/TitleBar'; import { trustedHTMLHandler } from '../../utils/trustedHTMLHandler'; +import { undoButton } from '../roosterjsReact/ribbon/buttons/undoButton'; import { UpdateContentPlugin } from '../plugins/UpdateContentPlugin'; import { WindowProvider } from '@fluentui/react/lib/WindowProvider'; +import { zoomButton } from '../demoButtons/zoomButton'; import { createContextMenuPlugin, createTableEditMenuProvider, @@ -54,6 +62,7 @@ export interface MainPaneState { scale: number; isDarkMode: boolean; isRtl: boolean; + activeTab: tabNames; tableBorderFormat?: Border; editorCreator: (div: HTMLDivElement, options: EditorOptions) => IEditor; } @@ -73,12 +82,11 @@ export class MainPane extends React.Component<{}, MainPaneState> { private eventViewPlugin: EventViewPlugin; private apiPlaygroundPlugin: ApiPlaygroundPlugin; private contentModelPanePlugin: ContentModelPanePlugin; + private presetPlugin: PresetPlugin; private ribbonPlugin: RibbonPlugin; private snapshotPlugin: SnapshotPlugin; private formatPainterPlugin: FormatPainterPlugin; private snapshots: Snapshots; - private buttons: RibbonButton[]; - private buttonsWithPopout: RibbonButton[]; protected sidePane = React.createRef(); protected updateContentPlugin: UpdateContentPlugin; @@ -112,12 +120,10 @@ export class MainPane extends React.Component<{}, MainPaneState> { this.apiPlaygroundPlugin = new ApiPlaygroundPlugin(); this.snapshotPlugin = new SnapshotPlugin(this.snapshots); this.contentModelPanePlugin = new ContentModelPanePlugin(); + this.presetPlugin = new PresetPlugin(); this.ribbonPlugin = createRibbonPlugin(); this.formatPainterPlugin = new FormatPainterPlugin(); - const baseButtons = [createFormatPainterButton(this.formatPainterPlugin)]; - this.buttons = baseButtons.concat(buttons); - this.buttonsWithPopout = baseButtons.concat(buttonsWithPopout); this.state = { showSidePane: window.location.hash != '', popoutWindow: null, @@ -131,17 +137,17 @@ export class MainPane extends React.Component<{}, MainPaneState> { style: 'solid', color: '#ABABAB', }, + activeTab: 'all', }; } render() { + const theme = getTheme(this.state.isDarkMode); return ( - + {this.renderTitleBar()} - {!this.state.popoutWindow && this.renderRibbon(false /*isPopout*/)} + {!this.state.popoutWindow && this.renderTabs()} + {!this.state.popoutWindow && this.renderRibbon()}
{this.state.popoutWindow ? this.renderPopout() : this.renderMainPane()}
@@ -220,6 +226,16 @@ export class MainPane extends React.Component<{}, MainPaneState> { }); } + changeRibbon(id: tabNames): void { + this.setState({ + activeTab: id, + }); + } + + setPreset(preset: ContentModelDocument) { + this.model = preset; + } + setPageDirection(isRtl: boolean): void { this.setState({ isRtl: isRtl }); [window, this.state.popoutWindow].forEach(win => { @@ -233,10 +249,32 @@ export class MainPane extends React.Component<{}, MainPaneState> { return ; } - private renderRibbon(isPopout: boolean) { + private renderTabs() { + const tabs = getTabs(); + const topRightButtons: RibbonButton[] = [ + undoButton, + redoButton, + zoomButton, + darkModeButton, + exportContentButton, + ]; + this.state.popoutWindow ? null : topRightButtons.push(popoutButton); + + return ( +
+ + +
+ ); + } + private renderRibbon() { return ( @@ -271,6 +309,13 @@ export class MainPane extends React.Component<{}, MainPaneState> { } private renderEditor() { + // Set preset if found + const search = new URLSearchParams(document.location.search); + const hasPreset = search.get('preset'); + if (hasPreset) { + this.setPreset(getPresetModelById(hasPreset)); + } + const editorStyles = { transform: `scale(${this.state.scale})`, transformOrigin: this.state.isRtl ? 'right top' : 'left top', @@ -353,7 +398,8 @@ export class MainPane extends React.Component<{}, MainPaneState> {
- {this.renderRibbon(true /*isPopout*/)} + {this.renderTabs()} + {this.renderRibbon()}
{this.renderEditor()}
@@ -415,6 +461,7 @@ export class MainPane extends React.Component<{}, MainPaneState> { this.apiPlaygroundPlugin, this.snapshotPlugin, this.contentModelPanePlugin, + this.presetPlugin, ]; } diff --git a/demo/scripts/controlsV2/roosterjsReact/ribbon/buttons/redoButton.ts b/demo/scripts/controlsV2/roosterjsReact/ribbon/buttons/redoButton.ts index 9719c1bffc1..0f2a68cb78a 100644 --- a/demo/scripts/controlsV2/roosterjsReact/ribbon/buttons/redoButton.ts +++ b/demo/scripts/controlsV2/roosterjsReact/ribbon/buttons/redoButton.ts @@ -14,4 +14,9 @@ export const redoButton: RibbonButton = { onClick: editor => { redo(editor); }, + commandBarProperties: { + buttonStyles: { + icon: { paddingBottom: '10px' }, + }, + }, }; diff --git a/demo/scripts/controlsV2/roosterjsReact/ribbon/buttons/undoButton.ts b/demo/scripts/controlsV2/roosterjsReact/ribbon/buttons/undoButton.ts index 8febeb8afd4..8b59d345335 100644 --- a/demo/scripts/controlsV2/roosterjsReact/ribbon/buttons/undoButton.ts +++ b/demo/scripts/controlsV2/roosterjsReact/ribbon/buttons/undoButton.ts @@ -14,4 +14,9 @@ export const undoButton: RibbonButton = { onClick: editor => { undo(editor); }, + commandBarProperties: { + buttonStyles: { + icon: { paddingBottom: '10px' }, + }, + }, }; diff --git a/demo/scripts/controlsV2/sidePane/SidePane.tsx b/demo/scripts/controlsV2/sidePane/SidePane.tsx index 887a2b47b08..85f3b42f204 100644 --- a/demo/scripts/controlsV2/sidePane/SidePane.tsx +++ b/demo/scripts/controlsV2/sidePane/SidePane.tsx @@ -22,6 +22,7 @@ export class SidePane extends React.Component { }; window.addEventListener('hashchange', this.updateStateFromHash); + window.location.hash ? this.updateStateFromHash() : this.updateHash(); } componentDidMount() { diff --git a/demo/scripts/controlsV2/sidePane/formatState/FormatStatePane.tsx b/demo/scripts/controlsV2/sidePane/formatState/FormatStatePane.tsx index d9ef783395f..c501957cc86 100644 --- a/demo/scripts/controlsV2/sidePane/formatState/FormatStatePane.tsx +++ b/demo/scripts/controlsV2/sidePane/formatState/FormatStatePane.tsx @@ -1,8 +1,10 @@ import * as React from 'react'; +import { MainPane } from '../../mainPane/MainPane'; import { SidePaneElementProps } from '../SidePaneElement'; import { ContentModelFormatState, EditorEnvironment, + ImageFormatState, TableMetadataFormat, } from 'roosterjs-content-model-types'; @@ -37,9 +39,13 @@ export default class FormatStatePane extends React.Component< render() { const { format, x, y } = this.state; const { isMac, isAndroid, isSafari, isMobileOrTablet } = this.props.env ?? {}; + const mpState = MainPane.getInstance(); const TableFormat = () => { const tableFormat = format.tableFormat; + const tableBorder = mpState.getTableBorder(); + const tableBorderFormat = + tableBorder.style + ' ' + tableBorder.width + ' ' + tableBorder.color; if (!tableFormat) { return <>; } @@ -47,9 +53,11 @@ export default class FormatStatePane extends React.Component< (key: keyof TableMetadataFormat, index: number, array) => { const rowStyle: React.CSSProperties = index == 0 - ? { borderTop: 'solid' } + ? { + borderTop: tableBorderFormat, + } : index == array.length - 1 - ? { borderBottom: 'solid' } + ? { borderBottom: tableBorderFormat } : {}; return ( @@ -61,9 +69,32 @@ export default class FormatStatePane extends React.Component< ); return tableFromatRows; }; + + const ImageFormat = () => { + const imageFormat = format.imageFormat; + if (!imageFormat) { + return <>; + } + const imageFormatRows = Object.keys(imageFormat).map( + (key: keyof ImageFormatState, index: number, array) => { + return ( + + {key} + {String(imageFormat[key])} + + ); + } + ); + return imageFormatRows; + }; + return format ? ( + + + + {ImageFormat()}