Compare commits

...

165 Commits

Author SHA1 Message Date
Guido D'Orsi
776e59709f Merge remote-tracking branch 'origin/main' into fix/loading-state 2025-04-02 20:56:19 +02:00
Guido D'Orsi
eefdf9783e Merge pull request #1774 from garden-co/changeset-release/main
Version Packages
2025-04-02 20:54:17 +02:00
github-actions[bot]
a821c71967 Version Packages 2025-04-02 18:54:03 +00:00
Guido D'Orsi
cc684eb5cd chore: changeset 2025-04-02 20:51:41 +02:00
Guido D'Orsi
8dd2f05b17 Merge pull request #1785 from joshua1/make-contructor-params-protected
changed the constructor parameters of the BrowserPasskeyAUth class iin jazz-browser's PasskeyAuth.ts to enable extension of the class
2025-04-02 20:49:45 +02:00
Guido D'Orsi
ba94aeab4c Merge pull request #1783 from garden-co/perf/expectedNewHashAfter
perf(expectedNewHashAfter): remove redundant clone and skip double hash generation when creating a local transaction
2025-04-02 20:49:20 +02:00
Guido D'Orsi
a013538c8b fix(coValueState): support CoValue re-load after it is marked as unavailable and improve timeout 2025-04-02 20:41:38 +02:00
joshua1
648140a370 changed the constructor parameters of the BrowserPasskeyAUth class in jazz-browser's PasskeyAuth.ts to enable extension of the class 2025-04-02 19:38:08 +02:00
Guido D'Orsi
c2f4827ac1 perf(expectedNewHashAfter): remove redundant clone and skip double hash generation when creating a local transaction 2025-04-02 17:38:06 +02:00
Guido D'Orsi
8a52dbb784 Merge pull request #1782 from garden-co/feat/customize-ping-timeout
feat(wsPeer): add an option to change the ping timeout
2025-04-02 17:07:41 +02:00
Guido D'Orsi
eb47ec6bbd feat: add an option to change the ping timeout 2025-04-02 16:30:47 +02:00
Guido D'Orsi
baa62e13b1 chore: remove debug code from sync 2025-04-02 15:53:18 +02:00
Trisha Lim
8a71835ca2 refactor(inspector): use goober for css (#1780)
* add text and badge component

* use button component for links

* add table components

* move inspector button to separate component

* refactor css to use goober

* add changeset
2025-04-02 20:33:43 +07:00
Trisha Lim
67a488cac7 fix: "old" line highlighting not working (#1777) 2025-04-01 16:40:56 +07:00
Guido D'Orsi
a11f531d4b Merge pull request #1752 from garden-co/fix/twoslash-dark
fix popover dark mode colors
2025-04-01 11:10:33 +02:00
Trisha Lim
9dd717bf0e lint fixes 2025-04-01 11:36:02 +07:00
Trisha Lim
42551bb4fd fix console errors on react guide 2025-04-01 11:34:49 +07:00
Benjamin S. Leveritt
5c5de61cb6 Merge pull request #1755 from garden-co/fix-multiauth-resolve
Use the new Resolve API for the multiauth example app
2025-03-31 17:44:56 +01:00
pax-k
7fdfc7fddb chore: changeset 2025-03-31 19:43:56 +03:00
pax-k
b108c6166e chore: changeset 2025-03-31 14:42:31 +03:00
pax-k
e0bc9a7f67 fix(example): use the new Resolve API 2025-03-31 14:41:39 +03:00
Benjamin S. Leveritt
f900495f8d Merge pull request #1742 from garden-co/1731-add-out-of-bounds-indicator
1731 Add out of bounds indicator
2025-03-31 12:13:25 +01:00
Benjamin S. Leveritt
4188c7a18d Rename variables 2025-03-31 11:49:48 +01:00
Benjamin S. Leveritt
7315960477 Fixes from comments 2025-03-31 11:40:41 +01:00
Benjamin S. Leveritt
815f485ee5 Fix log 2025-03-31 09:57:05 +01:00
Benjamin S. Leveritt
402008a08f Drop console.logs from build 2025-03-31 09:57:05 +01:00
Benjamin S. Leveritt
bc1576cb92 Adds tests 2025-03-31 09:57:05 +01:00
Benjamin S. Leveritt
acbe66ed60 Replace out of bounds circle with arrow 2025-03-31 09:57:04 +01:00
Benjamin S. Leveritt
ec1fd2aaa2 Fix cursor label positioning relative to the bounds 2025-03-31 09:57:04 +01:00
Benjamin S. Leveritt
bd796555f2 Tweaks label 2025-03-31 09:57:04 +01:00
Benjamin S. Leveritt
153f6ec245 Add proportional label placement 2025-03-31 09:57:04 +01:00
Benjamin S. Leveritt
42d007da13 WIP cursor labels 2025-03-31 09:57:04 +01:00
Benjamin S. Leveritt
c764eeff56 Adds debug flag 2025-03-31 09:57:04 +01:00
Benjamin S. Leveritt
a7a00e6a7c Joins label 2025-03-31 09:57:04 +01:00
Benjamin S. Leveritt
bc65695eee Merges OutOfBoundsMarker with Cursor 2025-03-31 09:57:03 +01:00
Benjamin S. Leveritt
153231aecb Removes OoB labels 2025-03-31 09:57:03 +01:00
Benjamin S. Leveritt
d814899d71 Adds an out of bounds marker 2025-03-31 09:57:03 +01:00
Benjamin S. Leveritt
0b6c35c08a Adds isOutOfBounds test 2025-03-31 09:57:03 +01:00
Benjamin S. Leveritt
e62ea5a8ac Adds Boundary viz 2025-03-31 09:57:03 +01:00
Benjamin S. Leveritt
a5bffd7312 Adds ViewBox type 2025-03-31 09:57:03 +01:00
Benjamin S. Leveritt
9aa91ec525 Adds additional logging during bootstrapping
More logs
2025-03-31 09:57:03 +01:00
Benjamin S. Leveritt
9b8c299ba5 Add basic creds to .env.example 2025-03-31 09:57:03 +01:00
Guido D'Orsi
7486ca768d Merge pull request #1753 from garden-co/fix/llms-txt-content
fix: missing content on llms.txt
2025-03-31 10:25:01 +02:00
Trisha Lim
fa4d501eb0 fix missing intro page on llms.txt 2025-03-31 08:43:38 +07:00
Trisha Lim
a126d5dbf8 fix: missing content on llms.txt 2025-03-31 08:35:43 +07:00
Trisha Lim
d697cc5713 fix popover dark mode colors 2025-03-30 23:10:57 +07:00
Guido D'Orsi
d95c8cc302 Merge pull request #1717 from garden-co/fix/missing-toc
fix: missing TOC on docs intro
2025-03-30 00:09:05 +01:00
Trisha Lim
9dee93af1b fix missing TOC on docs intro 2025-03-29 20:03:34 +07:00
Guido D'Orsi
0dffa407a8 Merge pull request #1748 from garden-co/changeset-release/main
Version Packages
2025-03-28 15:39:11 +01:00
github-actions[bot]
0d97f161bd Version Packages 2025-03-28 13:09:50 +00:00
Guido D'Orsi
b9525b675e Merge pull request #1747 from garden-co/perf/linked-list-queue
perf: re-introducing linked lists on PriorityBasedMessageQueue
2025-03-28 14:07:25 +01:00
Guido D'Orsi
5a00fe0862 perf: re-introducing linked lists on PriorityBasedMessageQueue 2025-03-28 12:54:44 +01:00
Guido D'Orsi
3db07f541f Merge pull request #1746 from garden-co/feat/upgrade-typedoc
fix(homepage): upgrade typedoc to v0.27 and ts v5.7
2025-03-28 12:12:04 +01:00
Guido D'Orsi
0db2e60d09 fix(homepage): upgrade typedoc to v0.27 and ts v5.7 2025-03-28 12:06:36 +01:00
Guido D'Orsi
f122147f03 Merge pull request #1745 from garden-co/changeset-release/main
Version Packages
2025-03-28 11:06:11 +01:00
github-actions[bot]
4e1bcde8b2 Version Packages 2025-03-28 10:02:02 +00:00
Guido D'Orsi
eaef418151 Merge pull request #1642 from garden-co/0-12-0
Jazz 0.12.0 - A clearer syntax for deep loading
2025-03-28 10:59:18 +01:00
Guido D'Orsi
8d17b192d0 Merge pull request #1743 from garden-co/improve-link-accounts
fix: make the linkAccounts test utility wait for the accounts coValues to be synced
2025-03-28 10:04:29 +01:00
Trisha Lim
9a56bb3d25 fix missing icon (#1744) 2025-03-28 14:08:32 +07:00
Guido D'Orsi
b6c6a0ae64 fix: make the linkAccounts test utility wait for the accounts coValues to be synced 2025-03-27 22:24:28 +01:00
Guido D'Orsi
e000774b3b Merge pull request #1739 from garden-co/changeset-release/main
Version Packages
2025-03-27 18:45:09 +01:00
github-actions[bot]
6f6cf23bc8 Version Packages 2025-03-27 17:38:35 +00:00
Guido D'Orsi
77a718656c Merge pull request #1741 from garden-co/issue-1373
fix: fixes expected header to be sent in first message error
2025-03-27 18:35:27 +01:00
Guido D'Orsi
6c86c4f7ee fix: fixes expected header to be sent in first message error 2025-03-27 18:34:39 +01:00
Guido D'Orsi
72508332fb Merge pull request #1728 from garden-co/gio/update-otel-dep
chore: update @opentelemetry/api dependency
2025-03-27 18:29:38 +01:00
Guido D'Orsi
0ac88b4c80 test: repro for expected header to be sent in first message 2025-03-27 17:41:01 +01:00
pax-k
11460b6f9f fix(cursor): refactored docs to include changes for Jazz v0.12.0 - Deeply resolved data 2025-03-27 18:34:03 +02:00
Trisha Lim
71b93909e6 fix(inspector): install clsx, remove lucide-react (#1737)
* install clsx

* remove lucide-react

* add changeset
2025-03-27 21:02:06 +07:00
Guido D'Orsi
26646cde0c chore: migrate code to the new resolve spec after merging with main 2025-03-27 12:02:06 +01:00
Guido D'Orsi
4033e95a50 Merge remote-tracking branch 'origin/main' into 0-12-0 2025-03-27 11:52:15 +01:00
Guido D'Orsi
f379fcc176 Merge pull request #1730 from garden-co/changeset-release/main
Version Packages
2025-03-27 11:49:13 +01:00
Guido D'Orsi
66d59b31d5 Merge pull request #1732 from garden-co/docs/loading-errors
docs: document loading errors
2025-03-27 11:48:23 +01:00
Guido D'Orsi
1e6da19d5e fix: The .load function now returns null on error 2025-03-27 11:48:12 +01:00
github-actions[bot]
d6ea4d4662 Version Packages 2025-03-27 10:37:27 +00:00
Guido D'Orsi
84b5dd8a0b Merge pull request #1719 from garden-co/feat/react-create-image
feat: re-export createImage on jazz-react
2025-03-27 11:35:02 +01:00
Guido D'Orsi
c730016572 Merge pull request #1726 from garden-co/fix/inspector-covalue-types
fix(inspector): CoFeeds and FileStreams are showing as "CoStream"
2025-03-27 11:32:53 +01:00
Guido D'Orsi
7677ca5240 Merge pull request #1735 from garden-co/feat/optimize-subscription-updates
fix: trigger a single update when loading a locally available list of items
2025-03-27 11:25:22 +01:00
Guido D'Orsi
cffe482f75 fix: apply the sync resolution on the ref access only during fullfillDepth to avoid issues with Svelte 2025-03-27 10:51:34 +01:00
Guido D'Orsi
a140f555ba fix: trigger a single update when loading a locally available list of items 2025-03-26 19:02:31 +01:00
Guido D'Orsi
10de4b6fc9 docs: document loading errors 2025-03-26 11:01:35 +01:00
Guido D'Orsi
2433344778 test: fix autoload test 2025-03-26 10:56:34 +01:00
Guido D'Orsi
4c01459942 fix(vue): fix types compilation for useAccount 2025-03-26 10:38:57 +01:00
Guido D'Orsi
8dacdd6e2f Merge pull request #1681 from garden-co/1656-document-loading-and-subscription
1656 Document loading and subscriptions
2025-03-25 19:16:39 +01:00
Guido D'Orsi
5b0580bfda docs: fix a broken vanilla example 2025-03-25 19:05:07 +01:00
Guido D'Orsi
2bed7e845d docs: complete the migration of the loading docs to twoslash 2025-03-25 18:55:25 +01:00
Anselm
76976026b7 Remove incorredct / unhelpful sections 2025-03-25 18:32:48 +01:00
Anselm
10ea8fbf88 Typecheck more of the subscribe and load docs, remove history docs again for now 2025-03-25 18:32:48 +01:00
Anselm
bd86b159b9 Fully type upgrade guide 2025-03-25 18:32:48 +01:00
Anselm
c4f5241818 More typechecking in upgrade guide 2025-03-25 18:32:48 +01:00
Anselm
181f433477 Fix Highlight component 2025-03-25 18:32:48 +01:00
Anselm
3897a7e137 Fix darkmode diff colours 2025-03-25 18:32:48 +01:00
Anselm
5082ecef3f Reintroduce Jazz colors 2025-03-25 18:32:47 +01:00
Anselm
268e433870 Typing in docs working 2025-03-25 18:32:47 +01:00
Anselm
6c185160c5 First attempt to make twoslash work 2025-03-25 18:32:47 +01:00
Anselm
d18323b74a Upgrade shiki and use built-in transformers for diffs 2025-03-25 18:32:47 +01:00
Anselm
edd91791c9 More details in deep loading 2025-03-25 18:32:47 +01:00
Anselm
958b13c050 Divide upgrade guide into breaking / new features 2025-03-25 18:32:47 +01:00
Anselm
bbe140f7be Remove incorrect stuff 2025-03-25 18:32:47 +01:00
Anselm
1625f82ab7 Clean up manual subscription & hooks 2025-03-25 18:32:47 +01:00
Anselm
843f729a62 Include current version of history & time travel 2025-03-25 18:32:47 +01:00
Anselm
cc4631bb42 "loading depth" -> "resolve query" 2025-03-25 18:32:47 +01:00
Anselm
3665ef0088 Container-like -> collections 2025-03-25 18:32:47 +01:00
Trisha Lim
e13039818e fix coming soon TOC 2025-03-25 18:32:44 +01:00
Benjamin S. Leveritt
2e79487982 Change to markdown + format
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:32:10 +01:00
Benjamin S. Leveritt
fc2c045a8d Fix ‘for example’
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:58 +01:00
Anselm
69bb94be06 Missing green line 2025-03-25 18:31:58 +01:00
Anselm
228c8fa796 Upgrade guide improvments 2025-03-25 18:31:58 +01:00
Benjamin S. Leveritt
a34b850824 Update CoMap.Record resolve example
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:45 +01:00
Benjamin S. Leveritt
96d518bb97 Remove auto-loading section
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:45 +01:00
Benjamin S. Leveritt
8355f5674d Add Vanilla examples
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
5c1d04ee88 Tweak copy
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
2ef98d01b0 Fix permissions in lists comment
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
15a86a3014 Move Framework detail to just under the fold
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
9c49704cf9 Update Subs and Loading docs
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
44f0d8d5c7 Update subs doc
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:44 +01:00
Benjamin S. Leveritt
d7af97d63f Fix version and date
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-03-25 18:31:41 +01:00
Giordano Ricci
9d0c9dc6ea chore: update @opentelemetry/api dependency 2025-03-25 15:20:34 +00:00
Trisha Lim
2c3761c8e8 add changeset 2025-03-25 18:52:16 +07:00
Trisha Lim
c91bcf9745 inspector: show CoStream as CoFeed 2025-03-25 18:32:37 +07:00
Trisha Lim
c1db6e087a reuse use-resolve-covalue 2025-03-25 18:31:14 +07:00
Trisha Lim
9d8cc194e0 inspector: show files as FileStream instead of CoStream 2025-03-25 18:30:45 +07:00
Guido D'Orsi
3b189e4def Merge pull request #1725 from garden-co/feat/increase-depth-limit
feat: increase depth limit to 10
2025-03-25 12:13:48 +01:00
Guido D'Orsi
7fe50922cc docs: update the version on the 0.12 upgrade guide 2025-03-25 11:05:09 +01:00
Guido D'Orsi
b04e2be665 feat: increase depth limit to 10 2025-03-25 11:03:23 +01:00
Guido D'Orsi
80b1535cdf Merge remote-tracking branch 'origin/main' into 0-12-0 2025-03-24 18:36:48 +01:00
Guido D'Orsi
3d882f0442 fix: update resolve in the new music player action 2025-03-14 15:25:23 +01:00
Guido D'Orsi
f61d568c9d Merge remote-tracking branch 'origin/main' into 0-12-0 2025-03-14 15:21:09 +01:00
Guido D'Orsi
6dd02d289c chore: fix a type error in the tests 2025-03-11 17:22:26 +01:00
Guido D'Orsi
33a4944ba3 Merge remote-tracking branch 'origin/jazz-581-add-docs' into 0-12-0 2025-03-11 17:17:26 +01:00
Guido D'Orsi
e367b6056d Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-03-11 17:14:38 +01:00
Guido D'Orsi
f3f56b9be0 docs: clarifications 2025-03-06 14:42:30 +01:00
Guido D'Orsi
4cae6bad34 Merge 2025-03-06 14:38:01 +01:00
Guido D'Orsi
17f2ef57de docs: bump the upgrade version 2025-03-06 14:37:19 +01:00
Guido D'Orsi
3a4d111a37 Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-03-06 14:33:18 +01:00
Guido D'Orsi
1e18c7f5fc Merge remote-tracking branch 'origin/0-11-0' into jazz-581-rfc-new-deep-loading-api 2025-02-28 14:58:32 +01:00
Guido D'Orsi
8c7a6b27ed docs: refine the examples and align the feature descripted with the implementation 2025-02-26 18:23:02 +01:00
Guido D'Orsi
91f96e1188 Merge branch 'jazz-581-rfc-new-deep-loading-api' into jazz-581-add-docs 2025-02-26 18:12:56 +01:00
Guido D'Orsi
28dac10723 Merge pull request #1517 from garden-co/fix/optional-fields-acl
feat(deepLoading): return undefined when an optional field is not accessible
2025-02-26 14:58:27 +01:00
Guido D'Orsi
9cb11e38dd feat(deepLoading): return undefined when an optional field is not accessible 2025-02-26 12:56:06 +01:00
Guido D'Orsi
f3e4bacb33 Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-02-25 17:46:22 +01:00
Guido D'Orsi
626d43f07b Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-02-21 18:27:14 +01:00
Benjamin S. Leveritt
1f5d073035 Update homepage/homepage/app/(docs)/docs/[framework]/[...slug]/upgrade/0-11-0.mdx
Co-authored-by: Guido D'Orsi <guido@float.com>
2025-02-13 17:34:20 +00:00
Benjamin S. Leveritt
a3b607e799 Update homepage/homepage/app/(docs)/docs/[framework]/[...slug]/upgrade/0-11-0.mdx
Co-authored-by: Guido D'Orsi <guido@float.com>
2025-02-13 17:34:06 +00:00
Benjamin S. Leveritt
8fb93502af Update homepage/homepage/app/(docs)/docs/[framework]/[...slug]/upgrade/0-11-0.mdx
Co-authored-by: Guido D'Orsi <guido@float.com>
2025-02-13 17:33:49 +00:00
Benjamin S. Leveritt
36774122e0 Updates react guide for new resolve API
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-02-13 16:08:52 +00:00
Benjamin S. Leveritt
a6923128c1 Adds upgrade guide
Signed-off-by: Benjamin S. Leveritt <benjamin@leveritt.co.uk>
2025-02-13 15:56:11 +00:00
Guido D'Orsi
706ca62feb Merge pull request #1363 from garden-co/unauthorized-deep-loading
fix: check CoValue permissions when loading/subscribing
2025-02-13 09:55:16 +01:00
Guido D'Orsi
01523dcca3 fix: check CoValue permissions when loading/subscribing 2025-02-13 09:19:19 +01:00
Guido D'Orsi
77f039b561 Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-02-13 09:18:47 +01:00
Guido D'Orsi
d661ba77be chore: improve pre-release comment output 2025-02-12 11:32:05 +01:00
Guido D'Orsi
f8fbc59b6f Merge remote-tracking branch 'origin/main' into jazz-581-rfc-new-deep-loading-api 2025-02-11 16:26:12 +01:00
Guido D'Orsi
cce0d22007 fix: update resolve property 2025-02-11 15:15:44 +01:00
Guido D'Orsi
e3ff76e9cb Merge remote-tracking branch 'origin/authv2' into jazz-581-rfc-new-deep-loading-api 2025-02-11 15:12:51 +01:00
Guido D'Orsi
4cbf71bff7 Merge pull request #1338 from garden-co/new-deep-loading-extra-props-fix
fix: disallow extra props in the resolve type
2025-02-11 14:38:43 +01:00
Guido D'Orsi
ceb060243a fix: disallow extra props in the resolve type 2025-02-10 20:04:32 +01:00
Anselm
a70bebb96a Clean up new deep-loading API 2025-01-29 14:39:16 +00:00
Anselm
b3b2507c35 Merge branch 'main' into jazz-581-rfc-new-deep-loading-api 2025-01-27 11:36:08 +00:00
Anselm
6a8fa16b49 Fix form and chat-rn-clerk examples 2024-12-16 15:56:48 +00:00
Anselm
1f08807701 Merge branch 'main' into jazz-581-rfc-new-deep-loading-api 2024-12-16 15:37:39 +00:00
Anselm
ba4a7f6170 Remove temp vite config 2024-12-16 15:35:06 +00:00
Anselm
a2854e3602 Upgrade to minor version change 2024-12-16 11:25:00 +00:00
Anselm
4ea87dc494 Add changeset 2024-12-16 10:55:51 +00:00
Anselm
d8c87c5314 Use $each instead of each 2024-12-16 10:54:25 +00:00
Anselm
46f624a12e Replace 'items' with 'each' 2024-12-13 16:28:40 +00:00
Anselm
86ce770f38 Implement clearer syntax for deep loading 2024-12-13 15:12:42 +00:00
337 changed files with 9613 additions and 4407 deletions

View File

@@ -0,0 +1,5 @@
---
"cojson": patch
---
Correctly load CoValues after they are marked as unavailable and improve timeout management

View File

@@ -1,5 +0,0 @@
---
"cojson": patch
---
Performance: optimize Group.roleOf getter and made the transactions validation incremental for CoMap and CoFeed

View File

@@ -1,5 +0,0 @@
---
"jazz-react": patch
---
Re-export createImage from jazz-browser-media-images

View File

@@ -1,5 +0,0 @@
---
"cojson": patch
---
Throw an error when the user tries to load an invalid or undefined id

View File

@@ -1,5 +0,0 @@
---
"jazz-tools": patch
---
Export CoFeedEntry type

4
.gitignore vendored
View File

@@ -24,4 +24,6 @@ test-results
.vscode/settings.json
.svelte-kit
.svelte-kit
.idea

8
.idea/.gitignore generated vendored Normal file
View 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

View 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
View 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
View 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
View 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
View 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
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -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

View File

@@ -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);

View File

@@ -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",

View File

@@ -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

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.83",
"version": "1.0.88",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",

View File

@@ -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, {});

View File

@@ -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

View File

@@ -1,6 +1,6 @@
{
"name": "chat-vue",
"version": "0.0.68",
"version": "0.0.73",
"private": true,
"type": "module",
"scripts": {

View File

@@ -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(() => {

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.165",
"version": "0.0.170",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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)

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -1,6 +1,6 @@
{
"name": "file-share-svelte",
"version": "0.0.48",
"version": "0.0.53",
"private": true,
"type": "module",
"scripts": {

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "filestream",
"private": true,
"version": "0.0.4",
"version": "0.0.9",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.1.6",
"version": "0.1.11",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;

View File

@@ -4,7 +4,7 @@ import { OrderThumbnail } from "./OrderThumbnail.tsx";
export function Orders() {
const { me } = useAccount({
root: { orders: [] },
resolve: { root: { orders: true } },
});
return (

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.62",
"version": "0.0.67",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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

View File

@@ -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",

View File

@@ -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>
);
}

View File

@@ -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;
}

View File

@@ -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

View 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

View File

@@ -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"
}
}

View File

@@ -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(

View 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"
/>
</>
);
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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}
</>
);
}

View 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}
</>
);
}

View File

@@ -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,
};
}

View File

@@ -18,3 +18,10 @@ export type RemoteCursor = Cursor & {
isRemote: true;
isDragging: boolean;
};
export type ViewBox = {
x: number;
y: number;
width: number;
height: number;
};

View File

@@ -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
});
});

View File

@@ -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,
});
});
});

View File

@@ -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);
});
});

View 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)),
}
);
}

View 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,
};
}

View 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,
};
}

View 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
);
}

View File

@@ -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;
}
}

View File

@@ -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,
},
},
},
});

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "multiauth",
"private": true,
"version": "0.0.5",
"version": "0.0.10",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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;

View File

@@ -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

View File

@@ -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",

View File

@@ -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;

View File

@@ -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,
},
},
});

View File

@@ -9,7 +9,7 @@ import { getNextTrack, getPrevTrack } from "./lib/getters";
export function useMediaPlayer() {
const { me } = useAccount({
root: {},
resolve: { root: true },
});
const playState = usePlayState();

View File

@@ -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,
},
},
});

View File

@@ -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,
},
},
},
},
});

View File

@@ -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 ?? [];

View File

@@ -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;

View File

@@ -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>) {

View File

@@ -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;

View File

@@ -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,
},
},
},
});

View File

@@ -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;

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "organization",
"private": true,
"version": "0.0.58",
"version": "0.0.63",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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(

View File

@@ -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;

View File

@@ -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 (

View File

@@ -13,7 +13,7 @@ export function OrganizationPage() {
.organizationId;
const organization = useCoState(Organization, paramOrganizationId, {
projects: [],
resolve: { projects: true },
});
if (!organization) return <p>Loading organization...</p>;

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -1,6 +1,6 @@
{
"name": "passkey-svelte",
"version": "0.0.52",
"version": "0.0.57",
"type": "module",
"private": true,
"scripts": {

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "passkey",
"private": true,
"version": "0.0.63",
"version": "0.0.68",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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

View File

@@ -1,7 +1,7 @@
{
"name": "passphrase",
"private": true,
"version": "0.0.60",
"version": "0.0.65",
"type": "module",
"scripts": {
"dev": "vite",

View File

@@ -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

View File

@@ -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",

View File

@@ -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);

View File

@@ -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 } },
}),
]);

View File

@@ -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

View File

@@ -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