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

v10 #1377

Merged
merged 2 commits into from
Feb 8, 2022
Merged

v10 #1377

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
7 changes: 7 additions & 0 deletions .changeset/balloon-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@udecode/plate-ui-toolbar': patch
---

- `BalloonToolbar`:
- fix: hide when the editor is not focused.
- fix: multiple editors can have a balloon toolbar.
5 changes: 5 additions & 0 deletions .changeset/core-fix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@udecode/plate-core': patch
---

- `eventEditorSelectors.focus()` should now return the currently focused editor id, and `null` if no editor is focused.
13 changes: 13 additions & 0 deletions .changeset/lovely-ads-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@udecode/plate-core': minor
---

- new dep: jotai
- `Plate`:
- set the store only if it's not already set (e.g. controlled use-case)
- there is now a jotai provider with plate id so it can be used by plate selectors if no id is given as parameter.
- `PlateProvider`: Create plate store and mount/unmount if `id` prop updates. `id` can be `string[]`. Use this component on top of components using plate hook selectors, otherwise your components would not rerender on change. Not needed for plate non-hook selectors (getters).
- `useCreatePlateStore`: hook that creates a plate store into the plates store, if not defined.
- `usePlateId`: returns the provider plate id (if any).
- `usePlateStore`: if the hook is used before the plate store is created, it will console warn "The plate hooks must be used inside the `<PlateProvider id={id}>` component's context."
-
6 changes: 6 additions & 0 deletions .changeset/tough-yaks-vanish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@udecode/plate-ui-toolbar': major
---

Before, `BalloonToolbar` could be outside `Plate`. Now, `BallonToolbar` should be a child of `Plate`.
This fixes the multi editor bug.
5 changes: 3 additions & 2 deletions docs/docs/components/balloon-toolbar.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,14 @@ npm install @udecode/plate-ui-toolbar

return (
<>
<BallonToolbarMarks />
<Plate
id="balloon-toolbar"
plugins={PLUGINS.basicNodes}
editableProps={CONFIG.editableProps}
initialValue={VALUES.balloonToolbar}
/>
>
<BallonToolbarMarks />
</Plate>
</>
);
}
Expand Down
5 changes: 3 additions & 2 deletions docs/docs/guides/multiple-editors.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ Let's render 3 editors with common heading and balloon toolbars.
id={id}
plugins={plugins}
initialValue={initialValue}
/>
>
<BallonToolbarMarks />
</Plate>
</div>
);

Expand All @@ -32,7 +34,6 @@ Let's render 3 editors with common heading and balloon toolbars.
<BasicMarkToolbarButtons />
</HeadingToolbar>

<BallonToolbarMarks />

