New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@codemirror-toolkit/react

Package Overview
Dependencies
Maintainers
0
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@codemirror-toolkit/react - npm Package Compare versions

Comparing version 0.6.0 to 0.7.0

dist/core.d.ts

17

dist/context.d.ts
import type { FunctionComponent, PropsWithChildren } from 'react';
import type { CodeMirror, GetView, ProvidedCodeMirrorConfig, UseContainerRefHook, UseViewDispatchHook, UseViewEffectHook, UseViewHook } from './types.js';
import type { CodeMirror, CodeMirrorConfig } from './types';
export interface CodeMirrorProps {
config?: ProvidedCodeMirrorConfig;
config?: CodeMirrorConfig;
}

@@ -10,14 +10,7 @@ export interface CodeMirrorProviderProps extends PropsWithChildren<CodeMirrorProps> {

}
export type UseCodeMirrorContextHook<ContainerElement extends Element = Element> = () => CodeMirror<ContainerElement>;
export type UseGetViewHook = () => GetView;
export interface CodeMirrorWithContext<ContainerElement extends Element = Element> {
export interface CodeMirrorContext {
Provider: CodeMirrorProvider;
useContext: UseCodeMirrorContextHook<ContainerElement>;
useGetView: UseGetViewHook;
useView: UseViewHook;
useViewEffect: UseViewEffectHook;
useViewDispatch: UseViewDispatchHook;
useContainerRef: UseContainerRefHook<ContainerElement>;
useCodeMirror: () => CodeMirror;
}
export declare function createCodeMirrorWithContext<ContainerElement extends Element>(displayName?: string | false): CodeMirrorWithContext<ContainerElement>;
export declare function createContext(): CodeMirrorContext;
//# sourceMappingURL=context.d.ts.map

@@ -1,3 +0,3 @@

import type { CodeMirror, ProvidedCodeMirrorConfig } from './types.js';
export declare function createCodeMirror<ContainerElement extends Element>(config?: ProvidedCodeMirrorConfig): CodeMirror<ContainerElement>;
import type { CodeMirrorConfig, CodeMirrorWithHooks } from './types';
export declare function create(config?: CodeMirrorConfig): CodeMirrorWithHooks;
//# sourceMappingURL=create.d.ts.map

@@ -1,4 +0,6 @@

export * from './context.js';
export * from './create.js';
export * from './types.js';
export * from './context';
export * from './core';
export * from './create';
export * from './hooks';
export * from './types';
//# sourceMappingURL=index.d.ts.map

@@ -1,152 +0,93 @@

import { useRef, useCallback, useInsertionEffect, useEffect, useSyncExternalStore, useDebugValue, createContext, createElement, useContext } from "react";
import * as React from "react";
import { useRef, createElement, useContext, useState, useEffect } from "react";
import { EditorView } from "@codemirror/view";
function queueTask(callback) {
let task = callback;
queueMicrotask(() => task == null ? void 0 : task());
return () => task = null;
function createScheduler() {
let task = [];
return {
request: (callback) => {
if (!task.length) {
queueMicrotask(() => task.shift()());
}
task = [callback];
},
idle: () => !task.length
};
}
function createAsyncScheduler() {
let cancelTask;
function createSubject(_value) {
const observers = /* @__PURE__ */ new Set();
return {
request: (callback) => cancelTask = queueTask(callback),
cancel: () => cancelTask == null ? void 0 : cancelTask()
get value() {
return _value;
},
getValue: () => _value,
next: (value) => {
if (_value !== value) {
_value = value;
[...observers].forEach((next) => next(value));
}
},
subscribe: (next) => {
observers.add(next);
next(_value);
return () => observers.delete(next);
}
};
}
function isFunction(value) {
return typeof value === "function";
}
const useIsomorphicInsertionEffect = typeof window !== "undefined" ? useInsertionEffect : useEffect;
function useEffectEvent(event) {
const eventRef = useRef(null);
useIsomorphicInsertionEffect(() => {
eventRef.current = event;
}, [event]);
return useCallback((...args) => {
const fn = eventRef.current;
return fn(...args);
}, []);
}
function createCodeMirror(config) {
let prevState;
let currentView = null;
function createConfig() {
return (isFunction(config) ? config : () => config)(prevState);
function createCodeMirror(initialConfig) {
const config$ = createSubject(initialConfig);
function getViewConfig(prevState) {
const config = config$.value;
return typeof config === "function" ? config(prevState) : { ...config };
}
const view$ = createSubject(null);
const container$ = createSubject(null);
function createView(container) {
var _a;
const prevState = (_a = view$.value) == null ? void 0 : _a.state;
return new EditorView({
...createConfig(),
...getViewConfig(prevState),
parent: container
});
}
const viewChangeCallbacks = /* @__PURE__ */ new Set();
function subscribeViewChange(callback) {
viewChangeCallbacks.add(callback);
return () => viewChangeCallbacks.delete(callback);
}
function publishViewChange() {
viewChangeCallbacks.forEach((callback) => callback());
}
function setView(view) {
if (view === currentView) {
return;
}
if (currentView) {
prevState = currentView.state;
currentView.destroy();
}
currentView = view;
publishViewChange();
}
const getView = () => currentView;
const getServerView = () => null;
const useView = () => {
const view = useSyncExternalStore(subscribeViewChange, getView, getServerView);
useDebugValue(view);
return view;
};
const useViewEffect = (setup) => {
const setupEvent = useEffectEvent((view) => view && setup(view));
useEffect(() => {
let cleanup = setupEvent(getView());
const unsubscribe = subscribeViewChange(() => {
cleanup == null ? void 0 : cleanup();
cleanup = setupEvent(getView());
const scheduler = createScheduler();
container$.subscribe((container) => {
scheduler.request(() => {
var _a;
(_a = view$.value) == null ? void 0 : _a.destroy();
view$.next(container && createView(container));
});
});
config$.subscribe(() => {
if (scheduler.idle()) {
scheduler.request(() => {
var _a;
const container = container$.value;
if (container) {
(_a = view$.value) == null ? void 0 : _a.destroy();
view$.next(createView(container));
}
});
return () => {
unsubscribe();
cleanup == null ? void 0 : cleanup();
};
}, [setupEvent]);
};
const useViewDispatch = () => useCallback((...specs) => {
const view = getView();
if (!view) {
throw new TypeError("Cannot dispatch transaction without a view");
}
view.dispatch(...specs);
}, []);
function createContainerRef() {
let currentContainer = null;
const scheduler = createAsyncScheduler();
return Object.seal({
get current() {
return currentContainer;
},
set current(container) {
if (container === currentContainer) {
return;
}
currentContainer = container;
scheduler.cancel();
scheduler.request(() => {
setView(null);
setView(container && createView(container));
});
}
});
}
let currentContainerRef;
function getContainerRef() {
return currentContainerRef != null ? currentContainerRef : currentContainerRef = createContainerRef();
}
const useContainerRef = () => {
const containerRef = getContainerRef();
useDebugValue(containerRef);
return containerRef;
};
});
return {
getView,
useView,
useViewEffect,
useViewDispatch,
useContainerRef
getView: view$.getValue,
subscribe: view$.subscribe,
setContainer: container$.next,
setConfig: config$.next
};
}
function toPascalCase(str) {
return str.split(/[-_]/).map((word) => word && word[0].toUpperCase() + word.slice(1)).join("");
}
function useSingleton(createInstance) {
const instanceRef = useRef(null);
if (instanceRef.current == null) {
instanceRef.current = createInstance();
}
return instanceRef.current;
}
function createCodeMirrorWithContext(displayName) {
const InternalCodeMirrorContext = createContext(null);
function createContext() {
const CodeMirrorContext = React.createContext(null);
const CodeMirrorProvider = ({ config, children }) => {
const instance = useSingleton(() => createCodeMirror(config));
return /* @__PURE__ */ createElement(
InternalCodeMirrorContext.Provider,
{ value: instance },
children
);
const instanceRef = useRef(null);
function getInstance() {
if (!instanceRef.current) {
instanceRef.current = createCodeMirror(config);
}
return instanceRef.current;
}
return createElement(CodeMirrorContext.Provider, { value: getInstance() }, children);
};
if (displayName) {
displayName = toPascalCase(displayName);
CodeMirrorProvider.displayName = `${displayName}.Provider`;
InternalCodeMirrorContext.displayName = `Internal${displayName}`;
}
const useCodeMirrorContext = () => {
const instance = useContext(InternalCodeMirrorContext);
function useCodeMirrorContext() {
const instance = useContext(CodeMirrorContext);
if (!instance) {

@@ -158,37 +99,48 @@ throw new Error(

return instance;
};
const useGetView = () => {
const { getView: getContextView } = useCodeMirrorContext();
return getContextView;
};
const useView = () => {
const { useView: useContextView } = useCodeMirrorContext();
return useContextView();
};
const useViewEffect = (setup) => {
const { useViewEffect: useContextViewEffect } = useCodeMirrorContext();
return useContextViewEffect(setup);
};
const useViewDispatch = () => {
const { useViewDispatch: useContextViewDispatch } = useCodeMirrorContext();
return useContextViewDispatch();
};
const useContainerRef = () => {
const { useContainerRef: useContextContainerRef } = useCodeMirrorContext();
return useContextContainerRef();
};
}
return {
Provider: CodeMirrorProvider,
useContext: useCodeMirrorContext,
useGetView,
useView,
useViewEffect,
useViewDispatch,
useContainerRef
useCodeMirror: useCodeMirrorContext
};
}
function useView({ getView, subscribe }) {
const [view, setView] = useState(getView);
useEffect(() => subscribe(setView), [subscribe]);
return view;
}
function defineViewEffect(setup) {
return setup;
}
function useViewEffect({ subscribe }, setup) {
useEffect(() => {
function setupEffect(view) {
return view && setup(view);
}
let cleanup;
const unsubscribe = subscribe((view) => {
cleanup == null ? void 0 : cleanup();
cleanup = setupEffect(view);
});
return () => {
unsubscribe();
cleanup == null ? void 0 : cleanup();
};
}, [setup, subscribe]);
}
function create(config) {
const cm = createCodeMirror(config);
return {
...cm,
useView: () => useView(cm),
useViewEffect: (setup) => useViewEffect(cm, setup)
};
}
export {
create,
createCodeMirror,
createCodeMirrorWithContext
createContext,
defineViewEffect,
useView,
useViewEffect
};
//# sourceMappingURL=index.js.map
import type { EditorState } from '@codemirror/state';
import type { EditorView, EditorViewConfig } from '@codemirror/view';
import type { EffectCallback, MutableRefObject } from 'react';
export type EditorViewConfigWithoutParentElement = Omit<EditorViewConfig, 'parent'>;
export interface CodeMirrorConfig extends EditorViewConfigWithoutParentElement {
import type { EffectCallback } from 'react';
export type EditorViewConfigCreator = (prevState: EditorState | undefined) => EditorViewConfig;
export type CodeMirrorConfig = EditorViewConfig | EditorViewConfigCreator;
export type ViewChangeHandler = (view: EditorView | null) => void;
export type ViewContainer = Element | DocumentFragment;
export interface CodeMirror {
getView: () => EditorView | null;
subscribe: (onViewChange: ViewChangeHandler) => () => void;
setContainer: (container: ViewContainer | null) => void;
setConfig: (config: CodeMirrorConfig) => void;
}
export type CodeMirrorConfigCreator = (prevState: EditorState | undefined) => CodeMirrorConfig;
export type ProvidedCodeMirrorConfig = CodeMirrorConfig | CodeMirrorConfigCreator;
export type GetView = () => EditorView | null;
export type UseViewHook = () => EditorView | null;
export type ViewEffectCleanup = ReturnType<EffectCallback>;
export type ViewEffectSetup = (view: EditorView) => ViewEffectCleanup;
export type UseViewEffectHook = (setup: ViewEffectSetup) => void;
export type ViewDispath = typeof EditorView.prototype.dispatch;
export type UseViewDispatchHook = () => ViewDispath;
export type ContainerRef<ContainerElement extends Element = Element> = MutableRefObject<ContainerElement | null>;
export type UseContainerRefHook<ContainerElement extends Element = Element> = () => ContainerRef<ContainerElement>;
export interface CodeMirror<ContainerElement extends Element = Element> {
getView: GetView;
useView: UseViewHook;
useViewEffect: UseViewEffectHook;
useViewDispatch: UseViewDispatchHook;
useContainerRef: UseContainerRefHook<ContainerElement>;
export interface CodeMirrorHooks {
useView: () => EditorView | null;
useViewEffect: (setup: ViewEffectSetup) => void;
}
export type CodeMirrorWithHooks = CodeMirror & CodeMirrorHooks;
//# sourceMappingURL=types.d.ts.map
{
"name": "@codemirror-toolkit/react",
"version": "0.6.0",
"version": "0.7.0",
"description": "A small and flexible solution for binding CodeMirror 6 to React",

@@ -50,6 +50,6 @@ "type": "module",

"@codemirror/view": "^6.0.0",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
"@types/react": ">=16.7.0",
"@types/react-dom": ">=16.7.0",
"react": ">=16.8.0",
"react-dom": ">=16.8.0"
},

@@ -65,10 +65,10 @@ "peerDependenciesMeta": {

"devDependencies": {
"@codemirror/state": "^6.3.3",
"@codemirror/view": "^6.22.3",
"@testing-library/react": "^14.1.2",
"@types/react": "^18.2.45",
"@types/react-dom": "^18.2.18",
"react": "^18.2.0",
"react-dom": "^18.2.0"
"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.33.0",
"@testing-library/react": "^16.0.1",
"@types/react": "^18.3.5",
"@types/react-dom": "^18.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
}
}

@@ -24,2 +24,5 @@ # @codemirror-toolkit/react

yarn add @codemirror-toolkit/react
# pnpm
pnpm add @codemirror-toolkit/react
```

@@ -29,2 +32,106 @@

<details>
<summary><h2>Migrate from 0.6.x</h2></summary>
- `createCodeMirror` is refactored to a core function without hooks. Use `create` instead for a similar functionality with hooks.
Before:
```typescript
const cm = createCodeMirror(config)
```
After:
```typescript
const cm = create(config)
```
- `create` now provides `useView` and `useViewEffect` hooks.
Before:
```typescript
const { useView, useViewEffect } = createCodeMirror(config)
```
After:
```typescript
const { useView, useViewEffect } = create(config)
```
- `createCodeMirrorContext` is renamed to `createContext` and does not provide hooks directly. Use `useCodeMirror` to access the CodeMirror instance, then use the exported hooks with this instance.
Before:
```typescript
const { Provider, useView, useViewEffect } = createCodeMirrorContext()
```
After:
```typescript
import { useView, useViewEffect } from '@codemirror-toolkit/react'
const { Provider, useCodeMirror } = createContext()
// Then in your component:
const cm = useCodeMirror()
useView(cm)
useViewEffect(cm, effectSetup)
```
- `useViewEffect` now requires the setup function to be memoized or have a stable reference to prevent the effect from firing on every render.
Before:
```typescript
useViewEffect((view) => {
// Effect logic
})
```
After:
<!-- prettier-ignore -->
```typescript
const effectSetup = useCallback((view) => {
// Effect logic
}, [/* dependencies */])
useViewEffect(cm, effectSetup)
```
- The `useContainerRef` hook has been replaced with a `setContainer` function.
Before:
```typescript
const { useContainerRef } = createCodeMirror(config)
function Editor() {
const containerRef = useContainerRef()
return <div ref={containerRef} />
}
```
After:
```typescript
const { setContainer } = create(config)
function Editor() {
return <div ref={setContainer} />
}
```
- Configuration can now be set using `setConfig`.
```typescript
const { setConfig } = create()
setConfig(config)
```
</details>
## Usage

@@ -34,78 +141,78 @@

<!-- prettier-ignore -->
```ts
import { createCodeMirror } from '@codemirror-toolkit/react'
import { create } from '@codemirror-toolkit/react'
const codeMirror = createCodeMirror<HTMLDivElement>((prevState) => ({
doc: prevState?.doc ?? 'Hello World!',
// ...otherConfig,
const cm = create((prevState) => ({
state: prevState, // useful for HMR
doc: 'Hello World!',
}))
// if you want to use them in other files
export const { useViewEffect, useContainerRef /* ... */ } = codeMirror
export const {
getView,
useView,
useViewEffect,
setContainer,
setConfig,
subscribe,
} = cm
```
Then bind your components with the hooks:
Then bind your components with a callback ref:
```tsx
function Editor() {
const containerRef = useContainerRef()
return <div ref={containerRef} />
return <div ref={setContainer} />
}
```
function App() {
const [showEditor, setShowEditor] = useState(true)
const [lastInput, setLastInput] = useState('')
useViewEffect((view) => {
console.log('EditorView is created')
return () => {
console.log('EditorView is destroyed')
// expect(view.dom.parentElement).toBeNull()
setLastInput(view.state.doc.toString())
### Initiate with data from component
#### Option 1:
<!-- prettier-ignore -->
```tsx
import { create } from '@codemirror-toolkit/react'
import { useCallback } from 'react'
const { setContainer, setConfig } = create()
interface Props {
initialInput: string
}
function Editor({ initialInput }: Props) {
const ref = useCallback((node: HTMLDivElement | null) => {
setContainer(node)
if (node) {
setConfig({
doc: initialInput,
})
}
})
return (
<>
<button onClick={() => setShowEditor(!showEditor)}>
{showEditor ? 'Destroy' : 'Create'} Editor
</button>
{showEditor ? (
<Editor />
) : (
<div>
<p>Editor destroyed</p>
<p>Last input: {lastInput}</p>
</div>
)}
</>
)
}, [initialInput])
return <div ref={ref} />
}
```
:warning: An instance of `EditorView` will be created **only when** a DOM node is assigned to `containerRef.current`, and will be destroyed **only when** `containerRef.current` is set back to `null`.
#### Option 2:
Use `createContext`, see below.
### With Context Provider
All the functions and hooks created with `createCodeMirror` don't require a context provider to use in different components, but in some cases you may want to instantiate `EditorView` with props from a component. In this case, you can use `createCodeMirrorWithContext` to create an instance within a context:
```tsx
import { createCodeMirrorWithContext } from '@codemirror-toolkit/react'
import { createContext } from '@codemirror-toolkit/react'
const {
Provider: CodeMirrorProvider,
useView,
useContainerRef,
// ...
} = createCodeMirrorWithContext<HTMLDivElement>('CodeMirrorContext')
const { Provider: CodeMirrorProvider, useCodeMirror } = createContext()
function MenuBar() {
const view = useView()
// ...
function Editor() {
const { setContainer } = useCodeMirror()
return <div ref={setContainer} />
}
function Editor() {
const containerRef = useContainerRef()
return <div ref={containerRef} />
interface Props {
initialInput: string
}
function App({ initialInput }: { initialInput: string }) {
function EditorWrapper({ initialInput }: Props) {
return (

@@ -115,5 +222,3 @@ <CodeMirrorProvider

doc: initialInput,
// ...otherConfig,
}}>
<MenuBar />
<Editor />

@@ -129,4 +234,2 @@ </CodeMirrorProvider>

There are only two functions exported: `createCodeMirror` and `createCodeMirrorWithContext`.
### Common Types

@@ -137,32 +240,27 @@

import type { EditorView, EditorViewConfig } from '@codemirror/view'
import type { EffectCallback, MutableRefObject } from 'react'
import type { EffectCallback } from 'react'
type EditorViewConfigWithoutParentElement = Omit<EditorViewConfig, 'parent'>
interface CodeMirrorConfig extends EditorViewConfigWithoutParentElement {}
type EditorViewConfigCreator = (prevState: EditorState | undefined) => EditorViewConfig
type CodeMirrorConfig = EditorViewConfig | EditorViewConfigCreator
type CodeMirrorConfigCreator = (prevState: EditorState | undefined) => CodeMirrorConfig
type ProvidedCodeMirrorConfig = CodeMirrorConfig | CodeMirrorConfigCreator
type ViewChangeHandler = (view: EditorView | null) => void
type GetView = () => EditorView | null
type UseViewHook = () => EditorView | null
type ViewContainer = Element | DocumentFragment
interface CodeMirror {
getView: () => EditorView | null
subscribe: (onViewChange: ViewChangeHandler) => () => void
setContainer: (container: ViewContainer | null) => void
setConfig: (config: CodeMirrorConfig) => void
}
type ViewEffectCleanup = ReturnType<EffectCallback>
type ViewEffectSetup = (view: EditorView) => ViewEffectCleanup
type UseViewEffectHook = (setup: ViewEffectSetup) => void
type ViewDispath = typeof EditorView.prototype.dispatch
type UseViewDispatchHook = () => ViewDispath
interface CodeMirrorHooks {
useView: () => EditorView | null
useViewEffect: (setup: ViewEffectSetup) => void
}
type ContainerRef<ContainerElement extends Element = Element> =
MutableRefObject<ContainerElement | null>
type UseContainerRefHook<ContainerElement extends Element = Element> =
() => ContainerRef<ContainerElement>
interface CodeMirror<ContainerElement extends Element = Element> {
getView: GetView
useView: UseViewHook
useViewEffect: UseViewEffectHook
useViewDispatch: UseViewDispatchHook
useContainerRef: UseContainerRefHook<ContainerElement>
}
type CodeMirrorWithHooks = CodeMirror & CodeMirrorHooks
```

@@ -173,40 +271,48 @@

```ts
function createCodeMirror<ContainerElement extends Element>(
config?: ProvidedCodeMirrorConfig,
): CodeMirror<ContainerElement>
function createCodeMirror(initialConfig?: CodeMirrorConfig): CodeMirror
```
### `createCodeMirrorWithContext`
### `create`
```ts
function create(config?: CodeMirrorConfig): CodeMirrorWithHooks
```
### `createContext`
```ts
import type { FunctionComponent, PropsWithChildren } from 'react'
interface CodeMirrorProps {
config?: ProvidedCodeMirrorConfig
config?: CodeMirrorConfig
}
interface CodeMirrorProviderProps extends PropsWithChildren<CodeMirrorProps> {}
interface CodeMirrorProvider extends FunctionComponent<CodeMirrorProviderProps> {}
type UseCodeMirrorContextHook<ContainerElement extends Element = Element> =
() => CodeMirror<ContainerElement>
type UseGetViewHook = () => GetView
interface CodeMirrorWithContext<ContainerElement extends Element = Element> {
interface CodeMirrorContext {
Provider: CodeMirrorProvider
useContext: UseCodeMirrorContextHook<ContainerElement>
useGetView: UseGetViewHook
useView: UseViewHook
useViewEffect: UseViewEffectHook
useViewDispatch: UseViewDispatchHook
useContainerRef: UseContainerRefHook<ContainerElement>
useCodeMirror: () => CodeMirror
}
function createCodeMirrorWithContext<ContainerElement extends Element>(
displayName?: string | false,
): CodeMirrorWithContext<ContainerElement>
function createContext(): CodeMirrorContext
```
### `useView`
```ts
function useView(cm: CodeMirror): EditorView | null
```
### `useViewEffect`
```ts
function defineViewEffect(setup: ViewEffectSetup): ViewEffectSetup
function useViewEffect(cm: CodeMirror, setup: ViewEffectSetup): void
```
## License
MIT License @ 2022-Present [Xuanbo Cheng](https://github.com/exuanbo)
import type { FunctionComponent, PropsWithChildren } from 'react'
import { createContext, createElement, useContext } from 'react'
import * as React from 'react'
import { createElement, useContext, useRef } from 'react'
import { createCodeMirror } from './create.js'
import type {
CodeMirror,
GetView,
ProvidedCodeMirrorConfig,
UseContainerRefHook,
UseViewDispatchHook,
UseViewEffectHook,
UseViewHook,
} from './types.js'
import { toPascalCase } from './utils/toPascalCase.js'
import { useSingleton } from './utils/useSingleton.js'
import { createCodeMirror } from './core'
import type { CodeMirror, CodeMirrorConfig } from './types'
export interface CodeMirrorProps {
config?: ProvidedCodeMirrorConfig
config?: CodeMirrorConfig
}

@@ -25,39 +16,23 @@

export type UseCodeMirrorContextHook<ContainerElement extends Element = Element> =
() => CodeMirror<ContainerElement>
export type UseGetViewHook = () => GetView
export interface CodeMirrorWithContext<ContainerElement extends Element = Element> {
export interface CodeMirrorContext {
Provider: CodeMirrorProvider
useContext: UseCodeMirrorContextHook<ContainerElement>
useGetView: UseGetViewHook
useView: UseViewHook
useViewEffect: UseViewEffectHook
useViewDispatch: UseViewDispatchHook
useContainerRef: UseContainerRefHook<ContainerElement>
useCodeMirror: () => CodeMirror
}
export function createCodeMirrorWithContext<ContainerElement extends Element>(
displayName?: string | false,
): CodeMirrorWithContext<ContainerElement> {
const InternalCodeMirrorContext = createContext<CodeMirror<ContainerElement> | null>(null)
export function createContext(): CodeMirrorContext {
const CodeMirrorContext = React.createContext<CodeMirror | null>(null)
const CodeMirrorProvider: CodeMirrorProvider = ({ config, children }) => {
const instance = useSingleton(() => createCodeMirror<ContainerElement>(config))
return /*#__PURE__*/ createElement(
InternalCodeMirrorContext.Provider,
{ value: instance },
children,
)
const instanceRef = useRef<CodeMirror | null>(null)
function getInstance() {
if (!instanceRef.current) {
instanceRef.current = createCodeMirror(config)
}
return instanceRef.current
}
return createElement(CodeMirrorContext.Provider, { value: getInstance() }, children)
}
if (displayName) {
displayName = toPascalCase(displayName)
CodeMirrorProvider.displayName = `${displayName}.Provider`
InternalCodeMirrorContext.displayName = `Internal${displayName}`
}
const useCodeMirrorContext: UseCodeMirrorContextHook<ContainerElement> = () => {
const instance = useContext(InternalCodeMirrorContext)
function useCodeMirrorContext() {
const instance = useContext(CodeMirrorContext)
if (!instance) {

@@ -71,36 +46,6 @@ throw new Error(

const useGetView: UseGetViewHook = () => {
const { getView: getContextView } = useCodeMirrorContext()
return getContextView
}
const useView: UseViewHook = () => {
const { useView: useContextView } = useCodeMirrorContext()
return useContextView()
}
const useViewEffect: UseViewEffectHook = (setup) => {
const { useViewEffect: useContextViewEffect } = useCodeMirrorContext()
return useContextViewEffect(setup)
}
const useViewDispatch: UseViewDispatchHook = () => {
const { useViewDispatch: useContextViewDispatch } = useCodeMirrorContext()
return useContextViewDispatch()
}
const useContainerRef: UseContainerRefHook<ContainerElement> = () => {
const { useContainerRef: useContextContainerRef } = useCodeMirrorContext()
return useContextContainerRef()
}
return {
Provider: CodeMirrorProvider,
useContext: useCodeMirrorContext,
useGetView,
useView,
useViewEffect,
useViewDispatch,
useContainerRef,
useCodeMirror: useCodeMirrorContext,
}
}

@@ -1,137 +0,12 @@

import type { EditorState } from '@codemirror/state'
import { EditorView } from '@codemirror/view'
import { useCallback, useDebugValue, useEffect, useSyncExternalStore } from 'react'
import { createCodeMirror } from './core'
import { useView, useViewEffect } from './hooks'
import type { CodeMirrorConfig, CodeMirrorWithHooks } from './types'
import type {
CodeMirror,
ContainerRef,
GetView,
ProvidedCodeMirrorConfig,
UseContainerRefHook,
UseViewDispatchHook,
UseViewEffectHook,
UseViewHook,
} from './types.js'
import { createAsyncScheduler } from './utils/asyncScheduler.js'
import { isFunction } from './utils/isFunction.js'
import { useEffectEvent } from './utils/useEffectEventShim.js'
export function createCodeMirror<ContainerElement extends Element>(
config?: ProvidedCodeMirrorConfig,
): CodeMirror<ContainerElement> {
let prevState: EditorState | undefined
let currentView: EditorView | null = null
function createConfig() {
return (isFunction(config) ? config : () => config)(prevState)
}
function createView(container: ContainerElement) {
return new EditorView({
...createConfig(),
parent: container,
})
}
type ViewChangeCallback = () => void
const viewChangeCallbacks = new Set<ViewChangeCallback>()
type UnsubscribeViewChange = () => void
function subscribeViewChange(callback: ViewChangeCallback): UnsubscribeViewChange {
viewChangeCallbacks.add(callback)
return () => viewChangeCallbacks.delete(callback)
}
function publishViewChange() {
viewChangeCallbacks.forEach((callback) => callback())
}
function setView(view: EditorView | null) {
if (view === currentView) {
return
}
if (currentView) {
prevState = currentView.state
currentView.destroy()
}
currentView = view
publishViewChange()
}
const getView: GetView = () => currentView
/* v8 ignore next */
const getServerView: GetView = () => null
const useView: UseViewHook = () => {
const view = useSyncExternalStore(subscribeViewChange, getView, getServerView)
useDebugValue(view)
return view
}
const useViewEffect: UseViewEffectHook = (setup) => {
const setupEvent = useEffectEvent((view: EditorView | null) => view && setup(view))
useEffect(() => {
let cleanup = setupEvent(getView())
const unsubscribe = subscribeViewChange(() => {
cleanup?.()
cleanup = setupEvent(getView())
})
return () => {
unsubscribe()
cleanup?.()
}
}, [setupEvent])
}
const useViewDispatch: UseViewDispatchHook = () =>
useCallback((...specs) => {
const view = getView()
if (!view) {
throw new TypeError('Cannot dispatch transaction without a view')
}
// @ts-expect-error: overloaded signature
view.dispatch(...specs)
}, [])
function createContainerRef(): ContainerRef<ContainerElement> {
let currentContainer: ContainerElement | null = null
const scheduler = createAsyncScheduler()
return Object.seal({
get current() {
return currentContainer
},
set current(container) {
if (container === currentContainer) {
return
}
currentContainer = container
scheduler.cancel()
scheduler.request(() => {
setView(null)
setView(container && createView(container))
})
},
})
}
let currentContainerRef: ContainerRef<ContainerElement> | undefined
function getContainerRef() {
return currentContainerRef ?? (currentContainerRef = createContainerRef())
}
const useContainerRef: UseContainerRefHook<ContainerElement> = () => {
const containerRef = getContainerRef()
useDebugValue(containerRef)
return containerRef
}
export function create(config?: CodeMirrorConfig): CodeMirrorWithHooks {
const cm = createCodeMirror(config)
return {
getView,
useView,
useViewEffect,
useViewDispatch,
useContainerRef,
...cm,
useView: () => useView(cm),
useViewEffect: (setup) => useViewEffect(cm, setup),
}
}

@@ -1,3 +0,5 @@

export * from './context.js'
export * from './create.js'
export * from './types.js'
export * from './context'
export * from './core'
export * from './create'
export * from './hooks'
export * from './types'
import type { EditorState } from '@codemirror/state'
import type { EditorView, EditorViewConfig } from '@codemirror/view'
import type { EffectCallback, MutableRefObject } from 'react'
import type { EffectCallback } from 'react'
export type EditorViewConfigWithoutParentElement = Omit<EditorViewConfig, 'parent'>
export interface CodeMirrorConfig extends EditorViewConfigWithoutParentElement {}
export type EditorViewConfigCreator = (prevState: EditorState | undefined) => EditorViewConfig
export type CodeMirrorConfig = EditorViewConfig | EditorViewConfigCreator
export type CodeMirrorConfigCreator = (prevState: EditorState | undefined) => CodeMirrorConfig
export type ProvidedCodeMirrorConfig = CodeMirrorConfig | CodeMirrorConfigCreator
export type ViewChangeHandler = (view: EditorView | null) => void
export type GetView = () => EditorView | null
export type UseViewHook = () => EditorView | null
export type ViewContainer = Element | DocumentFragment
export interface CodeMirror {
getView: () => EditorView | null
subscribe: (onViewChange: ViewChangeHandler) => () => void
setContainer: (container: ViewContainer | null) => void
setConfig: (config: CodeMirrorConfig) => void
}
export type ViewEffectCleanup = ReturnType<EffectCallback>
export type ViewEffectSetup = (view: EditorView) => ViewEffectCleanup
export type UseViewEffectHook = (setup: ViewEffectSetup) => void
export type ViewDispath = typeof EditorView.prototype.dispatch
export type UseViewDispatchHook = () => ViewDispath
export interface CodeMirrorHooks {
useView: () => EditorView | null
useViewEffect: (setup: ViewEffectSetup) => void
}
export type ContainerRef<ContainerElement extends Element = Element> =
MutableRefObject<ContainerElement | null>
export type UseContainerRefHook<ContainerElement extends Element = Element> =
() => ContainerRef<ContainerElement>
export interface CodeMirror<ContainerElement extends Element = Element> {
getView: GetView
useView: UseViewHook
useViewEffect: UseViewEffectHook
useViewDispatch: UseViewDispatchHook
useContainerRef: UseContainerRefHook<ContainerElement>
}
export type CodeMirrorWithHooks = CodeMirror & CodeMirrorHooks

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc