Skip to content

Commit

Permalink
Drop support for provider-less stores
Browse files Browse the repository at this point in the history
  • Loading branch information
12joan committed Dec 5, 2023
1 parent e1869ba commit e264333
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 90 deletions.
12 changes: 10 additions & 2 deletions apps/www/src/registry/default/plate-ui/image-element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
TImageElement,
useMediaState,
} from '@udecode/plate-media';
import { useResizableStore } from '@udecode/plate-resizable';
import { ResizableProvider, useResizableStore } from '@udecode/plate-resizable';

import { cn } from '@/lib/utils';

Expand All @@ -18,7 +18,7 @@ import {
ResizeHandle,
} from './resizable';

export function ImageElement({
function InnerImageElement({
className,
children,
nodeProps,
Expand Down Expand Up @@ -70,3 +70,11 @@ export function ImageElement({
</MediaPopover>
);
}

export function ImageElement(props: PlateElementProps<Value, TImageElement>) {
return (
<ResizableProvider>
<InnerImageElement {...props} />
</ResizableProvider>
);
}
13 changes: 11 additions & 2 deletions apps/www/src/registry/default/plate-ui/media-embed-element.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
TMediaEmbedElement,
useMediaState,
} from '@udecode/plate-media';
import { useResizableStore } from '@udecode/plate-resizable';
import { ResizableProvider, useResizableStore } from '@udecode/plate-resizable';
import LiteYouTubeEmbed from 'react-lite-youtube-embed';
import { Tweet } from 'react-tweet';

Expand All @@ -21,7 +21,7 @@ import {
ResizeHandle,
} from './resizable';

const MediaEmbedElement = React.forwardRef<
const InnerMediaEmbedElement = React.forwardRef<
React.ElementRef<typeof PlateElement>,
PlateElementProps<Value, TMediaEmbedElement>
>(({ className, children, ...props }, ref) => {
Expand Down Expand Up @@ -136,6 +136,15 @@ const MediaEmbedElement = React.forwardRef<
</MediaPopover>
);
});
InnerMediaEmbedElement.displayName = 'InnerMediaEmbedElement';

const MediaEmbedElement: typeof InnerMediaEmbedElement = React.forwardRef(
(props, ref) => (
<ResizableProvider>
<InnerMediaEmbedElement {...props} ref={ref} />
</ResizableProvider>
)
);
MediaEmbedElement.displayName = 'MediaEmbedElement';

export { MediaEmbedElement };
5 changes: 1 addition & 4 deletions apps/www/src/registry/default/plate-ui/toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,7 @@ const ToolbarButton = React.forwardRef<

const content =
typeof pressed === 'boolean' ? (
<ToolbarToggleGroup
type="single"
value="single"
>
<ToolbarToggleGroup type="single" value="single">
<ToolbarToggleItem
ref={ref}
className={cn(
Expand Down
38 changes: 16 additions & 22 deletions packages/core/src/jotai-factory/createAtomProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,36 @@ const getFullyQualifiedScope = (storeName: string, scope: string) => {
return `${storeName}:${scope}`;
};

// Map from store name to store. Used for provider-less stores only.
const globalAtomStores = new Map<string, JotaiStore>();

/**
* Context mapping store name and scope to store. Used for providers. The
* 'provider' scope is used to reference any provider belonging to the store,
* regardless of scope.
* Context mapping store name and scope to store. The 'provider' scope is used
* to reference any provider belonging to the store, regardless of scope.
*/
const PROVIDER_SCOPE = 'provider';
const AtomStoreContext = createContext<Map<string, JotaiStore>>(new Map());

// Get the global store for the given store name, creating it if necessary.
const getGlobalAtomStore = (storeName: string): JotaiStore => {
if (!globalAtomStores.has(storeName)) {
globalAtomStores.set(storeName, createStore());
}

return globalAtomStores.get(storeName)!;
};

/**
* Tries to find a store in each of the following places, in order:
* 1. The store context, matching the store name and scope
* 2. The store context, matching the store name and 'provider' scope
* 3. The global store for the store name
* 3. Otherwise, return undefined
*/
export const useAtomStore = (
storeName: string,
scope: string = PROVIDER_SCOPE
): JotaiStore => {
scope: string = PROVIDER_SCOPE,
warnIfUndefined: boolean = true
): JotaiStore | undefined => {
const storeContext = useContext(AtomStoreContext);
return (
const store =
storeContext.get(getFullyQualifiedScope(storeName, scope)) ??
storeContext.get(getFullyQualifiedScope(storeName, PROVIDER_SCOPE)) ??
getGlobalAtomStore(storeName)
);
storeContext.get(getFullyQualifiedScope(storeName, PROVIDER_SCOPE));

if (!store && warnIfUndefined) {
console.warn(
`Tried to access jotai store '${storeName}' outside of a matching provider.`
);
}

return store;
};

export type ProviderProps<T extends object> = AtomProviderProps &
Expand Down
52 changes: 0 additions & 52 deletions packages/core/src/jotai-factory/createAtomStore.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,42 +153,6 @@ describe('createAtomStore', () => {
expect(getByText(INITIAL_NAME)).toBeInTheDocument();
expect(getByText(WRITE_ONLY_CONSUMER_AGE)).toBeInTheDocument();
});

it('works without a provider', () => {
const { getByText } = render(
<>
<ReadOnlyConsumer />
<WriteOnlyConsumer />
</>
);

expect(getByText(INITIAL_NAME)).toBeInTheDocument();
expect(getByText(INITIAL_AGE)).toBeInTheDocument();

act(() => getByText('consumerSetAge').click());

expect(getByText(INITIAL_NAME)).toBeInTheDocument();
expect(getByText(WRITE_ONLY_CONSUMER_AGE)).toBeInTheDocument();
});

it('works adjacent to a provider', () => {
const { getByText } = render(
<>
<ReadOnlyConsumer />
<MyTestStoreProvider name="Jane" age={94}>
<WriteOnlyConsumer />
</MyTestStoreProvider>
</>
);

expect(getByText(INITIAL_NAME)).toBeInTheDocument();
expect(getByText(INITIAL_AGE)).toBeInTheDocument();

act(() => getByText('consumerSetAge').click());

expect(getByText(INITIAL_NAME)).toBeInTheDocument();
expect(getByText(INITIAL_AGE)).toBeInTheDocument();
});
});

describe('scoped providers', () => {
Expand Down Expand Up @@ -227,12 +191,6 @@ describe('createAtomStore', () => {
);
};

it('returns default value when no provider is present', () => {
const { getByText } = render(<ReadOnlyConsumer scope="scope1" />);

expect(getByText('null')).toBeInTheDocument();
});

it('returns value of first ancestor when scope matches no provider', () => {
const { getByText } = render(
<MyScopedTestStoreProvider scope="scope1" age={1}>
Expand Down Expand Up @@ -341,15 +299,5 @@ describe('createAtomStore', () => {
expect(getByText('Jane')).toBeInTheDocument();
expect(getByText('98')).toBeInTheDocument();
});

it('works without provider', () => {
const { getByText } = render(
<MyFirstTestStoreProvider name="Jane" scope="firstScope">
<SecondReadOnlyConsumer />
</MyFirstTestStoreProvider>
);

expect(getByText('72')).toBeInTheDocument();
});
});
});
2 changes: 1 addition & 1 deletion packages/core/src/jotai-factory/createAtomStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ export const createAtomStore = <
atoms[key] = atomConfig;
getAtoms[key] = (optionsOrScope: UseAtomOptionsOrScope = {}) => {
const options = convertScopeShorthand(optionsOrScope);
const contextStore = useAtomStore(name, options.scope);
const contextStore = useAtomStore(name, options.scope, false);

return useAtomValue(atomConfig, {
store: options.store ?? contextStore,
Expand Down
13 changes: 7 additions & 6 deletions packages/resizable/src/components/useResizableStore.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { CSSProperties } from 'react';
import { createAtomStore } from '@udecode/plate-common';

export const { resizableStore, useResizableStore } = createAtomStore(
{
width: 0 as CSSProperties['width'],
},
{ name: 'resizable' }
);
export const { resizableStore, useResizableStore, ResizableProvider } =
createAtomStore(
{
width: 0 as CSSProperties['width'],
},
{ name: 'resizable' }
);
2 changes: 2 additions & 0 deletions packages/table/src/createTablePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createPluginFactory } from '@udecode/plate-common';

import { onKeyDownTable } from './onKeyDownTable';
import { TableProvider } from './stores';
import { insertTableColumn, insertTableRow } from './transforms/index';
import { TablePlugin, TableStoreCellAttributes } from './types';
import { withTable } from './withTable';
Expand Down Expand Up @@ -40,6 +41,7 @@ export const createTablePlugin = createPluginFactory<TablePlugin>({
_cellIndices: new WeakMap() as TableStoreCellAttributes,
},
withOverrides: withTable,
renderAboveEditable: TableProvider,
plugins: [
{
key: ELEMENT_TR,
Expand Down
2 changes: 1 addition & 1 deletion packages/table/src/stores/tableStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createAtomStore, TElement } from '@udecode/plate-common';

export type TableStoreSizeOverrides = Map<number, number>;

export const { tableStore, useTableStore } = createAtomStore(
export const { tableStore, useTableStore, TableProvider } = createAtomStore(
{
colSizeOverrides: new Map() as TableStoreSizeOverrides,
rowSizeOverrides: new Map() as TableStoreSizeOverrides,
Expand Down

0 comments on commit e264333

Please sign in to comment.