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

Fix selection on focus #1435

Merged
merged 6 commits into from
Mar 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/popular-months-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@udecode/plate-ui-alignment": minor
"@udecode/plate-ui-code-block": minor
"@udecode/plate-ui-font": minor
"@udecode/plate-ui-image": minor
"@udecode/plate-ui-line-height": minor
---

new prop: editor `id`
11 changes: 11 additions & 0 deletions .changeset/stupid-readers-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@udecode/plate-core": minor
---

Fix a critical issue when using multiple editors #1352
- `withHOC`: 3rd parameter can be used to add props to HOC.
- `usePlateId` now just gets plate id atom value and no longer gets event editor id as fallback.
- `useEventEditorId`: Get last event editor id: focus, blur or last.
- `useEventPlateId`: Get provider plate id or event editor id.
- `PlateEventProvider`: `PlateProvider` where id is the event editor id (used for toolbar buttons).
- `withPlateEventProvider`
3 changes: 1 addition & 2 deletions docs/docs/guides/multiple-editors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ Let's render 3 editors with common heading and balloon toolbars.
<BasicMarkToolbarButtons />
</HeadingToolbar>


<div className="flex">
<MultipleEditor
id="multiple-editors-basic"
Expand All @@ -49,7 +48,7 @@ Let's render 3 editors with common heading and balloon toolbars.
<MultipleEditor
id="multiple-editors-image"
plugins={PLUGINS.image}
initialValue={VALUES.images}
initialValue={VALUES.image}
/>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/common/hoc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@

export * from './createNodeHOC';
export * from './createNodesHOC';
export * from './withHOC';
export * from './withProps';
export * from './withProviders';
export * from './withHOC';
5 changes: 3 additions & 2 deletions packages/core/src/common/hoc/withHOC.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import React, { FunctionComponent } from 'react';

export const withHOC = <T,>(
HOC: FunctionComponent<any>,
Component: FunctionComponent<T>
Component: FunctionComponent<T>,
hocProps?: any
): FunctionComponent<T> => (props: T) => (
<HOC>
<HOC {...hocProps}>
<Component {...props} />
</HOC>
);
19 changes: 19 additions & 0 deletions packages/core/src/components/PlateEventProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React, { FC } from 'react';
import { withHOC } from '../common/hoc/withHOC';
import { useEventPlateId } from '../stores/event-editor/selectors/useEventPlateId';
import { PlateProvider } from './PlateProvider';

export const PlateEventProvider = ({
id,
children,
}: {
id?: string;
children: any;
}) => {
id = useEventPlateId(id);

return <PlateProvider id={id}>{children}</PlateProvider>;
};

export const withPlateEventProvider = <T,>(Component: FC<T>, hocProps?: T) =>
withHOC<T>(PlateEventProvider, Component, hocProps);
16 changes: 6 additions & 10 deletions packages/core/src/components/PlateProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import React, { FC } from 'react';
import { castArray } from 'lodash';
import { withHOC } from '../common/hoc/withHOC';
import { usePlatesStoreEffect } from '../hooks/usePlatesStoreEffect';
import { usePlatesSelectors } from '../stores/plate/platesStore';

export const PlateProvider = ({
id: _ids = 'main',
id = 'main',
children,
}: {
id?: string | string[];
id?: string;
children: any;
}) => {
const ids = castArray<string>(_ids) ?? ['main'];
const id = ids[0];
const hasId = usePlatesSelectors.has(id);

const hasId = usePlatesSelectors.has(ids);

usePlatesStoreEffect(_ids);
usePlatesStoreEffect(id);

if (!hasId) return null;

return <React.Fragment key={id}>{children}</React.Fragment>;
};

export const withPlateProvider = <T,>(Component: FC<T>) =>
withHOC<T>(PlateProvider, Component);
export const withPlateProvider = <T,>(Component: FC<T>, hocProps?: T) =>
withHOC<T>(PlateProvider, Component, hocProps);
3 changes: 2 additions & 1 deletion packages/core/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

