Skip to content

Commit

Permalink
Bump main version to 9.2.0 (#2608)
Browse files Browse the repository at this point in the history
* code suport

* markdown

* adjust

* demo site

* WIP

* fix code pen

* fix demo site

* Handle Tab key on whole table selection or last cell on Edit Plugin (#2536)

* Implement indent whole table

* implement tab on last cell new row

* add Table selection and single cell handling

* export clearSelectedCells

* undefined check, simplify

* add tests

* add test for list in table edge case

* Fix seelection on void element (#2551)

* port hyphen

* Implement movement with Tab key inside Table (#2529)

* implement tab movement, tests

* remove unused variable

* fix name, normalisation, add test

* fix wrong parethesis

* restore normalizePos

* fix tests

* add formatTextSegmentBeforeSelectionMarker

* Improve backspace on list (#2555)

* fix selection with ctrl+a

* refactor code using formatTextSegmentBeforeSelectionMarkerTest

* remove getLinkSegment

* Set default format in demo site (#2559)

* clean demo site

* clean

* Enable selecting image when the only element in the range is an Image (#2554)

* init

* Address comment

* Reuse isReverted from Range Selection

* Fix build

* Fix build

* Unselect image when Up or Down, or it remains selected

* remove unneeded changes and improve name of tests

* Update

---------

Co-authored-by: Julia Roldi <[email protected]>

* fix markdown plugin

* Port Hyperlink plugin (#2560)

* Port Hyperlink plugin

* improve

---------

Co-authored-by: Bryan Valverde U <[email protected]>

* export formatTextSegmentBeforeSelectionMarker

* fix build

* Prevent ScrollTop to be lost when the focus is done to the editor (#2564)

* init

* init

---------

Co-authored-by: Julia Roldi <[email protected]>

* Fix 265959: extra empty line generated when get plain text (#2566)

Co-authored-by: Bryan Valverde U <[email protected]>

* Fix #2500 Hyperlink misses color (#2570)

* Fix #2500

* fix test

* mac shortcuts

* fix test

* restore selection (#2577)

* fix: on webkit-based applications, when the selection is empty, focus will cause the window to scroll to the top (#2571)

Co-authored-by: Julia Roldi <[email protected]>
Co-authored-by: Jiuqing Song <[email protected]>

* Port PickerPlugin (#2569)

* Port PickerPlugin

* fix buid

* Improve

* fix build

* Improve

* Improve

* add test

* Improve

* adjust image

* fix test

* fixes

* remove

* Preserve reverted selection info in Content Model (#2580)

* Preserve reverted selection info in Content Model

* improve

* fix empty text

* trigger Events

* Allow Shift+Delete to Cut (#2585)

* Allow Shift+Delete to Cut

* improve

* change source

* fix build

* Fix #2584: Safari context menu event causes selection to be expanded (#2588)

* Fix #2584: Safari context menu event causes selection to be expanded

* fix test

* Port AnnouncePlugin step 1: refactor list number code (#2589)

* test

* refactor

* fix demo site

* Select image after inserting it (#2593)

* Focus image after insertion

* Revert "Focus image after insertion"

This reverts commit 887c9e5.

* Use setSelection

* Port AnnouncePlugin Step 2: Add announce core API (#2591)

* Port AnnouncePlugin step 1: refactor list number code

* Port AnnouncePlugin step 2

---------

Co-authored-by: Bryan Valverde U <[email protected]>

* WIP

* custom replace

* Fix table mover selector (#2596)

* fix edge case tables and trigger contentchanged

* revert event

* trigger autolink

* wip

* Port AnnouncePlugin step 3: Add announce features for list and table (#2592)

* Port AnnouncePlugin step 1: refactor list number code

* Port AnnouncePlugin step 2

* Port AnnouncePlugin ste 3

* add test

* Fix #2575 Entity delimiter cursor moving (#2581)

* Preserve reverted selection info in Content Model

* Entity delimiter cursor moving (#2575)

* improve

* Add test

* add test

* update main version

* Fix difference with master

* Allow customizability for table editors (#2603)

* init

* Simplify type callback

* Also allow using Ctrl-Shift-Z on Windows (#2607)

* Also allow using Ctrl-Shift-Z on Windows

* Fix failing test

* Fix broken test

* Fix failing test

* Keep and deprecate old ShortcutRedoMacOS

* Remove test not needed anymore

* Fix test

* Try fix setFormatTest

* Fix merge issues

---------

Co-authored-by: Júlia Roldi <[email protected]>
Co-authored-by: Julia Roldi <[email protected]>
Co-authored-by: Andres-CT98 <[email protected]>
Co-authored-by: Jiuqing Song <[email protected]>
Co-authored-by: Bryan Valverde U <[email protected]>
Co-authored-by: Rain-Zheng <[email protected]>
Co-authored-by: 庄黛淳华 <[email protected]>
Co-authored-by: florian-msft <[email protected]>
  • Loading branch information
9 people committed Apr 26, 2024
1 parent fb71360 commit b71ce2f
Show file tree
Hide file tree
Showing 125 changed files with 7,619 additions and 1,383 deletions.
36 changes: 31 additions & 5 deletions demo/scripts/controlsV2/mainPane/MainPane.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import * as React from 'react';
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 { Colors, EditorPlugin, IEditor, Snapshots } from 'roosterjs-content-model-types';
import { ContentModelPanePlugin } from '../sidePane/contentModel/ContentModelPanePlugin';
import { createEmojiPlugin } from '../roosterjsReact/emoji';
import { createImageEditMenuProvider } from '../roosterjsReact/contextMenu/menus/createImageEditMenuProvider';
Expand All @@ -30,6 +28,7 @@ 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 { SamplePickerPlugin } from '../plugins/SamplePickerPlugin';
import { SidePane } from '../sidePane/SidePane';
import { SidePanePlugin } from '../sidePane/SidePanePlugin';
import { SnapshotPlugin } from '../sidePane/snapshot/SnapshotPlugin';
Expand All @@ -41,11 +40,18 @@ import { UpdateContentPlugin } from '../plugins/UpdateContentPlugin';
import { WindowProvider } from '@fluentui/react/lib/WindowProvider';
import { zoomButton } from '../demoButtons/zoomButton';
import {
createContextMenuPlugin,
createTableEditMenuProvider,
} from '../roosterjsReact/contextMenu';
Border,
Colors,
ContentModelDocument,
EditorOptions,
EditorPlugin,
IEditor,
KnownAnnounceStrings,
Snapshots,
} from 'roosterjs-content-model-types';
import {
AutoFormatPlugin,
CustomReplacePlugin,
EditPlugin,
HyperlinkPlugin,
MarkdownPlugin,
Expand All @@ -54,6 +60,10 @@ import {
TableEditPlugin,
WatermarkPlugin,
} from 'roosterjs-content-model-plugins';
import {
createContextMenuPlugin,
createTableEditMenuProvider,
} from '../roosterjsReact/contextMenu';

const styles = require('./MainPane.scss');

Expand Down Expand Up @@ -88,6 +98,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
private ribbonPlugin: RibbonPlugin;
private snapshotPlugin: SnapshotPlugin;
private formatPainterPlugin: FormatPainterPlugin;
private samplePickerPlugin: SamplePickerPlugin;
private snapshots: Snapshots;

protected sidePane = React.createRef<SidePane>();
Expand Down Expand Up @@ -125,6 +136,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
this.presetPlugin = new PresetPlugin();
this.ribbonPlugin = createRibbonPlugin();
this.formatPainterPlugin = new FormatPainterPlugin();
this.samplePickerPlugin = new SamplePickerPlugin();

this.state = {
showSidePane: window.location.hash != '',
Expand Down Expand Up @@ -327,6 +339,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
const plugins: EditorPlugin[] = [
this.ribbonPlugin,
this.formatPainterPlugin,
this.samplePickerPlugin,
...this.getToggleablePlugins(),
this.contentModelPanePlugin.getInnerRibbonPlugin(),
this.updateContentPlugin,
Expand Down Expand Up @@ -356,6 +369,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
dir={this.state.isRtl ? 'rtl' : 'ltr'}
knownColors={this.knownColors}
disableCache={this.state.initState.disableCache}
announcerStringGetter={getAnnouncingString}
/>
)}
</div>
Expand Down Expand Up @@ -478,6 +492,7 @@ export class MainPane extends React.Component<{}, MainPaneState> {
markdownOptions,
autoFormatOptions,
linkTitle,
customReplacements,
} = this.state.initState;
return [
pluginList.autoFormat && new AutoFormatPlugin(autoFormatOptions),
Expand All @@ -500,10 +515,21 @@ export class MainPane extends React.Component<{}, MainPaneState> {
? url => linkTitle.replace(UrlPlaceholder, url)
: linkTitle
),
pluginList.customReplace && new CustomReplacePlugin(customReplacements),
].filter(x => !!x);
}
}

const AnnounceStringMap: Record<KnownAnnounceStrings, string> = {
announceListItemBullet: 'Auto corrected Bullet',
announceListItemNumbering: 'Auto corrected {0}',
announceOnFocusLastCell: 'Warning, pressing tab here adds an extra row.',
};

function getAnnouncingString(key: KnownAnnounceStrings) {
return AnnounceStringMap[key];
}

export function mount(parent: HTMLElement) {
ReactDOM.render(<MainPane />, parent);
}
206 changes: 206 additions & 0 deletions demo/scripts/controlsV2/plugins/SamplePickerPlugin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import * as React from 'react';
import { Callout } from '@fluentui/react/lib/Callout';
import { DOMInsertPoint } from 'roosterjs-content-model-types';
import { IContextualMenuItem } from '@fluentui/react/lib/ContextualMenu';
import { mergeStyles } from '@fluentui/react/lib/Styling';
import { ReactEditorPlugin, UIUtilities } from '../roosterjsReact/common';
import {
PickerDirection,
PickerHandler,
PickerHelper,
PickerPlugin,
PickerSelectionChangMode,
getDOMInsertPointRect,
} from 'roosterjs-content-model-plugins';
import {
createContentModelDocument,
createEntity,
createParagraph,
} from 'roosterjs-content-model-dom';

const itemStyle = mergeStyles({
height: '20px',
margin: '4px',
padding: '4px',
minWidth: '200px',
});

const selectedItemStyle = mergeStyles({
backgroundColor: 'blue',
color: 'white',
fontWeight: 'bold',
});

export class SamplePickerPlugin extends PickerPlugin implements ReactEditorPlugin {
private pickerHandler: SamplePickerHandler;

constructor() {
const pickerHandler = new SamplePickerHandler();
super('@', pickerHandler);

this.pickerHandler = pickerHandler;
}

setUIUtilities(uiUtilities: UIUtilities): void {
this.pickerHandler.setUIUtilities(uiUtilities);
}
}

class SamplePickerHandler implements PickerHandler {
private uiUtilities: UIUtilities;
private index = 0;
private ref: IPickerMenu | null = null;
private queryString: string;
private items: IContextualMenuItem[] = [];
private onClose: (() => void) | null = null;
private helper: PickerHelper | null = null;

onInitialize(helper: PickerHelper) {
this.helper = helper;
}

onDispose() {
this.helper = null;
}

setUIUtilities(uiUtilities: UIUtilities): void {
this.uiUtilities = uiUtilities;
}

onTrigger(queryString: string, pos: DOMInsertPoint): PickerDirection | null {
this.index = 0;
this.queryString = queryString;
this.items = buildItems(queryString, this.index);

const rect = getDOMInsertPointRect(this.helper.editor.getDocument(), pos);

if (rect) {
this.onClose = this.uiUtilities.renderComponent(
<PickerMenu
x={rect.left}
y={(rect.bottom + rect.top) / 2}
ref={ref => (this.ref = ref)}
items={this.items}
/>
);
return 'vertical';
} else {
return null;
}
}

onClosePicker() {
this.onClose?.();
this.onClose = null;
}

onSelectionChanged(mode: PickerSelectionChangMode): void {
switch (mode) {
case 'first':
case 'firstInRow':
case 'previousPage':
this.index = 0;
break;

case 'last':
case 'lastInRow':
case 'nextPage':
this.index = 4;
break;

case 'previous':
this.index = this.index - 1;

if (this.index < 0) {
this.index = 4;
}

break;

case 'next':
this.index = (this.index + 1) % 5;
break;
}

this.items = buildItems(this.queryString, this.index);
this.ref?.setMenuItems(this.items);
}

onSelect(): void {
const text = this.items[this.index]?.text;

if (text) {
const span = this.helper.editor.getDocument().createElement('span');
span.textContent = '@' + text;
span.style.textDecoration = 'underline';
span.style.color = 'blue';

const entity = createEntity(span, true /*isReadonly*/, {}, 'TEST_ENTITY');
const paragraph = createParagraph();
const doc = createContentModelDocument();

paragraph.segments.push(entity);
doc.blocks.push(paragraph);

this.helper.replaceQueryString(
doc,
{
changeSource: 'SamplePicker',
},
true /*canUndoByBackspace*/
);
}

this.onClose?.();
this.onClose = null;
this.ref = null;
this.helper.closePicker();
}

onQueryStringChanged(queryString: string): void {
this.queryString = queryString;

if (queryString.length > 100 || queryString.split(' ').length > 4) {
// Querystring is too long, so close picker
this.helper.closePicker();
} else {
this.items = buildItems(this.queryString, this.index);
this.ref?.setMenuItems(this.items);
}
}
}

function buildItems(queryString: string, index: number): IContextualMenuItem[] {
return [1, 2, 3, 4, 5].map((x, i) => ({
key: 'item' + i,
text: queryString.substring(1) + ' item ' + x,
checked: i == index,
}));
}

interface IPickerMenu {
setMenuItems: (items: IContextualMenuItem[]) => void;
}

const PickerMenu = React.forwardRef(
(
props: { x: number; y: number; items: IContextualMenuItem[] },
ref: React.Ref<IPickerMenu>
) => {
const [items, setItems] = React.useState<IContextualMenuItem[]>(props.items);

React.useImperativeHandle(ref, () => ({
setMenuItems: setItems,
}));

return (
<Callout target={{ left: props.x, top: props.y }} isBeakVisible={false} gapSpace={10}>
{items.map(item => (
<div className={itemStyle + (item.checked ? ' ' + selectedItemStyle : '')}>
{item.text}
</div>
))}
</Callout>
);
}
);
17 changes: 2 additions & 15 deletions demo/scripts/controlsV2/plugins/createLegacyPlugins.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Announce, CustomReplace, ImageEdit } from 'roosterjs-editor-plugins';
import { EditorPlugin as LegacyEditorPlugin, KnownAnnounceStrings } from 'roosterjs-editor-types';
import { EditorPlugin as LegacyEditorPlugin } from 'roosterjs-editor-types';
import { ImageEdit } from 'roosterjs-editor-plugins';
import { LegacyPluginList, OptionState } from '../sidePane/editorOptions/OptionState';

export function createLegacyPlugins(initState: OptionState): LegacyEditorPlugin[] {
Expand All @@ -12,20 +12,7 @@ export function createLegacyPlugins(initState: OptionState): LegacyEditorPlugin[
applyChangesOnMouseUp: initState.applyChangesOnMouseUp,
})
: null,
customReplace: pluginList.customReplace ? new CustomReplace() : null,
announce: pluginList.announce ? new Announce(getDefaultStringsMap()) : null,
};

return Object.values(plugins).filter(x => !!x);
}

function getDefaultStringsMap(): Map<KnownAnnounceStrings, string> {
return new Map<KnownAnnounceStrings, string>([
[KnownAnnounceStrings.AnnounceListItemBullet, 'Autocorrected Bullet'],
[KnownAnnounceStrings.AnnounceListItemNumbering, 'Autocorrected {0}'],
[
KnownAnnounceStrings.AnnounceOnFocusLastCell,
'Warning, pressing tab here adds an extra row.',
],
]);
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import * as React from 'react';
import { ButtonKeys, Buttons } from '../utils/buttons';
import { Callout, DirectionalHint } from '@fluentui/react/lib/Callout';
import { getDOMInsertPointRect } from 'roosterjs-content-model-plugins';
import { getLocalizedString } from '../../common/index';
import { getObjectKeys } from 'roosterjs-content-model-dom';
import { getPositionRect } from '../utils/getPositionRect';
import { Icon } from '@fluentui/react/lib/Icon';
import { IconButton } from '@fluentui/react/lib/Button';
import { memoizeFunction } from '@fluentui/react/lib/Utilities';
import { mergeStyleSets } from '@fluentui/react/lib/Styling';
import { renderReactComponent } from '../../common/utils/renderReactComponent';
import { useTheme } from '@fluentui/react/lib/Theme';
import { useWindow } from '@fluentui/react/lib/WindowProvider';
import type { LocalizedStrings, UIUtilities } from '../../common/index';
import type { Theme } from '@fluentui/react/lib/Theme';
import type { PasteOptionButtonKeys, PasteOptionStringKeys } from '../type/PasteOptionStringKeys';
Expand Down Expand Up @@ -106,7 +107,7 @@ const PasteOptionComponent = React.forwardRef(function PasteOptionFunc(
const classNames = getPasteOptionClassNames(theme);
const [selectedKey, setSelectedKey] = React.useState<PasteOptionButtonKeys | null>(null);

const rect = getPositionRect(container, offset);
const rect = getDOMInsertPointRect(useWindow().document, { node: container, offset });
const target = rect && { x: props.isRtl ? rect.left : rect.right, y: rect.bottom };

React.useImperativeHandle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,14 @@ export function Rooster(props: RoosterProps) {
}, [inDarkMode]);

const divProps = getNativeProps<React.HTMLAttributes<HTMLDivElement>>(props, divProperties);
return <div ref={editorDiv} tabIndex={0} {...(divProps || {})}></div>;
return (
<div
ref={editorDiv}
tabIndex={0}
role="textbox"
aria-multiline="true"
{...(divProps || {})}></div>
);
}

function defaultEditorCreator(div: HTMLDivElement, options: EditorOptions) {
Expand Down
Loading

0 comments on commit b71ce2f

Please sign in to comment.