Compare commits

...

295 Commits

Author SHA1 Message Date
Trisha Lim
b4e31657a0 Fix typo 2024-11-18 12:36:39 +00:00
Trisha Lim
5bb1ad4c42 Move vue up the nav 2024-11-18 12:05:45 +00:00
Trisha Lim
3ed74b6b1d Write intro in react guide 2024-11-18 12:00:34 +00:00
Trisha Lim
823a343fe1 Rewrite docs intro page 2024-11-18 11:56:29 +00:00
Guido D'Orsi
6610aea708 Merge pull request #761 from gardencmp/changeset-release/main
Version Packages
2024-11-15 20:30:51 +01:00
github-actions[bot]
f6b6c01852 Version Packages 2024-11-15 18:40:37 +00:00
Trisha Lim
63f9aa6b97 fix: active route styling on docs 2024-11-15 18:39:20 +00:00
pax-k
822eb22da6 fix(docs): fix github URL reference 2024-11-15 20:22:46 +02:00
Anselm Eickhoff
fdf3c6e93d Merge pull request #742 from gardencmp/vue-docs
Vue docs
2024-11-15 18:06:41 +00:00
Guido D'Orsi
de38161023 Merge pull request #770 from gardencmp/gudorsi-jazz-492
fix(useAcceptInvite): trigger the onAccept callback on hashchange
2024-11-15 18:50:15 +01:00
Guido D'Orsi
59cc64d697 fix(useAcceptInvite): trigger the onAccept callback on hashchange 2024-11-15 18:33:27 +01:00
pax-k
55c249834a chore(docs): cleanup 2024-11-15 19:26:16 +02:00
pax-k
dd189abd4a chore: pnpm lock 2024-11-15 19:16:32 +02:00
pax-k
df1a8e9c99 feat: vue docs 2024-11-15 19:13:19 +02:00
pax-k
259467ac3f Merge branch 'main' into vue-docs 2024-11-15 19:09:34 +02:00
Anselm Eickhoff
9a93ab2476 Merge pull request #767 from gardencmp/aeplay-jazz-447
Implement dynamic tables of content
2024-11-15 17:02:39 +00:00
Anselm
337272bbdc Merge branch 'main' into aeplay-jazz-447 2024-11-15 16:56:36 +00:00
pax-k
464ef7d9c3 chore: cleanup 2024-11-15 18:50:27 +02:00
pax-k
8727089654 Merge branch 'aeplay-jazz-447' of https://github.com/gardencmp/jazz into aeplay-jazz-447 2024-11-15 18:45:57 +02:00
pax-k
753bceddb3 fix: SSG for docs 2024-11-15 18:44:47 +02:00
Trisha Lim
8202996108 fix: TOC grows too wide if text is long 2024-11-15 16:31:21 +00:00
Trisha Lim
1385c8a66f Remove custom IDs on headings in mdx files 2024-11-15 15:48:02 +00:00
Anselm
2a72942f8e Implement dynamic ToCs 2024-11-15 15:34:35 +00:00
Anselm Eickhoff
e16836becc Merge pull request #765 from gardencmp/trishalim-jazz-480
Move examples page outside of docs
2024-11-15 15:21:06 +00:00
Trisha Lim
134a101a52 Center align book app thumbnail 2024-11-15 14:11:12 +00:00
Trisha Lim
3fc6030776 Update music player thumbnail 2024-11-15 14:08:40 +00:00
Anselm Eickhoff
8aebe61bf9 Merge pull request #762 from gardencmp/trishalim-jazz-440
Put social icons back to nav
2024-11-15 13:58:08 +00:00
Trisha Lim
8c9e807c19 Move examples page outside of docs 2024-11-15 12:07:42 +00:00
Trisha Lim
e25e4080c7 Reduce large prose font size 2024-11-15 12:04:17 +00:00
Trisha Lim
70a8353fe6 Remove roadmap link from footer 2024-11-15 11:53:54 +00:00
Trisha Lim
185b0d866a Replace Twitter with X 2024-11-15 11:53:41 +00:00
Trisha Lim
717667ac4c Fix color of garden logo 2024-11-15 11:51:24 +00:00
Trisha Lim
a0151caf02 Put social icons back to nav 2024-11-15 11:48:19 +00:00
Guido D'Orsi
c259331f57 Merge pull request #752 from gardencmp/reuse-crypto
fix: reuse the crypto instance when creating the browser context
2024-11-15 12:33:35 +01:00
Guido D'Orsi
f6bc8afa06 chore: changeset 2024-11-15 12:21:47 +01:00
Anselm Eickhoff
cee0aea5e6 Merge pull request #713 from gardencmp/trishalim-jazz-440
Redesign main nav on desktop
2024-11-15 11:20:28 +00:00
Anselm Eickhoff
c0e11f543d Merge pull request #741 from gardencmp/marina-onboarding-example
Onboarding example
2024-11-15 10:57:51 +00:00
pax
df359ab6dd Update selfish-wolves-shout.md 2024-11-14 17:01:28 +02:00
Anselm Eickhoff
d89da07d42 Merge pull request #753 from gardencmp/bensleveritt-patch-1
Fix mesh reference
2024-11-14 11:37:46 +00:00
pax
94098c1f1f Merge pull request #755 from gardencmp/JAZZ-485-docs-pin-react-native-deps
Updated react-native docs and removed babel config section
2024-11-14 12:07:25 +02:00
pax-k
e71e83a217 Merge branch 'main' into JAZZ-485-docs-pin-react-native-deps 2024-11-14 11:58:30 +02:00
pax-k
df0b21caed chore: pnpm lock 2024-11-14 11:58:06 +02:00
Anselm Eickhoff
6921e621d7 Merge pull request #749 from gardencmp/changeset-release/main
Version Packages
2024-11-14 09:41:28 +00:00
pax-k
ec9e03c266 fix: updated react-native docs and removed babel config section 2024-11-14 11:40:27 +02:00
github-actions[bot]
1b0ef401fb Version Packages 2024-11-14 09:29:38 +00:00
pax
1833983b8d Merge pull request #754 from gardencmp/jazz-tools-ts-target
Change jazz-tools TS target to ES2021
2024-11-14 11:28:21 +02:00
pax-k
149ca97c48 chore: changeset 2024-11-14 11:15:25 +02:00
pax-k
f01a7621b0 fix: change jazz-tools TS target to ES2021 2024-11-14 11:13:13 +02:00
Benjamin S. Leveritt
e6a1e2f169 Fix mesh reference 2024-11-14 06:32:10 +00:00
Guido D'Orsi
6413059709 fix: assign a unique name to the IndexedDB storage peer 2024-11-13 20:14:22 +01:00
Guido D'Orsi
3c6fd37aba fix: reuse the crypto instance when creating the browser context 2024-11-13 18:39:49 +01:00
Marina Orlova
8dc90a3554 Fixed Jazz workspace versions 2024-11-13 18:26:15 +01:00
Marina Orlova
51b1818de6 Fix group creation 2024-11-13 16:19:48 +01:00
Anselm Eickhoff
ec7c416097 Merge pull request #744 from gardencmp/better-known-state
fix: dispatch more updates to knownState
2024-11-13 14:16:50 +00:00
Guido D'Orsi
0f30eeaec6 chore: changeset 2024-11-13 15:12:18 +01:00
Guido D'Orsi
5a3cf04ba7 fix: dispatch more updates to knownState 2024-11-13 12:32:24 +01:00
pax-k
1fe74be8af fix(jazz-vue): useCoState accepts id as either a ref or a plain value 2024-11-13 12:47:05 +02:00
pax-k
376032f54c chore: cleanup 2024-11-13 11:39:23 +02:00
Anselm Eickhoff
d6e744d948 Merge pull request #738 from gardencmp/changeset-release/main 2024-11-12 22:11:31 +00:00
github-actions[bot]
23b3acb58c Version Packages 2024-11-12 22:10:32 +00:00
Anselm Eickhoff
f32d0c1fad Merge pull request #743 from gardencmp/fix/react-provider-multiple-storage
fix: fixes the react provider intialization when multiple storage options are provided
2024-11-12 22:09:16 +00:00
Guido D'Orsi
a69ed0b7cd chore: changeset 2024-11-12 22:43:19 +01:00
Guido D'Orsi
b4d7024b98 fix: fixes the react provider intialization when multiple storage options are provided 2024-11-12 22:42:27 +01:00
Marina Orlova
222a2ce2e6 Fixed test 2024-11-12 20:41:26 +01:00
Marina Orlova
34a50a9173 Adds the app into Playwright Tests job 2024-11-12 20:28:15 +01:00
Marina Orlova
72c6198ef7 Adds tests 2024-11-12 20:28:15 +01:00
Marina Orlova
e4df1048c8 pnpm-lock 2024-11-12 20:28:15 +01:00
Marina Orlova
e8abd06406 Fix schema 2024-11-12 20:28:15 +01:00
Marina Orlova
968c2bd699 Onboarding app: Make tests run 2024-11-12 20:28:15 +01:00
Marina Orlova
12b6a3b291 Add path alias 2024-11-12 20:28:15 +01:00
Marina Orlova
c9f89e9c32 Adds onboarding example 2024-11-12 20:28:15 +01:00
pax-k
d27cff5c67 feat(docs): added VueJS docs 2024-11-12 20:41:53 +02:00
pax-k
a734530cc3 chore: added changeset 2024-11-12 19:55:58 +02:00
pax-k
cc51926d14 chore: biome fix 2024-11-12 19:53:52 +02:00
Guido D'Orsi
c0395dd0a3 Merge pull request #723 from gardencmp/feature/typescript-as-dev
fix: set up typescript as dev dependency
2024-11-12 18:48:28 +01:00
Guido D'Orsi
51d7ca09d9 Merge remote-tracking branch 'origin/main' into feature/typescript-as-dev 2024-11-12 18:41:56 +01:00
pax-k
fce808cc48 fix(chat-vue): pass computed(id) to useCoState 2024-11-12 19:37:49 +02:00
pax-k
4a9217eb25 fix(jazz-vue): useCoState reactive to id 2024-11-12 19:36:46 +02:00
pax-k
69df98f4fa feat(todo-vue): implemented a Todo demo app for jazz-vue 2024-11-12 19:35:59 +02:00
Anselm Eickhoff
cf0a38d6bf Merge pull request #739 from gardencmp/fix/autologin
Move auto login check to useEffect
2024-11-12 10:56:35 +00:00
Trisha Lim
dd9b13fbaa Add changeset 2024-11-11 20:37:22 +00:00
Trisha Lim
6a982a29cb Move auto login check to useEffect 2024-11-11 20:35:41 +00:00
Anselm Eickhoff
ebc1b03158 Merge pull request #737 from gardencmp/feat/demo-auth-user-prop 2024-11-11 19:41:24 +00:00
Trisha Lim
adaf01f7fa Add bg blur effect on popover 2024-11-11 19:37:41 +00:00
Trisha Lim
c048f4eda9 Increase spacing in popover 2024-11-11 19:37:41 +00:00
Trisha Lim
b06272ff17 Layout fix 2024-11-11 19:37:40 +00:00
Trisha Lim
ac37bfab2d Close popover on click of link 2024-11-11 19:37:40 +00:00
Trisha Lim
d8e50824cb Add description and icon to mega menu items 2024-11-11 19:37:40 +00:00
Trisha Lim
29b27291a3 Links placement in desktop nav 2024-11-11 19:37:40 +00:00
Trisha Lim
efa1b60585 Add mobile nav 2024-11-11 19:37:39 +00:00
Trisha Lim
9d0b39c5cb Add popover menu to main nav using headless 2024-11-11 19:37:18 +00:00
Trisha Lim
2a02a5b212 Remove unused shadcn configs 2024-11-11 19:37:18 +00:00
Trisha Lim
c6931b82a0 Add changeset 2024-11-11 18:58:22 +00:00
Anselm Eickhoff
279e2202ba Merge pull request #710 from gardencmp/trishalim-jazz-455 2024-11-11 18:40:32 +00:00
Anselm Eickhoff
ec2324519e Merge pull request #735 from gardencmp/feat/demo-auth-user-prop 2024-11-11 18:38:46 +00:00
Anselm Eickhoff
5932f50c68 Merge pull request #699 from gardencmp/trishalim-jazz-458 2024-11-11 18:36:30 +00:00
Anselm Eickhoff
00906e5d08 Merge pull request #732 from gardencmp/fix/todo-demo-link 2024-11-11 18:35:59 +00:00
Trisha Lim
7bc5fca440 Add user prop to demo auth to skip login on demos 2024-11-11 16:35:55 +00:00
Trisha Lim
e30eb224ae Update demo links 2024-11-11 16:20:09 +00:00
Trisha Lim
983ea7cf03 Fix link to demo for pets example 2024-11-11 16:15:12 +00:00
Trisha Lim
ad2d453e33 Thumbnail fixes for mobile/tablet 2024-11-11 16:13:40 +00:00
Trisha Lim
15d711f6de Formatting fixes 2024-11-11 16:13:40 +00:00
Trisha Lim
7441a7d3d8 Formatting fixes 2024-11-11 16:13:40 +00:00
Trisha Lim
0d756209e9 Layout for mobile 2024-11-11 16:13:40 +00:00
Trisha Lim
b20c2ca173 Add images, description to examples 2024-11-11 16:13:40 +00:00
Trisha Lim
987a186db3 Add tech and features to example apps 2024-11-11 16:13:40 +00:00
Trisha Lim
f4e0b59fa1 Indicate active page on side nav 2024-11-11 16:13:31 +00:00
Trisha Lim
0d2112d8d0 Fix link to demo for todo example 2024-11-11 12:40:31 +00:00
Anselm Eickhoff
6fdab780a9 Merge pull request #730 from gardencmp/changeset-release/main
Version Packages
2024-11-10 13:17:22 +00:00
github-actions[bot]
159e2eb7f6 Version Packages 2024-11-10 13:16:08 +00:00
Anselm Eickhoff
9daa50dd7d Merge pull request #729 from gardencmp/aeplay-jazz-479
Set a CoValue as errored per peer after first error
2024-11-10 13:14:49 +00:00
Anselm
9c2aadb7d5 Add changeset 2024-11-10 13:09:57 +00:00
Anselm
7d0d81b16e Set a CoValue as errored per peer after first error 2024-11-10 13:09:36 +00:00
Guido D'Orsi
760a1c10c5 chore(sync): add a comment about syncing after sending an ack 2024-11-08 16:46:29 +00:00
Anselm Eickhoff
fac73f0e44 Merge pull request #726 from gardencmp/changeset-release/main
Version Packages
2024-11-08 16:42:11 +00:00
github-actions[bot]
80b04e78c9 Version Packages 2024-11-08 16:39:19 +00:00
Anselm Eickhoff
b23c0d75fe Merge pull request #725 from gardencmp/aeplay-jazz-477
Immediately ack new content before syncing it upstream
2024-11-08 16:38:03 +00:00
Anselm
d4319d8a0e Add changeset 2024-11-08 16:32:29 +00:00
Anselm
52cd4a9a0f Immediately ack new content before syncing it upstream 2024-11-08 16:31:52 +00:00
Guido D'Orsi
3ef3ff3db9 chore: changeset 2024-11-08 12:22:34 +00:00
Guido D'Orsi
549ec2047f fix: set up typescript as dev dependency 2024-11-08 12:21:50 +00:00
Anselm Eickhoff
ac241981f6 Merge pull request #722 from gardencmp/changeset-release/main
Version Packages
2024-11-08 12:09:49 +00:00
github-actions[bot]
b3504dce9c Version Packages 2024-11-08 12:07:47 +00:00
Anselm Eickhoff
f859d9f1c5 Merge pull request #711 from gardencmp/feature/non-optimistic-sync-state
feat: add a sync state subscription manager
2024-11-08 12:06:34 +00:00
Guido D'Orsi
d433cf473f chore: changeset 2024-11-08 12:03:25 +00:00
Guido D'Orsi
c6cd6cba20 Merge remote-tracking branch 'origin/main' into feature/non-optimistic-sync-state 2024-11-08 12:01:05 +00:00
Guido D'Orsi
9c7333d4f0 fix(createWorkerAccount): use the new sync wait API 2024-11-08 12:00:55 +00:00
Anselm Eickhoff
970f870245 Merge pull request #720 from gardencmp/aeplay-jazz-475
Less noisy logs if clients send empty WebSocket messages
2024-11-08 11:42:30 +00:00
Anselm
a2dbaf86d2 Fix unused var 2024-11-08 11:38:24 +00:00
Anselm
b6162f0fc4 Add changeset 2024-11-08 11:34:52 +00:00
Anselm
91cfa6aa8f Less noisy logs if clients send empty WebSocket messages 2024-11-08 11:34:28 +00:00
Anselm Eickhoff
cd152b83ae Merge pull request #697 from gardencmp/changeset-release/main
Version Packages
2024-11-08 10:36:27 +00:00
github-actions[bot]
bac3ddddf5 Version Packages 2024-11-08 10:30:47 +00:00
Anselm
b934fab89e Add changeset 2024-11-08 10:29:18 +00:00
Anselm
dc4ea86819 More graceful handling of potentially multiple agents 2024-11-08 10:28:43 +00:00
Guido D'Orsi
4fd6bbd41d Merge remote-tracking branch 'origin/main' into feature/non-optimistic-sync-state 2024-11-08 09:57:46 +00:00
Anselm Eickhoff
e4c1f0eefd Merge pull request #717 from gardencmp/feature/git-hooks-and-build-optimizations 2024-11-08 07:49:00 +00:00
Guido D'Orsi
e8a509e41c Merge remote-tracking branch 'origin/main' into feature/git-hooks-and-build-optimizations 2024-11-07 23:14:56 +00:00
Guido D'Orsi
53560b7ce1 Merge pull request #718 from gardencmp/feature/improve-jazz-run-tests
fix: add a timeout on the create account command
2024-11-07 23:10:03 +00:00
Guido D'Orsi
2aa2304d4d chore: removed console.log 2024-11-07 23:09:31 +00:00
Guido D'Orsi
d4c8443c4a chore: changeset 2024-11-07 23:08:18 +00:00
Guido D'Orsi
f9faf719d4 chore: improve the createWorkerAccount tests to let them fail earlier when the cloud is stuck 2024-11-07 22:36:16 +00:00
Guido D'Orsi
1a32e0c73f chore: add git hooks for formatting and linting fixes 2024-11-07 22:24:26 +00:00
Guido D'Orsi
0ea3ef31ac chore(PeerState): explain the difference between knownState and optimisticKnownState 2024-11-07 10:11:32 +00:00
Guido D'Orsi
d02613e2ec chore: add jazz-tools.json to the biome ignore 2024-11-07 09:21:42 +00:00
Guido D'Orsi
8ff036e5ff test: cover the content acknowledgment flow 2024-11-07 09:15:09 +00:00
Guido D'Orsi
d0733e2a3b chore: revert jazz-run changes 2024-11-07 00:25:31 +00:00
Guido D'Orsi
ad4f1b74f6 chore: fix type error 2024-11-07 00:20:26 +00:00
Guido D'Orsi
04d97e4a2d chore: format 2024-11-07 00:17:03 +00:00
Guido D'Orsi
3f9e749122 Merge remote-tracking branch 'origin/main' into feature/non-optimistic-sync-state 2024-11-07 00:12:56 +00:00
Guido D'Orsi
aa1dd3e10a feat: add a sync state subscription manager 2024-11-07 00:06:30 +00:00
Anselm Eickhoff
9f0deeb31c Merge pull request #701 from gardencmp/home/e2e-styling
Make background more visible in e2e section on mobile
2024-11-06 16:46:49 +00:00
Anselm Eickhoff
4f21ba9a5f Merge pull request #708 from gardencmp/docs/small-copy-changes
Docs: minor copy changes
2024-11-06 16:46:29 +00:00
Anselm Eickhoff
bdc541e35f Merge pull request #707 from gardencmp/benjamin-jazz-438
Fix coList header docs
2024-11-06 16:45:50 +00:00
Trisha Lim
7350915006 Docs: minor copy changes 2024-11-06 16:44:01 +00:00
Benjamin S. Leveritt
d678ddbe11 Fix coList header docs 2024-11-06 16:39:34 +00:00
Anselm Eickhoff
7e92f85117 Merge pull request #704 from gardencmp/benjamin-jazz-461
Nix dev environment + Node version spec
2024-11-06 16:29:39 +00:00
Anselm
ffbeb0af43 Merge branch 'main' into benjamin-jazz-461 2024-11-06 16:29:08 +00:00
Anselm Eickhoff
1eba2a66af Merge pull request #706 from gardencmp/benjamin-jazz-470
Add folders to git ignore (and Biome)
2024-11-06 16:27:42 +00:00
Benjamin S. Leveritt
854ade8c06 Add folders to git ignore (and Biome)
- .next/
- dist/
- test-results/

