Skip to content

Commit

Permalink
fix: add global state for slides data
Browse files Browse the repository at this point in the history
  • Loading branch information
ttypic committed Aug 21, 2023
1 parent 86c3c46 commit 02e2caf
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 6 deletions.
2 changes: 1 addition & 1 deletion demo/src/components/EditableText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const EditableText: React.FC<EditableTextProps> = ({
const enterPressed = key === 'Enter';
const deleteButtonPressed = key === 'Backspace' || key === 'Delete';
const replacing = window.getSelection()?.toString() !== '';
const limitReached = elementRef.current?.innerText.length ?? 0 >= maxChars;
const limitReached = (elementRef.current?.innerText.length ?? 0) >= maxChars;
if (enterPressed || (limitReached && !replacing && !deleteButtonPressed)) {
event.stopPropagation();
event.preventDefault();
Expand Down
7 changes: 5 additions & 2 deletions demo/src/components/Paragraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { StickyLabel } from './StickyLabel';
import { LockFilledSvg } from './svg/LockedFilled.tsx';
import { EditableText } from './EditableText.tsx';
import { buildLockId } from '../utils/locking.ts';
import { useSlideElementContent } from '../hooks/useSlideElementContent.ts';

interface Props extends React.HTMLAttributes<HTMLParagraphElement> {
id: string;
Expand All @@ -23,11 +24,13 @@ export const Paragraph = ({ variant = 'regular', id, slide, className, children,
const { outlineClasses, stickyLabelClasses } = getOutlineClasses(activeMember);
const { locked, lockedByYou } = useLockStatus(slide, id, self?.connectionId);
const memberName = getMemberFirstName(activeMember);
const channelName = `[?rewind=1]${spaceName}-${buildLockId(slide, id)}`;
const lockId = buildLockId(slide, id);
const channelName = `[?rewind=1]${spaceName}${lockId}`;
const [content, setContent] = useSlideElementContent(lockId, children);
const { channel } = useChannel(channelName, (message) => {
if (message.connectionId === self?.connectionId) return;
setContent(message.data);
});
const [content, setContent] = useState(children);
const editIsNotAllowed = locked && !lockedByYou && !!activeMember;

return (
Expand Down
24 changes: 24 additions & 0 deletions demo/src/components/SlidesStateContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React, { useMemo, useState } from 'react';

interface SlidesStateContextProps {
slidesState: Record<string, string>;
setContent(id: string, nextContent: string): void;
}
export const SlidesStateContext = React.createContext<SlidesStateContextProps>({
slidesState: {},
setContent: () => {},
});

export const SlidesStateContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [slidesState, setSlidesState] = useState<Record<string, string>>({});
const value = useMemo(
() => ({
slidesState,
setContent: (id: string, nextContent: string) => {
setSlidesState((prevState) => ({ ...prevState, [id]: nextContent }));
},
}),
[slidesState, setSlidesState],
);
return <SlidesStateContext.Provider value={value}>{children}</SlidesStateContext.Provider>;
};
7 changes: 5 additions & 2 deletions demo/src/components/Title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { LockFilledSvg } from './svg/LockedFilled.tsx';
import { StickyLabel } from './StickyLabel.tsx';
import { EditableText } from './EditableText.tsx';
import { buildLockId } from '../utils/locking.ts';
import { useSlideElementContent } from '../hooks/useSlideElementContent.ts';

interface Props extends React.HTMLAttributes<HTMLHeadingElement> {
id: string;
Expand All @@ -24,11 +25,13 @@ export const Title = ({ variant = 'h1', className, id, slide, children, ...props
const { outlineClasses, stickyLabelClasses } = getOutlineClasses(activeMember);
const memberName = getMemberFirstName(activeMember);
const { locked, lockedByYou } = useLockStatus(slide, id, self?.connectionId);
const channelName = `[?rewind=1]${spaceName}-${buildLockId(slide, id)}`;
const lockId = buildLockId(slide, id);
const channelName = `[?rewind=1]${spaceName}${lockId}`;
const [content, setContent] = useSlideElementContent(lockId, children);
const { channel } = useChannel(channelName, (message) => {
if (message.connectionId === self?.connectionId) return;
setContent(message.data);
});
const [content, setContent] = useState(children);
const editIsNotAllowed = locked && !lockedByYou && !!activeMember;

return (
Expand Down
13 changes: 13 additions & 0 deletions demo/src/hooks/useSlideElementContent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useCallback, useContext } from 'react';
import { SlidesStateContext } from '../components/SlidesStateContext.tsx';

export const useSlideElementContent = (id: string, defaultContent: string) => {
const { slidesState, setContent } = useContext(SlidesStateContext);
const setNextContent = useCallback(
(nextContent: string) => {
setContent(id, nextContent);
},
[id],
);
return [slidesState[id] ?? defaultContent, setNextContent] as const;
};
5 changes: 4 additions & 1 deletion demo/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,17 @@ import App from './App';
import './index.css';

import { ably, SpaceContextProvider } from './components';
import { SlidesStateContext, SlidesStateContextProvider } from './components/SlidesStateContext.tsx';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);

root.render(
<React.StrictMode>
<SpaceContextProvider>
<AblyProvider client={ably}>
<App />
<SlidesStateContextProvider>
<App />
</SlidesStateContextProvider>
</AblyProvider>
</SpaceContextProvider>
</React.StrictMode>,
Expand Down

0 comments on commit 02e2caf

Please sign in to comment.