vzcode 1.6.0 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{index-BwUWRAvf.js → index--bvX81xc.js} +44 -44
- package/dist/assets/{index-DAYbg783.css → index-BKRpkJER.css} +1 -1
- package/dist/assets/{index-B2OgpmfL.js → index-CU0jqXHm.js} +62 -62
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/client/CodeEditor/getOrCreateEditor.ts +6 -0
- package/src/client/CodeEditor/index.tsx +19 -7
- package/src/client/CodeEditor/json1PresenceDisplay.ts +6 -5
- package/src/client/Icons/index.tsx +1 -0
- package/src/client/TabList/style.scss +2 -2
- package/src/client/VZCodeContext.tsx +8 -0
- package/src/client/VZSidebar/index.tsx +32 -1
- package/src/client/VZSidebar/styles.scss +5 -4
- package/src/client/useActions.ts +7 -0
- package/src/client/useTypeScript/worker/constants.ts +2 -1
- package/src/client/vzReducer/index.ts +12 -1
- package/src/client/vzReducer/toggleAutoFollowReducer.ts +12 -0
package/dist/index.html
CHANGED
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
|
|
21
21
|
rel="stylesheet"
|
|
22
22
|
/>
|
|
23
|
-
<script type="module" crossorigin src="/assets/index-
|
|
24
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
23
|
+
<script type="module" crossorigin src="/assets/index-CU0jqXHm.js"></script>
|
|
24
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BKRpkJER.css">
|
|
25
25
|
</head>
|
|
26
26
|
<body>
|
|
27
27
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -92,6 +92,7 @@ export const getOrCreateEditor = ({
|
|
|
92
92
|
typeScriptWorker,
|
|
93
93
|
customInteractRules,
|
|
94
94
|
allowGlobals,
|
|
95
|
+
enableAutoFollowRef,
|
|
95
96
|
}: {
|
|
96
97
|
fileId: FileId;
|
|
97
98
|
|
|
@@ -121,6 +122,10 @@ export const getOrCreateEditor = ({
|
|
|
121
122
|
typeScriptWorker: Worker;
|
|
122
123
|
customInteractRules?: Array<InteractRule>;
|
|
123
124
|
allowGlobals: boolean;
|
|
125
|
+
|
|
126
|
+
// Ref to a boolean that determines whether to
|
|
127
|
+
// enable auto-following the cursors of remote users.
|
|
128
|
+
enableAutoFollowRef: React.MutableRefObject<boolean>;
|
|
124
129
|
}): EditorCacheValue => {
|
|
125
130
|
// Cache hit
|
|
126
131
|
if (editorCache.has(fileId)) {
|
|
@@ -173,6 +178,7 @@ export const getOrCreateEditor = ({
|
|
|
173
178
|
json1PresenceDisplay({
|
|
174
179
|
path: textPath,
|
|
175
180
|
docPresence,
|
|
181
|
+
enableAutoFollowRef,
|
|
176
182
|
}),
|
|
177
183
|
);
|
|
178
184
|
}
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
useCallback,
|
|
5
5
|
useMemo,
|
|
6
6
|
useContext,
|
|
7
|
+
useEffect,
|
|
7
8
|
} from 'react';
|
|
8
9
|
import { Username } from '../../types';
|
|
9
10
|
import { EditorCacheValue } from '../useEditorCache';
|
|
@@ -36,10 +37,9 @@ export const CodeEditor = ({
|
|
|
36
37
|
typeScriptWorker,
|
|
37
38
|
theme,
|
|
38
39
|
codeEditorRef,
|
|
40
|
+
enableAutoFollow,
|
|
39
41
|
} = useContext(VZCodeContext);
|
|
40
42
|
|
|
41
|
-
const ref = codeEditorRef;
|
|
42
|
-
|
|
43
43
|
// Set `doc.data.isInteracting` to `true` when the user is interacting
|
|
44
44
|
// via interactive code widgets (e.g. Alt+drag), and `false` when they are not.
|
|
45
45
|
const interactTimeoutRef = useRef(null);
|
|
@@ -71,6 +71,13 @@ export const CodeEditor = ({
|
|
|
71
71
|
const usernameRef = useRef<Username>(username);
|
|
72
72
|
usernameRef.current = username;
|
|
73
73
|
|
|
74
|
+
// Track enableAutoFollow on a ref, so that we can use it in the
|
|
75
|
+
// CodeMirror extension.
|
|
76
|
+
const enableAutoFollowRef = useRef(enableAutoFollow);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
enableAutoFollowRef.current = enableAutoFollow;
|
|
79
|
+
}, [enableAutoFollow]);
|
|
80
|
+
|
|
74
81
|
// Get the editor corresponding to the active file.
|
|
75
82
|
// Looks in `editorCache` first, and if not found, creates a new editor.
|
|
76
83
|
const editorCacheValue: EditorCacheValue = useMemo(
|
|
@@ -89,6 +96,7 @@ export const CodeEditor = ({
|
|
|
89
96
|
typeScriptWorker,
|
|
90
97
|
customInteractRules,
|
|
91
98
|
allowGlobals,
|
|
99
|
+
enableAutoFollowRef,
|
|
92
100
|
}),
|
|
93
101
|
[
|
|
94
102
|
activeFileId,
|
|
@@ -109,11 +117,13 @@ export const CodeEditor = ({
|
|
|
109
117
|
// and the editor corresponding to the new file is added to the DOM.
|
|
110
118
|
useLayoutEffect(() => {
|
|
111
119
|
// Guard against cases where page is still loading.
|
|
112
|
-
if (!
|
|
120
|
+
if (!codeEditorRef.current) return;
|
|
113
121
|
if (!content) return;
|
|
114
122
|
|
|
115
123
|
// Add the editor and apply the prior scroll position to the DOM.
|
|
116
|
-
|
|
124
|
+
codeEditorRef.current.appendChild(
|
|
125
|
+
editorCacheValue.editor.dom,
|
|
126
|
+
);
|
|
117
127
|
editorCacheValue.editor.scrollDOM.scrollTo({
|
|
118
128
|
top: editorCacheValue.scrollPosition ?? 0,
|
|
119
129
|
});
|
|
@@ -123,7 +133,9 @@ export const CodeEditor = ({
|
|
|
123
133
|
// This happens every time `activeFileId` changes.
|
|
124
134
|
editorCacheValue.scrollPosition =
|
|
125
135
|
editorCacheValue.editor.scrollDOM.scrollTop;
|
|
126
|
-
|
|
136
|
+
codeEditorRef.current.removeChild(
|
|
137
|
+
editorCacheValue.editor.dom,
|
|
138
|
+
);
|
|
127
139
|
};
|
|
128
140
|
}, [shareDBDoc, editorCacheValue]);
|
|
129
141
|
|
|
@@ -142,8 +154,8 @@ export const CodeEditor = ({
|
|
|
142
154
|
return (
|
|
143
155
|
<div
|
|
144
156
|
className="vz-code-editor"
|
|
145
|
-
ref={
|
|
157
|
+
ref={codeEditorRef}
|
|
146
158
|
tabIndex={-1}
|
|
147
|
-
|
|
159
|
+
/>
|
|
148
160
|
);
|
|
149
161
|
};
|
|
@@ -10,10 +10,10 @@ import { Username } from '../../types';
|
|
|
10
10
|
|
|
11
11
|
const debug = false;
|
|
12
12
|
|
|
13
|
-
//
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
// export let enableAutoFollow = false;
|
|
14
|
+
// export const toggleAutoFollowButton = () => {
|
|
15
|
+
// enableAutoFollow = !enableAutoFollow;
|
|
16
|
+
// };
|
|
17
17
|
// Deals with receiving the broadcasted presence cursor locations
|
|
18
18
|
// from other clients and displaying them.
|
|
19
19
|
//
|
|
@@ -25,6 +25,7 @@ const enableAutoFollow = false;
|
|
|
25
25
|
export const json1PresenceDisplay = ({
|
|
26
26
|
path,
|
|
27
27
|
docPresence,
|
|
28
|
+
enableAutoFollowRef,
|
|
28
29
|
}) => [
|
|
29
30
|
ViewPlugin.fromClass(
|
|
30
31
|
class {
|
|
@@ -146,7 +147,7 @@ export const json1PresenceDisplay = ({
|
|
|
146
147
|
|
|
147
148
|
// Auto-follow all users when their presence is broadcast
|
|
148
149
|
// by scrolling them into view.
|
|
149
|
-
if (
|
|
150
|
+
if (enableAutoFollowRef.current) {
|
|
150
151
|
this.scrollToCursor(view);
|
|
151
152
|
}
|
|
152
153
|
});
|
|
@@ -10,6 +10,7 @@ export { FileSVG } from './FileSVG';
|
|
|
10
10
|
export { DirectoryArrowSVG } from './DirectoryArrowSVG';
|
|
11
11
|
export { PlaySVG } from './PlaySVG';
|
|
12
12
|
export { QuestionMarkSVG } from './QuestionMarkSVG';
|
|
13
|
+
export { PinSVG } from './PinSVG';
|
|
13
14
|
export { FolderSVG } from './FolderSVG';
|
|
14
15
|
export { SearchSVG } from './SearchSVG';
|
|
15
16
|
export { SearchFileSVG } from './SearchFileSVG';
|
|
@@ -149,6 +149,9 @@ export type VZCodeContextValue = {
|
|
|
149
149
|
|
|
150
150
|
hoveredItemId: ItemId | null;
|
|
151
151
|
setHoveredItemId: (itemId: ItemId | null) => void;
|
|
152
|
+
|
|
153
|
+
enableAutoFollow: boolean;
|
|
154
|
+
toggleAutoFollow: () => void;
|
|
152
155
|
};
|
|
153
156
|
|
|
154
157
|
export const VZCodeProvider = ({
|
|
@@ -236,6 +239,7 @@ export const VZCodeProvider = ({
|
|
|
236
239
|
isDocOpen,
|
|
237
240
|
editorWantsFocus,
|
|
238
241
|
username,
|
|
242
|
+
enableAutoFollow,
|
|
239
243
|
} = state;
|
|
240
244
|
|
|
241
245
|
// Functions for dispatching actions to the reducer.
|
|
@@ -256,6 +260,7 @@ export const VZCodeProvider = ({
|
|
|
256
260
|
closeDoc,
|
|
257
261
|
editorNoLongerWantsFocus,
|
|
258
262
|
setUsername,
|
|
263
|
+
toggleAutoFollow,
|
|
259
264
|
} = useActions(dispatch);
|
|
260
265
|
|
|
261
266
|
// Sync tab state to the URL.
|
|
@@ -428,6 +433,9 @@ export const VZCodeProvider = ({
|
|
|
428
433
|
|
|
429
434
|
hoveredItemId,
|
|
430
435
|
setHoveredItemId,
|
|
436
|
+
|
|
437
|
+
enableAutoFollow,
|
|
438
|
+
toggleAutoFollow,
|
|
431
439
|
};
|
|
432
440
|
|
|
433
441
|
return (
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
useCallback,
|
|
3
|
+
useContext,
|
|
4
|
+
useMemo,
|
|
5
|
+
useState,
|
|
6
|
+
} from 'react';
|
|
2
7
|
import {
|
|
3
8
|
FileId,
|
|
4
9
|
FileTree,
|
|
@@ -17,6 +22,7 @@ import {
|
|
|
17
22
|
NewSVG,
|
|
18
23
|
FileSVG,
|
|
19
24
|
QuestionMarkSVG,
|
|
25
|
+
PinSVG,
|
|
20
26
|
} from '../Icons';
|
|
21
27
|
import { VZCodeContext } from '../VZCodeContext';
|
|
22
28
|
import { Listing } from './Listing';
|
|
@@ -56,6 +62,8 @@ export const VZSidebar = ({
|
|
|
56
62
|
handleOpenCreateDirModal,
|
|
57
63
|
connected,
|
|
58
64
|
sidebarRef,
|
|
65
|
+
enableAutoFollow,
|
|
66
|
+
toggleAutoFollow,
|
|
59
67
|
} = useContext(VZCodeContext);
|
|
60
68
|
|
|
61
69
|
const fileTree = useMemo(
|
|
@@ -233,6 +241,29 @@ export const VZSidebar = ({
|
|
|
233
241
|
<FileSVG />
|
|
234
242
|
</i>
|
|
235
243
|
</OverlayTrigger>
|
|
244
|
+
|
|
245
|
+
{/*Toggle Follow*/}
|
|
246
|
+
<OverlayTrigger
|
|
247
|
+
placement="right"
|
|
248
|
+
overlay={
|
|
249
|
+
<Tooltip id="toggle-auto-follow">
|
|
250
|
+
{enableAutoFollow
|
|
251
|
+
? 'Disable Auto Follow'
|
|
252
|
+
: 'Enable Auto Follow'}
|
|
253
|
+
</Tooltip>
|
|
254
|
+
}
|
|
255
|
+
>
|
|
256
|
+
<i
|
|
257
|
+
onClick={toggleAutoFollow}
|
|
258
|
+
className={`icon-button icon-button-dark${
|
|
259
|
+
enableAutoFollow
|
|
260
|
+
? ' vh-color-success-01'
|
|
261
|
+
: ''
|
|
262
|
+
}`}
|
|
263
|
+
>
|
|
264
|
+
<PinSVG />
|
|
265
|
+
</i>
|
|
266
|
+
</OverlayTrigger>
|
|
236
267
|
</div>
|
|
237
268
|
|
|
238
269
|
<div className="files">
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
.files {
|
|
21
|
+
margin-top: 6px;
|
|
21
22
|
display: flex;
|
|
22
23
|
flex-direction: row;
|
|
23
24
|
justify-content: start;
|
|
@@ -35,9 +36,9 @@
|
|
|
35
36
|
align-items: center;
|
|
36
37
|
justify-content: space-between;
|
|
37
38
|
cursor: pointer;
|
|
38
|
-
margin: 0
|
|
39
|
-
padding: 0 4px 0
|
|
40
|
-
border-radius:
|
|
39
|
+
margin: 0 6px;
|
|
40
|
+
padding: 0 4px 0 8px;
|
|
41
|
+
border-radius: 8px;
|
|
41
42
|
font-family: var(--vzcode-font-family);
|
|
42
43
|
font-weight: 500;
|
|
43
44
|
}
|
|
@@ -59,7 +60,7 @@
|
|
|
59
60
|
gap: 6px;
|
|
60
61
|
padding: 6px;
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
a {
|
|
63
64
|
color: inherit;
|
|
64
65
|
}
|
|
65
66
|
}
|
package/src/client/useActions.ts
CHANGED
|
@@ -158,6 +158,12 @@ export const useActions = (
|
|
|
158
158
|
[dispatch],
|
|
159
159
|
);
|
|
160
160
|
|
|
161
|
+
const toggleAutoFollow = useCallback(() => {
|
|
162
|
+
dispatch({
|
|
163
|
+
type: 'toggle_auto_follow',
|
|
164
|
+
});
|
|
165
|
+
}, [dispatch]);
|
|
166
|
+
|
|
161
167
|
return {
|
|
162
168
|
setActiveFileId,
|
|
163
169
|
setActiveFileLeft,
|
|
@@ -175,5 +181,6 @@ export const useActions = (
|
|
|
175
181
|
closeDoc,
|
|
176
182
|
editorNoLongerWantsFocus,
|
|
177
183
|
setUsername,
|
|
184
|
+
toggleAutoFollow,
|
|
178
185
|
};
|
|
179
186
|
};
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
setSearchResultsReducer,
|
|
26
26
|
setSearchFileVisibilityReducer,
|
|
27
27
|
} from './searchReducer';
|
|
28
|
+
import { toggleAutoFollowReducer } from './toggleAutoFollowReducer';
|
|
28
29
|
export { createInitialState } from './createInitialState';
|
|
29
30
|
|
|
30
31
|
// The shape of the state managed by the reducer.
|
|
@@ -55,6 +56,11 @@ export type VZState = {
|
|
|
55
56
|
|
|
56
57
|
// The username of the current user.
|
|
57
58
|
username: Username;
|
|
59
|
+
|
|
60
|
+
// True if "auto-follow" is enabled.
|
|
61
|
+
// This is a feature that automatically scrolls the editor to the
|
|
62
|
+
// currently active remote user's cursor position.
|
|
63
|
+
enableAutoFollow: boolean;
|
|
58
64
|
};
|
|
59
65
|
|
|
60
66
|
// The shape of the actions that can be dispatched to the reducer.
|
|
@@ -121,7 +127,11 @@ export type VZAction =
|
|
|
121
127
|
|
|
122
128
|
// `set_username`
|
|
123
129
|
// * Sets the username.
|
|
124
|
-
| { type: 'set_username'; username: Username }
|
|
130
|
+
| { type: 'set_username'; username: Username }
|
|
131
|
+
|
|
132
|
+
// `toggle_auto_follow
|
|
133
|
+
// * Toggles the auto-follow feature.
|
|
134
|
+
| { type: 'toggle_auto_follow' };
|
|
125
135
|
|
|
126
136
|
// Representation of an open tab.
|
|
127
137
|
export type TabState = {
|
|
@@ -157,6 +167,7 @@ const reducers = [
|
|
|
157
167
|
setIsDocOpenReducer,
|
|
158
168
|
editorNoLongerWantsFocusReducer,
|
|
159
169
|
setUsernameReducer,
|
|
170
|
+
toggleAutoFollowReducer,
|
|
160
171
|
];
|
|
161
172
|
|
|
162
173
|
export const vzReducer = (
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { VZAction, VZState } from '.';
|
|
2
|
+
|
|
3
|
+
export const toggleAutoFollowReducer = (
|
|
4
|
+
state: VZState,
|
|
5
|
+
action: VZAction,
|
|
6
|
+
): VZState =>
|
|
7
|
+
action.type === 'toggle_auto_follow'
|
|
8
|
+
? {
|
|
9
|
+
...state,
|
|
10
|
+
enableAutoFollow: !state.enableAutoFollow,
|
|
11
|
+
}
|
|
12
|
+
: state;
|