export * from './DefaultLeaf';
export * from './EditablePlugins';
export * from './PlateProvider';
export * from './EditorRefEffect';
export * from './EditorStateEffect';
export * from './Plate';
export * from './PlateEventProvider';
export * from './PlateProvider';
export * from './PlateTest';
2 changes: 1 addition & 1 deletion packages/core/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@

export * from './useEditorRef';
export * from './useEditorState';
export * from './usePlate/index';
export * from './usePlatesStoreEffect';
export * from './usePlate/index';
1 change: 1 addition & 0 deletions packages/core/src/hooks/usePlate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
export * from './useEditableProps';
export * from './usePlate';
export * from './usePlateEffects';
export * from './usePlateStoreEffects';
export * from './useSlateProps';
26 changes: 4 additions & 22 deletions packages/core/src/hooks/usePlatesStoreEffect.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,16 @@
import { useEffect } from 'react';
import { castArray } from 'lodash';
import { PlateProps } from '../components/Plate';
import { platesActions, platesSelectors } from '../stores/plate/platesStore';
import { usePlateId } from '../stores/plate/selectors/getPlateId';

/**
* On mount: create plate store and set it to the plates store.
* If id is not defined, event id is used.
*/
export const usePlatesStoreEffect = (
_ids?: string | string[],
props?: PlateProps
) => {
const __ids = castArray<string>(_ids);
const id = usePlateId(__ids[0]);

export const usePlatesStoreEffect = (id?: string, props?: PlateProps) => {
useEffect(() => {
// Set multiple plate stores
if (Array.isArray(_ids)) {
const ids = castArray<string>(_ids);

ids.forEach((_id) => {
if (!platesSelectors.has(_id)) {
platesActions.set(_id, props);
}
});
} else if (!platesSelectors.has(id)) {
platesActions.set(id, props);
if (!platesSelectors.has(id)) {
platesActions.set(id!, props);
}

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [_ids, id]);
}, [id]);
};
1 change: 1 addition & 0 deletions packages/core/src/stores/event-editor/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
*/

export * from './event-editor.store';
export * from './selectors/index';
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { eventEditorSelectors } from '../event-editor.store';

export const getEventEditorId = (id?: string) => {
if (id) return id;

const focus = eventEditorSelectors.focus();
if (focus) return focus;

const blur = eventEditorSelectors.blur();
if (blur) return blur;

return eventEditorSelectors.last() ?? 'main';
};
7 changes: 7 additions & 0 deletions packages/core/src/stores/event-editor/selectors/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @file Automatically generated by barrelsby.
*/

export * from './getEventEditorId';
export * from './useEventEditorId';
export * from './useEventPlateId';
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useEventEditorSelectors } from '../event-editor.store';

/**
* Get last event editor id: focus, blur or last.
*/
export const useEventEditorId = () => {
const focus = useEventEditorSelectors.focus();
const blur = useEventEditorSelectors.blur();
const last = useEventEditorSelectors.last();

if (focus) return focus;
if (blur) return blur;
return last;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { usePlateId } from '../../plate/selectors/usePlateId';
import { useEventEditorId } from './useEventEditorId';

export const useEventPlateId = (id?: string) => {
const plateId = usePlateId();
const eventEditorId = useEventEditorId();

return id ?? plateId ?? eventEditorId ?? 'main';
};
2 changes: 1 addition & 1 deletion packages/core/src/stores/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
* @file Automatically generated by barrelsby.
*/

export * from './plateIdAtom';
export * from './event-editor/index';
export * from './plate/index';
export { plateIdAtom } from './plateIdAtom';
40 changes: 0 additions & 40 deletions packages/core/src/stores/plate/selectors/getPlateId.ts

This file was deleted.

2 changes: 1 addition & 1 deletion packages/core/src/stores/plate/selectors/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
* @file Automatically generated by barrelsby.
*/

export * from './getPlateId';
export * from './usePlateEditorRef';
export * from './usePlateEditorState';
export * from './usePlateId';
export * from './usePlatePlugins';
export * from './usePlateSelection';
11 changes: 11 additions & 0 deletions packages/core/src/stores/plate/selectors/usePlateId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useAtom } from 'jotai';
import { plateIdAtom } from '../../plateIdAtom';

