Compare commits
165 Commits
feat/react
...
fix/loadin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
776e59709f | ||
|
|
eefdf9783e | ||
|
|
a821c71967 | ||
|
|
cc684eb5cd | ||
|
|
8dd2f05b17 | ||
|
|
ba94aeab4c | ||
|
|
a013538c8b | ||
|
|
648140a370 | ||
|
|
c2f4827ac1 | ||
|
|
8a52dbb784 | ||
|
|
eb47ec6bbd | ||
|
|
baa62e13b1 | ||
|
|
8a71835ca2 | ||
|
|
67a488cac7 | ||
|
|
a11f531d4b | ||
|
|
9dd717bf0e | ||
|
|
42551bb4fd | ||
|
|
5c5de61cb6 | ||
|
|
7fdfc7fddb | ||
|
|
b108c6166e | ||
|
|
e0bc9a7f67 | ||
|
|
f900495f8d | ||
|
|
4188c7a18d | ||
|
|
7315960477 | ||
|
|
815f485ee5 | ||
|
|
402008a08f | ||
|
|
bc1576cb92 | ||
|
|
acbe66ed60 | ||
|
|
ec1fd2aaa2 | ||
|
|
bd796555f2 | ||
|
|
153f6ec245 | ||
|
|
42d007da13 | ||
|
|
c764eeff56 | ||
|
|
a7a00e6a7c | ||
|
|
bc65695eee | ||
|
|
153231aecb | ||
|
|
d814899d71 | ||
|
|
0b6c35c08a | ||
|
|
e62ea5a8ac | ||
|
|
a5bffd7312 | ||
|
|
9aa91ec525 | ||
|
|
9b8c299ba5 | ||
|
|
7486ca768d | ||
|
|
fa4d501eb0 | ||
|
|
a126d5dbf8 | ||
|
|
d697cc5713 | ||
|
|
d95c8cc302 | ||
|
|
9dee93af1b | ||
|
|
0dffa407a8 | ||
|
|
0d97f161bd | ||
|
|
b9525b675e | ||
|
|
5a00fe0862 | ||
|
|
3db07f541f | ||
|
|
0db2e60d09 | ||
|
|
f122147f03 | ||
|
|
4e1bcde8b2 | ||
|
|
eaef418151 | ||
|
|
8d17b192d0 | ||
|
|
9a56bb3d25 | ||
|
|
b6c6a0ae64 | ||
|
|
e000774b3b | ||
|
|
6f6cf23bc8 | ||
|
|
77a718656c | ||
|
|
6c86c4f7ee | ||
|
|
72508332fb | ||
|
|
0ac88b4c80 | ||
|
|
11460b6f9f | ||
|
|
71b93909e6 | ||
|
|
26646cde0c | ||
|
|
4033e95a50 | ||
|
|
f379fcc176 | ||
|
|
66d59b31d5 | ||
|
|
1e6da19d5e | ||
|
|
d6ea4d4662 | ||
|
|
84b5dd8a0b | ||
|
|
c730016572 | ||
|
|
7677ca5240 | ||
|
|
cffe482f75 | ||
|
|
a140f555ba | ||
|
|
10de4b6fc9 | ||
|
|
2433344778 | ||
|
|
4c01459942 | ||
|
|
8dacdd6e2f | ||
|
|
5b0580bfda | ||
|
|
2bed7e845d | ||
|
|
76976026b7 | ||
|
|
10ea8fbf88 | ||
|
|
bd86b159b9 | ||
|
|
c4f5241818 | ||
|
|
181f433477 | ||
|
|
3897a7e137 | ||
|
|
5082ecef3f | ||
|
|
268e433870 | ||
|
|
6c185160c5 | ||
|
|
d18323b74a | ||
|
|
edd91791c9 | ||
|
|
958b13c050 | ||
|
|
bbe140f7be | ||
|
|
1625f82ab7 | ||
|
|
843f729a62 | ||
|
|
cc4631bb42 | ||
|
|
3665ef0088 | ||
|
|
e13039818e | ||
|
|
2e79487982 | ||
|
|
fc2c045a8d | ||
|
|
69bb94be06 | ||
|
|
228c8fa796 | ||
|
|
a34b850824 | ||
|
|
96d518bb97 | ||
|
|
8355f5674d | ||
|
|
5c1d04ee88 | ||
|
|
2ef98d01b0 | ||
|
|
15a86a3014 | ||
|
|
9c49704cf9 | ||
|
|
44f0d8d5c7 | ||
|
|
d7af97d63f | ||
|
|
9d0c9dc6ea | ||
|
|
2c3761c8e8 | ||
|
|
c91bcf9745 | ||
|
|
c1db6e087a | ||
|
|
9d8cc194e0 | ||
|
|
3b189e4def | ||
|
|
7fe50922cc | ||
|
|
b04e2be665 | ||
|
|
80b1535cdf | ||
|
|
3d882f0442 | ||
|
|
f61d568c9d | ||
|
|
6dd02d289c | ||
|
|
33a4944ba3 | ||
|
|
e367b6056d | ||
|
|
f3f56b9be0 | ||
|
|
4cae6bad34 | ||
|
|
17f2ef57de | ||
|
|
3a4d111a37 | ||
|
|
1e18c7f5fc | ||
|
|
8c7a6b27ed | ||
|
|
91f96e1188 | ||
|
|
28dac10723 | ||
|
|
9cb11e38dd | ||
|
|
f3e4bacb33 | ||
|
|
626d43f07b | ||
|
|
1f5d073035 | ||
|
|
a3b607e799 | ||
|
|
8fb93502af | ||
|
|
36774122e0 | ||
|
|
a6923128c1 | ||
|
|
706ca62feb | ||
|
|
01523dcca3 | ||
|
|
77f039b561 | ||
|
|
d661ba77be | ||
|
|
f8fbc59b6f | ||
|
|
cce0d22007 | ||
|
|
e3ff76e9cb | ||
|
|
4cbf71bff7 | ||
|
|
ceb060243a | ||
|
|
a70bebb96a | ||
|
|
b3b2507c35 | ||
|
|
6a8fa16b49 | ||
|
|
1f08807701 | ||
|
|
ba4a7f6170 | ||
|
|
a2854e3602 | ||
|
|
4ea87dc494 | ||
|
|
d8c87c5314 | ||
|
|
46f624a12e | ||
|
|
86ce770f38 |
5
.changeset/cyan-eggs-think.md
Normal file
5
.changeset/cyan-eggs-think.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"cojson": patch
|
||||
---
|
||||
|
||||
Correctly load CoValues after they are marked as unavailable and improve timeout management
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"cojson": patch
|
||||
---
|
||||
|
||||
Performance: optimize Group.roleOf getter and made the transactions validation incremental for CoMap and CoFeed
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"jazz-react": patch
|
||||
---
|
||||
|
||||
Re-export createImage from jazz-browser-media-images
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"cojson": patch
|
||||
---
|
||||
|
||||
Throw an error when the user tries to load an invalid or undefined id
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"jazz-tools": patch
|
||||
---
|
||||
|
||||
Export CoFeedEntry type
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -24,4 +24,6 @@ test-results
|
||||
|
||||
.vscode/settings.json
|
||||
|
||||
.svelte-kit
|
||||
.svelte-kit
|
||||
|
||||
.idea
|
||||
|
||||
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
6
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
8
.idea/jazz.iml
generated
Normal file
8
.idea/jazz.iml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/jazz.iml" filepath="$PROJECT_DIR$/.idea/jazz.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
19
.idea/php.xml
generated
Normal file
19
.idea/php.xml
generated
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MessDetectorOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCSFixerOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PHPCodeSnifferOptionsConfiguration">
|
||||
<option name="highlightLevel" value="WARNING" />
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PhpStanOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
<component name="PsalmOptionsConfiguration">
|
||||
<option name="transferred" value="true" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/prettier.xml
generated
Normal file
6
.idea/prettier.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PrettierConfiguration">
|
||||
<option name="myConfigurationMode" value="AUTOMATIC" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,5 +1,56 @@
|
||||
# chat-rn-clerk
|
||||
|
||||
## 1.0.92
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.12.2
|
||||
- jazz-react-native-auth-clerk@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
- jazz-react-native-media-images@0.12.2
|
||||
|
||||
## 1.0.91
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.12.1
|
||||
- jazz-react-native-auth-clerk@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
- jazz-react-native-media-images@0.12.1
|
||||
|
||||
## 1.0.90
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react-native@0.12.0
|
||||
- jazz-react-native-auth-clerk@0.12.0
|
||||
- jazz-react-native-media-images@0.12.0
|
||||
|
||||
## 1.0.89
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.11.8
|
||||
- jazz-react-native-auth-clerk@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
- jazz-react-native-media-images@0.11.8
|
||||
|
||||
## 1.0.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react-native@0.11.7
|
||||
- jazz-react-native-auth-clerk@0.11.7
|
||||
- jazz-react-native-media-images@0.11.7
|
||||
|
||||
## 1.0.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function Conversation() {
|
||||
const { me } = useAccount();
|
||||
const [chat, setChat] = useState<Chat>();
|
||||
const [message, setMessage] = useState("");
|
||||
const loadedChat = useCoState(Chat, chat?.id, [{}]);
|
||||
const loadedChat = useCoState(Chat, chat?.id, { resolve: { $each: true } });
|
||||
const navigation = useNavigation();
|
||||
const [isUploading, setIsUploading] = useState(false);
|
||||
|
||||
@@ -71,7 +71,7 @@ export default function Conversation() {
|
||||
|
||||
const loadChat = async (chatId: ID<Chat>) => {
|
||||
try {
|
||||
const chat = await Chat.load(chatId, me, []);
|
||||
const chat = await Chat.load(chatId, me);
|
||||
setChat(chat);
|
||||
} catch (error) {
|
||||
console.log("Error loading chat", error);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "chat-rn-clerk",
|
||||
"main": "index.js",
|
||||
"version": "1.0.87",
|
||||
"version": "1.0.92",
|
||||
"scripts": {
|
||||
"build": "expo export -p ios",
|
||||
"start": "expo start",
|
||||
|
||||
@@ -1,5 +1,46 @@
|
||||
# chat-rn
|
||||
|
||||
## 1.0.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 1.0.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 1.0.86
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react-native@0.12.0
|
||||
|
||||
## 1.0.85
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react-native@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 1.0.84
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react-native@0.11.7
|
||||
|
||||
## 1.0.83
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chat-rn",
|
||||
"version": "1.0.83",
|
||||
"version": "1.0.88",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "expo export -p ios",
|
||||
|
||||
@@ -20,7 +20,7 @@ import { Chat, Message } from "./schema";
|
||||
export default function ChatScreen({ navigation }: { navigation: any }) {
|
||||
const { me, logOut } = useAccount();
|
||||
const [chatId, setChatId] = useState<ID<Chat>>();
|
||||
const loadedChat = useCoState(Chat, chatId, [{}]);
|
||||
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
|
||||
const [message, setMessage] = useState("");
|
||||
const profile = useCoState(Profile, me._refs.profile?.id, {});
|
||||
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
# chat-vue
|
||||
|
||||
## 0.0.73
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [cc684eb]
|
||||
- jazz-browser@0.12.2
|
||||
- jazz-vue@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.72
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
- jazz-vue@0.12.1
|
||||
|
||||
## 0.0.71
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- Updated dependencies [4c01459]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-vue@0.12.0
|
||||
- jazz-browser@0.12.0
|
||||
|
||||
## 0.0.70
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-browser@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
- jazz-vue@0.11.8
|
||||
|
||||
## 0.0.69
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-browser@0.11.7
|
||||
- jazz-vue@0.11.7
|
||||
|
||||
## 0.0.68
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "chat-vue",
|
||||
"version": "0.0.68",
|
||||
"version": "0.0.73",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -49,7 +49,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const chat = useCoState(Chat, props.chatId, [{}]);
|
||||
const chat = useCoState(Chat, props.chatId, { resolve: { $each: true } });
|
||||
const showNLastMessages = ref(30);
|
||||
|
||||
const displayedMessages = computed(() => {
|
||||
|
||||
@@ -1,5 +1,56 @@
|
||||
# jazz-example-chat
|
||||
|
||||
## 0.0.170
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8a71835]
|
||||
- jazz-inspector@0.12.2
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.169
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-inspector@0.12.1
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.168
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- Updated dependencies [9a56bb3]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-inspector@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.167
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [71b9390]
|
||||
- jazz-inspector@0.11.8
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.166
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2c3761c]
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-inspector@0.11.7
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.165
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-chat",
|
||||
"private": true,
|
||||
"version": "0.0.165",
|
||||
"version": "0.0.170",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -16,8 +16,8 @@ import {
|
||||
} from "./ui.tsx";
|
||||
|
||||
export function ChatScreen(props: { chatID: ID<Chat> }) {
|
||||
const chat = useCoState(Chat, props.chatID, { resolve: { $each: true } });
|
||||
const account = useAccount();
|
||||
const chat = useCoState(Chat, props.chatID, [{}]);
|
||||
const [showNLastMessages, setShowNLastMessages] = useState(30);
|
||||
|
||||
if (!chat)
|
||||
|
||||
@@ -1,5 +1,52 @@
|
||||
# minimal-auth-clerk
|
||||
|
||||
## 0.0.69
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-react-auth-clerk@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.68
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-react-auth-clerk@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.67
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
- jazz-react-auth-clerk@0.12.0
|
||||
|
||||
## 0.0.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-react-auth-clerk@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
- jazz-react-auth-clerk@0.11.7
|
||||
|
||||
## 0.0.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "clerk",
|
||||
"private": true,
|
||||
"version": "0.0.64",
|
||||
"version": "0.0.69",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -13,7 +13,7 @@
|
||||
"dependencies": {
|
||||
"@clerk/clerk-react": "^5.4.1",
|
||||
"jazz-react": "workspace:*",
|
||||
"jazz-react-auth-clerk": "workspace:0.11.6",
|
||||
"jazz-react-auth-clerk": "workspace:0.12.2",
|
||||
"jazz-tools": "workspace:*",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
|
||||
@@ -1,5 +1,46 @@
|
||||
# file-share-svelte
|
||||
|
||||
## 0.0.53
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.52
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.51
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-svelte@0.12.0
|
||||
|
||||
## 0.0.50
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.49
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-svelte@0.11.7
|
||||
|
||||
## 0.0.48
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "file-share-svelte",
|
||||
"version": "0.0.48",
|
||||
"version": "0.0.53",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# jazz-tailwind-demo-auth-starter
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "filestream",
|
||||
"private": true,
|
||||
"version": "0.0.4",
|
||||
"version": "0.0.9",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# form
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "form",
|
||||
"private": true,
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.11",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -12,7 +12,9 @@ import {
|
||||
} from "./schema.ts";
|
||||
|
||||
export function CreateOrder() {
|
||||
const { me } = useAccount({ root: { draft: {}, orders: [] } });
|
||||
const { me } = useAccount({
|
||||
resolve: { root: { draft: true, orders: true } },
|
||||
});
|
||||
const router = useIframeHashRouter();
|
||||
const [errors, setErrors] = useState<string[]>([]);
|
||||
|
||||
@@ -60,7 +62,7 @@ function CreateOrderForm({
|
||||
onSave: (draft: DraftBubbleTeaOrder) => void;
|
||||
}) {
|
||||
const draft = useCoState(DraftBubbleTeaOrder, id, {
|
||||
addOns: [],
|
||||
resolve: { addOns: true },
|
||||
});
|
||||
|
||||
if (!draft) return;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useAccount } from "jazz-react";
|
||||
|
||||
export function DraftIndicator() {
|
||||
const { me } = useAccount({
|
||||
root: { draft: {} },
|
||||
resolve: { root: { draft: true } },
|
||||
});
|
||||
|
||||
if (me?.root.draft?.hasChanges) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import { OrderThumbnail } from "./OrderThumbnail.tsx";
|
||||
import { BubbleTeaOrder } from "./schema.ts";
|
||||
|
||||
export function EditOrder(props: { id: ID<BubbleTeaOrder> }) {
|
||||
const order = useCoState(BubbleTeaOrder, props.id, []);
|
||||
const order = useCoState(BubbleTeaOrder, props.id);
|
||||
|
||||
if (!order) return;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { OrderThumbnail } from "./OrderThumbnail.tsx";
|
||||
|
||||
export function Orders() {
|
||||
const { me } = useAccount({
|
||||
root: { orders: [] },
|
||||
resolve: { root: { orders: true } },
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# image-upload
|
||||
|
||||
## 0.0.67
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.62
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "image-upload",
|
||||
"private": true,
|
||||
"version": "0.0.62",
|
||||
"version": "0.0.67",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,59 @@
|
||||
# jazz-example-inspector
|
||||
|
||||
## 0.0.120
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 8a71835: use goober for css
|
||||
- Updated dependencies [8a71835]
|
||||
- Updated dependencies [c2f4827]
|
||||
- jazz-inspector@0.12.2
|
||||
- cojson@0.12.2
|
||||
- cojson-transport-ws@0.12.2
|
||||
|
||||
## 0.0.119
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5a00fe0]
|
||||
- cojson@0.12.1
|
||||
- cojson-transport-ws@0.12.1
|
||||
- jazz-inspector@0.12.1
|
||||
|
||||
## 0.0.118
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [9a56bb3]
|
||||
- cojson@0.12.0
|
||||
- jazz-inspector@0.12.0
|
||||
- cojson-transport-ws@0.12.0
|
||||
|
||||
## 0.0.117
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [71b9390]
|
||||
- Updated dependencies [6c86c4f]
|
||||
- Updated dependencies [9d0c9dc]
|
||||
- jazz-inspector@0.11.8
|
||||
- cojson@0.11.8
|
||||
- cojson-transport-ws@0.11.8
|
||||
|
||||
## 0.0.116
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 2c3761c: fix: CoFeed and FileStream are showing as CoStream
|
||||
- Updated dependencies [2c3761c]
|
||||
- Updated dependencies [2b94bc8]
|
||||
- Updated dependencies [2957362]
|
||||
- jazz-inspector@0.11.7
|
||||
- cojson@0.11.7
|
||||
- cojson-transport-ws@0.11.7
|
||||
|
||||
## 0.0.115
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-inspector-app",
|
||||
"private": true,
|
||||
"version": "0.0.115",
|
||||
"version": "0.0.120",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -13,8 +13,8 @@
|
||||
"dependencies": {
|
||||
"jazz-inspector": "workspace:*",
|
||||
"clsx": "^2.0.0",
|
||||
"cojson": "workspace:0.11.6",
|
||||
"cojson-transport-ws": "workspace:0.11.6",
|
||||
"cojson": "workspace:0.12.2",
|
||||
"cojson-transport-ws": "workspace:0.12.2",
|
||||
"hash-slash": "workspace:0.2.2",
|
||||
"lucide-react": "^0.274.0",
|
||||
"react": "^18.3.1",
|
||||
|
||||
@@ -12,14 +12,15 @@ import { WasmCrypto } from "cojson/crypto/WasmCrypto";
|
||||
import {
|
||||
Breadcrumbs,
|
||||
Button,
|
||||
GlobalStyles,
|
||||
Icon,
|
||||
Input,
|
||||
PageStack,
|
||||
Select,
|
||||
} from "jazz-inspector";
|
||||
import { resolveCoValue, useResolvedCoValue } from "jazz-inspector";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { usePagePath } from "./use-page-path";
|
||||
import { resolveCoValue, useResolvedCoValue } from "./use-resolve-covalue";
|
||||
|
||||
interface Account {
|
||||
id: CoID<RawAccount>;
|
||||
@@ -126,7 +127,7 @@ export default function CoJsonViewerApp() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
<GlobalStyles
|
||||
className={clsx(
|
||||
"h-screen overflow-hidden flex flex-col",
|
||||
" text-stone-700 bg-white",
|
||||
@@ -202,7 +203,7 @@ export default function CoJsonViewerApp() {
|
||||
</form>
|
||||
)}
|
||||
</PageStack>
|
||||
</div>
|
||||
</GlobalStyles>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
import { CoID, LocalNode, RawBinaryCoStream, RawCoValue } from "cojson";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export type CoJsonType = "comap" | "costream" | "colist";
|
||||
export type ExtendedCoJsonType = "image" | "record" | "account" | "group";
|
||||
|
||||
type JSON = string | number | boolean | null | JSON[] | { [key: string]: JSON };
|
||||
type JSONObject = { [key: string]: JSON };
|
||||
|
||||
type ResolvedImageDefinition = {
|
||||
originalSize: [number, number];
|
||||
placeholderDataURL?: string;
|
||||
[res: `${number}x${number}`]: RawBinaryCoStream["id"];
|
||||
};
|
||||
|
||||
// Type guard for browser image
|
||||
export const isBrowserImage = (
|
||||
coValue: JSONObject,
|
||||
): coValue is ResolvedImageDefinition => {
|
||||
return "originalSize" in coValue && "placeholderDataURL" in coValue;
|
||||
};
|
||||
|
||||
export type ResolvedGroup = {
|
||||
readKey: string;
|
||||
[key: string]: JSON;
|
||||
};
|
||||
|
||||
export const isGroup = (coValue: JSONObject): coValue is ResolvedGroup => {
|
||||
return "readKey" in coValue;
|
||||
};
|
||||
|
||||
export type ResolvedAccount = {
|
||||
profile: {
|
||||
name: string;
|
||||
};
|
||||
[key: string]: JSON;
|
||||
};
|
||||
|
||||
export const isAccount = (coValue: JSONObject): coValue is ResolvedAccount => {
|
||||
return isGroup(coValue) && "profile" in coValue;
|
||||
};
|
||||
|
||||
export async function resolveCoValue(
|
||||
coValueId: CoID<RawCoValue>,
|
||||
node: LocalNode,
|
||||
): Promise<
|
||||
| {
|
||||
value: RawCoValue;
|
||||
snapshot: JSONObject;
|
||||
type: CoJsonType | null;
|
||||
extendedType: ExtendedCoJsonType | undefined;
|
||||
}
|
||||
| {
|
||||
value: undefined;
|
||||
snapshot: "unavailable";
|
||||
type: null;
|
||||
extendedType: undefined;
|
||||
}
|
||||
> {
|
||||
const value = await node.load(coValueId);
|
||||
|
||||
if (value === "unavailable") {
|
||||
return {
|
||||
value: undefined,
|
||||
snapshot: "unavailable",
|
||||
type: null,
|
||||
extendedType: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
const snapshot = value.toJSON() as JSONObject;
|
||||
const type = value.type as CoJsonType;
|
||||
|
||||
// Determine extended type
|
||||
let extendedType: ExtendedCoJsonType | undefined;
|
||||
|
||||
if (type === "comap") {
|
||||
if (isBrowserImage(snapshot)) {
|
||||
extendedType = "image";
|
||||
} else if (isAccount(snapshot)) {
|
||||
extendedType = "account";
|
||||
} else if (isGroup(snapshot)) {
|
||||
extendedType = "group";
|
||||
} else {
|
||||
// This check is a bit of a hack
|
||||
// There might be a better way to do this
|
||||
const children = Object.values(snapshot).slice(0, 10);
|
||||
if (
|
||||
children.every((c) => typeof c === "string" && c.startsWith("co_")) &&
|
||||
children.length > 3
|
||||
) {
|
||||
extendedType = "record";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
snapshot,
|
||||
type,
|
||||
extendedType,
|
||||
};
|
||||
}
|
||||
|
||||
function subscribeToCoValue(
|
||||
coValueId: CoID<RawCoValue>,
|
||||
node: LocalNode,
|
||||
callback: (result: Awaited<ReturnType<typeof resolveCoValue>>) => void,
|
||||
) {
|
||||
return node.subscribe(coValueId, (value) => {
|
||||
if (value === "unavailable") {
|
||||
callback({
|
||||
value: undefined,
|
||||
snapshot: "unavailable",
|
||||
type: null,
|
||||
extendedType: undefined,
|
||||
});
|
||||
} else {
|
||||
const snapshot = value.toJSON() as JSONObject;
|
||||
const type = value.type as CoJsonType;
|
||||
let extendedType: ExtendedCoJsonType | undefined;
|
||||
|
||||
if (type === "comap") {
|
||||
if (isBrowserImage(snapshot)) {
|
||||
extendedType = "image";
|
||||
} else if (isAccount(snapshot)) {
|
||||
extendedType = "account";
|
||||
} else if (isGroup(snapshot)) {
|
||||
extendedType = "group";
|
||||
} else {
|
||||
const children = Object.values(snapshot).slice(0, 10);
|
||||
if (
|
||||
children.every(
|
||||
(c) => typeof c === "string" && c.startsWith("co_"),
|
||||
) &&
|
||||
children.length > 3
|
||||
) {
|
||||
extendedType = "record";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback({
|
||||
value,
|
||||
snapshot,
|
||||
type,
|
||||
extendedType,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function useResolvedCoValue(
|
||||
coValueId: CoID<RawCoValue>,
|
||||
node: LocalNode,
|
||||
) {
|
||||
const [result, setResult] =
|
||||
useState<Awaited<ReturnType<typeof resolveCoValue>>>();
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
const unsubscribe = subscribeToCoValue(coValueId, node, (newResult) => {
|
||||
if (isMounted) {
|
||||
setResult(newResult);
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
unsubscribe();
|
||||
};
|
||||
}, [coValueId, node]);
|
||||
|
||||
return (
|
||||
result || {
|
||||
value: undefined,
|
||||
snapshot: undefined,
|
||||
type: undefined,
|
||||
extendedType: undefined,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function useResolvedCoValues(
|
||||
coValueIds: CoID<RawCoValue>[],
|
||||
node: LocalNode,
|
||||
) {
|
||||
const [results, setResults] = useState<
|
||||
Awaited<ReturnType<typeof resolveCoValue>>[]
|
||||
>([]);
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
const unsubscribes: (() => void)[] = [];
|
||||
|
||||
coValueIds.forEach((coValueId, index) => {
|
||||
const unsubscribe = subscribeToCoValue(coValueId, node, (newResult) => {
|
||||
if (isMounted) {
|
||||
setResults((prevResults) => {
|
||||
const newResults = [...prevResults];
|
||||
newResults[index] = newResult;
|
||||
return newResults;
|
||||
});
|
||||
}
|
||||
});
|
||||
unsubscribes.push(unsubscribe);
|
||||
});
|
||||
|
||||
return () => {
|
||||
isMounted = false;
|
||||
unsubscribes.forEach((unsubscribe) => unsubscribe());
|
||||
};
|
||||
}, [coValueIds, node]);
|
||||
|
||||
return results;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
VITE_CURSOR_FEED_ID=example-cursor-feed-id
|
||||
VITE_GROUP_ID=co_example-group-id
|
||||
VITE_CURSOR_FEED_ID=multi-cursors-250425-1708
|
||||
VITE_GROUP_ID=co_zXE8C8sd9QxEbxnt3neRvFRPFUc
|
||||
VITE_OLD_CURSOR_AGE_SECONDS=5
|
||||
43
examples/multi-cursors/CHANGELOG.md
Normal file
43
examples/multi-cursors/CHANGELOG.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# multi-cursors
|
||||
|
||||
## 0.0.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.62
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.61
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.60
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
@@ -1,16 +1,15 @@
|
||||
{
|
||||
"name": "multi-cursors",
|
||||
"private": true,
|
||||
"version": "0.0.58",
|
||||
"version": "0.0.63",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "tsc -b && vite build",
|
||||
"preview": "vite preview",
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:ui": "playwright test --ui",
|
||||
"format-and-lint": "biome check .",
|
||||
"format-and-lint:fix": "biome check . --write"
|
||||
"format-and-lint:fix": "biome check . --write",
|
||||
"test": "vitest"
|
||||
},
|
||||
"dependencies": {
|
||||
"@react-spring/web": "^9.7.5",
|
||||
@@ -30,6 +29,7 @@
|
||||
"postcss": "^8.4.27",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "~5.6.2",
|
||||
"vite": "^6.0.11"
|
||||
"vite": "^6.0.11",
|
||||
"vitest": "3.0.5"
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ function App() {
|
||||
const [cursorFeedID, setCursorFeedID] = useState<ID<CursorFeed> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Loading cursor feed...", me.id);
|
||||
if (!me?.id) return;
|
||||
const loadCursorFeed = async () => {
|
||||
const id = await loadCursorContainer(
|
||||
|
||||
16
examples/multi-cursors/src/components/Boundary.tsx
Normal file
16
examples/multi-cursors/src/components/Boundary.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import { ViewBox } from "../types";
|
||||
|
||||
export function Boundary({ bounds }: { bounds: ViewBox }) {
|
||||
return (
|
||||
<>
|
||||
<rect
|
||||
x={bounds.x}
|
||||
y={bounds.y}
|
||||
width={bounds.width}
|
||||
height={bounds.height}
|
||||
stroke="red"
|
||||
fill="none"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
import { useAccount } from "jazz-react";
|
||||
import { CoFeedEntry, co } from "jazz-tools";
|
||||
import { CursorMoveEvent, useCanvas } from "../hooks/useCanvas";
|
||||
import { Cursor as CursorType } from "../types";
|
||||
import { Cursor as CursorType, ViewBox } from "../types";
|
||||
import { centerOfBounds } from "../utils/centerOfBounds";
|
||||
import { getColor } from "../utils/getColor";
|
||||
import { getName } from "../utils/getName";
|
||||
import { Boundary } from "./Boundary";
|
||||
import { CanvasBackground } from "./CanvasBackground";
|
||||
import { CanvasDemoContent } from "./CanvasDemoContent";
|
||||
import { Cursor } from "./Cursor";
|
||||
@@ -12,6 +14,16 @@ const OLD_CURSOR_AGE_SECONDS = Number(
|
||||
import.meta.env.VITE_OLD_CURSOR_AGE_SECONDS,
|
||||
);
|
||||
|
||||
const DEBUG = import.meta.env.VITE_DEBUG === "true";
|
||||
|
||||
// For debugging purposes, we can set a fixed bounds
|
||||
const debugBounds: ViewBox = {
|
||||
x: 320,
|
||||
y: 320,
|
||||
width: 640,
|
||||
height: 640,
|
||||
};
|
||||
|
||||
interface CanvasProps {
|
||||
remoteCursors: CoFeedEntry<co<CursorType>>[];
|
||||
onCursorMove: (move: CursorMoveEvent) => void;
|
||||
@@ -28,8 +40,12 @@ function Canvas({ remoteCursors, onCursorMove, name }: CanvasProps) {
|
||||
mousePosition,
|
||||
bgPosition,
|
||||
dottedGridSize,
|
||||
viewBox,
|
||||
} = useCanvas({ onCursorMove });
|
||||
|
||||
const bounds = DEBUG ? debugBounds : viewBox;
|
||||
const center = centerOfBounds(bounds);
|
||||
|
||||
return (
|
||||
<svg width="100%" height="100%" {...svgProps}>
|
||||
<CanvasBackground
|
||||
@@ -38,6 +54,7 @@ function Canvas({ remoteCursors, onCursorMove, name }: CanvasProps) {
|
||||
/>
|
||||
|
||||
<CanvasDemoContent />
|
||||
{DEBUG && <Boundary bounds={bounds} />}
|
||||
|
||||
{remoteCursors.map((entry) => {
|
||||
if (
|
||||
@@ -48,14 +65,21 @@ function Canvas({ remoteCursors, onCursorMove, name }: CanvasProps) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const name = getName(entry.by?.profile?.name, entry.tx.sessionID);
|
||||
const color = getColor(entry.tx.sessionID);
|
||||
const age = new Date().getTime() - new Date(entry.madeAt).getTime();
|
||||
|
||||
return (
|
||||
<Cursor
|
||||
key={entry.tx.sessionID}
|
||||
position={entry.value.position}
|
||||
color={getColor(entry.tx.sessionID)}
|
||||
color={color}
|
||||
isDragging={false}
|
||||
isRemote={true}
|
||||
name={getName(entry.by?.profile?.name, entry.tx.sessionID)}
|
||||
name={name}
|
||||
age={age}
|
||||
centerOfBounds={center}
|
||||
bounds={bounds}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
@@ -67,6 +91,8 @@ function Canvas({ remoteCursors, onCursorMove, name }: CanvasProps) {
|
||||
isDragging={isDragging}
|
||||
isRemote={false}
|
||||
name={name}
|
||||
centerOfBounds={center}
|
||||
bounds={bounds}
|
||||
/>
|
||||
) : null}
|
||||
</svg>
|
||||
|
||||
@@ -7,7 +7,7 @@ import Canvas from "./Canvas";
|
||||
/** A higher order component that wraps the canvas. */
|
||||
function Container({ cursorFeedID }: { cursorFeedID: ID<CursorFeed> }) {
|
||||
const { me } = useAccount();
|
||||
const cursors = useCoState(CursorFeed, cursorFeedID, []);
|
||||
const cursors = useCoState(CursorFeed, cursorFeedID, { resolve: true });
|
||||
|
||||
return (
|
||||
<Canvas
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { animated, to, useSpring } from "@react-spring/web";
|
||||
import { Vec2, ViewBox } from "../types";
|
||||
import { calculateBoundaryIntersection } from "../utils/boundaryIntersection";
|
||||
import { isOutOfBounds } from "../utils/isOutOfBounds";
|
||||
import { CursorLabel } from "./CursorLabel";
|
||||
|
||||
interface CursorProps {
|
||||
position: { x: number; y: number };
|
||||
@@ -6,18 +10,56 @@ interface CursorProps {
|
||||
isDragging: boolean;
|
||||
isRemote: boolean;
|
||||
name: string;
|
||||
age?: number;
|
||||
centerOfBounds: Vec2;
|
||||
bounds?: ViewBox;
|
||||
}
|
||||
|
||||
const LABEL_BOUNDS_PADDING = 32;
|
||||
const CURSOR_VISIBILITY_OFFSET = 20;
|
||||
|
||||
export function Cursor({
|
||||
position,
|
||||
color,
|
||||
isDragging,
|
||||
isRemote,
|
||||
name,
|
||||
age = 0,
|
||||
centerOfBounds,
|
||||
bounds,
|
||||
}: CursorProps) {
|
||||
if (!bounds) return null;
|
||||
|
||||
const intersectionPoint = calculateBoundaryIntersection(
|
||||
centerOfBounds,
|
||||
position,
|
||||
bounds,
|
||||
);
|
||||
|
||||
const labelBounds = {
|
||||
x: bounds.x + LABEL_BOUNDS_PADDING / 2,
|
||||
y: bounds.y + LABEL_BOUNDS_PADDING / 2,
|
||||
width: bounds.width - LABEL_BOUNDS_PADDING,
|
||||
height: bounds.height - LABEL_BOUNDS_PADDING,
|
||||
};
|
||||
|
||||
const cursorIntersectionPoint = calculateBoundaryIntersection(
|
||||
centerOfBounds,
|
||||
position,
|
||||
labelBounds,
|
||||
);
|
||||
|
||||
const isStrictlyOutOfBounds = isOutOfBounds(position, bounds);
|
||||
const shouldHideCursor = isOutOfBounds(
|
||||
position,
|
||||
bounds,
|
||||
CURSOR_VISIBILITY_OFFSET,
|
||||
);
|
||||
|
||||
const springs = useSpring({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
opacity: age > 60000 ? 0 : 1,
|
||||
immediate: !isRemote,
|
||||
config: {
|
||||
tension: 170,
|
||||
@@ -25,40 +67,75 @@ export function Cursor({
|
||||
},
|
||||
});
|
||||
|
||||
const intersectionSprings = useSpring({
|
||||
x: intersectionPoint.x,
|
||||
y: intersectionPoint.y,
|
||||
config: {
|
||||
tension: 170,
|
||||
friction: 26,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<animated.g
|
||||
transform={to(
|
||||
[springs.x, springs.y],
|
||||
(x: number, y: number) => `translate(${x}, ${y})`,
|
||||
)}
|
||||
>
|
||||
<polygon
|
||||
points="0,0 0,20 14.3,14.3"
|
||||
fill={
|
||||
isDragging ? color : `color-mix(in oklch, ${color}, transparent 56%)`
|
||||
}
|
||||
stroke={color}
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
<text
|
||||
x="10"
|
||||
y="25"
|
||||
fill={color}
|
||||
stroke="white"
|
||||
strokeWidth="3"
|
||||
strokeLinejoin="round"
|
||||
paintOrder="stroke"
|
||||
fontSize="14"
|
||||
dominantBaseline="hanging"
|
||||
style={{
|
||||
fontFamily: "Inter, Manrope, system-ui, sans-serif",
|
||||
fontWeight: 500,
|
||||
}}
|
||||
<>
|
||||
<animated.g
|
||||
transform={to(
|
||||
[springs.x, springs.y],
|
||||
(x: number, y: number) => `translate(${x}, ${y})`,
|
||||
)}
|
||||
>
|
||||
{name}
|
||||
</text>
|
||||
</animated.g>
|
||||
{isStrictlyOutOfBounds ? (
|
||||
<circle cx={0} cy={0} r={4} fill={color} />
|
||||
) : null}
|
||||
{!shouldHideCursor ? (
|
||||
<polygon
|
||||
points="0,0 0,20 14.3,14.3"
|
||||
fill={
|
||||
isDragging
|
||||
? color
|
||||
: `color-mix(in oklch, ${color}, transparent 56%)`
|
||||
}
|
||||
stroke={color}
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
) : null}
|
||||
</animated.g>
|
||||
|
||||
{isRemote ? (
|
||||
<>
|
||||
<CursorLabel
|
||||
name={name}
|
||||
color={color}
|
||||
position={cursorIntersectionPoint}
|
||||
bounds={bounds}
|
||||
isOutOfBounds={isStrictlyOutOfBounds}
|
||||
/>
|
||||
{isStrictlyOutOfBounds ? (
|
||||
<animated.g
|
||||
transform={to(
|
||||
[intersectionSprings.x, intersectionSprings.y],
|
||||
(x: number, y: number) => {
|
||||
const angle =
|
||||
Math.atan2(centerOfBounds.y - y, centerOfBounds.x - x) *
|
||||
(180 / Math.PI);
|
||||
return `translate(${x}, ${y}) rotate(${angle})`;
|
||||
},
|
||||
)}
|
||||
>
|
||||
<path
|
||||
d="M 8,-4 L 2,0 L 8,4"
|
||||
fill="none"
|
||||
stroke={color}
|
||||
strokeWidth="3"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</animated.g>
|
||||
) : null}
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
93
examples/multi-cursors/src/components/CursorLabel.tsx
Normal file
93
examples/multi-cursors/src/components/CursorLabel.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { animated, to, useSpring } from "@react-spring/web";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Vec2, ViewBox } from "../types";
|
||||
import { getLabelPosition } from "../utils/getLabelPosition";
|
||||
|
||||
const DEBUG = import.meta.env.VITE_DEBUG === "true";
|
||||
|
||||
interface CursorLabelProps {
|
||||
name: string;
|
||||
color: string;
|
||||
position: Vec2;
|
||||
bounds?: ViewBox;
|
||||
isOutOfBounds?: boolean;
|
||||
}
|
||||
|
||||
interface TextDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export function CursorLabel({
|
||||
name,
|
||||
color,
|
||||
position,
|
||||
bounds,
|
||||
isOutOfBounds,
|
||||
}: CursorLabelProps) {
|
||||
const textRef = useRef<SVGTextElement>(null);
|
||||
const [dimensions, setDimensions] = useState<TextDimensions>({
|
||||
width: 0,
|
||||
height: 0,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const bbox = textRef.current?.getBBox();
|
||||
setDimensions({ width: bbox?.width ?? 0, height: bbox?.height ?? 0 });
|
||||
}, [name]);
|
||||
|
||||
const labelPosition = getLabelPosition(
|
||||
position,
|
||||
dimensions,
|
||||
bounds,
|
||||
isOutOfBounds,
|
||||
);
|
||||
const labelSprings = useSpring<Vec2>({
|
||||
...labelPosition,
|
||||
config: {
|
||||
tension: 170,
|
||||
friction: 26,
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<animated.text
|
||||
ref={textRef}
|
||||
x={to([labelSprings.x], (x) => x)}
|
||||
y={to([labelSprings.y], (y) => y)}
|
||||
fill={color}
|
||||
stroke="white"
|
||||
strokeWidth="3"
|
||||
strokeLinejoin="round"
|
||||
paintOrder="stroke"
|
||||
fontSize="14"
|
||||
dominantBaseline="hanging"
|
||||
textAnchor="start"
|
||||
>
|
||||
{name}
|
||||
</animated.text>
|
||||
{DEBUG ? (
|
||||
<>
|
||||
<text x={position.x} y={position.y} fill="red" fontSize="8">
|
||||
{position.x}, {position.y}
|
||||
</text>
|
||||
<text x={labelPosition.x} y={labelPosition.y} fill="red" fontSize="8">
|
||||
{bounds
|
||||
? `${bounds.x - labelPosition.x}, ${bounds.y - labelPosition.y}`
|
||||
: "no bounds"}
|
||||
</text>
|
||||
<line
|
||||
x1={position.x}
|
||||
y1={position.y}
|
||||
x2={labelPosition.x}
|
||||
y2={labelPosition.y}
|
||||
stroke="red"
|
||||
strokeWidth="1"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import type { ViewBox } from "../types";
|
||||
import { throttleTime } from "../utils/throttleTime";
|
||||
|
||||
export interface CursorMoveEvent {
|
||||
@@ -13,7 +14,7 @@ export function useCanvas({
|
||||
onCursorMove: (event: CursorMoveEvent) => void;
|
||||
throttleMs?: number;
|
||||
}) {
|
||||
const [viewBox, setViewBox] = useState({
|
||||
const [viewBox, setViewBox] = useState<ViewBox>({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: window.innerWidth,
|
||||
@@ -134,5 +135,6 @@ export function useCanvas({
|
||||
mousePosition,
|
||||
bgPosition,
|
||||
dottedGridSize,
|
||||
viewBox,
|
||||
};
|
||||
}
|
||||
|
||||
7
examples/multi-cursors/src/types.d.ts
vendored
7
examples/multi-cursors/src/types.d.ts
vendored
@@ -18,3 +18,10 @@ export type RemoteCursor = Cursor & {
|
||||
isRemote: true;
|
||||
isDragging: boolean;
|
||||
};
|
||||
|
||||
export type ViewBox = {
|
||||
x: number;
|
||||
y: number;
|
||||
width: number;
|
||||
height: number;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { calculateBoundaryIntersection } from "../boundaryIntersection";
|
||||
|
||||
describe("calculateBoundaryIntersection", () => {
|
||||
const bounds = { x: 0, y: 0, width: 100, height: 100 };
|
||||
|
||||
it("should handle vertical lines (dx = 0)", () => {
|
||||
const center = { x: 50, y: 50 };
|
||||
const point = { x: 50, y: 150 }; // Straight up from center
|
||||
|
||||
const intersection = calculateBoundaryIntersection(center, point, bounds);
|
||||
|
||||
expect(intersection).toEqual({ x: 50, y: 100 }); // Should intersect at bottom boundary
|
||||
});
|
||||
|
||||
it("should handle horizontal lines (dy = 0)", () => {
|
||||
const center = { x: 50, y: 50 };
|
||||
const point = { x: 150, y: 50 }; // Straight right from center
|
||||
|
||||
const intersection = calculateBoundaryIntersection(center, point, bounds);
|
||||
|
||||
expect(intersection).toEqual({ x: 100, y: 50 }); // Should intersect at right boundary
|
||||
});
|
||||
|
||||
it("should handle vertical lines at boundaries", () => {
|
||||
const center = { x: 0, y: 50 };
|
||||
const point = { x: 0, y: 150 }; // Vertical line at x=0
|
||||
|
||||
const intersection = calculateBoundaryIntersection(center, point, bounds);
|
||||
|
||||
expect(intersection).toEqual({ x: 0, y: 100 }); // Should intersect at bottom boundary
|
||||
});
|
||||
|
||||
it("should handle horizontal lines at boundaries", () => {
|
||||
const center = { x: 50, y: 0 };
|
||||
const point = { x: 150, y: 0 }; // Horizontal line at y=0
|
||||
|
||||
const intersection = calculateBoundaryIntersection(center, point, bounds);
|
||||
|
||||
expect(intersection).toEqual({ x: 100, y: 0 }); // Should intersect at right boundary
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { getLabelPosition } from "../getLabelPosition";
|
||||
|
||||
describe("getLabelPosition", () => {
|
||||
const dimensions = { width: 100, height: 20 };
|
||||
const bounds = { x: 0, y: 0, width: 1000, height: 1000 };
|
||||
|
||||
it("should position label with default offset when cursor is in bounds", () => {
|
||||
const position = { x: 500, y: 500 };
|
||||
const result = getLabelPosition(position, dimensions, bounds, false);
|
||||
|
||||
expect(result).toEqual({
|
||||
x: position.x + 15,
|
||||
y: position.y + 25,
|
||||
});
|
||||
});
|
||||
|
||||
it("should position label with default offset when bounds are undefined", () => {
|
||||
const position = { x: 500, y: 500 };
|
||||
const result = getLabelPosition(position, dimensions, undefined, true);
|
||||
|
||||
expect(result).toEqual({
|
||||
x: position.x + 15,
|
||||
y: position.y + 25,
|
||||
});
|
||||
});
|
||||
|
||||
it("should adjust label position based on cursor position when out of bounds", () => {
|
||||
const position = { x: 800, y: 600 };
|
||||
const result = getLabelPosition(position, dimensions, bounds, true);
|
||||
|
||||
// At x=800, percentageH = 0.8, so x offset should be -80 (0.8 * width)
|
||||
// At y=600, percentageV = 0.6, so y offset should be -12 (0.6 * height)
|
||||
expect(result).toEqual({
|
||||
x: position.x - 0.8 * dimensions.width,
|
||||
y: position.y - 0.6 * dimensions.height,
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle cursor at bounds edges", () => {
|
||||
const position = { x: 1000, y: 1000 }; // Bottom-right corner
|
||||
const result = getLabelPosition(position, dimensions, bounds, true);
|
||||
|
||||
// At the edges, percentages should be 1, so full dimension should be subtracted
|
||||
expect(result).toEqual({
|
||||
x: position.x - dimensions.width,
|
||||
y: position.y - dimensions.height,
|
||||
});
|
||||
});
|
||||
|
||||
it("should handle cursor at bounds origin", () => {
|
||||
const position = { x: 0, y: 0 }; // Top-left corner
|
||||
const result = getLabelPosition(position, dimensions, bounds, true);
|
||||
|
||||
// At origin, percentages should be 0, so no offset from position
|
||||
expect(result).toEqual({
|
||||
x: position.x,
|
||||
y: position.y,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { isOutOfBounds } from "../isOutOfBounds";
|
||||
|
||||
describe("isOutOfBounds", () => {
|
||||
it("should return true if the position is out of bounds", () => {
|
||||
expect(
|
||||
isOutOfBounds(
|
||||
{ x: 101, y: 101 },
|
||||
{ x: 0, y: 0, width: 100, height: 100 },
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false if the position is within bounds", () => {
|
||||
expect(
|
||||
isOutOfBounds({ x: 50, y: 50 }, { x: 0, y: 0, width: 100, height: 100 }),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false if the position is inside the grace area", () => {
|
||||
expect(
|
||||
isOutOfBounds(
|
||||
{ x: 110, y: 110 },
|
||||
{ x: 0, y: 0, width: 100, height: 100 },
|
||||
20,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
77
examples/multi-cursors/src/utils/boundaryIntersection.ts
Normal file
77
examples/multi-cursors/src/utils/boundaryIntersection.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
import { Vec2, ViewBox } from "../types";
|
||||
|
||||
/**
|
||||
* Calculate the intersection point of a line and a boundary.
|
||||
* @param center - The origin of the line.
|
||||
* @param point - The end of the line to calculate the intersection for.
|
||||
* @param bounds - The bounds of the boundary.
|
||||
* @returns The intersection point.
|
||||
*/
|
||||
export function calculateBoundaryIntersection(
|
||||
center: Vec2,
|
||||
point: Vec2,
|
||||
bounds: ViewBox,
|
||||
): Vec2 {
|
||||
// Calculate direction vector
|
||||
const dx = point.x - center.x;
|
||||
const dy = point.y - center.y;
|
||||
|
||||
// Calculate all possible intersections
|
||||
let horizontalIntersection: Vec2 | null = null;
|
||||
let verticalIntersection: Vec2 | null = null;
|
||||
|
||||
// Check horizontal bounds
|
||||
if (dx !== 0) {
|
||||
// Skip horizontal bounds check if line is vertical
|
||||
if (point.x < bounds.x) {
|
||||
const y = center.y + (dy * (bounds.x - center.x)) / dx;
|
||||
if (y >= bounds.y && y <= bounds.y + bounds.height) {
|
||||
horizontalIntersection = { x: bounds.x, y };
|
||||
}
|
||||
} else if (point.x > bounds.x + bounds.width) {
|
||||
const y = center.y + (dy * (bounds.x + bounds.width - center.x)) / dx;
|
||||
if (y >= bounds.y && y <= bounds.y + bounds.height) {
|
||||
horizontalIntersection = { x: bounds.x + bounds.width, y };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check vertical bounds
|
||||
if (dy !== 0) {
|
||||
// Skip vertical bounds check if line is horizontal
|
||||
if (point.y < bounds.y) {
|
||||
const x = center.x + (dx * (bounds.y - center.y)) / dy;
|
||||
if (x >= bounds.x && x <= bounds.x + bounds.width) {
|
||||
verticalIntersection = { x, y: bounds.y };
|
||||
}
|
||||
} else if (point.y > bounds.y + bounds.height) {
|
||||
const x = center.x + (dx * (bounds.y + bounds.height - center.y)) / dy;
|
||||
if (x >= bounds.x && x <= bounds.x + bounds.width) {
|
||||
verticalIntersection = { x, y: bounds.y + bounds.height };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Choose the intersection point that's closest to the actual point
|
||||
if (horizontalIntersection && verticalIntersection) {
|
||||
const horizontalDist = Math.hypot(
|
||||
point.x - horizontalIntersection.x,
|
||||
point.y - horizontalIntersection.y,
|
||||
);
|
||||
const verticalDist = Math.hypot(
|
||||
point.x - verticalIntersection.x,
|
||||
point.y - verticalIntersection.y,
|
||||
);
|
||||
return horizontalDist < verticalDist
|
||||
? horizontalIntersection
|
||||
: verticalIntersection;
|
||||
}
|
||||
|
||||
return (
|
||||
horizontalIntersection ||
|
||||
verticalIntersection || {
|
||||
x: Math.max(bounds.x, Math.min(bounds.x + bounds.width, point.x)),
|
||||
y: Math.max(bounds.y, Math.min(bounds.y + bounds.height, point.y)),
|
||||
}
|
||||
);
|
||||
}
|
||||
17
examples/multi-cursors/src/utils/centerOfBounds.ts
Normal file
17
examples/multi-cursors/src/utils/centerOfBounds.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Vec2, ViewBox } from "../types";
|
||||
|
||||
/**
|
||||
* Get the center of a bounds.
|
||||
* @param bounds - The bounds to get the center of.
|
||||
* @returns The center of the bounds.
|
||||
*/
|
||||
export function centerOfBounds(bounds?: ViewBox): Vec2 {
|
||||
if (!bounds) {
|
||||
return { x: 0, y: 0 };
|
||||
}
|
||||
|
||||
return {
|
||||
x: bounds.x + bounds.width / 2,
|
||||
y: bounds.y + bounds.height / 2,
|
||||
};
|
||||
}
|
||||
40
examples/multi-cursors/src/utils/getLabelPosition.ts
Normal file
40
examples/multi-cursors/src/utils/getLabelPosition.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { Vec2, ViewBox } from "../types";
|
||||
|
||||
interface TextDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface LabelPosition {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the position of a cursor label based on cursor position, label dimensions, and bounds
|
||||
* Such that the label is always on the same side of the bounds as the cursor
|
||||
* @param position - The cursor position
|
||||
* @param dimensions - The dimensions of the label text
|
||||
* @param bounds - The viewport bounds
|
||||
* @param isOutOfBounds - Whether the cursor is outside the bounds
|
||||
* @returns The calculated label position
|
||||
*/
|
||||
export function getLabelPosition(
|
||||
position: Vec2,
|
||||
dimensions: TextDimensions,
|
||||
bounds?: ViewBox,
|
||||
isOutOfBounds?: boolean,
|
||||
): LabelPosition {
|
||||
if (!isOutOfBounds || !bounds) {
|
||||
return { x: position.x + 15, y: position.y + 25 };
|
||||
}
|
||||
|
||||
// Calculate the percentage of the bounds that the intersection point is from the left
|
||||
const percentageH = (position.x - bounds.x) / bounds.width;
|
||||
const percentageV = (position.y - bounds.y) / bounds.height;
|
||||
|
||||
return {
|
||||
x: position.x - percentageH * dimensions.width,
|
||||
y: position.y - percentageV * dimensions.height,
|
||||
};
|
||||
}
|
||||
21
examples/multi-cursors/src/utils/isOutOfBounds.ts
Normal file
21
examples/multi-cursors/src/utils/isOutOfBounds.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Vec2, ViewBox } from "../types";
|
||||
|
||||
/**
|
||||
* Check if a position is out of bounds of a view box.
|
||||
* @param position - The position to check.
|
||||
* @param bounds - The bounds of the view box.
|
||||
* @param grace - The grace distance to allow for the position to be out of bounds.
|
||||
* @returns True if the position is out of bounds, false otherwise.
|
||||
*/
|
||||
export function isOutOfBounds(
|
||||
position: Vec2,
|
||||
bounds: ViewBox,
|
||||
grace: number = 0,
|
||||
): boolean {
|
||||
return (
|
||||
position.x < bounds.x - grace ||
|
||||
position.x > bounds.x + bounds.width + grace ||
|
||||
position.y < bounds.y - grace ||
|
||||
position.y > bounds.y + bounds.height + grace
|
||||
);
|
||||
}
|
||||
@@ -1,15 +1,30 @@
|
||||
import { Account, Group, type ID } from "jazz-tools";
|
||||
import { CursorContainer, CursorFeed } from "../schema";
|
||||
|
||||
/**
|
||||
* Creates a new group to own the cursor container.
|
||||
* @param me - The account of the current user.
|
||||
* @returns The group.
|
||||
*/
|
||||
function createGroup(me: Account) {
|
||||
const group = Group.create({
|
||||
owner: me,
|
||||
});
|
||||
group.addMember("everyone", "writer");
|
||||
console.log("Created group");
|
||||
console.log(`Add "VITE_GROUP_ID=${group.id}" to your .env file`);
|
||||
return group;
|
||||
}
|
||||
|
||||
export async function loadGroup(me: Account, groupID: ID<Group>) {
|
||||
if (groupID === undefined) {
|
||||
console.log("No group ID found in .env, creating group...");
|
||||
return createGroup(me);
|
||||
}
|
||||
const group = await Group.load(groupID, {});
|
||||
if (group === undefined) {
|
||||
const group = Group.create({
|
||||
owner: me,
|
||||
});
|
||||
group.addMember("everyone", "writer");
|
||||
console.log("Created group:", group.id);
|
||||
return group;
|
||||
if (group === null || group === undefined) {
|
||||
console.log("Group not found, creating group...");
|
||||
return createGroup(me);
|
||||
}
|
||||
return group;
|
||||
}
|
||||
@@ -24,26 +39,29 @@ export async function loadGroup(me: Account, groupID: ID<Group>) {
|
||||
*/
|
||||
export async function loadCursorContainer(
|
||||
me: Account,
|
||||
cursorFeedID: ID<CursorFeed>,
|
||||
cursorFeedID = "cursor-feed",
|
||||
groupID: ID<Group>,
|
||||
): Promise<ID<CursorFeed> | undefined> {
|
||||
if (!me) return;
|
||||
console.log("Loading group...");
|
||||
const group = await loadGroup(me, groupID);
|
||||
|
||||
const cursorContainerID = CursorContainer.findUnique(
|
||||
cursorFeedID,
|
||||
group?.id as ID<Group>,
|
||||
);
|
||||
console.log("Loading cursor container:", cursorContainerID);
|
||||
const cursorContainer = await CursorContainer.load(cursorContainerID, {
|
||||
cursorFeed: [],
|
||||
resolve: {
|
||||
cursorFeed: true,
|
||||
},
|
||||
});
|
||||
if (cursorContainer === undefined) {
|
||||
|
||||
if (cursorContainer === null || cursorContainer === undefined) {
|
||||
console.log("Global cursors does not exist, creating...");
|
||||
const cursorContainer = CursorContainer.create(
|
||||
{
|
||||
cursorFeed: CursorFeed.create([], {
|
||||
owner: group,
|
||||
}),
|
||||
cursorFeed: CursorFeed.create([], group),
|
||||
},
|
||||
{
|
||||
owner: group,
|
||||
@@ -60,6 +78,6 @@ export async function loadCursorContainer(
|
||||
"Global cursors already exists, loading...",
|
||||
cursorContainer.id,
|
||||
);
|
||||
return cursorContainer.cursorFeed.id;
|
||||
return cursorContainer.cursorFeed?.id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,12 @@ import { defineConfig } from "vite";
|
||||
// https://vite.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
build: {
|
||||
minify: "esbuild",
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,5 +1,53 @@
|
||||
# multiauth
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b108c61: Use the new Resolve API
|
||||
- jazz-react@0.12.2
|
||||
- jazz-react-auth-clerk@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-react-auth-clerk@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
- jazz-react-auth-clerk@0.12.0
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-react-auth-clerk@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
- jazz-react-auth-clerk@0.11.7
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "multiauth",
|
||||
"private": true,
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.10",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useAccount, useIsAuthenticated } from "jazz-react";
|
||||
|
||||
export function Home() {
|
||||
const { me, logOut } = useAccount({ root: {} });
|
||||
const { me, logOut } = useAccount({ resolve: { root: true } });
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
|
||||
if (!me) return;
|
||||
|
||||
@@ -1,5 +1,56 @@
|
||||
# jazz-example-musicplayer
|
||||
|
||||
## 0.0.91
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [8a71835]
|
||||
- jazz-inspector@0.12.2
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.90
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-inspector@0.12.1
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.89
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- Updated dependencies [9a56bb3]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-inspector@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [71b9390]
|
||||
- jazz-inspector@0.11.8
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2c3761c]
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-inspector@0.11.7
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.86
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-music-player",
|
||||
"private": true,
|
||||
"version": "0.0.86",
|
||||
"version": "0.0.91",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -22,8 +22,8 @@
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"jazz-inspector": "workspace:*",
|
||||
"jazz-react": "workspace:0.11.6",
|
||||
"jazz-tools": "workspace:0.11.6",
|
||||
"jazz-react": "workspace:0.12.2",
|
||||
"jazz-tools": "workspace:0.12.2",
|
||||
"lucide-react": "^0.274.0",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
|
||||
@@ -24,10 +24,7 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
|
||||
* access rights to CoValues. We get it from the top-level provider `<WithJazz/>`.
|
||||
*/
|
||||
const { me } = useAccount({
|
||||
root: {
|
||||
rootPlaylist: {},
|
||||
playlists: [],
|
||||
},
|
||||
resolve: { root: { rootPlaylist: true, playlists: true } },
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
@@ -51,8 +48,9 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
|
||||
|
||||
const params = useParams<{ playlistId: ID<Playlist> }>();
|
||||
const playlistId = params.playlistId ?? me?.root._refs.rootPlaylist.id;
|
||||
|
||||
const playlist = useCoState(Playlist, playlistId, {
|
||||
tracks: [],
|
||||
resolve: { tracks: true },
|
||||
});
|
||||
|
||||
const isRootPlaylist = !params.playlistId;
|
||||
|
||||
@@ -27,9 +27,11 @@ export async function uploadMusicTracks(
|
||||
isExampleTrack: boolean = false,
|
||||
) {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: [],
|
||||
resolve: {
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -65,8 +67,10 @@ export async function uploadMusicTracks(
|
||||
|
||||
export async function createNewPlaylist() {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {
|
||||
playlists: [],
|
||||
resolve: {
|
||||
root: {
|
||||
playlists: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -149,9 +153,11 @@ export async function updateMusicTrackTitle(track: MusicTrack, title: string) {
|
||||
|
||||
export async function updateActivePlaylist(playlist?: Playlist) {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {
|
||||
activePlaylist: {},
|
||||
rootPlaylist: {},
|
||||
resolve: {
|
||||
root: {
|
||||
activePlaylist: true,
|
||||
rootPlaylist: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -160,7 +166,9 @@ export async function updateActivePlaylist(playlist?: Playlist) {
|
||||
|
||||
export async function updateActiveTrack(track: MusicTrack) {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {},
|
||||
resolve: {
|
||||
root: {},
|
||||
},
|
||||
});
|
||||
|
||||
root.activeTrack = track;
|
||||
@@ -170,17 +178,23 @@ export async function onAnonymousAccountDiscarded(
|
||||
anonymousAccount: MusicaAccount,
|
||||
) {
|
||||
const { root: anonymousAccountRoot } = await anonymousAccount.ensureLoaded({
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: [{}],
|
||||
resolve: {
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: {
|
||||
$each: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: [],
|
||||
resolve: {
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -197,8 +211,10 @@ export async function onAnonymousAccountDiscarded(
|
||||
|
||||
export async function deletePlaylist(playlistId: string) {
|
||||
const { root } = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {
|
||||
playlists: [],
|
||||
resolve: {
|
||||
root: {
|
||||
playlists: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { getNextTrack, getPrevTrack } from "./lib/getters";
|
||||
|
||||
export function useMediaPlayer() {
|
||||
const { me } = useAccount({
|
||||
root: {},
|
||||
resolve: { root: true },
|
||||
});
|
||||
|
||||
const playState = usePlayState();
|
||||
|
||||
@@ -16,8 +16,10 @@ export function InvitePage() {
|
||||
const playlist = await Playlist.load(playlistId, {});
|
||||
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {
|
||||
playlists: [],
|
||||
resolve: {
|
||||
root: {
|
||||
playlists: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -22,9 +22,13 @@ export function AuthModal({ open, onOpenChange }: AuthModalProps) {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const { me } = useAccount({
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: [{}],
|
||||
resolve: {
|
||||
root: {
|
||||
rootPlaylist: {
|
||||
tracks: {
|
||||
$each: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -30,9 +30,7 @@ export function MusicTrackRow({
|
||||
const track = useCoState(MusicTrack, trackId);
|
||||
|
||||
const { me } = useAccount({
|
||||
root: {
|
||||
playlists: [{}],
|
||||
},
|
||||
resolve: { root: { playlists: { $each: true } } },
|
||||
});
|
||||
|
||||
const playlists = me?.root.playlists ?? [];
|
||||
|
||||
@@ -12,9 +12,7 @@ export function PlayerControls({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
|
||||
const isPlaying = playState.value === "play";
|
||||
|
||||
const activePlaylist = useAccount({
|
||||
root: {
|
||||
activePlaylist: {},
|
||||
},
|
||||
resolve: { root: { activePlaylist: true } },
|
||||
}).me?.root.activePlaylist;
|
||||
|
||||
useMediaEndListener(mediaPlayer.playNextTrack);
|
||||
@@ -25,7 +23,7 @@ export function PlayerControls({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
|
||||
});
|
||||
|
||||
const activeTrack = useCoState(MusicTrack, mediaPlayer.activeTrackId, {
|
||||
waveform: {},
|
||||
resolve: { waveform: true },
|
||||
});
|
||||
|
||||
if (!activeTrack) return null;
|
||||
|
||||
@@ -8,9 +8,7 @@ export function SidePanel() {
|
||||
const { playlistId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const { me } = useAccount({
|
||||
root: {
|
||||
playlists: [{}],
|
||||
},
|
||||
resolve: { root: { playlists: { $each: true } } },
|
||||
});
|
||||
|
||||
function handleAllTracksClick(evt: React.MouseEvent<HTMLAnchorElement>) {
|
||||
|
||||
@@ -8,7 +8,6 @@ export function Waveform(props: { track: MusicTrack; height: number }) {
|
||||
const waveformData = useCoState(
|
||||
MusicTrackWaveform,
|
||||
track._refs.waveform.id,
|
||||
{},
|
||||
)?.data;
|
||||
const duration = track.duration;
|
||||
|
||||
|
||||
@@ -2,9 +2,11 @@ import { MusicaAccount } from "../1_schema";
|
||||
|
||||
export async function getNextTrack() {
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {
|
||||
activePlaylist: {
|
||||
tracks: [],
|
||||
resolve: {
|
||||
root: {
|
||||
activePlaylist: {
|
||||
tracks: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -21,9 +23,11 @@ export async function getNextTrack() {
|
||||
|
||||
export async function getPrevTrack() {
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {
|
||||
activePlaylist: {
|
||||
tracks: [],
|
||||
resolve: {
|
||||
root: {
|
||||
activePlaylist: {
|
||||
tracks: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ export function useUploadExampleData() {
|
||||
|
||||
async function uploadOnboardingData() {
|
||||
const me = await MusicaAccount.getMe().ensureLoaded({
|
||||
root: {},
|
||||
resolve: { root: true },
|
||||
});
|
||||
|
||||
if (me.root.exampleDataLoaded) return;
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# organization
|
||||
|
||||
## 0.0.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.62
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.61
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.60
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "organization",
|
||||
"private": true,
|
||||
"version": "0.0.58",
|
||||
"version": "0.0.63",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -5,11 +5,11 @@ import { Organization } from "./schema.ts";
|
||||
|
||||
export function AcceptInvitePage() {
|
||||
const navigate = useNavigate();
|
||||
const { me } = useAccount({ root: { organizations: [] } });
|
||||
const { me } = useAccount({ resolve: { root: { organizations: true } } });
|
||||
|
||||
const onAccept = (organizationId: ID<Organization>) => {
|
||||
if (me?.root?.organizations) {
|
||||
Organization.load(organizationId, me, []).then((organization) => {
|
||||
Organization.load(organizationId).then((organization) => {
|
||||
if (organization) {
|
||||
// avoid duplicates
|
||||
const ids = me.root.organizations.map(
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Heading } from "./components/Heading.tsx";
|
||||
|
||||
export function HomePage() {
|
||||
const { me } = useAccount({
|
||||
root: { organizations: [{}] },
|
||||
resolve: { root: { organizations: true } },
|
||||
});
|
||||
|
||||
if (!me?.root.organizations) return;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { UserIcon } from "lucide-react";
|
||||
|
||||
export function Layout({ children }: { children: React.ReactNode }) {
|
||||
const { me, logOut } = useAccount({
|
||||
root: { draftOrganization: {} },
|
||||
resolve: { root: { draftOrganization: true } },
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -13,7 +13,7 @@ export function OrganizationPage() {
|
||||
.organizationId;
|
||||
|
||||
const organization = useCoState(Organization, paramOrganizationId, {
|
||||
projects: [],
|
||||
resolve: { projects: true },
|
||||
});
|
||||
|
||||
if (!organization) return <p>Loading organization...</p>;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { OrganizationForm } from "./OrganizationForm.tsx";
|
||||
|
||||
export function CreateOrganization() {
|
||||
const { me } = useAccount({
|
||||
root: { draftOrganization: {}, organizations: [] },
|
||||
resolve: { root: { draftOrganization: true, organizations: true } },
|
||||
});
|
||||
const [errors, setErrors] = useState<string[]>([]);
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Organization } from "../schema.ts";
|
||||
|
||||
export function OrganizationSelector({ className }: { className?: string }) {
|
||||
const { me } = useAccount({
|
||||
root: { organizations: [{}] },
|
||||
resolve: { root: { organizations: { $each: true } } },
|
||||
});
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# passkey-svelte
|
||||
|
||||
## 0.0.57
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.12.2
|
||||
|
||||
## 0.0.56
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.12.1
|
||||
|
||||
## 0.0.55
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.12.0
|
||||
|
||||
## 0.0.54
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.11.8
|
||||
|
||||
## 0.0.53
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-svelte@0.11.7
|
||||
|
||||
## 0.0.52
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "passkey-svelte",
|
||||
"version": "0.0.52",
|
||||
"version": "0.0.57",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# minimal-auth-passkey
|
||||
|
||||
## 0.0.68
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.67
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.66
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "passkey",
|
||||
"private": true,
|
||||
"version": "0.0.63",
|
||||
"version": "0.0.68",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# passphrase
|
||||
|
||||
## 0.0.65
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.64
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.62
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.61
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.60
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "passphrase",
|
||||
"private": true,
|
||||
"version": "0.0.60",
|
||||
"version": "0.0.65",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# jazz-password-manager
|
||||
|
||||
## 0.0.89
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.88
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.87
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.86
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.85
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.84
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-password-manager",
|
||||
"private": true,
|
||||
"version": "0.0.84",
|
||||
"version": "0.0.89",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -12,8 +12,8 @@
|
||||
"clean-install": "rm -rf node_modules pnpm-lock.yaml && pnpm install"
|
||||
},
|
||||
"dependencies": {
|
||||
"jazz-react": "workspace:0.11.6",
|
||||
"jazz-tools": "workspace:0.11.6",
|
||||
"jazz-react": "workspace:0.12.2",
|
||||
"jazz-tools": "workspace:0.12.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-hook-form": "^7.41.5",
|
||||
|
||||
@@ -43,9 +43,11 @@ const VaultPage: React.FC = () => {
|
||||
(item): item is Exclude<typeof item, null> => !!item,
|
||||
) || [],
|
||||
);
|
||||
const folders = useCoState(FolderList, me.root?._refs.folders?.id, [
|
||||
{ items: [{}] },
|
||||
]);
|
||||
const folders = useCoState(FolderList, me.root?._refs.folders?.id, {
|
||||
resolve: {
|
||||
$each: { items: { $each: true } },
|
||||
},
|
||||
});
|
||||
|
||||
const [selectedFolder, setSelectedFolder] = useState<Folder | undefined>();
|
||||
const [isNewItemModalOpen, setIsNewItemModalOpen] = useState(false);
|
||||
|
||||
@@ -60,11 +60,9 @@ export async function addSharedFolder(
|
||||
me: PasswordManagerAccount,
|
||||
) {
|
||||
const [sharedFolder, account] = await Promise.all([
|
||||
Folder.load(sharedFolderId, me, {}),
|
||||
PasswordManagerAccount.load(me.id, me, {
|
||||
root: {
|
||||
folders: [],
|
||||
},
|
||||
Folder.load(sharedFolderId),
|
||||
PasswordManagerAccount.load(me.id, {
|
||||
resolve: { root: { folders: true } },
|
||||
}),
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# jazz-example-pets
|
||||
|
||||
## 0.0.187
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.2
|
||||
- jazz-tools@0.12.2
|
||||
|
||||
## 0.0.186
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.12.1
|
||||
- jazz-tools@0.12.1
|
||||
|
||||
## 0.0.185
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [01523dc]
|
||||
- Updated dependencies [4ea87dc]
|
||||
- Updated dependencies [1e6da19]
|
||||
- Updated dependencies [b6c6a0a]
|
||||
- jazz-tools@0.12.0
|
||||
- jazz-react@0.12.0
|
||||
|
||||
## 0.0.184
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- jazz-react@0.11.8
|
||||
- jazz-tools@0.11.8
|
||||
|
||||
## 0.0.183
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [a140f55]
|
||||
- Updated dependencies [4019918]
|
||||
- Updated dependencies [2b0d1b0]
|
||||
- jazz-tools@0.11.7
|
||||
- jazz-react@0.11.7
|
||||
|
||||
## 0.0.182
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "jazz-example-pets",
|
||||
"private": true,
|
||||
"version": "0.0.182",
|
||||
"version": "0.0.187",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -19,8 +19,8 @@
|
||||
"@radix-ui/react-toast": "^1.1.4",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"jazz-react": "workspace:0.11.6",
|
||||
"jazz-tools": "workspace:0.11.6",
|
||||
"jazz-react": "workspace:0.12.2",
|
||||
"jazz-tools": "workspace:0.12.2",
|
||||
"lucide-react": "^0.274.0",
|
||||
"qrcode": "^1.5.3",
|
||||
"react": "^18.3.1",
|
||||
@@ -40,7 +40,7 @@
|
||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"is-ci": "^3.0.1",
|
||||
"jazz-run": "workspace:0.11.6",
|
||||
"jazz-run": "workspace:0.12.2",
|
||||
"postcss": "^8.4.27",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "~5.6.2",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user