<div className="flex">
<MultipleEditor
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"dependencies": {
"@udecode/zustood": "0.4.4",
"clsx": "1.1.1",
"jotai": "1.5.3",
"lodash": "4.17.21",
"use-deep-compare": "1.1.0",
"zustand": "3.6.7"
Expand Down
18 changes: 0 additions & 18 deletions packages/core/src/components/EditorProvider.tsx

This file was deleted.

17 changes: 11 additions & 6 deletions packages/core/src/components/Plate.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React, { useEffect } from 'react';
import { Provider } from 'jotai';
import { Editable, Slate } from 'slate-react';
import { useCreatePlateStore } from '../hooks/useCreatePlateStore';
import { usePlate } from '../hooks/usePlate/usePlate';
import { platesActions, usePlatesSelectors } from '../stores/plate/platesStore';
import { plateIdAtom } from '../stores/plateIdAtom';
import { PlateStoreState } from '../types/PlateStore';
import { SlateProps } from '../types/slate/SlateProps';
import { EditorRefEffect } from './EditorRefEffect';
Expand Down Expand Up @@ -74,7 +77,7 @@ export const PlateContent = <T extends {} = {}>({

export const Plate = <T extends {} = {}>(props: PlateProps<T>) => {
const { id = 'main' } = props;
const isReady = usePlatesSelectors.has(id);
const hasId = usePlatesSelectors.has(id);

// Clear the state on unmount.
useEffect(
Expand All @@ -85,11 +88,13 @@ export const Plate = <T extends {} = {}>(props: PlateProps<T>) => {
);

// Set initial state on mount
useEffect(() => {
platesActions.set(id);
}, [id]);
useCreatePlateStore(id);

if (!isReady) return null;
if (!hasId) return null;

return <PlateContent {...props} />;
return (
<Provider initialValues={[[plateIdAtom, id]]}>
<PlateContent {...props} />
</Provider>
);
};
30 changes: 30 additions & 0 deletions packages/core/src/components/PlateProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { FC } from 'react';
import { castArray } from 'lodash';
import { withHOC } from '../common/hoc/withHOC';
import { useCreatePlateStore } from '../hooks/useCreatePlateStore';
import { usePlatesSelectors } from '../stores/plate/platesStore';
import { usePlateId } from '../stores/plate/selectors/getPlateId';

export const PlateProvider = ({
id: _ids,
children,
}: {
id?: string | string[];
children: any;
}) => {
const ids = castArray<string>(_ids);
const id = usePlateId(ids[0]);
if (ids[0] === undefined) {
ids[0] = id;
}

const hasId = usePlatesSelectors.has(ids);
useCreatePlateStore(_ids);

if (!hasId) return null;

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

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

export * from './DefaultLeaf';
export * from './EditablePlugins';
export * from './EditorProvider';
export * from './PlateProvider';
export * from './EditorRefEffect';
export * from './EditorStateEffect';
export * from './Plate';
1 change: 1 addition & 0 deletions packages/core/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
export * from './useEditorRef';
export * from './useEditorState';
export * from './usePlate/index';
export * from './useCreatePlateStore';
28 changes: 28 additions & 0 deletions packages/core/src/hooks/useCreatePlateStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { useEffect } from 'react';
import { castArray } from 'lodash';
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 useCreatePlateStore = (_ids?: string | string[]) => {
const __ids = castArray<string>(_ids);
const id = usePlateId(__ids[0]);

useEffect(() => {
// Set multiple plate stores
if (Array.isArray(_ids)) {
const ids = castArray<string>(_ids);

ids.forEach((_id) => {
if (!platesSelectors.has(_id)) {
platesActions.set(_id);
}
});
} else if (!platesSelectors.has(id)) {
platesActions.set(id);
}
}, [_ids, id]);
};
13 changes: 10 additions & 3 deletions packages/core/src/plugins/createEventEditorPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { eventEditorActions } from '../stores/event-editor/event-editor.store';
import {
eventEditorActions,
eventEditorSelectors,
} from '../stores/event-editor/event-editor.store';
import { createPluginFactory } from '../utils/createPluginFactory';

export const KEY_EVENT_EDITOR = 'event-editor';
Expand All @@ -7,10 +10,14 @@ export const createEventEditorPlugin = createPluginFactory({
key: KEY_EVENT_EDITOR,
handlers: {
onFocus: (editor) => () => {
eventEditorActions.focus?.(editor.id);
eventEditorActions.focus(editor.id);
},
onBlur: (editor) => () => {
eventEditorActions.blur?.(editor.id);
const focus = eventEditorSelectors.focus();
if (focus === editor.id) {
eventEditorActions.focus(null);
}
eventEditorActions.blur(editor.id);
},
},
});
18 changes: 14 additions & 4 deletions packages/core/src/stores/event-editor/event-editor.store.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
import { createStore } from '@udecode/zustood';
import { EditorId } from '../../types/PlateStore';

export type EventEditorKey = 'blur' | 'focus' | 'last';

export type EventEditorState = Record<EventEditorKey, EditorId | null>;
export type EventEditorState = {
/**
* Last editor id that has been blurred.
*/
blur: string | null;
/**
* Editor id that is currently being focused.
*/
focus: string | null;
/**
* Last editor id.
*/
last: string | null;
};

/**
* Store where the keys are event names and the values are editor ids.
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/stores/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@

export * from './event-editor/index';
export * from './plate/index';
export { plateIdAtom } from './plateIdAtom';
7 changes: 5 additions & 2 deletions packages/core/src/stores/plate/platesStore.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createStore } from '@udecode/zustood';
import { castArray } from 'lodash';
import { PlatesStoreState } from '../../types/PlateStore';
import { eventEditorActions } from '../event-editor/event-editor.store';
import { createPlateStore } from './createPlateStore';
Expand Down Expand Up @@ -34,8 +35,10 @@ export const platesStore = createStore('plate')({} as PlatesStoreState)
get(id: string) {
return state[id];
},
has(id: string) {
return !!state[id];
has(id?: string | string[]) {
const ids = castArray<string>(id);

return ids.every((_id) => !!state[_id]);
},
}));

Expand Down
11 changes: 8 additions & 3 deletions packages/core/src/stores/plate/selectors/getPlateId.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useAtom } from 'jotai';
import {
eventEditorSelectors,
useEventEditorSelectors,
} from '../../event-editor/event-editor.store';
import { plateIdAtom } from '../../plateIdAtom';

/**
* - Get the last focused editor id if any
Expand All @@ -23,11 +25,14 @@ export const getPlateId = (id?: string): string => {
};

export const usePlateId = (id?: string): string => {
const focus = useEventEditorSelectors.focus?.();
const blur = useEventEditorSelectors.blur?.();
const last = useEventEditorSelectors.last?.();
const [plateId] = useAtom(plateIdAtom);

const focus = useEventEditorSelectors.focus();
const blur = useEventEditorSelectors.blur();
const last = useEventEditorSelectors.last();

if (id) return id;
if (plateId) return plateId;
if (focus) return focus;
if (blur) return blur;

Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/stores/plate/usePlateStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,13 @@ export const usePlateStore = (id?: string): PlateStoreApi => {

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

if (store) {
return store;
}

console.warn(
"The plate hooks must be used inside the <PlateProvider id={id}> component's context."
);

return store || loadingStore;
};
3 changes: 3 additions & 0 deletions packages/core/src/stores/plateIdAtom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { atom } from 'jotai';

export const plateIdAtom = atom<string | null>(null);
2 changes: 1 addition & 1 deletion packages/nodes/code-block/src/decorateCodeLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import 'prismjs/components/prism-cpp';
import 'prismjs/components/prism-csharp';
import 'prismjs/components/prism-css';
import 'prismjs/components/prism-dart';
import 'prismjs/components/prism-django';
// import 'prismjs/components/prism-django';
import 'prismjs/components/prism-docker';
import 'prismjs/components/prism-ejs';
import 'prismjs/components/prism-erlang';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
isCollapsed,
someNode,
usePlateEditorState,
withEditor,
withPlateProvider,
} from '@udecode/plate-core';
import { ToolbarButton, ToolbarButtonProps } from '@udecode/plate-ui-toolbar';

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import {
getPluginType,
getPreventDefaultHandler,
usePlateEditorState,
withEditor,
withPlateProvider,
} from '@udecode/plate-core';
import {
BlockToolbarButton,
ToolbarButtonProps,
} from '@udecode/plate-ui-toolbar';

export const CodeBlockToolbarButton = withEditor(
export const CodeBlockToolbarButton = withPlateProvider(
({
options,
...props
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
setMarks,
usePlateEditorRef,
usePlateEditorState,
withEditor,
withPlateProvider,
} from '@udecode/plate-core';
import {
ToolbarButton,
Expand All @@ -29,7 +29,7 @@ type ColorPickerToolbarDropdownProps = {
closeOnSelect?: boolean;
};

export const ColorPickerToolbarDropdown = withEditor(
export const ColorPickerToolbarDropdown = withPlateProvider(
({
pluginKey,
icon,
Expand Down
Loading