/**
* Get plate editor id provided by PlateProvider.
*/
export const usePlateId = () => {
const [plateId] = useAtom(plateIdAtom);

return plateId;
};
8 changes: 5 additions & 3 deletions packages/core/src/stores/plate/usePlateStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { PlateStoreApi } from '../../types/PlateStore';
import { getPlateId, usePlateId } from './selectors/getPlateId';
import { getEventEditorId } from '../event-editor/selectors/getEventEditorId';
import { usePlateId } from './selectors/usePlateId';
import { createPlateStore } from './createPlateStore';
import { platesStore } from './platesStore';

Expand All @@ -8,15 +9,16 @@ const loadingStore = createPlateStore({
});

export const getPlateStore = (id?: string): PlateStoreApi => {
id = getPlateId(id);
id = getEventEditorId(id);

const store = platesStore.get.get(id);

return store || loadingStore;
};

export const usePlateStore = (id?: string): PlateStoreApi => {
id = usePlateId(id);
const plateId = usePlateId();
id = id ?? plateId ?? 'main';

const store = platesStore.use.get(id);

Expand Down
4 changes: 4 additions & 0 deletions packages/nodes/mention/src/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/**
* @file Automatically generated by barrelsby.
*/

export * from './KeyboardEventHandler';
export * from './mentionOnKeyDownHandler';
export * from './moveSelectionByOffset';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/** @jsx jsx */

import { jsx } from '@udecode/plate-test-utils';
import { createEditorWithMentions } from '../testing/createEditorWithMentions';
import { createEditorWithMentions } from '../__tests__/createEditorWithMentions';
import { mentionOnKeyDownHandler } from './mentionOnKeyDownHandler';

jsx;
Expand Down
2 changes: 1 addition & 1 deletion packages/nodes/mention/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

export * from './createMentionPlugin';
export * from './getMentionOnSelectItem';
export * from './handlers';
export * from './types';
export * from './withMention';
export * from './handlers/index';
export * from './queries/index';
export * from './transforms/index';
2 changes: 1 addition & 1 deletion packages/nodes/mention/src/withMention.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { PlateEditor } from '@udecode/plate-core';
import { jsx } from '@udecode/plate-test-utils';
import { Range, Transforms } from 'slate';
import { createEditorWithMentions } from './testing/createEditorWithMentions';
import { createEditorWithMentions } from './__tests__/createEditorWithMentions';
import { getMentionOnSelectItem } from './getMentionOnSelectItem';
import { withMention } from './withMention';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ import {
getPreventDefaultHandler,
isCollapsed,
someNode,
useEventPlateId,
usePlateEditorState,
withPlateProvider,
withPlateEventProvider,
} from '@udecode/plate-core';
import { ToolbarButton, ToolbarButtonProps } from '@udecode/plate-ui-toolbar';

Expand All @@ -14,9 +15,10 @@ export interface AlignToolbarButtonProps extends ToolbarButtonProps {
pluginKey?: string;
}

export const AlignToolbarButton = withPlateProvider(
({ value, pluginKey = KEY_ALIGN, ...props }: AlignToolbarButtonProps) => {
const editor = usePlateEditorState()!;
export const AlignToolbarButton = withPlateEventProvider(
({ id, value, pluginKey = KEY_ALIGN, ...props }: AlignToolbarButtonProps) => {
id = useEventPlateId(id);
const editor = usePlateEditorState(id)!;

return (
<ToolbarButton
Expand Down
Loading