-
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(json-crdt-peritext-ui): 🎸 create
cursor
plugin
- Loading branch information
Showing
14 changed files
with
154 additions
and
99 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// biome-ignore lint: React is used for JSX | ||
import * as React from 'react'; | ||
import {usePeritext} from '../../react'; | ||
import {useSyncStore} from '../../react/hooks'; | ||
import {DefaultRendererColors} from './constants'; | ||
import type {InlineViewProps} from '../../react/InlineView'; | ||
|
||
interface RenderInlineSelectionProps extends RenderInlineProps { | ||
selection: [left: 'anchor' | 'focus' | '', right: 'anchor' | 'focus' | '']; | ||
} | ||
|
||
const RenderInlineSelection: React.FC<RenderInlineSelectionProps> = (props) => { | ||
const {children, selection} = props; | ||
const {dom} = usePeritext(); | ||
const focus = useSyncStore(dom.cursor.focus); | ||
|
||
const [left, right] = selection; | ||
const style: React.CSSProperties = { | ||
backgroundColor: focus ? DefaultRendererColors.ActiveSelection : DefaultRendererColors.InactiveSelection, | ||
borderRadius: left === 'anchor' ? '.25em 1px 1px .25em' : right === 'anchor' ? '1px .25em .25em 1px' : '1px', | ||
}; | ||
|
||
return <span style={style}>{children}</span>; | ||
}; | ||
|
||
export interface RenderInlineProps extends InlineViewProps { | ||
children: React.ReactNode; | ||
} | ||
|
||
export const RenderInline: React.FC<RenderInlineProps> = (props) => { | ||
const {inline, children} = props; | ||
const selection = inline.selection(); | ||
|
||
let element = children; | ||
|
||
if (selection) { | ||
element = ( | ||
<RenderInlineSelection {...props} selection={selection}> | ||
{element} | ||
</RenderInlineSelection> | ||
); | ||
} | ||
|
||
return element; | ||
}; |
59 changes: 59 additions & 0 deletions
59
src/json-crdt-peritext-ui/plugins/cursor/RenderPeritext.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import * as React from 'react'; | ||
import {context, type CursorPluginContextValue} from './context'; | ||
import {ValueSyncStore} from '../../../util/events/sync-store'; | ||
import type {ChangeDetail} from '../../events/types'; | ||
import type {PeritextSurfaceContextValue, PeritextViewProps} from '../../react'; | ||
|
||
export interface RenderPeritextProps extends PeritextViewProps { | ||
ctx?: PeritextSurfaceContextValue; | ||
children?: React.ReactNode; | ||
} | ||
|
||
export const RenderPeritext: React.FC<RenderPeritextProps> = ({ctx, children}) => { | ||
const value: CursorPluginContextValue = React.useMemo( | ||
() => ({ | ||
ctx, | ||
score: new ValueSyncStore(0), | ||
scoreDelta: new ValueSyncStore(0), | ||
lastVisScore: new ValueSyncStore(0), | ||
}), | ||
[ctx], | ||
); | ||
|
||
React.useEffect(() => { | ||
const dom = ctx?.dom; | ||
if (!dom || !value) return; | ||
let lastNow: number = 0; | ||
const listener = (event: CustomEvent<ChangeDetail>) => { | ||
const now = Date.now(); | ||
const timeDiff = now - lastNow; | ||
let delta = 0; | ||
switch (event.detail.ev?.type) { | ||
case 'delete': | ||
case 'insert': | ||
case 'format': | ||
case 'marker': { | ||
delta = timeDiff < 30 ? 10 : timeDiff < 70 ? 5 : timeDiff < 150 ? 2 : timeDiff <= 1000 ? 1 : -1; | ||
break; | ||
} | ||
default: { | ||
delta = timeDiff <= 1000 ? 0 : -1; | ||
break; | ||
} | ||
} | ||
if (delta) value.score.next(delta >= 0 ? value.score.value + delta : 0); | ||
value.scoreDelta.next(delta); | ||
lastNow = now; | ||
}; | ||
dom.et.addEventListener('change', listener); | ||
return () => { | ||
dom.et.removeEventListener('change', listener); | ||
}; | ||
}, [ctx?.dom, value]); | ||
|
||
return ( | ||
<context.Provider value={value}> | ||
{children} | ||
</context.Provider> | ||
); | ||
}; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import * as React from 'react'; | ||
import type {PeritextSurfaceContextValue} from '../../react'; | ||
import type {ValueSyncStore} from '../../../util/events/sync-store'; | ||
|
||
export interface CursorPluginContextValue { | ||
ctx?: PeritextSurfaceContextValue; | ||
|
||
/** Current score. */ | ||
score: ValueSyncStore<number>; | ||
|
||
/** By how much the score changed. */ | ||
scoreDelta: ValueSyncStore<number>; | ||
|
||
/** The last score that was shown to the user. */ | ||
lastVisScore: ValueSyncStore<number>; | ||
} | ||
|
||
export const context = React.createContext<CursorPluginContextValue>(null!); | ||
|
||
export const useCursorPlugin = () => React.useContext(context); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import * as React from 'react'; | ||
import {RenderCaret} from './RenderCaret'; | ||
import {RenderFocus} from './RenderFocus'; | ||
import {RenderAnchor} from './RenderAnchor'; | ||
import {RenderInline} from './RenderInline'; | ||
import {RenderPeritext} from './RenderPeritext'; | ||
import type {PeritextPlugin} from '../../react/types'; | ||
|
||
const h = React.createElement; | ||
|
||
/** | ||
* Plugin which renders the main cursor and all other current user local | ||
* cursors. | ||
*/ | ||
export const cursorPlugin: PeritextPlugin = { | ||
caret: (props, children) => h(RenderCaret, <any>props, children), | ||
focus: (props, children) => h(RenderFocus, <any>props, children), | ||
anchor: (props, children) => h(RenderAnchor, <any>props, children), | ||
inline: (props, children) => h(RenderInline, props as any, children), | ||
peritext: (props, children, ctx) => h(RenderPeritext, {...props, children, ctx}), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters