Skip to content

Commit

Permalink
Merge pull request #31 from streamich/api-improvements
Browse files Browse the repository at this point in the history
Api improvements
  • Loading branch information
streamich authored Jul 12, 2024
2 parents 54fa412 + c6cfaef commit f860dd6
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 16 deletions.
6 changes: 3 additions & 3 deletions src/ClickableJsonCrdt/JsonCrdtRegion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export interface JsonCrdtRegionProps {

export const JsonCrdtRegion: React.FC<JsonCrdtRegionProps> = ({node, editing, children}) => {
const {model} = useJsonCrdt();
const {compact} = useStyles();
const {compact, readonly} = useStyles();
const {focused, focus, pointed, point} = useFocus();
const nodeId = id(node);
const [edit, setEdit] = React.useState(false);
Expand Down Expand Up @@ -81,7 +81,7 @@ export const JsonCrdtRegion: React.FC<JsonCrdtRegionProps> = ({node, editing, ch
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onDelete={
editing
editing || readonly
? undefined
: !isFocused || isTombstone
? undefined
Expand All @@ -108,7 +108,7 @@ export const JsonCrdtRegion: React.FC<JsonCrdtRegionProps> = ({node, editing, ch
: undefined
}
onEdit={
editing
editing || readonly
? undefined
: isFocused &&
(parentNodeType === 'obj' ||
Expand Down
9 changes: 8 additions & 1 deletion src/ClickableJsonCrdt/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ const doc2 = {
};

export const Primary: StoryObj<typeof meta> = {
render: () => <Demo view={schema1} />,
render: () => <Demo view={schema1} onFocus={(id) => console.log('onFocus', id)} />,
parameters: {
layout: 'fullscreen',
},
};

export const Readonly: StoryObj<typeof meta> = {
render: () => <Demo view={schema1} readonly />,
parameters: {
layout: 'fullscreen',
},
Expand Down
8 changes: 4 additions & 4 deletions src/ClickableJsonCrdt/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {context as crdt} from './context';
import {StyleContextValue, context as styles} from '../context/style';
import {NodeRef, nodeRef} from './NodeRef';
import {Root} from '../Root';
import {FocusProvider} from '../context/focus';
import {FocusProvider, FocusProviderProps} from '../context/focus';
import {
ConNode,
ValNode,
Expand Down Expand Up @@ -34,7 +34,7 @@ const render = (node: NodeRef<JsonNode>): React.ReactNode => {
return '∅';
};

export interface ClickableJsonCrdtProps extends StyleContextValue {
export interface ClickableJsonCrdtProps extends StyleContextValue, Pick<FocusProviderProps, 'onFocus'> {
/**
* The JSON CRDT model to display.
*/
Expand All @@ -47,13 +47,13 @@ export interface ClickableJsonCrdtProps extends StyleContextValue {
}

export const ClickableJsonCrdt: React.FC<ClickableJsonCrdtProps> = (props) => {
const {model, compact, readonly, showRoot} = props;
const {model, compact, readonly, showRoot, onFocus} = props;
const node = React.useMemo(() => nodeRef(showRoot ? model.root : model.root.node(), null, ''), [model]);

return (
<styles.Provider value={{compact, readonly}}>
<crdt.Provider value={{model, render}}>
<FocusProvider>
<FocusProvider onFocus={onFocus}>
<Root>{render(node)}</Root>
</FocusProvider>
</crdt.Provider>
Expand Down
6 changes: 4 additions & 2 deletions src/ClickableJsonCrdt/nodes/JsonCrdtArrNode/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import {JsonCrdtProperty} from '../../JsonCrdtProperty';
import {JsonCrdtObjectLayout} from '../../JsonCrdtObjectLayout';
import {useRerender} from '../../hooks';
import {InsertElement} from './InsertElement';
import {useStyles} from '../../../context/style';
import type {ArrNode} from 'json-joy/lib/json-crdt';

export interface JsonCrdtArrNodeProps {
node: NodeRef<ArrNode>;
}

export const JsonCrdtArrNode: React.FC<JsonCrdtArrNodeProps> = ({node}) => {
const {readonly} = useStyles();
const {render} = useJsonCrdt();
useRerender(node);

Expand All @@ -27,7 +29,7 @@ export const JsonCrdtArrNode: React.FC<JsonCrdtArrNodeProps> = ({node}) => {
const key = child.id.sid + '.' + child.id.time + '.' + i;
entries.push(
<React.Fragment key={key}>
<InsertElement key={key} node={node} index={i} />
{!readonly && <InsertElement key={key} node={node} index={i} />}
<span className={css.line}>{render(childNodeRef)}</span>
</React.Fragment>,
);
Expand All @@ -43,7 +45,7 @@ export const JsonCrdtArrNode: React.FC<JsonCrdtArrNodeProps> = ({node}) => {
brackets={['[', ']']}
>
{entries}
<InsertElement key={node.node.length()} node={node} index={node.node.length()} />
{!readonly && <InsertElement key={node.node.length()} node={node} index={node.node.length()} />}
</JsonCrdtObjectLayout>
</JsonCrdtRegion>
);
Expand Down
4 changes: 3 additions & 1 deletion src/ClickableJsonCrdt/nodes/JsonCrdtObjNode/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {JsonCrdtObjectLayout} from '../../JsonCrdtObjectLayout';
import {useRerender} from '../../hooks';
import {AddKey} from './AddKey';
import {Tombstones} from './Tombstones';
import {useStyles} from '../../../context/style';

const isTombstone = (node: JsonNode) => node instanceof ConNode && node.val === undefined;

Expand All @@ -17,6 +18,7 @@ export interface JsonCrdtObjNodeProps {
}

export const JsonCrdtObjNode: React.FC<JsonCrdtObjNodeProps> = ({node}) => {
const {readonly} = useStyles();
const {render} = useJsonCrdt();
useRerender(node);

Expand All @@ -42,7 +44,7 @@ export const JsonCrdtObjNode: React.FC<JsonCrdtObjNodeProps> = ({node}) => {
collapsedView={!!entries.length && entries.length}
>
{entries}
<AddKey node={node} />
{!readonly && <AddKey node={node} />}
{!!tombstones.length && <Tombstones tombstones={tombstones} />}
</JsonCrdtObjectLayout>
</JsonCrdtRegion>
Expand Down
4 changes: 2 additions & 2 deletions src/ClickableJsonCrdt/nodes/JsonCrdtStrNode/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface JsonCrdtStrNodeProps {

export const JsonCrdtStrNode: React.FC<JsonCrdtStrNodeProps> = ({node}) => {
const [t] = useT();
const {formal} = useStyles();
const {formal, readonly} = useStyles();
const {focused} = useFocus();
const [editing, setEditing] = React.useState(false);

Expand All @@ -49,7 +49,7 @@ export const JsonCrdtStrNode: React.FC<JsonCrdtStrNodeProps> = ({node}) => {
) : (
<span
className={atomClass + (isFocused ? atomFocusedClass : '')}
onClick={isFocused ? () => setEditing(true) : undefined}
onClick={isFocused && !readonly ? () => setEditing(true) : undefined}
>
<JsonAtom value={node.node.view()} />
<span className={css.tooltip}>{t('Edit')}</span>
Expand Down
4 changes: 3 additions & 1 deletion src/ClickableJsonCrdt/nodes/JsonCrdtVecNode/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ import {JsonCrdtObjectLayout} from '../../JsonCrdtObjectLayout';
import {useRerenderModel} from '../../hooks';
import type {VecNode} from 'json-joy/lib/json-crdt';
import {PushElement} from './PushElement';
import {useStyles} from '../../../context/style';

export interface JsonCrdtVecNodeProps {
node: NodeRef<VecNode>;
}

export const JsonCrdtVecNode: React.FC<JsonCrdtVecNodeProps> = ({node}) => {
const {readonly} = useStyles();
const {render} = useJsonCrdt();
useRerenderModel();

Expand All @@ -40,7 +42,7 @@ export const JsonCrdtVecNode: React.FC<JsonCrdtVecNodeProps> = ({node}) => {
header={<span style={{opacity: 0.5, display: 'inline-block', margin: '0.25em 0 0 -0.3em'}}></span>}
>
{entries}
<PushElement node={node} />
{!readonly && <PushElement node={node} />}
</JsonCrdtObjectLayout>
</JsonCrdtRegion>
);
Expand Down
17 changes: 15 additions & 2 deletions src/context/focus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,23 @@ export const useIsFocused = (node: string) => {
return focused === node;
};

export const FocusProvider: React.FC<{children: React.ReactNode}> = ({children}) => {
const [focused, focus] = React.useState<string | null>(null);
export interface FocusProviderProps {
children: React.ReactNode;
onFocus?: (id: string | null) => void;
}

export const FocusProvider: React.FC<FocusProviderProps> = ({children, onFocus}) => {
const [focused, _focus] = React.useState<string | null>(null);
const [pointed, point] = React.useState<string | null>(null);

const focus = React.useCallback(
(node: string | null) => {
_focus(node);
onFocus?.(node);
},
[onFocus],
);

React.useEffect(() => {
const listener = (e: KeyboardEvent) => {
const active = document.activeElement;
Expand Down

0 comments on commit f860dd6

Please sign in to comment.