Resolves #705
2024-11-06 16:25:51 +00:00
Anselm Eickhoff
ccb060262f Fix vue changeset 2024-11-06 16:16:49 +00:00
Trisha Lim
981ad88fa1 Make background more visible in e2e section on mobile 2024-11-06 16:09:32 +00:00
Anselm Eickhoff
8caaca1267 Merge pull request #698 from tobiaslins/implement-multi-storage-forwarding-react
Allow to define multiple storage options
2024-11-06 16:07:49 +00:00
Anselm
2af107c676 Add changeset 2024-11-06 15:52:12 +00:00
Anselm
751a7394ff Apply formatting 2024-11-06 15:51:48 +00:00
Anselm
b1c0937bd2 Merge branch 'main' into implement-multi-storage-forwarding-react 2024-11-06 15:50:29 +00:00
Anselm Eickhoff
d5f9c57ed3 Merge pull request #694 from gardencmp/benjamin-jazz-405
Enforce coding standards
2024-11-06 15:40:49 +00:00
Benjamin S. Leveritt
f689a5871b Update readme tagline 2024-11-06 11:14:00 +00:00
Benjamin S. Leveritt
092359f37f Update readme with contribution guide link
Resolves #360
2024-11-06 10:33:38 +00:00
Benjamin S. Leveritt
0fb71c1938 Add tool versions to contribution guide 2024-11-06 10:26:14 +00:00
Benjamin S. Leveritt
60d150c8d0 Add nix flake for dev env
Resolves #684
2024-11-06 10:20:00 +00:00
Benjamin S. Leveritt
2dbfaf3ee0 Add git-blame-ignore 2024-11-06 09:43:03 +00:00
Benjamin S. Leveritt
a48f357928 Remove root format script 2024-11-06 09:36:56 +00:00
Benjamin S. Leveritt
a6e264d37b Remove monorepo-linting github action 2024-11-06 09:36:56 +00:00
Benjamin S. Leveritt
be0a09a222 Format workspace
Fix formatting on packages/jazz-run

Fix formatting on packages/jazz-react-native-media-images

Fix formatting on packages/jazz-react-native

Fix formatting on packages/jazz-react-auth-clerk

Fix formatting on packages/jazz-react

Fix formatting on packages/jazz-node

Fix formatting on packages/jazz-browser-media-images

Fix formatting on packages/jazz-browser-auth-clerk

Fix formatting on packages/jazz-browser

Fix formatting on packages/hash-slash

Fix formatting on packages/cojson-transport-ws

Fix formatting on packages/cojson-storage-sqlite

Fix formatting on packages/cojson-storage-indexeddb

Fix formatting on packages/cojson

Fix formatting on e2e/CoValues

Fix formatting in e2e/BinaryCoStream

Fix imports across workspace

Exclude homepage from formatting for now

Chore: Update pnpm lock

Fix formatting on workspace root files

Format examples

Fix formatting on examples/chat

Fix formatting on examples/chat-clerk

Fix formatting on examples/chat-rn

Fix formatting on examples/chat-rn-clerk

Fix formatting on examples/inspector

Fix formatting on examples/music-player

Fix formatting on examples/password-manager

Fix formatting on examples/pets

Fix formatting on examples/todo

Remove prettier from workspace deps

Include examples in formatting

Fix formatting in homepage/design-system

Fix formatting in homepage/gcmp

Fix formatting in homepage/homepage

Organise imports across workspace

Fix formatting for examples/chat-vue

Fix formatting for jazz-vue

Include homepage/* for formatting checks

Fix build script for jazz-vue
2024-11-06 09:36:56 +00:00
Benjamin S. Leveritt
4230cbf957 Rename github action 2024-11-06 09:32:09 +00:00
Tobias Lins
12ae46d10a Pull out logic into function and add tests 2024-11-05 21:11:37 +01:00
Tobias Lins
4e6a65de9d Allow to define multiple storage options 2024-11-05 19:51:33 +01:00
Anselm Eickhoff
4006544d11 Merge pull request #578 from gardencmp/jazz-vue
Support for Vue
2024-11-05 14:41:06 +00:00
pax-k
67c311b458 Merge branch 'main' into jazz-vue 2024-11-05 14:06:56 +02:00
pax-k
e796a6f2ba fix(vue): fixed logout and context re-creation 2024-11-05 14:06:10 +02:00
Benjamin S. Leveritt
f6cecfaaf9 Disable import sorting and linting for now 2024-11-05 11:47:44 +00:00
Benjamin S. Leveritt
572007139b Add github action for enforcing biome
Excluding examples for now
2024-11-05 11:26:06 +00:00
Benjamin S. Leveritt
47f3b72977 Fixed turbo commands for Biome 2024-11-05 11:08:51 +00:00
Anselm Eickhoff
4d9c5331d8 Merge pull request #671 from gardencmp/home/features-section
Rearrange feature sections
2024-11-05 09:58:16 +00:00
Anselm Eickhoff
d5482a32db Fix permission examples 2024-11-05 09:47:45 +00:00
Anselm Eickhoff
61b346a948 Merge pull request #691 from gardencmp/changeset-release/main
Version Packages
2024-11-05 09:38:34 +00:00
github-actions[bot]
c2dfe6a0dd Version Packages 2024-11-05 09:35:46 +00:00
Anselm Eickhoff
81e8910519 Merge pull request #676 from gardencmp/benjamin-jazz-452
Store clerk authentication locally
2024-11-05 09:34:29 +00:00
Anselm Eickhoff
577d5c2066 More specific testimonial credit 2024-11-05 09:33:18 +00:00
Benjamin S. Leveritt
cce679b031 Split changesets 2024-11-05 09:32:29 +00:00
Anselm Eickhoff
c2dbf45f26 Merge pull request #689 from gardencmp/changeset-release/main 2024-11-05 09:13:32 +00:00
Benjamin S. Leveritt
d9036bc47b Add editorconfig 2024-11-05 09:11:34 +00:00
github-actions[bot]
04d3a8c677 Version Packages 2024-11-05 09:05:45 +00:00
Anselm Eickhoff
91019f3f85 Merge pull request #687 from gardencmp/optimize-account-load-2
perf: optimize _loadedAs in CoList and CoValueBase
2024-11-05 09:04:20 +00:00
Benjamin S. Leveritt
4f61da553e Add root biome config 2024-11-05 09:02:35 +00:00
Benjamin S. Leveritt
ae11cbfded Add Biome dep 2024-11-05 15:19:22 +00:00
Benjamin S. Leveritt
06278c3d97 Update saveCredentials mock 2024-11-05 06:53:32 +00:00
Guido D'Orsi
36273b3114 chore: changeset 2024-11-04 23:09:34 +01:00
Guido D'Orsi
51a0a9f23f perf: optimize _loadedAs in CoList and CoValueBase 2024-11-04 23:07:51 +01:00
Anselm Eickhoff
fc24a65264 Merge pull request #685 from gardencmp/changeset-release/main
Version Packages
2024-11-04 20:10:10 +00:00
github-actions[bot]
fa0b9003dc Version Packages 2024-11-04 20:05:27 +00:00
Anselm Eickhoff
8a0da655e8 Merge pull request #686 from gardencmp/optimize-account-loadas
perf: cache the account refs resolution
2024-11-04 20:04:15 +00:00
Guido D'Orsi
fff11daca7 test: add tests for cache 2024-11-04 20:41:36 +01:00
pax-k
ef83947eb5 Merge branch 'main' into jazz-vue 2024-11-04 21:30:40 +02:00
pax-k
750cfa1b82 chore: cleanup 2024-11-04 21:29:43 +02:00
Guido D'Orsi
fd011d76f4 chore: changeset 2024-11-04 20:21:32 +01:00
Guido D'Orsi
0681a8301e perf: cache the account refs resolution 2024-11-04 20:09:34 +01:00
Benjamin S. Leveritt
221c58f1f7 Add changeset 2024-11-04 18:51:03 +00:00
pax-k
244e5ee582 chore: changeset 2024-11-04 20:48:44 +02:00
Benjamin S. Leveritt
ebca75bf70 Add check for existance and await 2024-11-04 18:43:01 +00:00
Trisha Lim
ea5bd59528 Make e2e icon smaller 2024-11-04 18:25:07 +00:00
Trisha Lim
5977fa3244 Copy changes 2024-11-04 17:56:21 +00:00
Trisha Lim
81179a4c34 Change e2e icon 2024-11-04 17:46:13 +00:00
Benjamin S. Leveritt
b5e516f974 Add tests
Particularly covering log out and checking for storing creds
2024-11-04 17:37:47 +00:00
Benjamin S. Leveritt
8fc5a49ca8 Refactor setItem into fn 2024-11-04 17:37:40 +00:00
Benjamin S. Leveritt
00054aa9a5 Export Credential type from jazz-tools 2024-11-04 17:11:05 +00:00
Benjamin S. Leveritt
6f3c98f704 Make saveCredentials optional 2024-11-04 17:00:28 +00:00
Anselm Eickhoff
8823957c6e Merge pull request #677 from gardencmp/feature/websocker-unique-name
feat(browser): refactor the WebSocket reconnection to assign the peer as id
2024-11-04 16:58:17 +00:00
Benjamin S. Leveritt
47ec0cd8fe Rename type 2024-11-04 16:53:42 +00:00
Benjamin S. Leveritt
685031c39c Remove check for user before passing to BrowserClerkAuth 2024-11-04 16:53:22 +00:00
Benjamin S. Leveritt
e4fd89dbbb Add saveCredentials to existing Clerk accounts authentications 2024-11-04 16:32:37 +00:00
pax-k
4968e194dc chore: sherif deps 2024-11-04 16:54:36 +02:00
pax-k
36e53ee462 chore: pnpm lock 2024-11-04 16:49:15 +02:00
pax-k
7e2e89be6d fix(vue): toRaw 2024-11-04 16:48:45 +02:00
pax-k
232801efdc fix(vue): Progressive image + DemoAuth UI 2024-11-04 16:47:21 +02:00
Guido D'Orsi
e0dd0065fb chore: changeset 2024-11-04 15:06:33 +01:00
Guido D'Orsi
98d7d402eb feat(browser): refactor the WebSocket reconnection to assign the peer as id 2024-11-04 14:28:11 +01:00
Trisha Lim
ba5dfd34f2 Dark mode for server workers illustration 2024-11-04 11:45:36 +00:00
Trisha Lim
2701cd7e4c 4-col layout for local-first section 2024-11-04 11:33:36 +00:00
Trisha Lim
5429590797 Mobile view for e2e 2024-11-04 11:04:06 +00:00
Trisha Lim
c1dfda1321 Dark mode styling 2024-11-04 10:51:15 +00:00
Benjamin S. Leveritt
57deec451a Check for local credentials before Clerk checks 2024-11-04 10:47:42 +00:00
Trisha Lim
a7f38c946d Fix build 2024-11-04 10:42:38 +00:00
Trisha Lim
8a4204e262 Clean up features section 2024-11-04 10:26:19 +00:00
Trisha Lim
77090f4368 Remove "coming soon" badges under coming soon section 2024-11-04 10:13:29 +00:00
Trisha Lim
d655bb5638 Move home page sections to separate components 2024-11-04 10:09:24 +00:00
Benjamin S. Leveritt
bc8ea23e6d Store clerk authentication locally
Introduce LocallyStoredCredentials for storing and validating local storage values
2024-11-04 09:39:46 +00:00
Trisha Lim
0a30b719f1 Move encryption letters around 2024-11-01 20:17:58 +00:00
Trisha Lim
82c7b5ff85 Delete datastructure section, move rich text to "coming soon" section 2024-11-01 20:15:38 +00:00
Trisha Lim
faab6c02df Delete unused mdx files 2024-11-01 20:12:40 +00:00
Trisha Lim
de7631c5b3 Update heading 2024-11-01 20:00:37 +00:00
Trisha Lim
3cdf823f74 Add testimonial from SA1 2024-11-01 18:43:43 +00:00
Trisha Lim
ec91b6b3c2 Add "offline-first" feature and redesign layout for local-first section 2024-11-01 18:43:34 +00:00
Trisha Lim
a725119e0f Refactor random chars 2024-11-01 17:12:22 +00:00
Trisha Lim
520a8e736f Use random letters for illustration in e2e section 2024-11-01 16:54:04 +00:00
Trisha Lim
a1a0b203f0 Fix duplicate h3 2024-11-01 15:33:36 +00:00
Trisha Lim
7059196ca2 Add illustration for server worker feature 2024-11-01 15:21:17 +00:00
Anselm
d2ad2db930 Fix anselm's bluesky 2024-11-01 15:17:55 +00:00
Trisha Lim
b53d40dad8 Make e2ee section HUGE 2024-11-01 15:12:09 +00:00
Trisha Lim
84ca2f7af1 Explain e2ee 2024-11-01 15:04:15 +00:00
Trisha Lim
61655d3b53 Replace state management with server workers 2024-11-01 14:51:42 +00:00
Trisha Lim
b1263b85e9 Make e2e more prominent 2024-11-01 14:00:25 +00:00
Trisha Lim
49a7fa2d9a Illustration for auth feature 2024-11-01 13:38:11 +00:00
Trisha Lim
f1b0abc377 Illustration for "image loading" feature 2024-11-01 13:20:18 +00:00
Trisha Lim
a62f0bf852 Illustration for "file uploads" feature 2024-11-01 13:05:38 +00:00
Trisha Lim
17165523f4 Illustration placeholders 2024-11-01 12:51:16 +00:00
Trisha Lim
5395f0bb69 Mobile layout for features section 2024-11-01 11:06:48 +00:00
Trisha Lim
3bb5421a37 Fix build error 2024-11-01 11:02:02 +00:00
Trisha Lim
dd48e52a75 Add margin between heading and content 2024-11-01 10:57:50 +00:00
Trisha Lim
e18537eb67 Styling for Jazz Cloud section 2024-11-01 10:44:25 +00:00
pax-k
82d81975d3 Merge branch 'main' into jazz-vue 2024-11-01 12:27:31 +02:00
Anselm Eickhoff
44497fd058 Merge pull request #668 from gardencmp/changeset-release/main
Version Packages
2024-11-01 10:20:07 +00:00
Trisha Lim
ff2b5ce0a0 Styling for collaboration section 2024-11-01 10:11:52 +00:00
github-actions[bot]
a18c187818 Version Packages 2024-11-01 10:04:27 +00:00
Anselm Eickhoff
f49949cc25 Merge pull request #653 from gardencmp/feature/react-provider-dev-mode
fix: ensure that the react provider doesn't run twice on dev
2024-11-01 10:03:09 +00:00
Trisha Lim
cbc723f129 Add kicker to collaboration section 2024-11-01 09:56:24 +00:00
Anselm
3cc6aee7e6 Add changeset 2024-11-01 09:54:11 +00:00
Trisha Lim
624442b1c1 Move e2e to collaboration section 2024-11-01 09:52:24 +00:00
Trisha Lim
74e672b38b Remove old sections 2024-11-01 09:50:55 +00:00
Trisha Lim
a0d169fea8 Divide features into 3 sections: local-first, collaboration, everything else 2024-11-01 09:50:40 +00:00
Anselm Eickhoff
c80763100e Merge pull request #651 from gardencmp/gudorsi-jazz-248-storage-peer
feat: introduce the storage peer role
2024-11-01 09:50:14 +00:00
Anselm
6ed75ebb35 Add changeset 2024-11-01 09:49:30 +00:00
Anselm Eickhoff
30d7734124 Merge pull request #663 from gardencmp/trishalim-jazz-443
Close mobile nav after clicking a link
2024-11-01 09:41:10 +00:00
Anselm Eickhoff
bca8b44189 Merge pull request #664 from gardencmp/trishalim-jazz-445
Docs: create separate pages for nextjs and react native
2024-11-01 09:31:11 +00:00
Anselm Eickhoff
36a069c90f Merge pull request #666 from gardencmp/feature/jazz-run-integration-test
chore(jazz-run): extract commands business logic and add tests
2024-11-01 09:29:12 +00:00
Guido D'Orsi
757b37e8ed feat: introduce the storage peer role 2024-10-31 23:18:47 +01:00
Guido D'Orsi
46b1163058 chore(jazz-run): split commands and core logic and add tests 2024-10-31 23:09:42 +01:00
Trisha Lim
8c261b0409 Create separate pages for nextjs and react native 2024-10-31 19:36:19 +00:00
Trisha Lim
fdacde57dd Lint fix 2024-10-31 19:10:38 +00:00
Trisha Lim
817dd7dde1 Close mobile nav after clicking a link 2024-10-31 19:07:11 +00:00
Anselm Eickhoff
6279dd1467 Merge pull request #662 from gardencmp/trishalim-jazz-446
Add yellow dot as legend for docs that are WIP
2024-10-31 17:30:18 +00:00
Trisha Lim
abd4b94392 Add legend in side nav to indicate WIP docs 2024-10-31 17:24:03 +00:00
Trisha Lim
68c6ee77c0 Remove % progress in docs, add '/coming-soon' page 2024-10-31 17:18:33 +00:00
Anselm Eickhoff
d2b2812428 Merge pull request #658 from gardencmp/fix/sticky-nav
Fix nav is not sticking to top
2024-10-31 16:29:52 +00:00
Anselm Eickhoff
fe214cc3c2 Merge pull request #657 from gardencmp/fix/h4-style
Fix styling for h4 in prose
2024-10-31 16:29:39 +00:00
Anselm Eickhoff
2cca9506ad Merge pull request #656 from gardencmp/react-native-docs
React native docs
2024-10-31 16:29:06 +00:00
Trisha Lim
17e69aff8f Add space between main content and footer 2024-10-31 14:22:33 +00:00
Trisha Lim
c45331e645 Fix nav is not sticking to top 2024-10-31 14:21:13 +00:00
Trisha Lim
4337001526 Fix styling for h4 in prose 2024-10-31 13:52:23 +00:00
Guido D'Orsi
911add3dea fix: ensure that the react provider doesn't run twice on dev 2024-10-31 11:19:48 +01:00
pax-k
d998fdf6f6 fix: lint 2024-10-16 15:33:23 +03:00
pax-k
6cdedd63d9 fix(vue): reactivity 2024-10-16 15:30:58 +03:00
pax-k
73630b4d94 Merge branch 'main' into jazz-vue 2024-10-16 13:22:08 +03:00
pax-k
cb8dfcadbc feat: jazz-vue and chat-vue implementation (wip) 2024-10-16 13:21:36 +03:00
740 changed files with 52635 additions and 46827 deletions

View File

@@ -1,30 +1,30 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [
[
"cojson",
"jazz-tools",
"jazz-browser",
"jazz-browser-media-images",
"jazz-browser-auth-clerk",
"jazz-react-auth-clerk",
"jazz-react",
"jazz-react-native",
"jazz-nodejs",
"jazz-run",
"cojson-transport-ws",
"cojson-storage-indexeddb",
"cojson-storage-sqlite"
]
],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": [],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
"$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [
[
"cojson",
"jazz-tools",
"jazz-browser",
"jazz-browser-media-images",
"jazz-browser-auth-clerk",
"jazz-react-auth-clerk",
"jazz-react",
"jazz-react-native",
"jazz-nodejs",
"jazz-run",
"cojson-transport-ws",
"cojson-storage-indexeddb",
"cojson-storage-sqlite"
]
],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": [],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"onlyUpdatePeerDependentsWhenOutOfRange": true
}
}

11
.editorconfig Normal file
View File

@@ -0,0 +1,11 @@
# EditorConfig is awesome: https://editorconfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

2
.git-blame-ignore-revs Normal file
View File

@@ -0,0 +1,2 @@
# Formatted workspace with biome
be0a09a22295cd5d2ee3ef323e2d999da8a14110

View File

@@ -17,6 +17,7 @@ jobs:
"password-manager",
"pets",
"todo",
"onboarding",
]
steps:
@@ -55,4 +56,4 @@ jobs:
run: |
pnpm install
pnpm turbo build;
working-directory: ./examples/${{ matrix.example }}
working-directory: ./examples/${{ matrix.example }}

18
.github/workflows/code-quality.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: Code quality
on:
push:
pull_request:
jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Biome
uses: biomejs/setup-biome@v2
with:
version: latest
- name: Run Biome
run: biome ci .

View File

@@ -9,7 +9,7 @@ on:
jobs:
test:
runs-on: ubuntu-latest
continue-on-error: true
timeout-minutes: 5
steps:
- uses: actions/checkout@v3

View File

@@ -1,21 +0,0 @@
name: Monorepo linting
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
monorepo-linting:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.node-version'
- name: Run sherif
run: npx sherif@1.0.0

View File

@@ -13,7 +13,7 @@ jobs:
continue-on-error: true
strategy:
matrix:
project: ["e2e/BinaryCoStream", "e2e/CoValues", "examples/chat", "examples/music-player", "examples/pets"]
project: ["e2e/BinaryCoStream", "e2e/CoValues", "examples/chat", "examples/music-player", "examples/pets", "examples/onboarding"]
steps:
- uses: actions/checkout@v3

13
.gitignore vendored
View File

@@ -4,4 +4,15 @@ lerna-debug.log
docsTmp
.DS_Store
.turbo
coverage
coverage
# Next.js
**/.next
# Vite output
**/dist
# Playwright
test-results
.husky

View File

@@ -1,9 +0,0 @@
/** @type {import("prettier").Config} */
const config = {
trailingComma: "all",
tabWidth: 4,
semi: true,
singleQuote: false,
};
export default config;

3
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,3 @@
{
"editor.defaultFormatter": "biomejs.biome"
}

View File

@@ -36,6 +36,8 @@ We welcome all ideas! If you have suggestions, feel free to open an issue marked
### 5. Local Setup
You'll need Node.js 20.x or 22.x installed (we're working on support for 23.x), and pnpm 9.x installed. If you're using nix, run `nix develop` to get a shell with the correct versions of everything installed.
1. **Clone the repository**:
```bash
git clone https://github.com/gardencmp/jazz.git
@@ -53,7 +55,13 @@ We welcome all ideas! If you have suggestions, feel free to open an issue marked
### 6. Testing
Please write tests for any new features or bug fixes. We use Vitest for unit tests. Make sure all tests pass before submitting a pull request.
Please write tests for any new features or bug fixes. We use Vitest for unit tests, and Playwright for e2e tests. Make sure all tests pass before submitting a pull request.
```bash
pnpm test
```
NB: You'll need to run `pnpm exec playwright install` to install the Playwright browsers before first run.
### 7. Communication

View File

@@ -1,12 +1,20 @@
# Jazz - Instant sync
# Jazz - Build local-first apps
**Jazz is an open-source toolkit for building apps with *distributed state.***
## Getting started
We recommend reading the [homepage](https://jazz.tools) and [docs](https://jazz.tools/docs) to get an overview of what Jazz is and how it works.
If you're interested in contributing, please read [CONTRIBUTING.md](./CONTRIBUTING.md).
For community and support, please join our [Discord](https://discord.gg/utDMjHYg42).
---
- Homepage: [jazz.tools](https://jazz.tools)
- Docs: [jazz.tools/docs](https://jazz.tools/docs)
- Community & support: [Discord](https://discord.gg/utDMjHYg42)
- Updates: [Twitter](https://twitter.com/jazz_tools) & [Email](https://gcmp.io/news)
- Updates: [X](https://x.com/jazz_tools) & [Email](https://gcmp.io/news)
Copyright 2024 — Garden Computing, Inc.
Copyright 2024 — Garden Computing, Inc.

25
biome.json Normal file
View File

@@ -0,0 +1,25 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": false,
"ignore": ["jazz-tools.json", "**/ios/**", "**/android/**"]
},
"formatter": {
"enabled": true,
"indentStyle": "space"
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": false,
"rules": {
"recommended": true
}
}
}

View File

@@ -1,64 +1,162 @@
# @jazz-e2e/binarycostream
## 0.0.100
### Patch Changes
- Updated dependencies [59cc64d]
- jazz-react@0.8.22
## 0.0.99
### Patch Changes
- Updated dependencies [0f30eea]
- Updated dependencies [149ca97]
- cojson@0.8.21
- jazz-tools@0.8.21
- jazz-react@0.8.21
## 0.0.98
### Patch Changes
- Updated dependencies [dd9b13f]
- Updated dependencies [a69ed0b]
- Updated dependencies [3ef3ff3]
- Updated dependencies [c6931b8]
- jazz-react@0.8.20
## 0.0.97
### Patch Changes
- Updated dependencies [9c2aadb]
- cojson@0.8.19
- jazz-react@0.8.19
- jazz-tools@0.8.19
## 0.0.96
### Patch Changes
- Updated dependencies [d4319d8]
- cojson@0.8.18
- jazz-react@0.8.18
- jazz-tools@0.8.18
## 0.0.95
### Patch Changes
- Updated dependencies [d433cf4]
- cojson@0.8.17
- jazz-react@0.8.17
- jazz-tools@0.8.17
## 0.0.94
### Patch Changes
- Updated dependencies [2af107c]
- Updated dependencies [b934fab]
- jazz-react@0.8.16
- cojson@0.8.16
- jazz-tools@0.8.16
## 0.0.93
### Patch Changes
- Updated dependencies [cce679b]
- jazz-tools@0.8.15
- jazz-react@0.8.15
## 0.0.92
### Patch Changes
- Updated dependencies [36273b3]
- jazz-tools@0.8.14
- jazz-react@0.8.14
## 0.0.91
### Patch Changes
- Updated dependencies [fd011d7]
- jazz-tools@0.8.13
- jazz-react@0.8.13
## 0.0.90
### Patch Changes
- Updated dependencies [6ed75eb]
- Updated dependencies [3cc6aee]
- cojson@0.8.12
- jazz-react@0.8.12
- jazz-tools@0.8.12
## 0.0.89
### Patch Changes
- Updated dependencies [1ed4ab5]
- cojson@0.8.11
- jazz-react@0.8.11
- jazz-tools@0.8.11
- Updated dependencies [1ed4ab5]
- cojson@0.8.11
- jazz-react@0.8.11
- jazz-tools@0.8.11
## 0.0.88
### Patch Changes
- jazz-react@0.8.7
- jazz-react@0.8.7
## 0.0.87
### Patch Changes
- jazz-react@0.8.6
- jazz-react@0.8.6
## 0.0.86
### Patch Changes
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- jazz-tools@0.8.5
- cojson@0.8.5
- jazz-react@0.8.5
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- jazz-tools@0.8.5
- cojson@0.8.5
- jazz-react@0.8.5
## 0.0.85
### Patch Changes
- Updated dependencies
- hash-slash@0.2.1
- Updated dependencies
- hash-slash@0.2.1
## 0.0.84
### Patch Changes
- Updated dependencies
- cojson@0.8.3
- jazz-react@0.8.3
- jazz-tools@0.8.3
- Updated dependencies
- cojson@0.8.3
- jazz-react@0.8.3
- jazz-tools@0.8.3
## 0.0.83
### Patch Changes
- Updated dependencies [a075f90]
- jazz-tools@0.8.2
- jazz-react@0.8.2
- Updated dependencies [a075f90]
- jazz-tools@0.8.2
- jazz-react@0.8.2
## 0.0.82
### Patch Changes
- Updated dependencies
- jazz-tools@0.8.1
- jazz-react@0.8.1
- Updated dependencies
- jazz-tools@0.8.1
- jazz-react@0.8.1

View File

@@ -1,24 +1,23 @@
{
"name": "@jazz-e2e/binarycostream",
"private": true,
"version": "0.0.89",
"version": "0.0.100",
"type": "module",
"scripts": {
"dev": "vite",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"build": "tsc && vite build",
"preview": "vite preview",
"test": "playwright test",
"test:ui": "playwright test --ui"
},
"lint-staged": {
"*.{js,jsx,mdx,json}": "prettier --write"
},
"dependencies": {
"cojson": "workspace:0.8.11",
"cojson": "workspace:0.8.21",
"hash-slash": "workspace:0.2.1",
"is-ci": "^3.0.1",
"jazz-react": "workspace:0.8.11",
"jazz-tools": "workspace:0.8.11",
"jazz-react": "workspace:0.8.22",
"jazz-tools": "workspace:0.8.21",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},

View File

@@ -12,38 +12,42 @@ import isCI from "is-ci";
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: isCI,
/* Retry on CI only */
retries: isCI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: isCI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: isCI,
/* Retry on CI only */
retries: isCI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: isCI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: isCI ? "http://localhost:4173/" : "http://localhost:5173",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:5173/",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
permissions: ["clipboard-read", "clipboard-write"],
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
/* Run your local dev server before starting the tests */
webServer: isCI ? {
command: "pnpm preview",
url: "http://localhost:4173/",
} : undefined,
/* Run your local dev server before starting the tests */
webServer: [
{
command: "pnpm preview --port 5173",
url: "http://localhost:5173/",
reuseExistingServer: !isCI,
},
],
});

View File

@@ -1,13 +1,17 @@
import { Account, BinaryCoStream, ID } from "jazz-tools";
import { useEffect } from "react";
import { useAccount, useCoState } from "./jazz";
import { UploadedFile } from "./schema";
import { waitForCoValue } from "./lib/waitForCoValue";
import { UploadedFile } from "./schema";
async function getUploadedFile(
me: Account,
uploadedFileId: ID<UploadedFile>) {
const uploadedFile = await waitForCoValue(UploadedFile, uploadedFileId, me, Boolean, {})
async function getUploadedFile(me: Account, uploadedFileId: ID<UploadedFile>) {
const uploadedFile = await waitForCoValue(
UploadedFile,
uploadedFileId,
me,
Boolean,
{},
);
uploadedFile.coMapDownloaded = true;
@@ -21,7 +25,7 @@ export function DownloaderPeer(props: { testCoMapId: ID<UploadedFile> }) {
const testCoMap = useCoState(UploadedFile, props.testCoMapId, {});
useEffect(() => {
getUploadedFile(account.me, props.testCoMapId).then(value => {
getUploadedFile(account.me, props.testCoMapId).then((value) => {
value.syncCompleted = true;
});
}, []);

View File

@@ -1,13 +1,13 @@
import { ID } from "jazz-tools";
import { useEffect, useState } from "react";
import { useAccount, useCoState } from "./jazz";
import { BytesRadioGroup } from "./lib/BytesRadioGroup";
import { createCredentiallessIframe } from "./lib/createCredentiallessIframe";
import { generateTestFile } from "./lib/generateTestFile";
import { getDownloaderPeerUrl } from "./lib/getDownloaderPeerUrl";
import { UploadedFile } from "./schema";
import { waitForCoValue } from "./lib/waitForCoValue";
import { getDefaultFileSize, getIsAutoUpload } from "./lib/searchParams";
import { BytesRadioGroup } from "./lib/BytesRadioGroup";
import { waitForCoValue } from "./lib/waitForCoValue";
import { UploadedFile } from "./schema";
export function UploaderPeer() {
const account = useAccount();
@@ -41,7 +41,7 @@ export function UploaderPeer() {
file.id,
account.me,
(value) => value.syncCompleted,
{}
{},
);
iframe.remove();
@@ -75,12 +75,8 @@ export function UploaderPeer() {
</div>
)}
{testFile?.coMapDownloaded && (
<div data-testid="co-map-downloaded">
CoMap synced!
</div>
<div data-testid="co-map-downloaded">CoMap synced!</div>
)}
</>
);
}

View File

@@ -2,8 +2,8 @@ import React from "react";
import ReactDOM from "react-dom/client";
import { DownloaderPeer } from "./DownloaderPeer";
import { UploaderPeer } from "./UploaderPeer";
import { getValueId } from "./lib/searchParams";
import { AuthAndJazz } from "./jazz";
import { getValueId } from "./lib/searchParams";
function Main() {
const valueId = getValueId();
@@ -17,8 +17,8 @@ function Main() {
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<AuthAndJazz>
<Main />
</AuthAndJazz>
<AuthAndJazz>
<Main />
</AuthAndJazz>
</React.StrictMode>,
);

View File

@@ -1,6 +1,6 @@
import { createJazzReactApp, useDemoAuth } from "jazz-react";
import { getValueId } from "./lib/searchParams";
import { useEffect, useRef } from "react";
import { getValueId } from "./lib/searchParams";
const key = getValueId()
? `downloader-e2e@jazz.tools`
@@ -19,17 +19,20 @@ export function AuthAndJazz({ children }: { children: React.ReactNode }) {
useEffect(() => {
if (state.state === "ready" && !signedUp.current) {
state.signUp('Mister X');
state.signUp("Mister X");
signedUp.current = true;
}
}, [state.state])
}, [state.state]);
return (
<Jazz.Provider auth={auth} peer={
localSync
? `ws://localhost:4200?key=${key}`
: `wss://cloud.jazz.tools/?key=${key}`
}>
<Jazz.Provider
auth={auth}
peer={
localSync
? `ws://localhost:4200?key=${key}`
: `wss://cloud.jazz.tools/?key=${key}`
}
>
{children}
</Jazz.Provider>
);

View File

@@ -4,46 +4,54 @@ export function BytesRadioGroup(props: {
}) {
return (
<p>
<BytesRadioInput
label="1KB"
value={1e3}
selectedValue={props.selectedValue}
onChange={props.onChange} />
<BytesRadioInput
label="10KB"
value={1e4}
selectedValue={props.selectedValue}
onChange={props.onChange} />
<BytesRadioInput
label="1KB"
value={1e3}
selectedValue={props.selectedValue}
onChange={props.onChange}
/>
<BytesRadioInput
label="10KB"
value={1e4}
selectedValue={props.selectedValue}
onChange={props.onChange}
/>
<BytesRadioInput
label="100KB"
value={1e5}
selectedValue={props.selectedValue}
onChange={props.onChange} />
onChange={props.onChange}
/>
<BytesRadioInput
label="150KB"
value={1e5 + 5e4}
selectedValue={props.selectedValue}
onChange={props.onChange} />
onChange={props.onChange}
/>
<BytesRadioInput
label="200KB"
value={2e6}
selectedValue={props.selectedValue}
onChange={props.onChange} />
onChange={props.onChange}
/>
<BytesRadioInput
label="500KB"
value={5e6}
selectedValue={props.selectedValue}
onChange={props.onChange} />
onChange={props.onChange}
/>
<BytesRadioInput
label="1MB"
value={1e6}
selectedValue={props.selectedValue}
onChange={props.onChange} />
onChange={props.onChange}
/>
<BytesRadioInput
label="10MB"
value={1e7}
selectedValue={props.selectedValue}
onChange={props.onChange} />
onChange={props.onChange}
/>
</p>
);
}
@@ -60,7 +68,8 @@ function BytesRadioInput(props: {
name="bytes"
value={props.value}
checked={props.value === props.selectedValue}
onChange={() => props.onChange(props.value)} />
onChange={() => props.onChange(props.value)}
/>
{props.label}
</label>
);

View File

@@ -1,4 +1,4 @@
import { Account, Group, BinaryCoStream } from "jazz-tools";
import { Account, BinaryCoStream, Group } from "jazz-tools";
import { UploadedFile } from "../schema";
export async function generateTestFile(me: Account, bytes: number) {
@@ -9,13 +9,13 @@ export async function generateTestFile(me: Account, bytes: number) {
const testFile = UploadedFile.create(
{
file: await BinaryCoStream.createFromBlob(
new Blob(['1'.repeat(bytes)], { type: 'image/png' }),
ownership
new Blob(["1".repeat(bytes)], { type: "image/png" }),
ownership,
),
syncCompleted: false,
coMapDownloaded: false,
},
ownership
ownership,
);
const url = new URL(window.location.href);
@@ -24,4 +24,3 @@ export async function generateTestFile(me: Account, bytes: number) {
return testFile;
}

View File

@@ -1,6 +1,5 @@
import { UploadedFile } from "src/schema";
export function getDownloaderPeerUrl(value: UploadedFile) {
const url = new URL(window.location.href);
url.searchParams.set("valueId", value.id);

View File

@@ -2,13 +2,19 @@ import { ID } from "jazz-tools";
import { UploadedFile } from "../schema";
export function getValueId() {
return new URLSearchParams(location.search).get("valueId") as ID<UploadedFile> | undefined ?? undefined;
return (
(new URLSearchParams(location.search).get("valueId") as
| ID<UploadedFile>
| undefined) ?? undefined
);
}
export function getIsAutoUpload() {
return new URLSearchParams(location.search).has("auto");
return new URLSearchParams(location.search).has("auto");
}
export function getDefaultFileSize() {
return parseInt(new URLSearchParams(location.search).get("fileSize") ?? 1e3.toString());
}
return parseInt(
new URLSearchParams(location.search).get("fileSize") ?? (1e3).toString(),
);
}

View File

@@ -12,7 +12,7 @@ export function waitForCoValue<T extends CoValue>(
valueId: ID<T>,
account: Account,
predicate: (value: T) => boolean,
depth: DepthsIn<T>
depth: DepthsIn<T>,
) {
return new Promise<T>((resolve) => {
function subscribe() {
@@ -30,7 +30,7 @@ export function waitForCoValue<T extends CoValue>(
() => {
unsubscribe();
setTimeout(subscribe, 100);
}
},
);
}

View File

@@ -1,4 +1,4 @@
import { BinaryCoStream, co, CoMap } from "jazz-tools";
import { BinaryCoStream, CoMap, co } from "jazz-tools";
export class UploadedFile extends CoMap {
file = co.ref(BinaryCoStream);

View File

@@ -1,5 +1,5 @@
import { test, expect } from "@playwright/test";
import { setTimeout } from "node:timers/promises";
import { expect, test } from "@playwright/test";
test.describe("BinaryCoStream - Sync", () => {
test("should sync a file between the two peers", async ({ page }) => {

View File

@@ -21,5 +21,5 @@
"noFallthroughCasesInSwitch": true,
"baseUrl": "."
},
"include": ["src"],
"include": ["src"]
}

View File

@@ -1,10 +1,10 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import react from "@vitejs/plugin-react-swc";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
build: {
minify: false
}
})
minify: false,
},
});

View File

@@ -1,56 +1,154 @@
# @jazz-e2e/covalues
## 0.0.99
### Patch Changes
- Updated dependencies [59cc64d]
- jazz-react@0.8.22
## 0.0.98
### Patch Changes
- Updated dependencies [0f30eea]
- Updated dependencies [149ca97]
- cojson@0.8.21
- jazz-tools@0.8.21
- jazz-react@0.8.21
## 0.0.97
### Patch Changes
- Updated dependencies [dd9b13f]
- Updated dependencies [a69ed0b]
- Updated dependencies [3ef3ff3]
- Updated dependencies [c6931b8]
- jazz-react@0.8.20
## 0.0.96
### Patch Changes
- Updated dependencies [9c2aadb]
- cojson@0.8.19
- jazz-react@0.8.19
- jazz-tools@0.8.19
## 0.0.95
### Patch Changes
- Updated dependencies [d4319d8]
- cojson@0.8.18
- jazz-react@0.8.18
- jazz-tools@0.8.18
## 0.0.94
### Patch Changes
- Updated dependencies [d433cf4]
- cojson@0.8.17
- jazz-react@0.8.17
- jazz-tools@0.8.17
## 0.0.93
### Patch Changes
- Updated dependencies [2af107c]
- Updated dependencies [b934fab]
- jazz-react@0.8.16
- cojson@0.8.16
- jazz-tools@0.8.16
## 0.0.92
### Patch Changes
- Updated dependencies [cce679b]
- jazz-tools@0.8.15
- jazz-react@0.8.15
## 0.0.91
### Patch Changes
- Updated dependencies [36273b3]
- jazz-tools@0.8.14
- jazz-react@0.8.14
## 0.0.90
### Patch Changes
- Updated dependencies [fd011d7]
- jazz-tools@0.8.13
- jazz-react@0.8.13
## 0.0.89
### Patch Changes
- Updated dependencies [6ed75eb]
- Updated dependencies [3cc6aee]
- cojson@0.8.12
- jazz-react@0.8.12
- jazz-tools@0.8.12
## 0.0.88
### Patch Changes
- Updated dependencies [1ed4ab5]
- cojson@0.8.11
- jazz-react@0.8.11
- jazz-tools@0.8.11
- Updated dependencies [1ed4ab5]
- cojson@0.8.11
- jazz-react@0.8.11
- jazz-tools@0.8.11
## 0.0.87
### Patch Changes
- jazz-react@0.8.7
- jazz-react@0.8.7
## 0.0.86
### Patch Changes
- jazz-react@0.8.6
- jazz-react@0.8.6
## 0.0.85
### Patch Changes
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- jazz-tools@0.8.5
- cojson@0.8.5
- jazz-react@0.8.5
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- jazz-tools@0.8.5
- cojson@0.8.5
- jazz-react@0.8.5
## 0.0.84
### Patch Changes
- Updated dependencies
- hash-slash@0.2.1
- Updated dependencies
- hash-slash@0.2.1
## 0.0.83
### Patch Changes
- Updated dependencies
- cojson@0.8.3
- jazz-react@0.8.3
- jazz-tools@0.8.3
- Updated dependencies
- cojson@0.8.3
- jazz-react@0.8.3
- jazz-tools@0.8.3
## 0.0.82
### Patch Changes
- Updated dependencies [a075f90]
- jazz-tools@0.8.2
- jazz-react@0.8.2
- Updated dependencies [a075f90]
- jazz-tools@0.8.2
- jazz-react@0.8.2

View File

@@ -1,18 +1,17 @@
{
"name": "@jazz-e2e/covalues",
"private": true,
"version": "0.0.88",
"version": "0.0.99",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"test": "playwright test",
"test:ui": "playwright test --ui"
},
"lint-staged": {
"*.{js,jsx,mdx,json}": "prettier --write"
},
"dependencies": {
"cojson": "workspace:*",
"hash-slash": "workspace:*",

View File

@@ -12,42 +12,42 @@ import isCI from "is-ci";
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: isCI,
/* Retry on CI only */
retries: isCI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: isCI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
testDir: "./tests",
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: isCI,
/* Retry on CI only */
retries: isCI ? 2 : 0,
/* Opt out of parallel tests on CI. */
workers: isCI ? 1 : undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:5173/",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: "http://localhost:5173/",
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
permissions: ["clipboard-read", "clipboard-write"],
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
permissions: ["clipboard-read", "clipboard-write"],
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
/* Run your local dev server before starting the tests */
webServer: [
{
command: "pnpm preview --port 5173",
url: "http://localhost:5173/",
reuseExistingServer: !isCI,
},
],
/* Run your local dev server before starting the tests */
webServer: [
{
command: "pnpm preview --port 5173",
url: "http://localhost:5173/",
reuseExistingServer: !isCI,
},
],
});

View File

@@ -1,30 +1,29 @@
import React from "react";
import ReactDOM from "react-dom/client";
import { AuthAndJazz } from "./jazz";
import { TestInput } from "./pages/TestInput";
import { ResumeSyncState } from "./pages/ResumeSyncState";
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { AuthAndJazz } from "./jazz";
import { ResumeSyncState } from "./pages/ResumeSyncState";
import { TestInput } from "./pages/TestInput";
const router = createBrowserRouter([
{
path: "/test-input",
element: <TestInput />,
path: "/test-input",
element: <TestInput />,
},
{
path: "/resume-sync",
element: <ResumeSyncState />,
path: "/resume-sync",
element: <ResumeSyncState />,
},
{
path: "/",
element: <TestInput />,
path: "/",
element: <TestInput />,
},
]);
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<AuthAndJazz>
<RouterProvider router={router} />
</AuthAndJazz>
<AuthAndJazz>
<RouterProvider router={router} />
</AuthAndJazz>
</React.StrictMode>,
);

View File

@@ -5,39 +5,39 @@ const key = `test-comap@jazz.tools`;
const url = new URL(window.location.href);
const peer =
(url.searchParams.get("peer") as `ws://${string}`) ??
`wss://cloud.jazz.tools/`;
(url.searchParams.get("peer") as `ws://${string}`) ??
`wss://cloud.jazz.tools/`;
const Jazz = createJazzReactApp();
export const { useAccount, useCoState } = Jazz;
function getUserInfo() {
return url.searchParams.get("userName") ?? "Mister X";
return url.searchParams.get("userName") ?? "Mister X";
}
export function AuthAndJazz({ children }: { children: React.ReactNode }) {
const [auth, state] = useDemoAuth();
const [auth, state] = useDemoAuth();
const signedUp = useRef(false);
const signedUp = useRef(false);
useEffect(() => {
if (state.state === "ready" && !signedUp.current) {
const userName = getUserInfo();
useEffect(() => {
if (state.state === "ready" && !signedUp.current) {
const userName = getUserInfo();
if (state.existingUsers.includes(userName)) {
state.logInAs(userName);
} else {
state.signUp(userName);
}
if (state.existingUsers.includes(userName)) {
state.logInAs(userName);
} else {
state.signUp(userName);
}
signedUp.current = true;
}
}, [state.state]);
signedUp.current = true;
}
}, [state.state]);
return (
<Jazz.Provider auth={auth} peer={`${peer}?key=${key}`}>
{children}
</Jazz.Provider>
);
return (
<Jazz.Provider auth={auth} peer={`${peer}?key=${key}`}>
{children}
</Jazz.Provider>
);
}

View File

@@ -1,53 +1,53 @@
import { co, CoMap, Group, ID } from "jazz-tools";
import { useAccount, useCoState } from "../jazz";
import { CoMap, Group, ID, co } from "jazz-tools";
import { useEffect, useState } from "react";
import { useAccount, useCoState } from "../jazz";
export class ResumeSyncCoMap extends CoMap {
value = co.string;
value = co.string;
}
function getIdParam() {
const url = new URL(window.location.href);
return (url.searchParams.get("id") as ID<ResumeSyncCoMap>) ?? undefined;
const url = new URL(window.location.href);
return (url.searchParams.get("id") as ID<ResumeSyncCoMap>) ?? undefined;
}
export function ResumeSyncState() {
const [id, setId] = useState(getIdParam);
const coMap = useCoState(ResumeSyncCoMap, id);
const { me } = useAccount();
const [id, setId] = useState(getIdParam);
const coMap = useCoState(ResumeSyncCoMap, id);
const { me } = useAccount();
useEffect(() => {
if (id) {
const url = new URL(window.location.href);
url.searchParams.set("id", id);
history.pushState({}, "", url.toString());
}
}, [id])
useEffect(() => {
if (id) {
const url = new URL(window.location.href);
url.searchParams.set("id", id);
history.pushState({}, "", url.toString());
}
}, [id]);
useEffect(() => {
if (!me || id) return;
useEffect(() => {
if (!me || id) return;
const group = Group.create({ owner: me });
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
group.addMember("everyone", "writer");
setId(ResumeSyncCoMap.create({ value: "" }, { owner: group }).id);
}, [me]);
setId(ResumeSyncCoMap.create({ value: "" }, { owner: group }).id);
}, [me]);
if (!coMap) return null;
if (!coMap) return null;
return (
<div>
<h1>Resume Sync State</h1>
<p data-testid="id">{coMap.id}</p>
<label htmlFor="value">Value</label>
<input
id="value"
value={coMap.value ?? ""}
onChange={(e) => {
coMap.value = e.target.value;
}}
/>
</div>
);
return (
<div>
<h1>Resume Sync State</h1>
<p data-testid="id">{coMap.id}</p>
<label htmlFor="value">Value</label>
<input
id="value"
value={coMap.value ?? ""}
onChange={(e) => {
coMap.value = e.target.value;
}}
/>
</div>
);
}

View File

@@ -1,6 +1,6 @@
import { co, CoMap, Group, ID } from "jazz-tools";
import { useAccount, useCoState } from "../jazz";
import { CoMap, Group, ID, co } from "jazz-tools";
import { useEffect, useState } from "react";
import { useAccount, useCoState } from "../jazz";
export class InputTestCoMap extends CoMap {
title = co.string;

View File

@@ -1,8 +1,11 @@
import { test, expect } from "@playwright/test";
import { setTimeout } from "node:timers/promises";
import { expect, test } from "@playwright/test";
test.describe("ResumeSyncState", () => {
test.skip("should resume the sync even after a page reload", async ({ page, browser }) => {
test.skip("should resume the sync even after a page reload", async ({
page,
browser,
}) => {
const context = page.context();
await page.goto("/resume-sync?userName=SuperMario");
@@ -20,7 +23,7 @@ test.describe("ResumeSyncState", () => {
// Navigate away from the page
await page.goto(`about:blank`);
await setTimeout(1000);
await context.setOffline(false);
@@ -40,8 +43,10 @@ test.describe("ResumeSyncState", () => {
// The initial user should have synced the value even if the coValue was not loaded
// when the user is back online
await expect(newUserPage.getByRole("textbox", { name: "Value" })).toHaveValue("Mammamia!", {
timeout: 20_000
await expect(
newUserPage.getByRole("textbox", { name: "Value" }),
).toHaveValue("Mammamia!", {
timeout: 20_000,
});
});
});

View File

@@ -1,14 +1,14 @@
import { test, expect } from "@playwright/test";
import { expect, test } from "@playwright/test";
test.describe("CoMap - TestInput", () => {
test("should keep the cursor position when typing", async ({ page }) => {
await page.goto("/test-input");
await page.getByRole("textbox").fill("xx");
await page.getByRole('textbox').press('ArrowLeft');
await page.getByRole("textbox").press("ArrowLeft");
await page.getByRole("textbox").press("y");
await page.getByRole("textbox").press("y");
await expect(page.getByRole('textbox')).toHaveValue("xyyx");
await expect(page.getByRole("textbox")).toHaveValue("xyyx");
});
});

View File

@@ -21,5 +21,5 @@
"noFallthroughCasesInSwitch": true,
"baseUrl": "."
},
"include": ["src"],
"include": ["src"]
}

View File

@@ -1,10 +1,10 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import react from "@vitejs/plugin-react-swc";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
build: {
minify: false
}
})
minify: false,
},
});

View File

@@ -1,11 +0,0 @@
{
"extends": [
"next/core-web-vitals",
"prettier",
"plugin:prettier/recommended"
],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": ["error"]
}
}

View File

@@ -1,11 +0,0 @@
{
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid",
"printWidth": 80,
"plugins": ["prettier-plugin-tailwindcss"]
}

View File

@@ -1,5 +1,102 @@
# jazz-example-book-shelf
## 0.1.15
### Patch Changes
- Updated dependencies [59cc64d]
- jazz-react@0.8.22
- jazz-browser-media-images@0.8.22
## 0.1.14
### Patch Changes
- Updated dependencies [149ca97]
- jazz-tools@0.8.21
- jazz-react@0.8.21
- jazz-browser-media-images@0.8.21
## 0.1.13
### Patch Changes
- Updated dependencies [dd9b13f]
- Updated dependencies [a69ed0b]
- Updated dependencies [3ef3ff3]
- Updated dependencies [c6931b8]
- jazz-react@0.8.20
- jazz-browser-media-images@0.8.20
## 0.1.12
### Patch Changes
- jazz-react@0.8.19
- jazz-tools@0.8.19
- jazz-browser-media-images@0.8.19
## 0.1.11
### Patch Changes
- jazz-react@0.8.18
- jazz-tools@0.8.18
- jazz-browser-media-images@0.8.18
## 0.1.10
### Patch Changes
- jazz-react@0.8.17
- jazz-tools@0.8.17
- jazz-browser-media-images@0.8.17
## 0.1.9
### Patch Changes
- Updated dependencies [2af107c]
- jazz-react@0.8.16
- jazz-browser-media-images@0.8.16
- jazz-tools@0.8.16
## 0.1.8
### Patch Changes
- Updated dependencies [cce679b]
- jazz-tools@0.8.15
- jazz-browser-media-images@0.8.15
- jazz-react@0.8.15
## 0.1.7
### Patch Changes
- Updated dependencies [36273b3]
- jazz-tools@0.8.14
- jazz-browser-media-images@0.8.14
- jazz-react@0.8.14
## 0.1.6
### Patch Changes
- Updated dependencies [fd011d7]
- jazz-tools@0.8.13
- jazz-browser-media-images@0.8.13
- jazz-react@0.8.13
## 0.1.5
### Patch Changes
- Updated dependencies [3cc6aee]
- jazz-react@0.8.12
- jazz-tools@0.8.12
- jazz-browser-media-images@0.8.12
## 0.1.4
### Patch Changes

View File

@@ -1,19 +1,19 @@
{
"name": "jazz-example-book-shelf",
"version": "0.1.4",
"version": "0.1.15",
"private": true,
"scripts": {
"dev": "next dev",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"build": "next build",
"start": "next start",
"lint": "next lint",
"format": "prettier --write ."
"start": "next start"
},
"dependencies": {
"clsx": "^2.0.0",
"jazz-browser-media-images": "workspace:0.8.11",
"jazz-react": "workspace:0.8.11",
"jazz-tools": "workspace:0.8.11",
"jazz-browser-media-images": "workspace:0.8.22",
"jazz-react": "workspace:0.8.22",
"jazz-tools": "workspace:0.8.21",
"next": "14.2.5",
"react": "^18.2.0",
"react-dom": "^18.2.0"
@@ -22,13 +22,7 @@
"@types/node": "^22.5.1",
"@types/react": "^18.2.19",
"@types/react-dom": "^18.2.7",
"eslint": "^8.46.0",
"eslint-config-next": "14.2.5",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.2.1",
"postcss": "^8.4.27",
"prettier": "^3.1.1",
"prettier-plugin-tailwindcss": "^0.6.5",
"tailwindcss": "3.3.2",
"typescript": "^5.3.3"
}

View File

@@ -1,14 +1,14 @@
"use client";
import { ChangeEvent, useState } from "react";
import { BookReview, ListOfBookReviews } from "@/schema";
import { Button } from "@/components/Button";
import { Container } from "@/components/Container";
import { useAccount } from "@/components/JazzAndAuth";
import { useRouter } from "next/navigation";
import RatingInput from "@/components/RatingInput";
import { BookReview, ListOfBookReviews } from "@/schema";
import { createImage } from "jazz-browser-media-images";
import { Group, ImageDefinition } from "jazz-tools";
import { Container } from "@/components/Container";
import { Button } from "@/components/Button";
import { useRouter } from "next/navigation";
import { ChangeEvent, useState } from "react";
export default function AddBookReview() {
const { me } = useAccount();
@@ -18,7 +18,7 @@ export default function AddBookReview() {
const [review, setReview] = useState("");
const [rating, setRating] = useState(0);
const [dateRead, setDateRead] = useState(
new Date().toISOString().split("T")[0]
new Date().toISOString().split("T")[0],
);
const [coverImage, setCoverImage] = useState<ImageDefinition | undefined>();
@@ -37,7 +37,7 @@ export default function AddBookReview() {
group.addMember("everyone", "reader");
if (file) {
createImage(file, { owner: group }).then(image => {
createImage(file, { owner: group }).then((image) => {
setCoverImage(image);
});
}
@@ -59,7 +59,7 @@ export default function AddBookReview() {
},
{
owner: me.profile._owner,
}
},
);
if (!me.profile.bookReviews) {
@@ -88,7 +88,7 @@ export default function AddBookReview() {
type="text"
value={title}
required
onChange={e => setTitle(e.target.value)}
onChange={(e) => setTitle(e.target.value)}
></input>
</label>
@@ -99,7 +99,7 @@ export default function AddBookReview() {
type="text"
value={author}
required
onChange={e => setAuthor(e.target.value)}
onChange={(e) => setAuthor(e.target.value)}
></input>
</label>
@@ -116,7 +116,10 @@ export default function AddBookReview() {
<div className="grid gap-1 text-sm text-gray-600">
Rating
<RatingInput value={rating} onChange={rating => setRating(rating)} />
<RatingInput
value={rating}
onChange={(rating) => setRating(rating)}
/>
</div>
<label className="grid gap-1 text-sm text-gray-600">
@@ -124,7 +127,7 @@ export default function AddBookReview() {
<textarea
className="rounded border border-gray-300 px-2 py-1 shadow-sm"
value={review}
onChange={e => setReview(e.target.value)}
onChange={(e) => setReview(e.target.value)}
></textarea>
</label>
<Button variant="primary" type="submit">

View File

@@ -1,13 +1,13 @@
"use client";
import { useCoState } from "@/components/JazzAndAuth";
import { BookReview } from "@/schema";
import { Group, ID } from "jazz-tools";
import { BookCover } from "@/components/BookCover";
import clsx from "clsx";
import RatingInput from "@/components/RatingInput";
import Rating from "@/components/Rating";
import { Container } from "@/components/Container";
import { useCoState } from "@/components/JazzAndAuth";
import Rating from "@/components/Rating";
import RatingInput from "@/components/RatingInput";
import { BookReview } from "@/schema";
import clsx from "clsx";
import { Group, ID } from "jazz-tools";
const BookReviewTitle = ({
bookReview,
@@ -28,9 +28,9 @@ const BookReviewTitle = ({
placeholder="Book title"
className={clsx(
className,
"w-full rounded border border-transparent px-2 py-1 hover:border-gray-300 hover:shadow-sm"
"w-full rounded border border-transparent px-2 py-1 hover:border-gray-300 hover:shadow-sm",
)}
onChange={e => (bookReview.title = e.target.value)}
onChange={(e) => (bookReview.title = e.target.value)}
></input>
);
};
@@ -54,9 +54,9 @@ const BookReviewAuthor = ({
placeholder="Author"
className={clsx(
className,
"w-full rounded border border-transparent px-2 py-1 hover:border-gray-300 hover:shadow-sm"
"w-full rounded border border-transparent px-2 py-1 hover:border-gray-300 hover:shadow-sm",
)}
onChange={e => (bookReview.author = e.target.value)}
onChange={(e) => (bookReview.author = e.target.value)}
></input>
);
};
@@ -85,9 +85,9 @@ const BookReviewDateRead = ({
placeholder="Date read"
className={clsx(
className,
"w-full rounded border border-transparent px-2 py-1 hover:border-gray-300 hover:shadow-sm"
"w-full rounded border border-transparent px-2 py-1 hover:border-gray-300 hover:shadow-sm",
)}
onChange={e => {
onChange={(e) => {
const date = new Date(e.target.value);
bookReview.dateRead = date;
}}
@@ -116,9 +116,9 @@ const BookReviewReview = ({
placeholder="Write your review here..."
className={clsx(
className,
"w-full rounded border border-transparent px-2 py-1 hover:border-gray-300 hover:shadow-sm"
"w-full rounded border border-transparent px-2 py-1 hover:border-gray-300 hover:shadow-sm",
)}
onChange={e => (bookReview.review = e.target.value)}
onChange={(e) => (bookReview.review = e.target.value)}
></textarea>
);
};
@@ -139,7 +139,7 @@ const BookReviewRating = ({
return (
<RatingInput
className={clsx(className, "p-2")}
onChange={rating => (bookReview.rating = rating)}
onChange={(rating) => (bookReview.rating = rating)}
value={bookReview.rating}
/>
);

View File

@@ -3,8 +3,8 @@ import { Inter } from "next/font/google";
import "./globals.css";
import { JazzAndAuth } from "@/components/JazzAndAuth";
import { Nav } from "@/components/Nav";
import { Fraunces } from "next/font/google";
import clsx from "clsx";
import { Fraunces } from "next/font/google";
const fraunces = Fraunces({
subsets: ["latin"],

View File

@@ -1,10 +1,10 @@
"use client";
import { Container } from "@/components/Container";
import { useAccount } from "@/components/JazzAndAuth";
import UserProfile from "@/components/UserProfile";
import { JazzAccount } from "@/schema";
import { ID } from "jazz-tools";
import { Container } from "@/components/Container";
export default function Home() {
const { me } = useAccount();

View File

@@ -1,7 +1,7 @@
import { Container } from "@/components/Container";
import UserProfile from "@/components/UserProfile";
import { JazzAccount } from "@/schema";
import { ID } from "jazz-tools";
import { Container } from "@/components/Container";
export default function Page({ params }: { params: { slug: string } }) {
const { slug } = params;

View File

@@ -1,12 +1,12 @@
import { ProgressiveImg } from "jazz-react";
import { BookReview } from "@/schema";
import { ChangeEvent, useRef, useState } from "react";
import { Group, ImageDefinition } from "jazz-tools";
import { createImage } from "jazz-browser-media-images";
import { useAccount } from "@/components/JazzAndAuth";
import clsx from "clsx";
import PlusIcon from "@/components/icons/PlusIcon";
import { Button } from "@/components/Button";
import { useAccount } from "@/components/JazzAndAuth";
import PlusIcon from "@/components/icons/PlusIcon";
import { BookReview } from "@/schema";
import clsx from "clsx";
import { createImage } from "jazz-browser-media-images";
import { ProgressiveImg } from "jazz-react";
import { Group, ImageDefinition } from "jazz-tools";
import { ChangeEvent, useRef, useState } from "react";
const BookCoverContainer = ({
children,
@@ -68,7 +68,7 @@ export function BookCoverInput({ bookReview }: { bookReview: BookReview }) {
const file = event.currentTarget.files?.[0];
if (file) {
createImage(file, { owner: me.profile._owner }).then(image => {
createImage(file, { owner: me.profile._owner }).then((image) => {
bookReview.cover = image;
});
}

View File

@@ -1,8 +1,8 @@
import { BookReview } from "@/schema";
import Rating from "@/components/Rating";
import { Group } from "jazz-tools";
import RatingInput from "@/components/RatingInput";
import { BookCover } from "@/components/BookCover";
import Rating from "@/components/Rating";
import RatingInput from "@/components/RatingInput";
import { BookReview } from "@/schema";
import { Group } from "jazz-tools";
export function BookReviewHeader({ bookReview }: { bookReview: BookReview }) {
const { title, author, rating, review, dateRead } = bookReview;
@@ -19,7 +19,7 @@ export function BookReviewHeader({ bookReview }: { bookReview: BookReview }) {
{bookReview._owner.castAs(Group).myRole() === "admin" ? (
<RatingInput
onChange={rating => (bookReview.rating = rating)}
onChange={(rating) => (bookReview.rating = rating)}
value={rating}
/>
) : (

View File

@@ -1,11 +1,11 @@
"use client";
import { BookReview } from "../schema";
import { ID } from "jazz-tools";
import { useCoState } from "@/components/JazzAndAuth";
import Link from "next/link";
import { BookCover, BookCoverReadOnly } from "@/components/BookCover";
import { useCoState } from "@/components/JazzAndAuth";
import StarIcon from "@/components/icons/StarIcon";
import { ID } from "jazz-tools";
import Link from "next/link";
import { BookReview } from "../schema";
export function BookReviewThumbnail({ id }: { id: ID<BookReview> }) {
const bookReview = useCoState(BookReview, id);

View File

@@ -1,6 +1,6 @@
import clsx from "clsx";
import Link from "next/link";
import type { ComponentProps } from "react";
import clsx from "clsx";
interface Props {
variant?: "primary" | "secondary" | "tertiary";
@@ -43,7 +43,7 @@ export function Button(props: AnchorProps | ButtonProps) {
customClassName,
variantClassNames.base,
variantClassNames[variant],
sizeClassNames[size]
sizeClassNames[size],
);
if (!!(props as AnchorProps).href) {

View File

@@ -1,7 +1,7 @@
"use client";
import { createJazzReactApp, useDemoAuth, DemoAuthBasicUI } from "jazz-react";
import { JazzAccount } from "@/schema";
import { DemoAuthBasicUI, createJazzReactApp, useDemoAuth } from "jazz-react";
const Jazz = createJazzReactApp({
AccountSchema: JazzAccount,

View File

@@ -1,9 +1,9 @@
"use client";
import { Button } from "@/components/Button";
import { Container } from "@/components/Container";
import { useAccount } from "@/components/JazzAndAuth";
import Link from "next/link";
import { Container } from "@/components/Container";
import { Button } from "@/components/Button";
export function Nav() {
const { me, logOut } = useAccount();

View File

@@ -1,7 +1,7 @@
"use client";
import StarOutlineIcon from "@/components/icons/StarOutlineIcon";
import StarIcon from "@/components/icons/StarIcon";
import StarOutlineIcon from "@/components/icons/StarOutlineIcon";
import clsx from "clsx";
interface RatingInputProps {

View File

@@ -1,10 +1,10 @@
"use client";
import { useCoState } from "@/components/JazzAndAuth";
import { Group, ID } from "jazz-tools";
import { JazzAccount, JazzProfile, ListOfBookReviews } from "@/schema";
import { BookReviewThumbnail } from "@/components/BookReviewThumbnail";
import { Button } from "@/components/Button";
import { useCoState } from "@/components/JazzAndAuth";
import { JazzAccount, JazzProfile, ListOfBookReviews } from "@/schema";
import { Group, ID } from "jazz-tools";
export default function UserProfile({ id }: { id: ID<JazzAccount> }) {
const user = useCoState(JazzAccount, id);
@@ -13,7 +13,7 @@ export default function UserProfile({ id }: { id: ID<JazzAccount> }) {
const bookReviews = useCoState(
ListOfBookReviews,
user?.profile?._refs.bookReviews?.id,
[{}]
[{}],
);
return (
@@ -30,7 +30,7 @@ export default function UserProfile({ id }: { id: ID<JazzAccount> }) {
</div>
<div className="grid gap-4 md:grid-cols-4">
{bookReviews?.map(bookReview => (
{bookReviews?.map((bookReview) => (
<BookReviewThumbnail key={bookReview.id} id={bookReview.id} />
))}
</div>

View File

@@ -1,11 +1,11 @@
import {
CoMap,
co,
CoList,
Account,
Profile,
ImageDefinition,
CoList,
CoMap,
Encoders,
ImageDefinition,
Profile,
co,
} from "jazz-tools";
export class BookReview extends CoMap {

View File

@@ -1,13 +0,0 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {},
};

View File

@@ -1,10 +0,0 @@
{
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": false,
"trailingComma": "es5",
"bracketSpacing": true,
"arrowParens": "avoid",
"printWidth": 80
}

View File

@@ -1,5 +1,115 @@
# jazz-example-chat
## 0.0.99
### Patch Changes
- Updated dependencies [59cc64d]
- jazz-react@0.8.22
- jazz-react-auth-clerk@0.8.22
## 0.0.98
### Patch Changes
- Updated dependencies [0f30eea]
- Updated dependencies [149ca97]
- cojson@0.8.21
- jazz-tools@0.8.21
- jazz-react@0.8.21
- jazz-react-auth-clerk@0.8.21
## 0.0.97
### Patch Changes
- Updated dependencies [dd9b13f]
- Updated dependencies [a69ed0b]
- Updated dependencies [3ef3ff3]
- Updated dependencies [c6931b8]
- jazz-react@0.8.20
- jazz-react-auth-clerk@0.8.20
## 0.0.96
### Patch Changes
- Updated dependencies [9c2aadb]
- cojson@0.8.19
- jazz-react@0.8.19
- jazz-react-auth-clerk@0.8.19
- jazz-tools@0.8.19
## 0.0.95
### Patch Changes
- Updated dependencies [d4319d8]
- cojson@0.8.18
- jazz-react@0.8.18
- jazz-react-auth-clerk@0.8.18
- jazz-tools@0.8.18
## 0.0.94
### Patch Changes
- Updated dependencies [d433cf4]
- cojson@0.8.17
- jazz-react@0.8.17
- jazz-react-auth-clerk@0.8.17
- jazz-tools@0.8.17
## 0.0.93
### Patch Changes
- Updated dependencies [2af107c]
- Updated dependencies [b934fab]
- jazz-react@0.8.16
- cojson@0.8.16
- jazz-react-auth-clerk@0.8.16
- jazz-tools@0.8.16
## 0.0.92
### Patch Changes
- Updated dependencies [cce679b]
- Updated dependencies [221c58f]
- jazz-tools@0.8.15
- jazz-react-auth-clerk@0.8.15
- jazz-react@0.8.15
## 0.0.91
### Patch Changes
- Updated dependencies [36273b3]
- jazz-tools@0.8.14
- jazz-react@0.8.14
- jazz-react-auth-clerk@0.8.14
## 0.0.90
### Patch Changes
- Updated dependencies [fd011d7]
- jazz-tools@0.8.13
- jazz-react@0.8.13
- jazz-react-auth-clerk@0.8.13
## 0.0.89
### Patch Changes
- Updated dependencies [6ed75eb]
- Updated dependencies [3cc6aee]
- cojson@0.8.12
- jazz-react@0.8.12
- jazz-react-auth-clerk@0.8.12
- jazz-tools@0.8.12
## 0.0.88
### Patch Changes

View File

@@ -1,19 +1,15 @@
{
"name": "jazz-example-chat-clerk",
"private": true,
"version": "0.0.88",
"version": "0.0.99",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"format": "echo 'chat example is codegolfed'",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"preview": "vite preview"
},
"lint-staged": {
"*.{ts,tsx}": "eslint --fix",
"*.{js,jsx,mdx,json}": "prettier --write"
},
"dependencies": {
"@clerk/clerk-react": "^5.4.1",
"@radix-ui/react-checkbox": "^1.0.4",
@@ -21,11 +17,11 @@
"@radix-ui/react-toast": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"cojson": "workspace:0.8.11",
"cojson": "workspace:0.8.21",
"hash-slash": "workspace:0.2.1",
"jazz-react": "workspace:0.8.11",
"jazz-react-auth-clerk": "workspace:0.8.11",
"jazz-tools": "workspace:0.8.11",
"jazz-react": "workspace:0.8.22",
"jazz-react-auth-clerk": "workspace:0.8.22",
"jazz-tools": "workspace:0.8.21",
"lucide-react": "^0.274.0",
"qrcode": "^1.5.3",
"react": "^18.2.0",
@@ -41,13 +37,8 @@
"@types/qrcode": "^1.5.1",
"@types/react": "^18.2.19",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.2.1",
"@typescript-eslint/parser": "^6.2.1",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.14",
"eslint": "^8.46.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"postcss": "^8.4.27",
"tailwindcss": "3.3.2",
"typescript": "^5.3.3",

View File

@@ -1,8 +1,8 @@
import { Group, ID } from "jazz-tools";
import { useIframeHashRouter } from "hash-slash";
import { Group, ID } from "jazz-tools";
import { ChatScreen } from "./chatScreen.tsx";
import { useAccount } from "./main.tsx";
import { Chat } from "./schema.ts";
import { ChatScreen } from "./chatScreen.tsx";
import { AppContainer, TopBar } from "./ui.tsx";
export function App() {
@@ -24,7 +24,7 @@ export function App() {
</TopBar>
{router.route({
"/": () => createChat() as never,
"/chat/:id": id => <ChatScreen chatID={id as ID<Chat>} />,
"/chat/:id": (id) => <ChatScreen chatID={id as ID<Chat>} />,
})}
</AppContainer>
);

View File

@@ -1,6 +1,6 @@
import { ID } from "jazz-tools";
import { Chat, Message } from "./schema.ts";
import { useCoState } from "./main.tsx";
import { Chat, Message } from "./schema.ts";
import {
BubbleBody,
BubbleContainer,
@@ -16,12 +16,12 @@ export function ChatScreen(props: { chatID: ID<Chat> }) {
return chat ? (
<ChatContainer>
{chat.length > 0 ? (
chat.map(msg => <ChatBubble msg={msg} key={msg.id} />)
chat.map((msg) => <ChatBubble msg={msg} key={msg.id} />)
) : (
<EmptyChatMessage />
)}
<ChatInput
onSubmit={text => {
onSubmit={(text) => {
chat.push(Message.create({ text }, { owner: chat._owner }));
}}
/>

View File

@@ -1,6 +1,6 @@
import { createJazzReactApp } from "jazz-react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { createJazzReactApp } from "jazz-react";
import { App } from "./app.tsx";
import { ClerkProvider, SignInButton, useClerk } from "@clerk/clerk-react";
@@ -15,7 +15,7 @@ function JazzAndAuth({ children }: { children: React.ReactNode }) {
return (
<>
{state.errors.map(error => (
{state.errors.map((error) => (
<div key={error}>{error}</div>
))}
{auth ? (
@@ -42,5 +42,5 @@ createRoot(document.getElementById("root")!).render(
<App />
</JazzAndAuth>
</ClerkProvider>
</StrictMode>
</StrictMode>,
);

View File

@@ -1,4 +1,4 @@
import { CoMap, CoList, co } from "jazz-tools";
import { CoList, CoMap, co } from "jazz-tools";
export class Message extends CoMap {
text = co.string;

View File

@@ -1,6 +1,6 @@
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import react from "@vitejs/plugin-react-swc";
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({

View File

@@ -1,4 +0,0 @@
// https://docs.expo.dev/guides/using-eslint/
module.exports = {
extends: 'expo',
};

View File

@@ -1,34 +1,135 @@
# chat-rn-clerk
## 1.0.15
### Patch Changes
- jazz-react-auth-clerk@0.8.22
## 1.0.14
### Patch Changes
- Updated dependencies [149ca97]
- jazz-tools@0.8.21
- jazz-react-auth-clerk@0.8.21
- jazz-react-native@0.8.21
- jazz-react-native-media-images@0.8.17
## 1.0.13
### Patch Changes
- Updated dependencies [3ef3ff3]
- jazz-react-native-media-images@0.8.16
- jazz-react-native@0.8.20
- jazz-react-auth-clerk@0.8.20
## 1.0.12
### Patch Changes
- jazz-react-auth-clerk@0.8.19
- jazz-react-native@0.8.19
- jazz-tools@0.8.19
- jazz-react-native-media-images@0.8.15
## 1.0.11
### Patch Changes
- jazz-react-auth-clerk@0.8.18
- jazz-react-native@0.8.18
- jazz-tools@0.8.18
- jazz-react-native-media-images@0.8.14
## 1.0.10
### Patch Changes
- jazz-react-auth-clerk@0.8.17
- jazz-react-native@0.8.17
- jazz-tools@0.8.17
- jazz-react-native-media-images@0.8.13
## 1.0.9
### Patch Changes
- jazz-react-auth-clerk@0.8.16
- jazz-react-native@0.8.16
- jazz-tools@0.8.16
- jazz-react-native-media-images@0.8.12
## 1.0.8
### Patch Changes
- Updated dependencies [cce679b]
- Updated dependencies [221c58f]
- jazz-tools@0.8.15
- jazz-react-auth-clerk@0.8.15
- jazz-react-native@0.8.15
- jazz-react-native-media-images@0.8.11
## 1.0.7
### Patch Changes
- Updated dependencies [36273b3]
- jazz-tools@0.8.14
- jazz-react-auth-clerk@0.8.14
- jazz-react-native@0.8.14
- jazz-react-native-media-images@0.8.10
## 1.0.6
### Patch Changes
- Updated dependencies [fd011d7]
- jazz-tools@0.8.13
- jazz-react-auth-clerk@0.8.13
- jazz-react-native@0.8.13
- jazz-react-native-media-images@0.8.9
## 1.0.5
### Patch Changes
- jazz-react-auth-clerk@0.8.12
- jazz-react-native@0.8.12
- jazz-tools@0.8.12
- jazz-react-native-media-images@0.8.8
## 1.0.4
### Patch Changes
- jazz-react-auth-clerk@0.8.11
- jazz-react-native@0.8.11
- jazz-tools@0.8.11
- jazz-react-native-media-images@0.8.7
- jazz-react-auth-clerk@0.8.11
- jazz-react-native@0.8.11
- jazz-tools@0.8.11
- jazz-react-native-media-images@0.8.7
## 1.0.3
### Patch Changes
- b7639cf: feat(react-native): replaced react-native-mmkv with expo-secure-store and initialize it by default as kvStore in createJazzRNApp() (BREAKING)
- Updated dependencies [b7639cf]
- jazz-react-native@0.8.8
- b7639cf: feat(react-native): replaced react-native-mmkv with expo-secure-store and initialize it by default as kvStore in createJazzRNApp() (BREAKING)
- Updated dependencies [b7639cf]
- jazz-react-native@0.8.8
## 1.0.2
### Patch Changes
- Updated dependencies [32b05b6]
- jazz-react-native-media-images@0.8.6
- jazz-react-native@0.8.7
- jazz-react-auth-clerk@0.8.7
- Updated dependencies [32b05b6]
- jazz-react-native-media-images@0.8.6
- jazz-react-native@0.8.7
- jazz-react-auth-clerk@0.8.7
## 1.0.1
### Patch Changes
- jazz-react-native@0.8.6
- jazz-react-auth-clerk@0.8.6
- jazz-react-native@0.8.6
- jazz-react-auth-clerk@0.8.6

View File

@@ -1,17 +1,15 @@
import { Redirect, Stack } from "expo-router";
import React from "react";
import { useAuth } from "../../src/auth-context";
import { Redirect, Stack } from "expo-router";
export default function HomeLayout() {
const { isAuthenticated } = useAuth();
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
return <Redirect href={"/chat"} />;
}
if (isAuthenticated) {
return <Redirect href={"/chat"} />;
}
return (
<Stack
screenOptions={{ headerShown: false, headerBackVisible: true }}
/>
);
return (
<Stack screenOptions={{ headerShown: false, headerBackVisible: true }} />
);
}

View File

@@ -1,33 +1,33 @@
import React from "react";
import { SignedOut } from "@clerk/clerk-expo";
import { Link } from "expo-router";
import React from "react";
import { Text, View } from "react-native";
export default function HomePage() {
return (
<View className="flex-1 justify-center items-center bg-gray-100 p-6">
<SignedOut>
<View className="bg-white p-6 rounded-lg shadow-lg w-11/12 max-w-md">
<Text className="text-2xl font-bold text-center text-gray-900 mb-4">
Jazz 🤝 Clerk 🤝 Expo
</Text>
<Link href="/sign-in" className="mb-4">
<Text className="text-center text-blue-600 underline text-lg">
Sign In
</Text>
</Link>
<Link href="/sign-in-oauth" className="mb-4">
<Text className="text-center text-blue-600 underline text-lg">
Sign In OAuth
</Text>
</Link>
<Link href="/sign-up">
<Text className="text-center text-blue-600 underline text-lg">
Sign Up
</Text>
</Link>
</View>
</SignedOut>
return (
<View className="flex-1 justify-center items-center bg-gray-100 p-6">
<SignedOut>
<View className="bg-white p-6 rounded-lg shadow-lg w-11/12 max-w-md">
<Text className="text-2xl font-bold text-center text-gray-900 mb-4">
Jazz 🤝 Clerk 🤝 Expo
</Text>
<Link href="/sign-in" className="mb-4">
<Text className="text-center text-blue-600 underline text-lg">
Sign In
</Text>
</Link>
<Link href="/sign-in-oauth" className="mb-4">
<Text className="text-center text-blue-600 underline text-lg">
Sign In OAuth
</Text>
</Link>
<Link href="/sign-up">
<Text className="text-center text-blue-600 underline text-lg">
Sign Up
</Text>
</Link>
</View>
);
</SignedOut>
</View>
);
}

View File

@@ -2,19 +2,19 @@ import { Redirect, Stack } from "expo-router";
import { useAuth } from "../../src/auth-context";
export default function UnAuthenticatedLayout() {
const { isAuthenticated } = useAuth();
const { isAuthenticated } = useAuth();
if (isAuthenticated) {
return <Redirect href={"/chat"} />;
}
if (isAuthenticated) {
return <Redirect href={"/chat"} />;
}
return (
<Stack
screenOptions={{
headerShown: true,
headerBackVisible: true,
headerTitle: "",
}}
/>
);
return (
<Stack
screenOptions={{
headerShown: true,
headerBackVisible: true,
headerTitle: "",
}}
/>
);
}

View File

@@ -1,65 +1,65 @@
import React from "react";
import * as WebBrowser from "expo-web-browser";
import { Text, View, TouchableOpacity } from "react-native";
import { Link } from "expo-router";
import { useOAuth } from "@clerk/clerk-expo";
import * as Linking from "expo-linking";
import { Link } from "expo-router";
import * as WebBrowser from "expo-web-browser";
import React from "react";
import { Text, TouchableOpacity, View } from "react-native";
export const useWarmUpBrowser = () => {
React.useEffect(() => {
// Warm up the android browser to improve UX
// https://docs.expo.dev/guides/authentication/#improving-user-experience
void WebBrowser.warmUpAsync();
return () => {
void WebBrowser.coolDownAsync();
};
}, []);
React.useEffect(() => {
// Warm up the android browser to improve UX
// https://docs.expo.dev/guides/authentication/#improving-user-experience
void WebBrowser.warmUpAsync();
return () => {
void WebBrowser.coolDownAsync();
};
}, []);
};
WebBrowser.maybeCompleteAuthSession();
const SignInWithOAuth = () => {
useWarmUpBrowser();
useWarmUpBrowser();
const { startOAuthFlow } = useOAuth({ strategy: "oauth_google" });
const { startOAuthFlow } = useOAuth({ strategy: "oauth_google" });
const onPress = React.useCallback(async () => {
try {
const { createdSessionId, signIn, signUp, setActive } =
await startOAuthFlow({
redirectUrl: Linking.createURL("/", {
scheme: "jazz-chat-rn-clerk",
}),
});
const onPress = React.useCallback(async () => {
try {
const { createdSessionId, signIn, signUp, setActive } =
await startOAuthFlow({
redirectUrl: Linking.createURL("/", {
scheme: "jazz-chat-rn-clerk",
}),
});
if (createdSessionId) {
setActive!({ session: createdSessionId });
} else {
// Use signIn or signUp for next steps such as MFA
}
} catch (err) {
console.error("OAuth error", err);
}
}, []);
if (createdSessionId) {
setActive!({ session: createdSessionId });
} else {
// Use signIn or signUp for next steps such as MFA
}
} catch (err) {
console.error("OAuth error", err);
}
}, []);
return (
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-lg items-center">
<TouchableOpacity
onPress={onPress}
className="w-full bg-red-500 py-3 rounded-lg flex items-center justify-center"
>
<Text className="text-white text-lg font-semibold">
Sign in with Google
</Text>
</TouchableOpacity>
<Link href="/" className="mt-4">
<Text className="text-blue-600 text-lg font-semibold underline mb-6">
Back to Home
</Text>
</Link>
</View>
</View>
);
return (
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-lg items-center">
<TouchableOpacity
onPress={onPress}
className="w-full bg-red-500 py-3 rounded-lg flex items-center justify-center"
>
<Text className="text-white text-lg font-semibold">
Sign in with Google
</Text>
</TouchableOpacity>
<Link href="/" className="mt-4">
<Text className="text-blue-600 text-lg font-semibold underline mb-6">
Back to Home
</Text>
</Link>
</View>
</View>
);
};
export default SignInWithOAuth;

View File

@@ -1,91 +1,79 @@
import { useSignIn } from "@clerk/clerk-expo";
import { Text, TextInput, View, TouchableOpacity } from "react-native";
import React from "react";
import { Link } from "expo-router";
import React from "react";
import { Text, TextInput, TouchableOpacity, View } from "react-native";
export default function SignInPage() {
const { signIn, setActive, isLoaded } = useSignIn();
const [emailAddress, setEmailAddress] = React.useState("");
const [password, setPassword] = React.useState("");
const [errorMessage, setErrorMessage] = React.useState("");
const { signIn, setActive, isLoaded } = useSignIn();
const [emailAddress, setEmailAddress] = React.useState("");
const [password, setPassword] = React.useState("");
const [errorMessage, setErrorMessage] = React.useState("");
const onSignInPress = React.useCallback(async () => {
if (!isLoaded) {
return;
}
const onSignInPress = React.useCallback(async () => {
if (!isLoaded) {
return;
}
setErrorMessage("");
setErrorMessage("");
try {
const signInAttempt = await signIn.create({
identifier: emailAddress,
password,
});
try {
const signInAttempt = await signIn.create({
identifier: emailAddress,
password,
});
if (signInAttempt.status === "complete") {
await setActive({ session: signInAttempt.createdSessionId });
} else {
console.error(JSON.stringify(signInAttempt, null, 2));
setErrorMessage("Invalid credentials. Please try again.");
}
} catch (err: any) {
console.error(JSON.stringify(err, null, 2));
if (err.errors && err.errors[0]?.message) {
setErrorMessage(err.errors[0].message);
} else {
setErrorMessage(
"An unexpected error occurred. Please try again.",
);
}
}
}, [isLoaded, emailAddress, password]);
if (signInAttempt.status === "complete") {
await setActive({ session: signInAttempt.createdSessionId });
} else {
console.error(JSON.stringify(signInAttempt, null, 2));
setErrorMessage("Invalid credentials. Please try again.");
}
} catch (err: any) {
console.error(JSON.stringify(err, null, 2));
if (err.errors && err.errors[0]?.message) {
setErrorMessage(err.errors[0].message);
} else {
setErrorMessage("An unexpected error occurred. Please try again.");
}
}
}, [isLoaded, emailAddress, password]);
return (
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-md">
<Text className="text-3xl font-bold text-center text-gray-800 mb-6">
Sign In
</Text>
{errorMessage ? (
<Text className="text-red-500 text-center mb-4">
{errorMessage}
</Text>
) : null}
<TextInput
autoCapitalize="none"
value={emailAddress}
placeholder="Email..."
onChangeText={(emailAddress) =>
setEmailAddress(emailAddress)
}
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TextInput
value={password}
placeholder="Password..."
secureTextEntry={true}
onChangeText={(password) => setPassword(password)}
className="w-full h-12 mb-6 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TouchableOpacity
onPress={onSignInPress}
className="w-full h-12 bg-blue-600 rounded-lg flex items-center justify-center"
>
<Text className="text-white text-lg font-semibold">
Sign In
</Text>
</TouchableOpacity>
<View className="flex-row items-center justify-center mt-4">
<Text className="text-gray-600">
Don't have an account?
</Text>
<Link href="/sign-up">
<Text className="text-blue-500 ml-2 font-semibold">
Sign up
</Text>
</Link>
</View>
</View>
return (
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-md">
<Text className="text-3xl font-bold text-center text-gray-800 mb-6">
Sign In
</Text>
{errorMessage ? (
<Text className="text-red-500 text-center mb-4">{errorMessage}</Text>
) : null}
<TextInput
autoCapitalize="none"
value={emailAddress}
placeholder="Email..."
onChangeText={(emailAddress) => setEmailAddress(emailAddress)}
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TextInput
value={password}
placeholder="Password..."
secureTextEntry={true}
onChangeText={(password) => setPassword(password)}
className="w-full h-12 mb-6 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TouchableOpacity
onPress={onSignInPress}
className="w-full h-12 bg-blue-600 rounded-lg flex items-center justify-center"
>
<Text className="text-white text-lg font-semibold">Sign In</Text>
</TouchableOpacity>
<View className="flex-row items-center justify-center mt-4">
<Text className="text-gray-600">Don't have an account?</Text>
<Link href="/sign-up">
<Text className="text-blue-500 ml-2 font-semibold">Sign up</Text>
</Link>
</View>
);
</View>
</View>
);
}

View File

@@ -1,128 +1,120 @@
import * as React from "react";
import { TextInput, View, Text, TouchableOpacity } from "react-native";
import { useSignUp } from "@clerk/clerk-expo";
import { useNavigation } from "@react-navigation/native";
import * as React from "react";
import { Text, TextInput, TouchableOpacity, View } from "react-native";
export default function SignUpPage() {
const { isLoaded, signUp, setActive } = useSignUp();
const { isLoaded, signUp, setActive } = useSignUp();
const [emailAddress, setEmailAddress] = React.useState("");
const [password, setPassword] = React.useState("");
const [pendingVerification, setPendingVerification] = React.useState(false);
const [code, setCode] = React.useState("");
const [errorMessage, setErrorMessage] = React.useState("");
const navigation = useNavigation();
const [emailAddress, setEmailAddress] = React.useState("");
const [password, setPassword] = React.useState("");
const [pendingVerification, setPendingVerification] = React.useState(false);
const [code, setCode] = React.useState("");
const [errorMessage, setErrorMessage] = React.useState("");
const navigation = useNavigation();
const onSignUpPress = async () => {
if (!isLoaded) return;
const onSignUpPress = async () => {
if (!isLoaded) return;
setErrorMessage("");
setErrorMessage("");
try {
await signUp.create({
emailAddress,
password,
});
try {
await signUp.create({
emailAddress,
password,
});
await signUp.prepareEmailAddressVerification({
strategy: "email_code",
});
await signUp.prepareEmailAddressVerification({
strategy: "email_code",
});
setPendingVerification(true);
} catch (err: any) {
console.error(JSON.stringify(err, null, 2));
if (err.errors && err.errors[0]?.message) {
setErrorMessage(err.errors[0].message);
} else {
setErrorMessage(
"An unexpected error occurred. Please try again.",
);
}
}
};
setPendingVerification(true);
} catch (err: any) {
console.error(JSON.stringify(err, null, 2));
if (err.errors && err.errors[0]?.message) {
setErrorMessage(err.errors[0].message);
} else {
setErrorMessage("An unexpected error occurred. Please try again.");
}
}
};
const onPressVerify = async () => {
if (!isLoaded) return;
const onPressVerify = async () => {
if (!isLoaded) return;
setErrorMessage("");
setErrorMessage("");
try {
const completeSignUp = await signUp.attemptEmailAddressVerification(
{
code,
},
);
try {
const completeSignUp = await signUp.attemptEmailAddressVerification({
code,
});
if (completeSignUp.status === "complete") {
await setActive({ session: completeSignUp.createdSessionId });
} else {
console.error(JSON.stringify(completeSignUp, null, 2));
setErrorMessage("Failed to verify. Please check your code.");
}
} catch (err: any) {
console.error(JSON.stringify(err, null, 2));
setErrorMessage("Invalid verification code. Please try again.");
}
};
if (completeSignUp.status === "complete") {
await setActive({ session: completeSignUp.createdSessionId });
} else {
console.error(JSON.stringify(completeSignUp, null, 2));
setErrorMessage("Failed to verify. Please check your code.");
}
} catch (err: any) {
console.error(JSON.stringify(err, null, 2));
setErrorMessage("Invalid verification code. Please try again.");
}
};
return (
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-lg">
<Text className="text-3xl font-bold text-center text-gray-800 mb-6">
{pendingVerification ? "Verify Email" : "Sign Up"}
</Text>
{errorMessage ? (
<Text className="text-red-500 text-center mb-4">
{errorMessage}
</Text>
) : null}
return (
<View className="flex-1 justify-center items-center bg-gray-50 p-6">
<View className="bg-white w-11/12 max-w-md p-8 rounded-lg shadow-lg">
<Text className="text-3xl font-bold text-center text-gray-800 mb-6">
{pendingVerification ? "Verify Email" : "Sign Up"}
</Text>
{errorMessage ? (
<Text className="text-red-500 text-center mb-4">{errorMessage}</Text>
) : null}
{!pendingVerification && (
<>
<TextInput
autoCapitalize="none"
value={emailAddress}
placeholder="Email..."
onChangeText={(email) => setEmailAddress(email)}
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TextInput
value={password}
placeholder="Password..."
secureTextEntry={true}
onChangeText={(password) => setPassword(password)}
className="w-full h-12 mb-6 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TouchableOpacity
onPress={onSignUpPress}
className="w-full h-12 bg-blue-600 rounded-lg flex justify-center items-center mb-4"
>
<Text className="text-white text-lg font-semibold">
Sign Up
</Text>
</TouchableOpacity>
</>
)}
{!pendingVerification && (
<>
<TextInput
autoCapitalize="none"
value={emailAddress}
placeholder="Email..."
onChangeText={(email) => setEmailAddress(email)}
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TextInput
value={password}
placeholder="Password..."
secureTextEntry={true}
onChangeText={(password) => setPassword(password)}
className="w-full h-12 mb-6 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TouchableOpacity
onPress={onSignUpPress}
className="w-full h-12 bg-blue-600 rounded-lg flex justify-center items-center mb-4"
>
<Text className="text-white text-lg font-semibold">Sign Up</Text>
</TouchableOpacity>
</>
)}
{pendingVerification && (
<>
<TextInput
value={code}
placeholder="Verification Code..."
onChangeText={(code) => setCode(code)}
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TouchableOpacity
onPress={onPressVerify}
className="w-full h-12 bg-green-600 rounded-lg flex justify-center items-center mb-4"
>
<Text className="text-white text-lg font-semibold">
Verify Email
</Text>
</TouchableOpacity>
</>
)}
</View>
</View>
);
{pendingVerification && (
<>
<TextInput
value={code}
placeholder="Verification Code..."
onChangeText={(code) => setCode(code)}
className="w-full h-12 mb-4 px-4 bg-gray-100 border border-gray-300 rounded-lg focus:border-blue-500 focus:outline-none"
/>
<TouchableOpacity
onPress={onPressVerify}
className="w-full h-12 bg-green-600 rounded-lg flex justify-center items-center mb-4"
>
<Text className="text-white text-lg font-semibold">
Verify Email
</Text>
</TouchableOpacity>
</>
)}
</View>
</View>
);
}

View File

@@ -6,31 +6,29 @@ import { type PropsWithChildren } from "react";
* The contents of this function only run in Node.js environments and do not have access to the DOM or browser APIs.
*/
export default function Root({ children }: PropsWithChildren) {
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
return (
<html lang="en">
<head>
<meta charSet="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
{/*
{/*
Disable body scrolling on web. This makes ScrollView components work closer to how they do on native.
However, body scrolling is often nice to have for mobile web. If you want to enable it, remove this line.
*/}
<ScrollViewStyleReset />
<ScrollViewStyleReset />
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
<style
dangerouslySetInnerHTML={{ __html: responsiveBackground }}
/>
{/* Add any additional <head> elements that you want globally available on web... */}
</head>
<body>{children}</body>
</html>
);
{/* Using raw CSS styles as an escape-hatch to ensure the background color never flickers in dark-mode. */}
<style dangerouslySetInnerHTML={{ __html: responsiveBackground }} />
{/* Add any additional <head> elements that you want globally available on web... */}
</head>
<body>{children}</body>
</html>
);
}
const responsiveBackground = `

View File

@@ -1,5 +1,5 @@
import { Link, Stack } from "expo-router";
import { StyleSheet, View, Text } from "react-native";
import { StyleSheet, Text, View } from "react-native";
export default function NotFoundScreen() {
return (

View File

@@ -1,43 +1,43 @@
import { useFonts } from "expo-font";
import { ClerkLoaded, ClerkProvider } from "@clerk/clerk-expo";
import { useFonts } from "expo-font";
import { Slot } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import React, { useEffect } from "react";
import { Slot } from "expo-router";
import { tokenCache } from "../cache";
import { JazzAndAuth } from "../src/auth-context";
SplashScreen.preventAutoHideAsync();
export default function RootLayout() {
const [loaded] = useFonts({
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
});
const [loaded] = useFonts({
SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
});
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
if (!loaded) {
return null;
useEffect(() => {
if (loaded) {
SplashScreen.hideAsync();
}
}, [loaded]);
const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;
if (!loaded) {
return null;
}
if (!publishableKey) {
throw new Error(
"Missing Publishable Key. Please set EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY in your .env",
);
}
const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY;
return (
<ClerkProvider tokenCache={tokenCache} publishableKey={publishableKey}>
<ClerkLoaded>
<JazzAndAuth>
<Slot />
</JazzAndAuth>
</ClerkLoaded>
</ClerkProvider>
if (!publishableKey) {
throw new Error(
"Missing Publishable Key. Please set EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY in your .env",
);
}
return (
<ClerkProvider tokenCache={tokenCache} publishableKey={publishableKey}>
<ClerkLoaded>
<JazzAndAuth>
<Slot />
</JazzAndAuth>
</ClerkLoaded>
</ClerkProvider>
);
}

View File

@@ -1,173 +1,168 @@
import React, {
SafeAreaView,
View,
Text,
Alert,
TouchableOpacity,
FlatList,
KeyboardAvoidingView,
TextInput,
Button,
} from "react-native";
import { useLocalSearchParams } from "expo-router";
import { useState, useEffect, useLayoutEffect } from "react";
import { useAccount, useCoState } from "@/src/jazz";
import { Chat, Message } from "@/src/schema";
import { Group, ID } from "jazz-tools";
import { useFocusEffect, useNavigation } from "@react-navigation/native";
import clsx from "clsx";
import { useNavigation, useFocusEffect } from "@react-navigation/native";
import * as Clipboard from "expo-clipboard";
import { useLocalSearchParams } from "expo-router";
import { Group, ID } from "jazz-tools";
import { useEffect, useLayoutEffect, useState } from "react";
import React, {
SafeAreaView,
View,
Text,
Alert,
TouchableOpacity,
FlatList,
KeyboardAvoidingView,
TextInput,
Button,
} from "react-native";
export default function Conversation() {
const { chatId } = useLocalSearchParams();
const { me } = useAccount();
const [chat, setChat] = useState<Chat>();
const [message, setMessage] = useState("");
const loadedChat = useCoState(Chat, chat?.id, [{}]);
const navigation = useNavigation();
const { chatId } = useLocalSearchParams();
const { me } = useAccount();
const [chat, setChat] = useState<Chat>();
const [message, setMessage] = useState("");
const loadedChat = useCoState(Chat, chat?.id, [{}]);
const navigation = useNavigation();
useEffect(() => {
if (chat) return;
if (chatId === "new") {
createChat();
} else {
loadChat(chatId as ID<Chat>);
}
}, [chat]);
useEffect(() => {
if (chat) return;
if (chatId === "new") {
createChat();
} else {
loadChat(chatId as ID<Chat>);
}
}, [chat]);
// Effect to dynamically set header options
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: "Chat",
headerRight: () =>
chat ? (
<Button
onPress={() => {
if (chat?.id) {
Clipboard.setStringAsync(
`https://chat.jazz.tools/#/chat/${chat.id}`,
);
Alert.alert(
"Copied to clipboard",
`Chat ID: ${chat.id}`,
);
}
}}
title="Share"
/>
) : null,
});
}, [navigation, chat]);
// Effect to dynamically set header options
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: "Chat",
headerRight: () =>
chat ? (
<Button
onPress={() => {
if (chat?.id) {
Clipboard.setStringAsync(
`https://chat.jazz.tools/#/chat/${chat.id}`,
);
Alert.alert("Copied to clipboard", `Chat ID: ${chat.id}`);
}
}}
title="Share"
/>
) : null,
});
}, [navigation, chat]);
const createChat = () => {
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
setChat(chat);
};
const createChat = () => {
const group = Group.create({ owner: me });
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
setChat(chat);
};
const loadChat = async (chatId: ID<Chat>) => {
try {
const chat = await Chat.load(chatId, me, []);
setChat(chat);
} catch (error) {
console.log("Error loading chat", error);
Alert.alert("Error", `Error loading chat: ${error}`);
}
};
const loadChat = async (chatId: ID<Chat>) => {
try {
const chat = await Chat.load(chatId, me, []);
setChat(chat);
} catch (error) {
console.log("Error loading chat", error);
Alert.alert("Error", `Error loading chat: ${error}`);
}
};
const sendMessage = () => {
if (!chat) return;
if (message.trim()) {
chat.push(
Message.create({ text: message }, { owner: chat._owner }),
);
setMessage("");
}
};
const renderMessageItem = ({ item }: { item: Message }) => {
const isMe = item._edits.text.by?.isMe;
return (
<View
className={clsx(
`rounded-xl px-3 py-2 max-w-[75%] my-1`,
isMe ? `bg-blue-500 self-end` : `bg-gray-200 self-start`,
)}
>
{!isMe ? (
<Text
className={clsx(
`text-xs text-gray-500 mb-1`,
isMe ? "text-right" : "text-left",
)}
>
{item._edits.text.by?.profile?.name}
</Text>
) : null}
<View
className={clsx(
"flex relative items-end justify-between",
isMe ? "flex-row" : "flex-row",
)}
>
<Text
className={clsx(
!isMe ? "text-black" : "text-gray-200",
`text-md max-w-[85%]`,
)}
>
{item.text}
</Text>
<Text
className={clsx(
"text-[10px] text-right ml-2",
!isMe ? "mt-2 text-gray-500" : "mt-1 text-gray-200",
)}
>
{item._edits.text.madeAt.getHours()}:
{item._edits.text.madeAt.getMinutes()}
</Text>
</View>
</View>
);
};
const sendMessage = () => {
if (!chat) return;
if (message.trim()) {
chat.push(Message.create({ text: message }, { owner: chat._owner }));
setMessage("");
}
};
const renderMessageItem = ({ item }: { item: Message }) => {
const isMe = item._edits.text.by?.isMe;
return (
<View className="flex-1 bg-gray-50">
<FlatList
contentContainerStyle={{
flexGrow: 1,
paddingVertical: 10,
paddingHorizontal: 8,
}}
className="flex"
data={loadedChat}
keyExtractor={(item) => item.id}
renderItem={renderMessageItem}
/>
<KeyboardAvoidingView
keyboardVerticalOffset={110}
behavior="padding"
className="p-3 bg-white border-t border-gray-300"
>
<SafeAreaView className="flex-row items-center gap-2">
<TextInput
className="flex-1 rounded-full h-10 px-4 bg-gray-100 border border-gray-300 focus:border-blue-500 focus:bg-white"
value={message}
onChangeText={setMessage}
placeholder="Type a message..."
textAlignVertical="center"
onSubmitEditing={sendMessage}
/>
<TouchableOpacity
onPress={sendMessage}
className="bg-blue-500 rounded-full h-10 w-10 items-center justify-center"
>
<Text className="text-white text-xl"></Text>
</TouchableOpacity>
</SafeAreaView>
</KeyboardAvoidingView>
<View
className={clsx(
`rounded-xl px-3 py-2 max-w-[75%] my-1`,
isMe ? `bg-blue-500 self-end` : `bg-gray-200 self-start`,
)}
>
{!isMe ? (
<Text
className={clsx(
`text-xs text-gray-500 mb-1`,
isMe ? "text-right" : "text-left",
)}
>
{item._edits.text.by?.profile?.name}
</Text>
) : null}
<View
className={clsx(
"flex relative items-end justify-between",
isMe ? "flex-row" : "flex-row",
)}
>
<Text
className={clsx(
!isMe ? "text-black" : "text-gray-200",
`text-md max-w-[85%]`,
)}
>
{item.text}
</Text>
<Text
className={clsx(
"text-[10px] text-right ml-2",
!isMe ? "mt-2 text-gray-500" : "mt-1 text-gray-200",
)}
>
{item._edits.text.madeAt.getHours()}:
{item._edits.text.madeAt.getMinutes()}
</Text>
</View>
</View>
);
};
return (
<View className="flex-1 bg-gray-50">
<FlatList
contentContainerStyle={{
flexGrow: 1,
paddingVertical: 10,
paddingHorizontal: 8,
}}
className="flex"
data={loadedChat}
keyExtractor={(item) => item.id}
renderItem={renderMessageItem}
/>
<KeyboardAvoidingView
keyboardVerticalOffset={110}
behavior="padding"
className="p-3 bg-white border-t border-gray-300"
>
<SafeAreaView className="flex-row items-center gap-2">
<TextInput
className="flex-1 rounded-full h-10 px-4 bg-gray-100 border border-gray-300 focus:border-blue-500 focus:bg-white"
value={message}
onChangeText={setMessage}
placeholder="Type a message..."
textAlignVertical="center"
onSubmitEditing={sendMessage}
/>
<TouchableOpacity
onPress={sendMessage}
className="bg-blue-500 rounded-full h-10 w-10 items-center justify-center"
>
<Text className="text-white text-xl"></Text>
</TouchableOpacity>
</SafeAreaView>
</KeyboardAvoidingView>
</View>
);
}

View File

@@ -1,14 +1,14 @@
import React from "react";
import { Stack } from "expo-router";
import React from "react";
export default function ChatLayout() {
return (
<Stack
screenOptions={{
headerShown: true,
headerBackVisible: true,
headerTitle: "",
}}
/>
);
return (
<Stack
screenOptions={{
headerShown: true,
headerBackVisible: true,
headerTitle: "",
}}
/>
);
}

View File

@@ -1,85 +1,85 @@
import { useNavigation } from "@react-navigation/native";
import { useRouter } from "expo-router";
import { ID } from "jazz-tools";
import { useLayoutEffect } from "react";
import React, {
Button,
Text,
TouchableOpacity,
View,
Alert,
Button,
Text,
TouchableOpacity,
View,
Alert,
} from "react-native";
import { ID } from "jazz-tools";
import { useRouter } from "expo-router";
import { useNavigation } from "@react-navigation/native";
import { Chat } from "../../src/schema";
import { useAccount } from "../../src/jazz";
import { useUser } from "@clerk/clerk-expo";
import { useAccount } from "../../src/jazz";
import { Chat } from "../../src/schema";
export default function ChatScreen() {
const { logOut } = useAccount();
const router = useRouter();
const navigation = useNavigation();
const { user } = useUser();
const { logOut } = useAccount();
const router = useRouter();
const navigation = useNavigation();
const { user } = useUser();
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: "Chat",
headerRight: () => <Button onPress={logOut} title="Logout" />,
});
}, [navigation]);
useLayoutEffect(() => {
navigation.setOptions({
headerTitle: "Chat",
headerRight: () => <Button onPress={logOut} title="Logout" />,
});
}, [navigation]);
const loadChat = async (chatId: ID<Chat> | "new") => {
router.navigate(`/chat/${chatId}`);
};
const loadChat = async (chatId: ID<Chat> | "new") => {
router.navigate(`/chat/${chatId}`);
};
const joinChat = () => {
Alert.prompt(
"Join Chat",
"Enter the Chat ID (example: co_zBGEHYvRfGuT2YSBraY3njGjnde)",
[
{
text: "Cancel",
style: "cancel",
},
{
text: "Join",
onPress: (chatId) => {
if (chatId) {
loadChat(chatId as ID<Chat>);
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}
},
},
],
"plain-text",
);
};
return (
<View className="flex-1 bg-gray-50">
<View className="flex-1 justify-center items-center px-6">
<View className="w-full max-w-sm bg-white p-8 rounded-lg shadow-lg">
<Text className="text-xl font-semibold text-gray-800">
Welcome, {user?.emailAddresses[0].emailAddress}
</Text>
<TouchableOpacity
onPress={() => loadChat("new")}
className="w-full bg-blue-600 py-4 rounded-md mb-4 mt-4"
>
<Text className="text-white text-lg font-semibold text-center">
Start New Chat
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={joinChat}
className="w-full bg-green-500 py-4 rounded-md"
>
<Text className="text-white text-lg font-semibold text-center">
Join Chat
</Text>
</TouchableOpacity>
</View>
</View>
</View>
const joinChat = () => {
Alert.prompt(
"Join Chat",
"Enter the Chat ID (example: co_zBGEHYvRfGuT2YSBraY3njGjnde)",
[
{
text: "Cancel",
style: "cancel",
},
{
text: "Join",
onPress: (chatId) => {
if (chatId) {
loadChat(chatId as ID<Chat>);
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}
},
},
],
"plain-text",
);
};
return (
<View className="flex-1 bg-gray-50">
<View className="flex-1 justify-center items-center px-6">
<View className="w-full max-w-sm bg-white p-8 rounded-lg shadow-lg">
<Text className="text-xl font-semibold text-gray-800">
Welcome, {user?.emailAddresses[0].emailAddress}
</Text>
<TouchableOpacity
onPress={() => loadChat("new")}
className="w-full bg-blue-600 py-4 rounded-md mb-4 mt-4"
>
<Text className="text-white text-lg font-semibold text-center">
Start New Chat
</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={joinChat}
className="w-full bg-green-500 py-4 rounded-md"
>
<Text className="text-white text-lg font-semibold text-center">
Join Chat
</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}

View File

@@ -1,10 +1,7 @@
module.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: [
"nativewind/babel",
"@babel/plugin-transform-class-static-block",
],
};
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: ["nativewind/babel"],
};
};

View File

@@ -2,35 +2,35 @@ import * as SecureStore from "expo-secure-store";
import { Platform } from "react-native";
export interface TokenCache {
getToken: (key: string) => Promise<string | undefined | null>;
saveToken: (key: string, token: string) => Promise<void>;
clearToken?: (key: string) => void;
getToken: (key: string) => Promise<string | undefined | null>;
saveToken: (key: string, token: string) => Promise<void>;
clearToken?: (key: string) => void;
}
const createTokenCache = (): TokenCache => {
return {
getToken: async (key: string) => {
try {
const item = await SecureStore.getItemAsync(key);
if (item) {
console.log(`${key} was used 🔐 \n`);
} else {
console.log("No values stored under key: " + key);
}
return item;
} catch (error) {
console.error("secure store get item error: ", error);
await SecureStore.deleteItemAsync(key);
return null;
}
},
saveToken: (key: string, token: string) => {
return SecureStore.setItemAsync(key, token);
},
};
return {
getToken: async (key: string) => {
try {
const item = await SecureStore.getItemAsync(key);
if (item) {
console.log(`${key} was used 🔐 \n`);
} else {
console.log("No values stored under key: " + key);
}
return item;
} catch (error) {
console.error("secure store get item error: ", error);
await SecureStore.deleteItemAsync(key);
return null;
}
},
saveToken: (key: string, token: string) => {
return SecureStore.setItemAsync(key, token);
},
};
};
// SecureStore is not supported on the web
// https://github.com/expo/expo/issues/7744#issuecomment-611093485
export const tokenCache =
Platform.OS !== "web" ? createTokenCache() : undefined;
Platform.OS !== "web" ? createTokenCache() : undefined;

View File

@@ -1,27 +1,27 @@
{
"cli": {
"version": ">= 12.5.1",
"appVersionSource": "remote"
"cli": {
"version": ">= 12.5.1",
"appVersionSource": "remote"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"ios-simulator": {
"extends": "development",
"ios": {
"simulator": true
}
},
"preview": {
"distribution": "internal"
},
"production": {
"autoIncrement": true
}
"ios-simulator": {
"extends": "development",
"ios": {
"simulator": true
}
},
"submit": {
"production": {}
"preview": {
"distribution": "internal"
},
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {}
}
}

View File

@@ -14,8 +14,8 @@ const config = getDefaultConfig(projectRoot);
config.watchFolders = [workspaceRoot];
// #2 - Try resolving with project modules first, then workspace modules
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, "node_modules"),
path.resolve(workspaceRoot, "node_modules"),
path.resolve(projectRoot, "node_modules"),
path.resolve(workspaceRoot, "node_modules"),
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.unstable_enablePackageExports = true;
@@ -23,9 +23,9 @@ config.resolver.requireCycleIgnorePatterns = [/(^|\/|\\)node_modules($|\/|\\)/];
// Use turborepo to restore the cache when possible
config.cacheStores = [
new FileStore({
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
}),
new FileStore({
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
}),
];
module.exports = config;

View File

@@ -1,80 +1,78 @@
{
"name": "chat-rn-clerk",
"main": "index.js",
"version": "1.0.4",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
"test": "jest --watchAll",
"lint": "expo lint"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bam.tech/react-native-image-resizer": "^3.0.10",
"@clerk/clerk-expo": "^2.2.21",
"@expo/vector-icons": "^14.0.2",
"@react-native-community/netinfo": "^11.3.1",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",
"base-64": "^1.0.0",
"buffer": "^6.0.3",
"clsx": "^2.0.0",
"expo": "~51.0.37",
"expo-build-properties": "~0.12.5",
"expo-clipboard": "~6.0.3",
"expo-constants": "~16.0.2",
"expo-crypto": "~13.0.2",
"expo-dev-client": "~4.0.28",
"expo-file-system": "^17.0.1",
"expo-font": "~12.0.4",
"expo-linking": "~6.3.1",
"expo-router": "~3.5.23",
"expo-secure-store": "~13.0.2",
"expo-splash-screen": "~0.27.5",
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.7",
"expo-web-browser": "~13.0.3",
"jazz-react-auth-clerk": "workspace:*",
"jazz-react-native": "workspace:*",
"jazz-react-native-media-images": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^2.0.11",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-native": "~0.74.5",
"react-native-fetch-api": "^3.0.0",
"react-native-gesture-handler": "~2.16.1",
"react-native-get-random-values": "^1.11.0",
"react-native-mmkv": "3.0.1",
"react-native-polyfill-globals": "^3.1.0",
"react-native-quick-base64": "^2.1.2",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
"react-native-url-polyfill": "^2.0.0",
"react-native-web": "~0.19.10",
"text-encoding": "^0.7.0",
"web-streams-polyfill": "^3.2.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/plugin-transform-class-static-block": "^7.24.7",
"@types/jest": "^29.5.3",
"@types/react": "^18.2.19",
"@types/react-test-renderer": "^18.0.7",
"eslint": "^8.46.0",
"eslint-config-expo": "^7.1.2",
"jest": "^29.2.1",
"jest-expo": "~51.0.3",
"react-test-renderer": "18.2.0",
"tailwindcss": "3.3.2",
"typescript": "^5.3.3"
},
"private": true
"name": "chat-rn-clerk",
"main": "index.js",
"version": "1.0.15",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
"test": "jest --watchAll"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bam.tech/react-native-image-resizer": "^3.0.10",
"@clerk/clerk-expo": "^2.2.21",
"@expo/vector-icons": "^14.0.2",
"@react-native-community/netinfo": "^11.3.1",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",
"base-64": "^1.0.0",
"buffer": "^6.0.3",
"clsx": "^2.0.0",
"expo": "~51.0.37",
"expo-build-properties": "~0.12.5",
"expo-clipboard": "~6.0.3",
"expo-constants": "~16.0.2",
"expo-crypto": "~13.0.2",
"expo-dev-client": "~4.0.28",
"expo-file-system": "^17.0.1",
"expo-font": "~12.0.4",
"expo-linking": "~6.3.1",
"expo-router": "~3.5.23",
"expo-secure-store": "~13.0.2",
"expo-splash-screen": "~0.27.5",
"expo-status-bar": "~1.12.1",
"expo-system-ui": "~3.0.7",
"expo-web-browser": "~13.0.3",
"jazz-react-auth-clerk": "workspace:*",
"jazz-react-native": "workspace:*",
"jazz-react-native-media-images": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^2.0.11",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-native": "~0.74.5",
"react-native-fetch-api": "^3.0.0",
"react-native-gesture-handler": "~2.16.1",
"react-native-get-random-values": "^1.11.0",
"react-native-mmkv": "3.0.1",
"react-native-polyfill-globals": "^3.1.0",
"react-native-quick-base64": "^2.1.2",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
"react-native-url-polyfill": "^2.0.0",
"react-native-web": "~0.19.10",
"text-encoding": "^0.7.0",
"web-streams-polyfill": "^3.2.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/jest": "^29.5.3",
"@types/react": "^18.2.19",
"@types/react-test-renderer": "^18.0.7",
"jest": "^29.2.1",
"jest-expo": "~51.0.3",
"react-test-renderer": "18.2.0",
"tailwindcss": "3.3.2",
"typescript": "^5.3.3"
},
"private": true
}

View File

@@ -1,8 +1,8 @@
import "react-native-polyfill-globals/auto";
import "@azure/core-asynciterator-polyfill";
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { Buffer } from "buffer";
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
polyfillGlobal("Buffer", () => Buffer);
polyfillGlobal("ReadableStream", () => ReadableStream);

View File

@@ -1,62 +1,62 @@
import React, {
useContext,
createContext,
useEffect,
useState,
PropsWithChildren,
} from "react";
import { useClerk, useUser } from "@clerk/clerk-expo";
import { useJazzClerkAuth } from "jazz-react-auth-clerk";
import { Jazz } from "./jazz";
import React, {
useContext,
createContext,
useEffect,
useState,
PropsWithChildren,
} from "react";
import { Text, View } from "react-native";
import { Jazz } from "./jazz";
const AuthContext = createContext<{
isAuthenticated: boolean;
isLoading: boolean;
isAuthenticated: boolean;
isLoading: boolean;
}>({
isAuthenticated: false,
isLoading: true,
isAuthenticated: false,
isLoading: true,
});
export function useAuth() {
return useContext(AuthContext);
return useContext(AuthContext);
}
export function JazzAndAuth({ children }: PropsWithChildren) {
const { isSignedIn, isLoaded: isClerkLoaded } = useUser();
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const { isSignedIn, isLoaded: isClerkLoaded } = useUser();
const clerk = useClerk();
const [auth, state] = useJazzClerkAuth(clerk);
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
if (isSignedIn && isClerkLoaded && auth) {
setIsAuthenticated(true);
} else {
setIsAuthenticated(false);
}
}, [isSignedIn, isClerkLoaded, auth]);
useEffect(() => {
if (isSignedIn && isClerkLoaded && auth) {
setIsAuthenticated(true);
} else {
setIsAuthenticated(false);
}
}, [isSignedIn, isClerkLoaded, auth]);
return (
<AuthContext.Provider
value={{ isAuthenticated, isLoading: !isClerkLoaded || !auth }}
return (
<AuthContext.Provider
value={{ isAuthenticated, isLoading: !isClerkLoaded || !auth }}
>
{state?.errors?.length > 0 &&
state.errors.map((error) => (
<View key={error}>
<Text style={{ color: "red" }}>{error}</Text>
</View>
))}
{auth ? (
<Jazz.Provider
auth={auth}
peer="wss://cloud.jazz.tools/?key=chat-rn-clerk-example-jazz@gcmp.io"
storage={undefined}
>
{state?.errors?.length > 0 &&
state.errors.map((error) => (
<View key={error}>
<Text style={{ color: "red" }}>{error}</Text>
</View>
))}
{auth ? (
<Jazz.Provider
auth={auth}
peer="wss://cloud.jazz.tools/?key=chat-rn-clerk-example-jazz@gcmp.io"
storage={undefined}
>
{children}
</Jazz.Provider>
) : (
children
)}
</AuthContext.Provider>
);
{children}
</Jazz.Provider>
) : (
children
)}
</AuthContext.Provider>
);
}

View File

@@ -1,7 +1,7 @@
import { CoMap, CoList, co } from "jazz-tools";
import { CoList, CoMap, co } from "jazz-tools";
export class Message extends CoMap {
text = co.string;
text = co.string;
}
export class Chat extends CoList.Of(co.ref(Message)) {}

View File

@@ -1,12 +1,12 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}",
],
theme: {
extend: {},
},
plugins: [],
};

View File

@@ -4,13 +4,8 @@
"strict": true,
"moduleResolution": "bundler",
"paths": {
"@/*": [
"./*"
]
"@/*": ["./*"]
}
},
"include": [
"**/*.ts",
"**/*.tsx"
]
"include": ["**/*.ts", "**/*.tsx"]
}

View File

@@ -1,46 +1,120 @@
# chat-rn
## 1.0.16
### Patch Changes
- Updated dependencies [149ca97]
- jazz-tools@0.8.21
- jazz-react-native@0.8.21
## 1.0.15
### Patch Changes
- Updated dependencies [3ef3ff3]
- jazz-react-native@0.8.20
## 1.0.14
### Patch Changes
- jazz-react-native@0.8.19
- jazz-tools@0.8.19
## 1.0.13
### Patch Changes
- jazz-react-native@0.8.18
- jazz-tools@0.8.18
## 1.0.12
### Patch Changes
- jazz-react-native@0.8.17
- jazz-tools@0.8.17
## 1.0.11
### Patch Changes
- jazz-react-native@0.8.16
- jazz-tools@0.8.16
## 1.0.10
### Patch Changes
- Updated dependencies [cce679b]
- jazz-tools@0.8.15
- jazz-react-native@0.8.15
## 1.0.9
### Patch Changes
- Updated dependencies [36273b3]
- jazz-tools@0.8.14
- jazz-react-native@0.8.14
## 1.0.8
### Patch Changes
- Updated dependencies [fd011d7]
- jazz-tools@0.8.13
- jazz-react-native@0.8.13
## 1.0.7
### Patch Changes
- jazz-react-native@0.8.12
- jazz-tools@0.8.12
## 1.0.6
### Patch Changes
- jazz-react-native@0.8.11
- jazz-tools@0.8.11
- jazz-react-native@0.8.11
- jazz-tools@0.8.11
## 1.0.5
### Patch Changes
- b7639cf: feat(react-native): replaced react-native-mmkv with expo-secure-store and initialize it by default as kvStore in createJazzRNApp() (BREAKING)
- Updated dependencies [b7639cf]
- jazz-react-native@0.8.8
- b7639cf: feat(react-native): replaced react-native-mmkv with expo-secure-store and initialize it by default as kvStore in createJazzRNApp() (BREAKING)
- Updated dependencies [b7639cf]
- jazz-react-native@0.8.8
## 1.0.4
### Patch Changes
- Updated dependencies [32b05b6]
- jazz-react-native@0.8.7
- Updated dependencies [32b05b6]
- jazz-react-native@0.8.7
## 1.0.3
### Patch Changes
- jazz-react-native@0.8.6
- jazz-react-native@0.8.6
## 1.0.2
### Patch Changes
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- jazz-react-native@0.8.5
- jazz-tools@0.8.5
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- jazz-react-native@0.8.5
- jazz-tools@0.8.5
## 1.0.1
### Patch Changes
- Updated dependencies
- jazz-react-native@0.8.3
- jazz-tools@0.8.3
- Updated dependencies
- jazz-react-native@0.8.3
- jazz-tools@0.8.3

View File

@@ -1,10 +1,7 @@
module.exports = function (api) {
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: [
"nativewind/babel",
"@babel/plugin-transform-class-static-block",
],
};
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: ["nativewind/babel"],
};
};

View File

@@ -1,27 +1,27 @@
{
"cli": {
"version": ">= 12.5.1",
"appVersionSource": "remote"
"cli": {
"version": ">= 12.5.1",
"appVersionSource": "remote"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"ios-simulator": {
"extends": "development",
"ios": {
"simulator": true
}
},
"preview": {
"distribution": "internal"
},
"production": {
"autoIncrement": true
}
"ios-simulator": {
"extends": "development",
"ios": {
"simulator": true
}
},
"submit": {
"production": {}
"preview": {
"distribution": "internal"
},
"production": {
"autoIncrement": true
}
},
"submit": {
"production": {}
}
}

View File

@@ -14,8 +14,8 @@ const config = getDefaultConfig(projectRoot);
config.watchFolders = [workspaceRoot];
// #2 - Try resolving with project modules first, then workspace modules
config.resolver.nodeModulesPaths = [
path.resolve(projectRoot, "node_modules"),
path.resolve(workspaceRoot, "node_modules"),
path.resolve(projectRoot, "node_modules"),
path.resolve(workspaceRoot, "node_modules"),
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.unstable_enablePackageExports = true;
@@ -23,9 +23,9 @@ config.resolver.requireCycleIgnorePatterns = [/(^|\/|\\)node_modules($|\/|\\)/];
// Use turborepo to restore the cache when possible
config.cacheStores = [
new FileStore({
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
}),
new FileStore({
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
}),
];
module.exports = config;

View File

@@ -1,52 +1,53 @@
{
"name": "chat-rn",
"version": "1.0.6",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@react-native-community/netinfo": "^11.3.1",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",
"base-64": "^1.0.0",
"clsx": "^2.0.0",
"expo": "~51.0.37",
"expo-build-properties": "~0.12.5",
"expo-clipboard": "~6.0.3",
"expo-constants": "~16.0.2",
"expo-crypto": "~13.0.2",
"expo-dev-client": "~4.0.28",
"expo-linking": "~6.3.1",
"expo-secure-store": "~13.0.2",
"expo-status-bar": "~1.12.1",
"expo-web-browser": "~13.0.3",
"jazz-react-native": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^2.0.11",
"react": "^18.2.0",
"react-native": "~0.74.5",
"react-native-fetch-api": "^3.0.0",
"react-native-get-random-values": "^1.11.0",
"react-native-mmkv": "3.0.1",
"react-native-polyfill-globals": "^3.1.0",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
"react-native-url-polyfill": "^2.0.0",
"text-encoding": "^0.7.0",
"web-streams-polyfill": "^3.2.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@babel/plugin-transform-class-static-block": "^7.24.7",
"@types/react": "^18.2.19",
"tailwindcss": "3.3.2",
"typescript": "^5.3.3"
},
"private": true
"name": "chat-rn",
"version": "1.0.16",
"main": "index.js",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@react-native-community/netinfo": "^11.3.1",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",
"base-64": "^1.0.0",
"clsx": "^2.0.0",
"expo": "~51.0.37",
"expo-build-properties": "~0.12.5",
"expo-clipboard": "~6.0.3",
"expo-constants": "~16.0.2",
"expo-crypto": "~13.0.2",
"expo-dev-client": "~4.0.28",
"expo-linking": "~6.3.1",
"expo-secure-store": "~13.0.2",
"expo-status-bar": "~1.12.1",
"expo-web-browser": "~13.0.3",
"jazz-react-native": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^2.0.11",
"react": "^18.2.0",
"react-native": "~0.74.5",
"react-native-fetch-api": "^3.0.0",
"react-native-get-random-values": "^1.11.0",
"react-native-mmkv": "3.0.1",
"react-native-polyfill-globals": "^3.1.0",
"react-native-safe-area-context": "4.10.5",
"react-native-screens": "3.31.1",
"react-native-url-polyfill": "^2.0.0",
"text-encoding": "^0.7.0",
"web-streams-polyfill": "^3.2.1"
},
"devDependencies": {
"@babel/core": "^7.20.0",
"@types/react": "^18.2.19",
"tailwindcss": "3.3.2",
"typescript": "^5.3.3"
},
"private": true
}

View File

@@ -1,6 +1,6 @@
import "react-native-polyfill-globals/auto";
import "@azure/core-asynciterator-polyfill";
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
import { polyfillGlobal } from "react-native/Libraries/Utilities/PolyfillFunctions";
import { ReadableStream } from "web-streams-polyfill/ponyfill/es6";
polyfillGlobal("ReadableStream", () => ReadableStream);

View File

@@ -1,13 +1,13 @@
import React, { StrictMode, useEffect, useState } from "react";
import {
NavigationContainer,
useNavigationContainerRef,
NavigationContainer,
useNavigationContainerRef,
} from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import * as Linking from "expo-linking";
import React, { StrictMode, useEffect, useState } from "react";
import HandleInviteScreen from "./invite";
import { useDemoAuth, DemoAuthBasicUI } from "jazz-react-native";
import { DemoAuthBasicUI, useDemoAuth } from "jazz-react-native";
import ChatScreen from "./chat";
import { Jazz } from "./jazz";
@@ -16,64 +16,64 @@ const Stack = createNativeStackNavigator();
const prefix = Linking.createURL("/");
const linking = {
prefixes: [prefix],
config: {
screens: {
HandleInviteScreen: {
path: "router/invite/:valueHint?/:valueID/:inviteSecret",
},
},
prefixes: [prefix],
config: {
screens: {
HandleInviteScreen: {
path: "router/invite/:valueHint?/:valueID/:inviteSecret",
},
},
},
};
function App() {
const [auth, state] = useDemoAuth();
const [initialRoute, setInitialRoute] = useState<
"ChatScreen" | "HandleInviteScreen"
>("ChatScreen");
const navigationRef = useNavigationContainerRef();
const [auth, state] = useDemoAuth();
const [initialRoute, setInitialRoute] = useState<
"ChatScreen" | "HandleInviteScreen"
>("ChatScreen");
const navigationRef = useNavigationContainerRef();
useEffect(() => {
Linking.getInitialURL().then((url) => {
if (url) {
if (url && url.includes("invite")) {
setInitialRoute("HandleInviteScreen");
}
}
});
}, []);
useEffect(() => {
Linking.getInitialURL().then((url) => {
if (url) {
if (url && url.includes("invite")) {
setInitialRoute("HandleInviteScreen");
}
}
});
}, []);
if (!auth) {
return null;
}
if (!auth) {
return null;
}
return (
<StrictMode>
<Jazz.Provider
auth={auth}
peer="wss://cloud.jazz.tools/?key=chat-rn-example-jazz@gcmp.io"
storage={undefined}
>
<NavigationContainer linking={linking} ref={navigationRef}>
<Stack.Navigator initialRouteName={initialRoute}>
<Stack.Screen
options={{ title: "Jazz Chat" }}
name="ChatScreen"
// @ts-ignore
component={ChatScreen}
/>
<Stack.Screen
name="HandleInviteScreen"
component={HandleInviteScreen}
/>
</Stack.Navigator>
</NavigationContainer>
</Jazz.Provider>
{state.state !== "signedIn" ? (
<DemoAuthBasicUI appName="Jazz Chat" state={state} />
) : null}
</StrictMode>
);
return (
<StrictMode>
<Jazz.Provider
auth={auth}
peer="wss://cloud.jazz.tools/?key=chat-rn-example-jazz@gcmp.io"
storage={undefined}
>
<NavigationContainer linking={linking} ref={navigationRef}>
<Stack.Navigator initialRouteName={initialRoute}>
<Stack.Screen
options={{ title: "Jazz Chat" }}
name="ChatScreen"
// @ts-ignore
component={ChatScreen}
/>
<Stack.Screen
name="HandleInviteScreen"
component={HandleInviteScreen}
/>
</Stack.Navigator>
</NavigationContainer>
</Jazz.Provider>
{state.state !== "signedIn" ? (
<DemoAuthBasicUI appName="Jazz Chat" state={state} />
) : null}
</StrictMode>
);
}
export default App;

Some files were not shown because too many files have changed in this diff Show More