Compare commits

..

61 Commits

Author SHA1 Message Date
Guido D'Orsi
14f52dbc4e Merge pull request #2365 from garden-co/changeset-release/main
Version Packages
2025-05-26 12:48:04 +02:00
github-actions[bot]
82e4256e26 Version Packages 2025-05-26 10:07:42 +00:00
Guido D'Orsi
5e253cc717 chore: version bump 2025-05-26 11:12:59 +02:00
Guido D'Orsi
0c1663505c Merge pull request #2363 from garden-co/changeset-release/main
Version Packages
2025-05-26 11:07:20 +02:00
github-actions[bot]
ad85703373 Version Packages 2025-05-25 15:01:21 +00:00
Guido D'Orsi
3a6ec3791c Merge pull request #2364 from garden-co/fix/storage-group-deps
feat(react): API for SSR and Server Components
2025-05-25 16:58:34 +02:00
Guido D'Orsi
f9590f9120 feat(react): API for SSR and Server Components 2025-05-25 16:54:29 +02:00
Guido D'Orsi
706ebf87da Merge pull request #2357 from balazshevesi/main
Fix docs
2025-05-25 16:24:47 +02:00
Guido D'Orsi
00dd317a5d Merge pull request #2362 from garden-co/fix/storage-group-deps
fix(storage): align groups dependencies calculation to LocalNode
2025-05-25 16:24:04 +02:00
Guido D'Orsi
5ced45fb90 test: cover the group dependency loading with a test (temporary) 2025-05-25 15:35:00 +02:00
Guido D'Orsi
23daa7cdde fix(storage): align groups dependencies calculation to LocalNode 2025-05-25 14:34:50 +02:00
Guido D'Orsi
c018752c0c Merge pull request #2361 from garden-co/changeset-release/main
Version Packages
2025-05-24 22:54:04 +02:00
github-actions[bot]
ba3bdcc268 Version Packages 2025-05-24 20:31:26 +00:00
Guido D'Orsi
4177f6f92c Merge pull request #2360 from garden-co/feat/ssr
feat(react): add experimental_enableSSR
2025-05-24 22:28:20 +02:00
Guido D'Orsi
e32a1f7392 feat(react): add experimental_enableSSR 2025-05-24 19:11:23 +02:00
Guido D'Orsi
7c43fd37ae Merge pull request #2358 from garden-co/feat/improve-music-player-mobile
feat(music-player): make the ui usable on mobile
2025-05-24 18:37:59 +02:00
Guido D'Orsi
48168d619b feat(music-player): make the ui usable on mobile 2025-05-24 18:37:15 +02:00
Balazs Hevesi
1b9b9273e5 Update 0-14-0.mdx 2025-05-23 22:18:05 +02:00
Guido D'Orsi
2f4eada56c Merge pull request #2356 from garden-co/changeset-release/main
Version Packages
2025-05-23 21:37:52 +02:00
github-actions[bot]
709b3432d7 Version Packages 2025-05-23 19:33:52 +00:00
Guido D'Orsi
78a7672401 fix: update lockfile 2025-05-23 21:31:34 +02:00
Guido D'Orsi
bb214f0e8b fix: remove react-dom from the peerDependencies 2025-05-23 21:22:22 +02:00
Guido D'Orsi
8706398f74 Merge pull request #2355 from garden-co/changeset-release/main
Version Packages
2025-05-23 20:31:09 +02:00
github-actions[bot]
1502a6b421 Version Packages 2025-05-23 18:15:41 +00:00
Guido D'Orsi
f167112d99 fix: remove react and react-dom dev dependencies due to npm install issues 2025-05-23 20:12:58 +02:00
Guido D'Orsi
d4d6cb3307 Merge pull request #2354 from garden-co/changeset-release/main
Version Packages
2025-05-23 20:01:42 +02:00
github-actions[bot]
9565cdf323 Version Packages 2025-05-23 18:01:27 +00:00
Guido D'Orsi
dfb21ff0f2 fix: add missing deps for sqlite and secure storage 2025-05-23 19:59:08 +02:00
Guido D'Orsi
98d697fafb fix: remove react and react-native dev dependencies 2025-05-23 19:50:54 +02:00
Guido D'Orsi
9150d53f90 Merge pull request #2353 from garden-co/changeset-release/main
Version Packages
2025-05-23 19:46:39 +02:00
github-actions[bot]
ac7ecc278c Version Packages 2025-05-23 17:46:11 +00:00
Guido D'Orsi
99595bc7e3 fix: remove React Native specific steps only for chat-rn-expo 2025-05-23 19:42:45 +02:00
Guido D'Orsi
f5bae09679 fix: remove React Native specific steps as not required anymore 2025-05-23 19:40:51 +02:00
Guido D'Orsi
a7b9ae0b76 Merge pull request #2350 from garden-co/changeset-release/main
Version Packages
2025-05-23 19:24:34 +02:00
github-actions[bot]
196efcf48e Version Packages 2025-05-23 17:23:15 +00:00
Guido D'Orsi
153aa972b3 Merge pull request #2351 from garden-co/fix/chat-rn-expo
fix: fix chat-rn-expo example app
2025-05-23 19:20:25 +02:00
Guido D'Orsi
4508524f77 feat: rename demo to minimal, change React Native template to minimal auth 2025-05-23 19:20:05 +02:00
Guido D'Orsi
e7e9062dff test: disable the chat navigation step on RN expo 2025-05-23 18:44:03 +02:00
Guido D'Orsi
65e8d135c1 fix: React 19 upgrade type fixes 2025-05-23 18:36:54 +02:00
Meg Culotta
0b8e84e22d Merge pull request #2352 from garden-co/feat/2345-add-example-links-to-readmes
Add URL's to live demos in all readme files in examples
2025-05-23 11:15:46 -05:00
Margaret Culotta
7b51e38cf6 Add all other examples 2025-05-23 11:11:57 -05:00
Margaret Culotta
fcc2cbdc93 Add URL's to live demos in all readme files in examples 2025-05-23 11:09:00 -05:00
Guido D'Orsi
5aa13b5afc feat: upgrade to React 19 2025-05-23 17:53:49 +02:00
Guido D'Orsi
dc746a2fc9 chore: changeset 2025-05-23 17:36:38 +02:00
Guido D'Orsi
ca39bae001 fix: fix chat-rn-expo when used as template 2025-05-23 17:35:49 +02:00
Guido D'Orsi
020b12fa32 fix: correct definition of react in peerDependencies 2025-05-23 17:33:26 +02:00
Guido D'Orsi
bfea02c229 Merge pull request #2348 from garden-co/feat/deprecate-with-helpers
fix: deprecate withHelpers
2025-05-23 14:45:01 +02:00
Guido D'Orsi
74e6495beb Merge pull request #2349 from garden-co/feat/default-catch
feat: add shallow support for default/catch
2025-05-23 14:40:01 +02:00
Guido D'Orsi
3fe683206a feat: add shallow support for default/catch 2025-05-23 14:37:15 +02:00
Guido D'Orsi
f869d9a4dd fix: deprecate withHelpers 2025-05-23 14:30:52 +02:00
Guido D'Orsi
0724cfb95e Merge pull request #2344 from garden-co/changeset-release/main
Version Packages
2025-05-23 09:54:27 +02:00
github-actions[bot]
3b7fd14976 Version Packages 2025-05-23 07:54:03 +00:00
Guido D'Orsi
55fbe8a0a8 Merge pull request #2343 from garden-co/feat/back-to-zod
fix: move back to zod and clean up zod re-export
2025-05-23 09:50:45 +02:00
Guido D'Orsi
22c2600ef1 fix: move back to zod and clean up zod re-export 2025-05-23 09:46:36 +02:00
Guido D'Orsi
d41feafebe Merge pull request #2342 from garden-co/changeset-release/main
Version Packages
2025-05-22 23:33:33 +02:00
github-actions[bot]
05e3e30451 Version Packages 2025-05-22 21:29:40 +00:00
Guido D'Orsi
637ae13131 chore: changeset 2025-05-22 23:26:46 +02:00
Guido D'Orsi
4a601a6441 Merge pull request #2340 from garden-co/fix/zod-fork
fix: switch to our zod fork with RN fixes
2025-05-22 23:24:29 +02:00
Guido D'Orsi
15b422f711 fix: switch to our zod fork with RN fixes 2025-05-22 19:48:58 +02:00
Trisha Lim
2e42825971 Merge pull request #2332 from garden-co/fix/passkey-svelte
fix(passkey-svelte): use AccountCoState instead of useAccount
2025-05-22 14:07:22 +01:00
Trisha Lim
089cdb2031 fix(passkey-svelte): use AccountCoState instead of useAccount 2025-05-22 13:55:06 +01:00
243 changed files with 7805 additions and 3803 deletions

View File

@@ -1,5 +1,94 @@
# betterauth
## 0.1.19
### Patch Changes
- jazz-betterauth-server-plugin@0.14.16
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-react-auth-betterauth@0.14.16
- jazz-tools@0.14.16
- jazz-betterauth-client-plugin@0.14.16
## 0.1.18
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-betterauth-server-plugin@0.14.15
- jazz-inspector@0.14.15
- jazz-react-auth-betterauth@0.14.15
- jazz-tools@0.14.15
- jazz-betterauth-client-plugin@0.14.15
## 0.1.17
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-betterauth-server-plugin@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
- jazz-react-auth-betterauth@0.14.14
- jazz-betterauth-client-plugin@0.14.14
## 0.1.16
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
- jazz-react-auth-betterauth@0.14.13
## 0.1.15
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
- jazz-react-auth-betterauth@0.14.12
## 0.1.14
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react-auth-betterauth@0.14.10
- jazz-inspector@0.14.10
- jazz-react@0.14.10
- jazz-tools@0.14.10
- jazz-betterauth-server-plugin@0.14.10
- jazz-betterauth-client-plugin@0.14.10
## 0.1.13
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-betterauth-server-plugin@0.14.9
- jazz-inspector@0.14.9
- jazz-react@0.14.9
- jazz-react-auth-betterauth@0.14.9
- jazz-betterauth-client-plugin@0.14.9
## 0.1.12
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-betterauth-server-plugin@0.14.8
- jazz-inspector@0.14.8
- jazz-react@0.14.8
- jazz-react-auth-betterauth@0.14.8
- jazz-betterauth-client-plugin@0.14.8
## 0.1.11
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "betterauth",
"version": "0.1.11",
"version": "0.1.19",
"private": true,
"type": "module",
"scripts": {

View File

@@ -1,5 +1,78 @@
# chat-rn-expo-clerk
## 1.0.139
### Patch Changes
- jazz-expo@0.14.16
- jazz-tools@0.14.16
- jazz-react-native-media-images@0.14.16
## 1.0.138
### Patch Changes
- jazz-expo@0.14.15
- jazz-tools@0.14.15
- jazz-react-native-media-images@0.14.15
## 1.0.137
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-expo@0.14.14
- jazz-react-native-media-images@0.14.14
## 1.0.136
### Patch Changes
- jazz-expo@0.14.13
## 1.0.135
### Patch Changes
- jazz-expo@0.14.12
## 1.0.134
### Patch Changes
- Updated dependencies [98d697f]
- jazz-expo@0.14.11
## 1.0.133
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react-native-media-images@0.14.10
- jazz-tools@0.14.10
- jazz-expo@0.14.10
## 1.0.132
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-expo@0.14.9
- jazz-react-native-media-images@0.14.9
## 1.0.131
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-expo@0.14.8
- jazz-react-native-media-images@0.14.8
## 1.0.130
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "chat-rn-expo-clerk",
"main": "index.js",
"version": "1.0.130",
"version": "1.0.139",
"scripts": {
"build": "expo export -p ios",
"start": "expo start",

View File

@@ -7,8 +7,10 @@ node_modules/
.expo/
dist/
web-build/
expo-env.d.ts
# Native
.kotlin/
*.orig.*
*.jks
*.p8
@@ -33,6 +35,5 @@ yarn-error.*
# typescript
*.tsbuildinfo
ios
android
android/
ios/

View File

@@ -1,977 +1,52 @@
# chat-rn-expo
## 1.0.117
### Patch Changes
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-expo@0.14.7
## 1.0.116
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-expo@0.14.6
## 1.0.115
### Patch Changes
- Updated dependencies [91cbb2f]
- Updated dependencies [20b3d88]
- jazz-tools@0.14.5
- jazz-expo@0.14.5
## 1.0.114
### Patch Changes
- Updated dependencies [011af55]
- jazz-tools@0.14.4
- jazz-expo@0.14.4
## 1.0.113
### Patch Changes
- Updated dependencies [3d1027f]
- Updated dependencies [c240eed]
- jazz-tools@0.14.2
- jazz-expo@0.14.2
## 1.0.112
### Patch Changes
- Updated dependencies [cdfc105]
- jazz-tools@0.14.1
- jazz-expo@0.14.1
## 1.0.111
### Patch Changes
- Updated dependencies [5835ed1]
- jazz-tools@0.14.0
- jazz-expo@0.14.0
## 1.0.110
### Patch Changes
- jazz-expo@0.13.32
## 1.0.109
### Patch Changes
- Updated dependencies [e5b170f]
- jazz-tools@0.13.31
- jazz-expo@0.13.31
## 1.0.108
### Patch Changes
- jazz-expo@0.13.30
- jazz-tools@0.13.30
## 1.0.107
### Patch Changes
- jazz-expo@0.13.29
- jazz-tools@0.13.29
## 1.0.106
### Patch Changes
- jazz-expo@0.13.28
- jazz-tools@0.13.28
## 1.0.105
### Patch Changes
- jazz-expo@0.13.27
- jazz-tools@0.13.27
## 1.0.104
### Patch Changes
- Updated dependencies [ff846d9]
- jazz-tools@0.13.26
- jazz-expo@0.13.26
## 1.0.103
### Patch Changes
- jazz-expo@0.13.25
- jazz-tools@0.13.25
## 1.0.102
### Patch Changes
- Updated dependencies [02a240c]
- jazz-tools@0.13.23
- jazz-expo@0.13.23
## 1.0.101
### Patch Changes
- jazz-expo@0.13.22
## 1.0.100
### Patch Changes
- jazz-expo@0.13.21
- jazz-tools@0.13.21
## 1.0.99
### Patch Changes
- Updated dependencies [439f0fe]
- jazz-tools@0.13.20
- jazz-expo@0.13.20
## 1.0.98
### Patch Changes
- Updated dependencies [80530a4]
- jazz-tools@0.13.19
- jazz-expo@0.13.19
## 1.0.97
### Patch Changes
- Updated dependencies [761759c]
- jazz-tools@0.13.18
- jazz-expo@0.13.18
## 1.0.96
### Patch Changes
- jazz-expo@0.13.17
- jazz-tools@0.13.17
## 1.0.95
### Patch Changes
- jazz-expo@0.13.16
- jazz-tools@0.13.16
## 1.0.94
### Patch Changes
- jazz-expo@0.13.15
- jazz-tools@0.13.15
## 1.0.93
### Patch Changes
- Updated dependencies [bd94012]
- jazz-expo@0.13.14
- jazz-tools@0.13.14
## 1.0.92
### Patch Changes
- jazz-expo@0.13.13
- jazz-tools@0.13.13
## 1.0.91
### Patch Changes
- Updated dependencies [4547525]
- jazz-tools@0.13.12
- jazz-expo@0.13.12
## 1.0.90
### Patch Changes
- Updated dependencies [17273a6]
- jazz-tools@0.13.11
- jazz-expo@0.13.11
## 1.0.89
### Patch Changes
- jazz-expo@0.13.10
- jazz-tools@0.13.10
## 1.0.88
### Patch Changes
- Updated dependencies [a6cf01f]
- jazz-tools@0.13.9
- jazz-expo@0.13.9
## 1.0.87
### Patch Changes
- jazz-expo@0.13.8
## 1.0.86
### Patch Changes
- Updated dependencies [bc3d7bb]
- jazz-tools@0.13.7
- jazz-expo@0.13.7
## 1.0.85
### Patch Changes
- Updated dependencies [fe6f561]
- jazz-tools@0.13.5
- jazz-expo@0.13.5
## 1.0.84
### Patch Changes
- Updated dependencies [3129982]
- Updated dependencies [3129982]
- jazz-expo@0.13.4
- jazz-tools@0.13.4
## 1.0.83
### Patch Changes
- Updated dependencies [12f8bfa]
- Updated dependencies [bd57177]
- jazz-tools@0.13.3
- jazz-expo@0.13.3
## 1.0.82
### Patch Changes
- jazz-expo@0.13.2
- jazz-tools@0.13.2
## 1.0.81
### Patch Changes
- Updated dependencies [63a7aa0]
- jazz-expo@0.13.1
## 1.0.80
### Patch Changes
- Updated dependencies [bce3bcc]
- Updated dependencies [afd1374]
- jazz-expo@0.13.0
- jazz-tools@0.13.0
## 1.0.88
### Patch Changes
- jazz-react-native@0.12.2
- jazz-tools@0.12.2
## 1.0.87
### Patch Changes
- jazz-react-native@0.12.1
- jazz-tools@0.12.1
## 1.0.86
### Patch Changes
- Updated dependencies [01523dc]
- Updated dependencies [4ea87dc]
- Updated dependencies [1e6da19]
- Updated dependencies [b6c6a0a]
- jazz-tools@0.12.0
- jazz-react-native@0.12.0
## 1.0.85
### Patch Changes
- jazz-react-native@0.11.8
- jazz-tools@0.11.8
## 1.0.84
### Patch Changes
- Updated dependencies [a140f55]
- Updated dependencies [2b0d1b0]
- jazz-tools@0.11.7
- jazz-react-native@0.11.7
## 1.0.83
### Patch Changes
- Updated dependencies [e7c85b7]
- jazz-react-native@0.11.6
- jazz-tools@0.11.6
## 1.0.82
### Patch Changes
- jazz-react-native@0.11.5
- jazz-tools@0.11.5
## 1.0.81
### Patch Changes
- Updated dependencies [57a3dbe]
- Updated dependencies [a717754]
- Updated dependencies [a91f343]
- jazz-tools@0.11.4
- jazz-react-native@0.11.4
## 1.0.80
### Patch Changes
- jazz-react-native@0.11.3
- jazz-tools@0.11.3
## 1.0.79
### Patch Changes
- Updated dependencies [6892dc6]
- jazz-tools@0.11.2
- jazz-react-native@0.11.2
## 1.0.78
### Patch Changes
- jazz-react-native@0.11.1
## 1.0.77
### Patch Changes
- Updated dependencies [6a96d8b]
- Updated dependencies [a35249a]
- Updated dependencies [b9d194a]
- Updated dependencies [a4713df]
- Updated dependencies [34cbdc3]
- Updated dependencies [f039e8f]
- Updated dependencies [e22de9f]
- jazz-tools@0.11.0
- jazz-react-native@0.11.0
## 1.0.76
### Patch Changes
- Updated dependencies [2f99de0]
- jazz-tools@0.10.15
- jazz-react-native@0.10.15
## 1.0.75
### Patch Changes
- Updated dependencies [75211e3]
- jazz-tools@0.10.14
- jazz-react-native@0.10.14
## 1.0.74
### Patch Changes
- Updated dependencies [07feedd]
- jazz-tools@0.10.13
- jazz-react-native@0.10.13
## 1.0.73
### Patch Changes
- Updated dependencies [4612e05]
- jazz-tools@0.10.12
- jazz-react-native@0.10.12
## 1.0.72
### Patch Changes
- Updated dependencies [5a54e4a]
- jazz-react-native@0.10.11
## 1.0.71
### Patch Changes
- Updated dependencies [3405d8f]
- jazz-react-native@0.10.10
## 1.0.70
### Patch Changes
- Updated dependencies [2fb6428]
- jazz-tools@0.10.8
- jazz-react-native@0.10.8
## 1.0.69
### Patch Changes
- Updated dependencies [1136d9b]
- Updated dependencies [0eed228]
- jazz-react-native@0.10.7
- jazz-tools@0.10.7
## 1.0.68
### Patch Changes
- Updated dependencies [ada802b]
- jazz-tools@0.10.6
- jazz-react-native@0.10.6
## 1.0.67
### Patch Changes
- Updated dependencies [59ff77e]
- jazz-tools@0.10.5
- jazz-react-native@0.10.5
## 1.0.66
### Patch Changes
- jazz-react-native@0.10.4
- jazz-tools@0.10.4
## 1.0.65
### Patch Changes
- Updated dependencies [d8582fc]
- jazz-tools@0.10.3
- jazz-react-native@0.10.3
## 1.0.64
### Patch Changes
- jazz-react-native@0.10.2
- jazz-tools@0.10.2
## 1.0.63
### Patch Changes
- Updated dependencies [5a63cba]
- jazz-tools@0.10.1
- jazz-react-native@0.10.1
## 1.0.62
### Patch Changes
- Updated dependencies [498954f]
- Updated dependencies [d42c2aa]
- Updated dependencies [dd03464]
- Updated dependencies [b426342]
- jazz-react-native@0.10.0
- jazz-tools@0.10.0
## 1.0.61
### Patch Changes
- jazz-react-native@0.9.23
- jazz-tools@0.9.23
## 1.0.60
### Patch Changes
- jazz-react-native@0.9.22
## 1.0.59
### Patch Changes
- Updated dependencies [1be017d]
- jazz-tools@0.9.21
- jazz-react-native@0.9.21
## 1.0.58
### Patch Changes
- Updated dependencies [b01cc1f]
- jazz-tools@0.9.20
- jazz-react-native@0.9.20
## 1.0.57
### Patch Changes
- jazz-react-native@0.9.19
- jazz-tools@0.9.19
## 1.0.56
### Patch Changes
- jazz-react-native@0.9.18
- jazz-tools@0.9.18
## 1.0.55
### Patch Changes
- Updated dependencies [c2ca1fe]
- Updated dependencies [1227047]
- jazz-tools@0.9.17
- jazz-react-native@0.9.17
## 1.0.54
### Patch Changes
- Updated dependencies [24b3b6a]
- jazz-tools@0.9.16
- jazz-react-native@0.9.16
## 1.0.53
### Patch Changes
- Updated dependencies [7491711]
- jazz-tools@0.9.15
- jazz-react-native@0.9.15
## 1.0.52
### Patch Changes
- Updated dependencies [3df93cc]
- jazz-tools@0.9.14
- jazz-react-native@0.9.14
## 1.0.51
### Patch Changes
- jazz-react-native@0.9.13
- jazz-tools@0.9.13
## 1.0.50
### Patch Changes
- jazz-react-native@0.9.12
- jazz-tools@0.9.12
## 1.0.49
### Patch Changes
- jazz-react-native@0.9.11
- jazz-tools@0.9.11
## 1.0.48
### Patch Changes
- Updated dependencies [f76274c]
- Updated dependencies [5e83864]
- jazz-react-native@0.9.10
- jazz-tools@0.9.10
## 1.0.47
### Patch Changes
- Updated dependencies [8eb9247]
- jazz-tools@0.9.9
- jazz-react-native@0.9.9
## 1.0.46
### Patch Changes
- Updated dependencies [d1d773b]
- jazz-tools@0.9.8
- jazz-react-native@0.9.8
## 1.0.45
### Patch Changes
- Updated dependencies [8a390d2]
- jazz-react-native@0.9.6
## 1.0.44
### Patch Changes
- Updated dependencies [c871912]
- jazz-react-native@0.9.5
## 1.0.43
### Patch Changes
- jazz-react-native@0.9.4
## 1.0.42
### Patch Changes
- Updated dependencies [7cd691f]
- jazz-react-native@0.9.3
## 1.0.41
### Patch Changes
- Updated dependencies [80fd3e9]
- jazz-react-native@0.9.2
## 1.0.40
### Patch Changes
- Updated dependencies [1b71969]
- jazz-tools@0.9.1
- jazz-react-native@0.9.1
## 1.0.39
### Patch Changes
- Updated dependencies [1da4d55]
- Updated dependencies [8eda792]
- Updated dependencies [1e5e3a1]
- jazz-react-native@0.9.0
- jazz-tools@0.9.0
## 1.0.38
### Patch Changes
- Updated dependencies [dc62b95]
- Updated dependencies [1de26f8]
- jazz-tools@0.8.51
- jazz-react-native@0.8.51
## 1.0.37
### Patch Changes
- jazz-react-native@0.8.50
- jazz-tools@0.8.50
## 1.0.36
### Patch Changes
- jazz-react-native@0.8.49
- jazz-tools@0.8.49
## 1.0.35
### Patch Changes
- Updated dependencies [635e824]
- Updated dependencies [0a85982]
- jazz-tools@0.8.48
- jazz-react-native@0.8.48
## 1.0.34
### Patch Changes
- Updated dependencies [33ef9c4]
- jazz-react-native@0.8.47
## 1.0.33
### Patch Changes
- Updated dependencies [ab4ffbd]
- jazz-react-native@0.8.46
## 1.0.32
### Patch Changes
- Updated dependencies [7701307]
- Updated dependencies [fa41f8e]
- Updated dependencies [88d7d9a]
- Updated dependencies [60e35ea]
- jazz-react-native@0.8.45
- jazz-tools@0.8.45
## 1.0.31
### Patch Changes
- jazz-react-native@0.8.44
- jazz-tools@0.8.44
## 1.0.30
### Patch Changes
- jazz-react-native@0.8.41
- jazz-tools@0.8.41
## 1.0.29
### Patch Changes
- Updated dependencies [0c6b0f3]
- Updated dependencies [249eecb]
- jazz-react-native@0.8.39
- jazz-tools@0.8.39
## 1.0.28
### Patch Changes
- jazz-react-native@0.8.38
- jazz-tools@0.8.38
## 1.0.27
### Patch Changes
- jazz-react-native@0.8.37
- jazz-tools@0.8.37
## 1.0.26
### Patch Changes
- Updated dependencies [c84764a]
- Updated dependencies [441fe27]
- jazz-react-native@0.8.36
- jazz-tools@0.8.36
## 1.0.25
### Patch Changes
- Updated dependencies [8b87117]
- jazz-tools@0.8.35
- jazz-react-native@0.8.35
## 1.0.24
### Patch Changes
- jazz-react-native@0.8.34
- jazz-tools@0.8.34
## 1.0.23
### Patch Changes
- Updated dependencies [df42b2b]
- jazz-tools@0.8.32
- jazz-react-native@0.8.32
## 1.0.22
### Patch Changes
- jazz-react-native@0.8.31
- jazz-tools@0.8.31
## 1.0.21
### Patch Changes
- jazz-react-native@0.8.30
- jazz-tools@0.8.30
## 1.0.20
### Patch Changes
- jazz-react-native@0.8.29
- jazz-tools@0.8.29
## 1.0.19
### Patch Changes
- jazz-react-native@0.8.28
- jazz-tools@0.8.28
## 1.0.18
### Patch Changes
- jazz-react-native@0.8.27
- jazz-tools@0.8.27
## 1.0.17
### Patch Changes
- Updated dependencies [d348c2d]
- Updated dependencies [6902b5b]
- Updated dependencies [1a0cd3d]
- jazz-tools@0.8.23
- jazz-react-native@0.8.23
## 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
- jazz-expo@0.14.16
- jazz-tools@0.14.16
## 1.0.6
### Patch Changes
- jazz-react-native@0.8.11
- jazz-tools@0.8.11
- jazz-expo@0.14.15
- jazz-tools@0.14.15
## 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
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-expo@0.14.14
## 1.0.4
### Patch Changes
- Updated dependencies [32b05b6]
- jazz-react-native@0.8.7
- jazz-expo@0.14.13
## 1.0.3
### Patch Changes
- jazz-react-native@0.8.6
- jazz-expo@0.14.12
## 1.0.2
### Patch Changes
- Updated dependencies [c3f4e6b]
- Updated dependencies [d9152ed]
- jazz-react-native@0.8.5
- jazz-tools@0.8.5
- Updated dependencies [98d697f]
- jazz-expo@0.14.11
## 1.0.1
### Patch Changes
- Updated dependencies
- jazz-react-native@0.8.3
- jazz-tools@0.8.3
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-tools@0.14.10
- jazz-expo@0.14.10

View File

@@ -1,24 +0,0 @@
# 🎷 Jazz + Expo + `react-navigation` + Demo Auth
## 🚀 How to Run
### 1. Inside the Workspace Root
First, install dependencies and build the project:
```bash
pnpm i
pnpm run build
```
### 2. Inside the `examples/chat-rn-expo` Directory
Next, navigate to the specific example project and run the following commands:
```bash
pnpm expo prebuild
pnpx pod-install
pnpm expo run:ios
```
This will set up and launch the app on iOS. For Android, you can replace the last command with `pnpm expo run:android`.

View File

@@ -1,55 +0,0 @@
const { withBuildProperties } = require("expo-build-properties");
const { withDangerousMod } = require("@expo/config-plugins");
const fs = require("fs/promises");
const path = require("path");
/**
* https://github.com/mrousavy/nitro/issues/422#issuecomment-2545988256
*/
function withCustomIosMod(config) {
// Use expo-build-properties to bump iOS deployment target
config = withBuildProperties(config, { ios: { deploymentTarget: "16.0" } });
// Patch the generated Podfile fallback to ensure platform is always 16.0
config = withDangerousMod(config, [
"ios",
async (modConfig) => {
const podfilePath = path.join(
modConfig.modRequest.platformProjectRoot,
"Podfile",
);
let contents = await fs.readFile(podfilePath, "utf-8");
// Check if the IPHONEOS_DEPLOYMENT_TARGET setting is already present
// We search for the key being assigned, e.g., config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] =
const deploymentTargetSettingExists =
/\.build_settings\s*\[\s*['"]IPHONEOS_DEPLOYMENT_TARGET['"]\s*\]\s*=/.test(
contents,
);
if (!deploymentTargetSettingExists) {
// IPHONEOS_DEPLOYMENT_TARGET setting not found, proceed to add it.
contents = contents.replace(
/(post_install\s+do\s+\|installer\|[\s\S]*?)(\r?\n\s end\s*)$/m,
`$1
# Expo Build Properties: force deployment target
# https://github.com/mrousavy/nitro/issues/422#issuecomment-2545988256
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '16.0'
end
end
$2`,
);
}
await fs.writeFile(podfilePath, contents);
return modConfig;
},
]);
return config;
}
module.exports = ({ config }) => {
return withCustomIosMod(config);
};

View File

@@ -1,39 +1,32 @@
{
"expo": {
"name": "jazz-chat-rn-expo",
"scheme": "jazz-chat-rn-expo",
"slug": "jazz-chat-rn-expo",
"name": "chat-rn-expo",
"slug": "chat-rn-expo",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"newArchEnabled": true,
"splash": {
"image": "./assets/splash.png",
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.jazz.chatrn"
"bundleIdentifier": "com.anonymous.chatrnexpo"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.jazz.chatrn"
"edgeToEdgeEnabled": true,
"package": "com.anonymous.chatrnexpo"
},
"plugins": [
"expo-secure-store",
"expo-sqlite",
"expo-build-properties",
"expo-web-browser"
],
"extra": {
"eas": {
"projectId": "e0e61872-1906-4c84-b9d8-9be77355cad0"
}
"web": {
"favicon": "./assets/favicon.png"
},
"owner": "paxx"
"plugins": ["expo-secure-store", "expo-sqlite"]
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -1,9 +0,0 @@
module.exports = function (api) {
api.cache(true);
return {
presets: [
["babel-preset-expo", { jsxImportSource: "nativewind" }],
"nativewind/babel",
],
};
};

View File

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

View File

@@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -1,4 +0,0 @@
import "./polyfills";
import { registerRootComponent } from "expo";
import App from "./src/App";
registerRootComponent(App);

View File

@@ -0,0 +1,9 @@
import { registerRootComponent } from "expo";
import "./polyfills";
import App from "./src/App";
// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);

View File

@@ -1,35 +0,0 @@
// Learn more https://docs.expo.dev/guides/monorepos
const { getDefaultConfig } = require("expo/metro-config");
const { withNativeWind } = require("nativewind/metro");
const { FileStore } = require("metro-cache");
const path = require("path");
// eslint-disable-next-line no-undef
const projectRoot = __dirname;
const workspaceRoot = path.resolve(projectRoot, "../..");
const config = getDefaultConfig(projectRoot, { isCSSEnabled: true });
// Since we are using pnpm, we have to setup the monorepo manually for Metro
// #1 - Watch all files in the monorepo
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"),
];
config.resolver.sourceExts = ["mjs", "js", "json", "ts", "tsx"];
config.resolver.requireCycleIgnorePatterns = [
/(^|\/|\\)node_modules($|\/|\\)/,
/(^|\/|\\)packages($|\/|\\)/,
];
// Use turborepo to restore the cache when possible
config.cacheStores = [
new FileStore({
root: path.join(projectRoot, "node_modules", ".cache", "metro"),
}),
];
// module.exports = config;
module.exports = withNativeWind(config, { input: "./global.css" });

View File

@@ -1 +0,0 @@
/// <reference types="nativewind/types" />

View File

@@ -1,53 +1,35 @@
{
"name": "chat-rn-expo",
"version": "1.0.117",
"main": "index.js",
"version": "1.0.7",
"main": "index.ts",
"scripts": {
"build": "tsc --noEmit && expo export -p ios",
"build": "expo prebuild",
"start": "expo start",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"android": "expo run:android",
"ios": "expo prebuild && pnpx pod-install && expo run:ios",
"ios": "expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0",
"@craftzdog/react-native-buffer": "6.0.5",
"@bacons/text-decoder": "^0.0.0",
"@craftzdog/react-native-buffer": "^6.0.5",
"@react-native-community/netinfo": "11.4.1",
"@react-navigation/native": "7.0.19",
"@react-navigation/native-stack": "7.2.1",
"clsx": "^2.0.0",
"expo": "53.0.8",
"expo-build-properties": "~0.14.6",
"expo-clipboard": "~7.1.4",
"expo-constants": "~17.1.6",
"expo-dev-client": "~5.1.8",
"expo-linking": "~7.1.4",
"expo": "~53.0.9",
"expo-clipboard": "^7.1.4",
"expo-secure-store": "~14.2.3",
"expo-sqlite": "15.2.9",
"expo-sqlite": "~15.2.10",
"expo-status-bar": "~2.2.3",
"expo-web-browser": "~14.1.6",
"jazz-expo": "workspace:*",
"jazz-tools": "workspace:*",
"nativewind": "^4.1.21",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-native": "0.79.2",
"react-native-get-random-values": "^1.11.0",
"react-native-safe-area-context": "5.4.0",
"react-native-screens": "4.10.0",
"react-native-nitro-modules": "0.25.2",
"react-native-quick-crypto": "1.0.0-beta.15",
"react-native-url-polyfill": "^2.0.0",
"readable-stream": "4.7.0"
"readable-stream": "^4.7.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
"@types/react": "~19.0.14",
"tailwindcss": "^3.4.17",
"typescript": "5.8.3"
"@types/react": "~19.0.10",
"typescript": "~5.8.3"
},
"private": true
}

View File

@@ -1,74 +1,18 @@
import "../global.css";
import {
NavigationContainer,
useNavigationContainerRef,
} from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import * as Linking from "expo-linking";
import { RNQuickCrypto } from "jazz-expo/crypto";
import React, { StrictMode, useEffect, useState } from "react";
import HandleInviteScreen from "./invite";
import { JazzProvider } from "jazz-expo";
import React, { StrictMode } from "react";
import { apiKey } from "./apiKey";
import ChatScreen from "./chat";
const Stack = createNativeStackNavigator();
const prefix = Linking.createURL("/");
const linking = {
prefixes: [prefix],
config: {
screens: {
HandleInviteScreen: {
path: "router/invite/:valueHint?/:valueID/:inviteSecret",
},
},
},
};
function App() {
const [initialRoute, setInitialRoute] = useState<
"ChatScreen" | "HandleInviteScreen"
>("ChatScreen");
const navigationRef = useNavigationContainerRef();
useEffect(() => {
Linking.getInitialURL().then((url) => {
if (url) {
if (url && url.includes("invite")) {
setInitialRoute("HandleInviteScreen");
}
}
});
}, []);
export default function App() {
return (
<StrictMode>
<JazzProvider
CryptoProvider={RNQuickCrypto}
sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}}
>
<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>
<ChatScreen />
</JazzProvider>
</StrictMode>
);
}
export default App;

View File

@@ -1,7 +1,6 @@
import clsx from "clsx";
import * as Clipboard from "expo-clipboard";
import { Group, ID, Loaded, Profile } from "jazz-tools";
import { useEffect, useState } from "react";
import { Account, Group } from "jazz-tools";
import { useState } from "react";
import React, {
Button,
FlatList,
@@ -12,54 +11,38 @@ import React, {
TouchableOpacity,
View,
Alert,
StyleSheet,
} from "react-native";
import { useAccount, useCoState } from "jazz-expo";
import { Chat, Message } from "./schema";
export default function ChatScreen({ navigation }: { navigation: any }) {
const { me, logOut } = useAccount();
export default function ChatScreen() {
const { me, logOut } = useAccount(Account, { resolve: { profile: true } });
const [chatId, setChatId] = useState<string>();
const [chatIdInput, setChatIdInput] = useState<string>();
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});
function handleLogOut() {
setChatId(undefined);
logOut();
}
useEffect(() => {
navigation.setOptions({
headerRight: () => <Button onPress={handleLogOut} title="Logout" />,
headerLeft: () =>
loadedChat ? (
<Button
onPress={() => {
if (loadedChat?.id) {
Clipboard.setStringAsync(
`https://chat.jazz.tools/#/chat/${loadedChat.id}`,
);
Alert.alert("Copied to clipboard", `Chat ID: ${loadedChat.id}`);
}
}}
title="Share"
/>
) : null,
});
}, [navigation, loadedChat]);
const createChat = () => {
const group = Group.create({ owner: me });
const group = Group.create();
group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group });
const chat = Chat.create([], group);
setChatId(chat.id);
};
const joinChat = () => {
if (chatIdInput) {
setChatId(chatIdInput);
if (chatIdInput.startsWith("https://chat.jazz.tools/#/chat/")) {
setChatId(chatIdInput.split("/").pop());
} else {
setChatId(chatIdInput);
}
} else {
Alert.alert("Error", "Chat ID cannot be empty.");
}
@@ -75,41 +58,28 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
}
};
const renderMessageItem = ({ item }: { item: Loaded<typeof Message> }) => {
const renderMessageItem = ({ item }: { item: Message }) => {
const isMe = item._edits?.text?.by?.isMe;
return (
<View
className={clsx(
`rounded-lg p-1 px-1.5 max-w-[80%] `,
isMe ? `bg-gray-200 self-end text-right` : `bg-gray-300 self-start `,
)}
style={[
styles.messageContainer,
isMe ? styles.myMessage : styles.otherMessage,
]}
>
{!isMe ? (
<Text
className={clsx(
`text-xs text-gray-500`,
isMe ? "text-right" : "text-left",
)}
style={[
styles.messageSender,
{ textAlign: isMe ? "right" : "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(`text-black text-md max-w-[85%]`)}>
{item.text}
</Text>
<Text
className={clsx(
"text-[10px] text-gray-500 text-right ml-2",
!isMe ? "mt-2" : "mt-1",
)}
>
<View style={styles.messageContent}>
<Text style={styles.messageText}>{item.text}</Text>
<Text style={[styles.messageTime, { marginTop: !isMe ? 8 : 4 }]}>
{item?._edits?.text?.madeAt?.getHours().toString().padStart(2, "0")}
:
{item?._edits?.text?.madeAt
@@ -123,31 +93,28 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
};
return (
<View className="flex flex-col h-full">
<View style={styles.container}>
{!loadedChat ? (
<View className="flex flex-col h-full items-center justify-center">
<Text className="text-m font-bold mb-6">Username</Text>
<View style={styles.welcomeContainer}>
<Text style={styles.usernameTitle}>Username</Text>
<TextInput
className="rounded h-12 p-2 mb-12 w-40 border border-gray-200 block"
value={profile?.name ?? ""}
style={styles.usernameInput}
value={me?.profile.name ?? ""}
onChangeText={(value) => {
if (profile) {
profile.name = value;
if (me?.profile) {
me.profile.name = value;
}
}}
textAlignVertical="center"
onSubmitEditing={sendMessage}
testID="username-input"
/>
<TouchableOpacity
onPress={createChat}
className="bg-blue-500 p-4 rounded-md"
>
<Text className="text-white font-semibold">Start new chat</Text>
<TouchableOpacity onPress={createChat} style={styles.newChatButton}>
<Text style={styles.newChatButtonText}>Start new chat</Text>
</TouchableOpacity>
<Text className="text-m font-bold mt-6">Join existing chat</Text>
<Text style={styles.joinChatTitle}>Join existing chat</Text>
<TextInput
className="rounded h-12 p-2 m-2 mt-4 w-80 border border-gray-200 block"
style={styles.chatIdInput}
placeholder="Chat ID"
value={chatIdInput ?? ""}
onChangeText={(value) => {
@@ -161,22 +128,38 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
}}
testID="chat-id-input"
/>
<TouchableOpacity
onPress={joinChat}
className="bg-green-500 p-4 rounded-md"
>
<Text className="text-white font-semibold">Join chat</Text>
<TouchableOpacity onPress={joinChat} style={styles.joinChatButton}>
<Text style={styles.newChatButtonText}>Join chat</Text>
</TouchableOpacity>
</View>
) : (
<>
<View style={styles.chatHeader}>
<Button
onPress={() => {
if (loadedChat?.id) {
Clipboard.setStringAsync(
`https://chat.jazz.tools/#/chat/${loadedChat.id}`,
);
Alert.alert(
"Copied to clipboard",
`Chat ID: ${loadedChat.id}`,
);
}
}}
title="Share"
/>
<Text style={{ fontWeight: "bold", fontSize: 18 }}>Jazz chat</Text>
<Button onPress={handleLogOut} title="Logout" />
</View>
<FlatList
contentContainerStyle={{
flexGrow: 1,
gap: 6,
padding: 8,
justifyContent: "flex-end",
}}
className="flex"
style={styles.messageList}
data={loadedChat}
keyExtractor={(item) => item.id}
renderItem={renderMessageItem}
@@ -185,11 +168,11 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
<KeyboardAvoidingView
keyboardVerticalOffset={110}
behavior="padding"
className="p-3 bg-white border-t border-gray-300"
style={styles.inputContainer}
>
<SafeAreaView className="flex flex-row items-center gap-2">
<SafeAreaView style={styles.inputRow}>
<TextInput
className="rounded-full h-8 py-0 px-2 border border-gray-200 block flex-1"
style={styles.messageInput}
value={message}
onChangeText={setMessage}
placeholder="Type a message..."
@@ -199,7 +182,7 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
/>
<TouchableOpacity
onPress={sendMessage}
className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center"
style={styles.sendButton}
testID="send-button"
>
<Text></Text>
@@ -211,3 +194,133 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
height: "100%",
},
chatHeader: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
padding: 8,
paddingTop: 48,
backgroundColor: "#f0f0f0",
},
welcomeContainer: {
flex: 1,
flexDirection: "column",
height: "100%",
alignItems: "center",
justifyContent: "center",
},
usernameTitle: {
fontSize: 16,
fontWeight: "bold",
marginBottom: 24,
},
usernameInput: {
borderRadius: 4,
height: 48,
padding: 8,
marginBottom: 48,
width: 160,
borderWidth: 1,
borderColor: "#e5e5e5",
},
newChatButton: {
backgroundColor: "#3b82f6",
padding: 16,
borderRadius: 6,
},
newChatButtonText: {
color: "white",
fontWeight: "600",
},
joinChatTitle: {
fontSize: 16,
fontWeight: "bold",
marginTop: 24,
},
chatIdInput: {
borderRadius: 4,
height: 48,
padding: 8,
margin: 8,
marginTop: 16,
width: 320,
borderWidth: 1,
borderColor: "#e5e5e5",
},
joinChatButton: {
backgroundColor: "#22c55e",
padding: 16,
borderRadius: 6,
},
messageList: {
display: "flex",
},
messageContainer: {
borderRadius: 8,
padding: 4,
paddingHorizontal: 6,
maxWidth: "80%",
},
myMessage: {
backgroundColor: "#e5e5e5",
alignSelf: "flex-end",
},
otherMessage: {
backgroundColor: "#d4d4d4",
alignSelf: "flex-start",
},
messageSender: {
fontSize: 12,
color: "#6b7280",
},
messageContent: {
flexDirection: "row",
alignItems: "flex-end",
justifyContent: "space-between",
},
messageText: {
color: "black",
fontSize: 16,
maxWidth: "85%",
},
messageTime: {
fontSize: 10,
color: "#6b7280",
marginLeft: 8,
},
inputContainer: {
padding: 12,
backgroundColor: "white",
borderTopWidth: 1,
borderTopColor: "#d4d4d4",
},
inputRow: {
flexDirection: "row",
alignItems: "center",
gap: 8,
},
messageInput: {
borderRadius: 9999,
height: 32,
paddingVertical: 0,
paddingHorizontal: 8,
borderWidth: 1,
borderColor: "#e5e5e5",
flex: 1,
},
sendButton: {
backgroundColor: "#d4d4d4",
borderRadius: 9999,
height: 32,
width: 32,
alignItems: "center",
justifyContent: "center",
},
});

View File

@@ -1,18 +0,0 @@
import { useAcceptInvite } from "jazz-expo";
import React, { Text } from "react-native";
import { Chat } from "./schema";
export default function HandleInviteScreen({
navigation,
}: {
navigation: any;
}) {
useAcceptInvite({
invitedObjectSchema: Chat,
onAccept: async (chatId) => {
navigation.navigate("ChatScreen", { chatId });
},
});
return <Text>Accepting invite...</Text>;
}

View File

@@ -3,5 +3,7 @@ import { co, z } from "jazz-tools";
export const Message = co.map({
text: z.string(),
});
export type Message = co.loaded<typeof Message>;
export const Chat = co.list(Message);
export type Chat = co.loaded<typeof Chat>;

View File

@@ -1,14 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
// NOTE: Update this to include the paths to all of your component files.
content: [
"./app/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./src/**/*.{js,jsx,ts,tsx}",
],
presets: [require("nativewind/preset")],
theme: {
extend: {},
},
plugins: [],
};

View File

@@ -8,10 +8,7 @@ appId: com.jazz.chatrn
# - assertVisible: "Reload"
# - tapOn: "Reload"
# login
- assertVisible: "Logout"
- tapOn: "Logout"
- assertVisible: "Anonymous user"
- assertVisible: "Username"
- runFlow:
label: "Erase existing username"
file: erase_text.yml
@@ -43,12 +40,13 @@ appId: com.jazz.chatrn
# logout
- tapOn: "Logout"
- assertVisible: "Username"
- assertVisible: "Anonymous user"
# join chat
- tapOn:
id: "chat-id-input"
- inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
- tapOn: "Join chat"
- assertVisible: "boorad"
- assertVisible: "bro, low key, it do be like that tho"
# - tapOn:
# id: "chat-id-input"
# - inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
# - tapOn: "Join chat"
# - assertVisible: "boorad"
# - assertVisible: "bro, low key, it do be like that tho"

View File

@@ -3,14 +3,14 @@
# This script is necessary, because unlike ios, the android emulator action
# accepts a script, runs it as your tests, then terminates.
set -e
# set -e
# build and install the app
echo "Building and installing Android app."
echo "If it fails, its output will be in artifact: android-install.log..."
cd ./android/
./gradlew installRelease >> ~/output/android-install.log 2>&1
cd ..
# # build and install the app
# echo "Building and installing Android app."
# echo "If it fails, its output will be in artifact: android-install.log..."
# cd ./android/
# ./gradlew installRelease >> ~/output/android-install.log 2>&1
# cd ..
# run the e2e tests
export PATH="$PATH":"$HOME/.maestro/bin"

View File

@@ -1,8 +1,6 @@
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true,
"moduleResolution": "bundler"
},
"exclude": ["src/tests"]
"strict": true
}
}

View File

@@ -1,5 +1,78 @@
# chat-rn
## 1.0.134
### Patch Changes
- Updated dependencies [5e253cc]
- cojson@0.14.16
- cojson-transport-ws@0.14.16
- jazz-react-native@0.14.16
- jazz-tools@0.14.16
## 1.0.133
### Patch Changes
- Updated dependencies [23daa7c]
- cojson@0.14.15
- jazz-react-native@0.14.15
- cojson-transport-ws@0.14.15
- jazz-tools@0.14.15
## 1.0.132
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react-native@0.14.14
## 1.0.131
### Patch Changes
- jazz-react-native@0.14.13
## 1.0.130
### Patch Changes
- jazz-react-native@0.14.12
## 1.0.129
### Patch Changes
- Updated dependencies [98d697f]
- jazz-react-native@0.14.11
## 1.0.128
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react-native@0.14.10
- jazz-tools@0.14.10
## 1.0.127
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-react-native@0.14.9
## 1.0.126
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-react-native@0.14.8
## 1.0.125
### Patch Changes

View File

@@ -1,6 +1,6 @@
{
"name": "chat-rn",
"version": "1.0.125",
"version": "1.0.134",
"main": "index.js",
"scripts": {
"android": "react-native run-android",
@@ -23,7 +23,7 @@
"cojson-transport-ws": "workspace:*",
"jazz-react-native": "workspace:*",
"jazz-tools": "workspace:*",
"react": "18.3.1",
"react": "19.0.0",
"react-native": "0.79.2",
"react-native-get-random-values": "^1.11.0",
"react-native-mmkv": "^3.2.0",

View File

@@ -1,5 +1,59 @@
# chat-vue
## 0.0.114
### Patch Changes
- jazz-browser@0.14.16
- jazz-tools@0.14.16
- jazz-vue@0.14.16
## 0.0.113
### Patch Changes
- jazz-browser@0.14.15
- jazz-tools@0.14.15
- jazz-vue@0.14.15
## 0.0.112
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-browser@0.14.14
- jazz-vue@0.14.14
## 0.0.111
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-tools@0.14.10
- jazz-browser@0.14.10
- jazz-vue@0.14.10
## 0.0.110
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-browser@0.14.9
- jazz-vue@0.14.9
## 0.0.109
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-browser@0.14.8
- jazz-vue@0.14.8
## 0.0.108
### Patch Changes

View File

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

View File

@@ -1,5 +1,75 @@
# jazz-example-chat
## 0.0.214
### Patch Changes
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.213
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-inspector@0.14.15
- jazz-tools@0.14.15
## 0.0.212
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
## 0.0.211
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
## 0.0.210
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
## 0.0.209
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-inspector@0.14.10
- hash-slash@0.2.3
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.208
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-inspector@0.14.9
- jazz-react@0.14.9
## 0.0.207
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-inspector@0.14.8
- jazz-react@0.14.8
## 0.0.206
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-chat",
"private": true,
"version": "0.0.206",
"version": "0.0.214",
"type": "module",
"scripts": {
"dev": "vite",
@@ -19,14 +19,14 @@
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"zod": "4.0.0-beta.20250505T012514"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"is-ci": "^3.0.1",

View File

@@ -1,5 +1,74 @@
# minimal-auth-clerk
## 0.0.113
### Patch Changes
- jazz-react@0.14.16
- jazz-react-auth-clerk@0.14.16
- jazz-tools@0.14.16
## 0.0.112
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-react-auth-clerk@0.14.15
- jazz-tools@0.14.15
## 0.0.111
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
- jazz-react-auth-clerk@0.14.14
## 0.0.110
### Patch Changes
- jazz-react@0.14.13
- jazz-react-auth-clerk@0.14.13
## 0.0.109
### Patch Changes
- jazz-react@0.14.12
- jazz-react-auth-clerk@0.14.12
## 0.0.108
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react-auth-clerk@0.14.10
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.107
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-react@0.14.9
- jazz-react-auth-clerk@0.14.9
## 0.0.106
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-react@0.14.8
- jazz-react-auth-clerk@0.14.8
## 0.0.105
### Patch Changes

View File

@@ -2,7 +2,7 @@
This is an example of how to use clerk authentication with Jazz.
Live version: https://clerk-demo.jazz.tools
Live version: [https://clerk-demo.jazz.tools](https://clerk-demo.jazz.tools)
## Getting started

View File

@@ -1,7 +1,7 @@
{
"name": "clerk",
"private": true,
"version": "0.0.105",
"version": "0.0.113",
"type": "module",
"scripts": {
"dev": "vite",
@@ -17,14 +17,14 @@
"jazz-react": "workspace:*",
"jazz-react-auth-clerk": "workspace:*",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@biomejs/biome": "1.9.4",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0",
"typescript": "5.6.2",

View File

@@ -4,6 +4,7 @@ import { createRoot } from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { JazzProviderWithClerk } from "jazz-react-auth-clerk";
import { ReactNode } from "react";
import { apiKey } from "./apiKey";
// Import your publishable key
@@ -13,7 +14,7 @@ if (!PUBLISHABLE_KEY) {
throw new Error("Add your Clerk publishable key to the .env.local file");
}
function JazzProvider({ children }: { children: React.ReactNode }) {
function JazzProvider({ children }: { children: ReactNode }) {
const clerk = useClerk();
return (

View File

@@ -1,5 +1,71 @@
# file-share-svelte
## 0.0.98
### Patch Changes
- jazz-svelte@0.14.16
- jazz-tools@0.14.16
- jazz-inspector-element@0.14.16
## 0.0.97
### Patch Changes
- jazz-svelte@0.14.15
- jazz-tools@0.14.15
- jazz-inspector-element@0.14.15
## 0.0.96
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector-element@0.14.14
- jazz-svelte@0.14.14
## 0.0.95
### Patch Changes
- jazz-inspector-element@0.14.13
## 0.0.94
### Patch Changes
- jazz-inspector-element@0.14.12
## 0.0.93
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-tools@0.14.10
- jazz-inspector-element@0.14.10
- jazz-svelte@0.14.10
## 0.0.92
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-inspector-element@0.14.9
- jazz-svelte@0.14.9
## 0.0.91
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-inspector-element@0.14.8
- jazz-svelte@0.14.8
## 0.0.90
### Patch Changes

View File

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

View File

@@ -1,5 +1,74 @@
# jazz-tailwind-demo-auth-starter
## 0.0.53
### Patch Changes
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.52
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-inspector@0.14.15
- jazz-tools@0.14.15
## 0.0.51
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
## 0.0.50
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
## 0.0.49
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
## 0.0.48
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-inspector@0.14.10
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.47
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-inspector@0.14.9
- jazz-react@0.14.9
## 0.0.46
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-inspector@0.14.8
- jazz-react@0.14.8
## 0.0.45
### Patch Changes

View File

@@ -2,7 +2,7 @@
This is an example of how to upload and render images with Jazz.
Live version: https://file-upload-demo.jazz.tools
Live version: [https://file-upload-demo.jazz.tools](https://file-upload-demo.jazz.tools)
## Getting started

View File

@@ -1,7 +1,7 @@
{
"name": "filestream",
"private": true,
"version": "0.0.45",
"version": "0.0.53",
"type": "module",
"scripts": {
"dev": "vite",
@@ -14,13 +14,13 @@
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"jazz-inspector": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",

View File

@@ -1,5 +1,67 @@
# form
## 0.1.54
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.1.53
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.1.52
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.1.51
### Patch Changes
- jazz-react@0.14.13
## 0.1.50
### Patch Changes
- jazz-react@0.14.12
## 0.1.49
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- hash-slash@0.2.3
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.1.48
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-react@0.14.9
## 0.1.47
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-react@0.14.8
## 0.1.46
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "form",
"private": true,
"version": "0.1.46",
"version": "0.1.54",
"type": "module",
"scripts": {
"dev": "vite",
@@ -14,15 +14,15 @@
"hash-slash": "workspace:*",
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@playwright/test": "^1.50.1",
"@tailwindcss/forms": "^0.5.9",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",

View File

@@ -1,5 +1,66 @@
# image-upload
## 0.0.110
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.109
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.108
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.107
### Patch Changes
- jazz-react@0.14.13
## 0.0.106
### Patch Changes
- jazz-react@0.14.12
## 0.0.105
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.104
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-react@0.14.9
## 0.0.103
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-react@0.14.8
## 0.0.102
### Patch Changes

View File

@@ -2,7 +2,7 @@
This is an example of how to upload and render images with Jazz.
Live version: https://image-upload-demo.jazz.tools
Live version: [https://image-upload-demo.jazz.tools](https://image-upload-demo.jazz.tools)
## Getting started

View File

@@ -1,7 +1,7 @@
{
"name": "image-upload",
"private": true,
"version": "0.0.102",
"version": "0.0.110",
"type": "module",
"scripts": {
"dev": "vite",
@@ -13,13 +13,13 @@
"dependencies": {
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0",
"typescript": "5.6.2",

View File

@@ -1,5 +1,61 @@
# jazz-example-inspector
## 0.0.163
### Patch Changes
- Updated dependencies [5e253cc]
- cojson@0.14.16
- cojson-transport-ws@0.14.16
- jazz-inspector@0.14.16
## 0.0.162
### Patch Changes
- Updated dependencies [23daa7c]
- cojson@0.14.15
- cojson-transport-ws@0.14.15
- jazz-inspector@0.14.15
## 0.0.161
### Patch Changes
- jazz-inspector@0.14.14
## 0.0.160
### Patch Changes
- jazz-inspector@0.14.13
## 0.0.159
### Patch Changes
- jazz-inspector@0.14.12
## 0.0.158
### Patch Changes
- Updated dependencies [dc746a2]
- jazz-inspector@0.14.10
- hash-slash@0.2.3
## 0.0.157
### Patch Changes
- jazz-inspector@0.14.9
## 0.0.156
### Patch Changes
- jazz-inspector@0.14.8
## 0.0.155
### Patch Changes

View File

@@ -1,6 +1,6 @@
# Jazz Inspector
Live address: https://inspector.jazz.tools
Live address: [https://inspector.jazz.tools](https://inspector.jazz.tools)
Use this to visually inspect a Jazz account or other CoValue.

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-inspector-app",
"private": true,
"version": "0.0.155",
"version": "0.0.163",
"type": "module",
"scripts": {
"dev": "vite",
@@ -17,15 +17,15 @@
"cojson-transport-ws": "workspace:*",
"hash-slash": "workspace:*",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-router": "^6.16.0",
"react-router-dom": "^6.16.0",
"react-use": "^17.4.0"
},
"devDependencies": {
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",

41
examples/jazz-nextjs/.gitignore vendored Normal file
View File

@@ -0,0 +1,41 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# env files (can opt-in for committing if needed)
.env*
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@@ -0,0 +1,24 @@
# jazz-nextjs
## 0.1.3
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.1.2
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.1.1
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14

View File

@@ -0,0 +1,36 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.

View File

@@ -0,0 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;

View File

@@ -0,0 +1,26 @@
{
"name": "jazz-nextjs",
"version": "0.1.3",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"next": "15.3.2",
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@tailwindcss/postcss": "^4",
"tailwindcss": "^4"
}
}

View File

@@ -0,0 +1,5 @@
const config = {
plugins: ["@tailwindcss/postcss"],
};
export default config;

View File

@@ -0,0 +1,26 @@
@import "tailwindcss";
:root {
--background: #ffffff;
--foreground: #171717;
}
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
background: var(--background);
color: var(--foreground);
font-family: Arial, Helvetica, sans-serif;
}

View File

@@ -0,0 +1,35 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
import { Jazz } from "../jazz";
const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<Jazz>{children}</Jazz>
</body>
</html>
);
}

View File

@@ -0,0 +1,46 @@
"use client";
import { useAccount } from "jazz-react";
import { Account } from "jazz-tools";
import Link from "next/link";
export default function Home() {
const { me } = useAccount(Account, {
resolve: {
profile: true,
},
});
return (
<div className="flex flex-col items-center justify-center h-screen gap-4">
<h1 className="text-2xl font-bold">SSR rendering example with Jazz</h1>
<div className="text-sm text-gray-500 w-1/2 text-center">
Data is still loaded only on the client, the components are rendered on
the server with all the CoValues as null
</div>
<label>
<div className="text-sm">
Your profile name{" "}
<span className="text-xs">(only loaded on the client)</span>
</div>
<input
className="border-2 border-gray-300 rounded-md p-2 w-full"
value={me?.profile.name ?? ""}
onChange={(e) => {
if (!me) {
return;
}
me.profile.name = e.target.value;
}}
/>
</label>
<Link
href={`/profile/${me?.profile.id}`}
className="bg-blue-500 text-white px-4 py-2 rounded-md"
>
Your profile name in a Server Component
</Link>
</div>
);
}

View File

@@ -0,0 +1,23 @@
import { jazzSSR } from "@/jazzSSR";
import { Profile } from "jazz-tools";
export default async function ServerSidePage(props: {
params: Promise<{ profileId: string }>;
}) {
const { profileId } = await props.params;
const profile = await Profile.load(profileId, {
loadAs: jazzSSR,
});
return (
<div className="flex flex-col items-center justify-center h-screen gap-4">
<h1 className="text-2xl font-bold">SSR rendering example with Jazz</h1>
<div className="text-sm text-gray-500 w-1/2 text-center">
This is a server component!
</div>
<label>
<div className="text-sm">Your profile name "{profile?.name}"</div>
</label>
</div>
);
}

View File

@@ -0,0 +1,16 @@
"use client";
import { JazzProvider } from "jazz-react";
export function Jazz({ children }: { children: React.ReactNode }) {
return (
<JazzProvider
experimental_enableSSR
sync={{
peer: `wss://cloud.jazz.tools/`,
}}
>
{children}
</JazzProvider>
);
}

View File

@@ -0,0 +1,5 @@
import { createSSRJazzAgent } from "jazz-react/ssr";
export const jazzSSR = createSSRJazzAgent({
peer: "wss://cloud.jazz.tools/",
});

View File

@@ -0,0 +1,27 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -27,15 +27,15 @@
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.485.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.17",
"tw-animate-css": "^1.2.5"
},
"devDependencies": {
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.4",
"jazz-run": "workspace:*",
"npm-run-all": "^4.1.5",

View File

@@ -47,7 +47,7 @@ export const JoinGameRequest = co.map({
});
export type JoinGameRequest = co.loaded<typeof JoinGameRequest>;
export const InboxMessage = z.discriminatedUnion([
export const InboxMessage = z.discriminatedUnion("type", [
PlayIntent,
NewGameIntent,
CreateGameRequest,

View File

@@ -1,5 +1,66 @@
# multi-cursors
## 0.0.106
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.105
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.104
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.103
### Patch Changes
- jazz-react@0.14.13
## 0.0.102
### Patch Changes
- jazz-react@0.14.12
## 0.0.101
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.100
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-react@0.14.9
## 0.0.99
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-react@0.14.8
## 0.0.98
### Patch Changes

View File

@@ -1,6 +1,7 @@
# Jazz Multi-Cursors Example
Track user presence on a canvas with multiple cursors and out of bounds indicators.
Live version: [https://multi-cursors-demo.jazz.tools/](https://multi-cursors-demo.jazz.tools/)
## Getting started

View File

@@ -1,7 +1,7 @@
{
"name": "multi-cursors",
"private": true,
"version": "0.0.98",
"version": "0.0.106",
"type": "module",
"scripts": {
"dev": "vite",
@@ -15,14 +15,14 @@
"@react-spring/web": "^9.7.5",
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"zod": "3.25.0-beta.20250518T002810"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",

View File

@@ -78,6 +78,7 @@ export function Cursor({
return (
<>
{/* @ts-expect-error - TODO: invalid after the React 19 upgrade */}
<animated.g
transform={to(
[springs.x, springs.y],
@@ -113,6 +114,7 @@ export function Cursor({
isOutOfBounds={isStrictlyOutOfBounds}
/>
{isStrictlyOutOfBounds ? (
// @ts-expect-error - TODO: invalid after the React 19 upgrade
<animated.g
transform={to(
[intersectionSprings.x, intersectionSprings.y],

View File

@@ -52,6 +52,7 @@ export function CursorLabel({
return (
<>
{/* @ts-expect-error - TODO: invalid after the React 19 upgrade */}
<animated.text
ref={textRef}
x={to([labelSprings.x], (x) => x)}

View File

@@ -1,4 +1,4 @@
import { z } from "zod/v4";
import { z } from "jazz-tools";
export const Vec2 = z.object({
x: z.number(),

View File

@@ -1,5 +1,74 @@
# multiauth
## 0.0.54
### Patch Changes
- jazz-react@0.14.16
- jazz-react-auth-clerk@0.14.16
- jazz-tools@0.14.16
## 0.0.53
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-react-auth-clerk@0.14.15
- jazz-tools@0.14.15
## 0.0.52
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
- jazz-react-auth-clerk@0.14.14
## 0.0.51
### Patch Changes
- jazz-react@0.14.13
- jazz-react-auth-clerk@0.14.13
## 0.0.50
### Patch Changes
- jazz-react@0.14.12
- jazz-react-auth-clerk@0.14.12
## 0.0.49
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react-auth-clerk@0.14.10
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.48
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-react@0.14.9
- jazz-react-auth-clerk@0.14.9
## 0.0.47
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-react@0.14.8
- jazz-react-auth-clerk@0.14.8
## 0.0.46
### Patch Changes

View File

@@ -1,7 +1,7 @@
{
"name": "multiauth",
"private": true,
"version": "0.0.46",
"version": "0.0.54",
"type": "module",
"scripts": {
"dev": "vite",
@@ -15,13 +15,13 @@
"jazz-react": "workspace:*",
"jazz-react-auth-clerk": "workspace:*",
"jazz-tools": "workspace:*",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"globals": "^15.11.0",
"typescript": "5.6.2",

View File

@@ -1,5 +1,74 @@
# jazz-example-musicplayer
## 0.0.135
### Patch Changes
- jazz-inspector@0.14.16
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.134
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-inspector@0.14.15
- jazz-tools@0.14.15
## 0.0.133
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-inspector@0.14.14
- jazz-react@0.14.14
## 0.0.132
### Patch Changes
- jazz-inspector@0.14.13
- jazz-react@0.14.13
## 0.0.131
### Patch Changes
- jazz-inspector@0.14.12
- jazz-react@0.14.12
## 0.0.130
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-inspector@0.14.10
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.129
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-inspector@0.14.9
- jazz-react@0.14.9
## 0.0.128
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-inspector@0.14.8
- jazz-react@0.14.8
## 0.0.127
### Patch Changes

View File

@@ -1,6 +1,6 @@
# Music player example with Jazz and React
Live version: https://music-demo.jazz.tools
Live version: [https://music-demo.jazz.tools](https://music-demo.jazz.tools)
## Getting started

View File

@@ -4,7 +4,7 @@
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"config": "tailwind.config.ts",
"css": "src/index.css",
"baseColor": "stone",
"cssVariables": true

View File

@@ -1,7 +1,7 @@
{
"name": "jazz-example-music-player",
"private": true,
"version": "0.0.127",
"version": "0.0.135",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,17 +16,18 @@
"@radix-ui/react-dialog": "^1.1.4",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-label": "^2.1.1",
"@radix-ui/react-separator": "^1.1.2",
"@radix-ui/react-slot": "^1.1.1",
"@radix-ui/react-toast": "^1.1.4",
"@radix-ui/react-tooltip": "^1.1.6",
"class-variance-authority": "^0.7.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.0.0",
"jazz-inspector": "workspace:*",
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-router": "^6.16.0",
"react-router-dom": "^6.16.0",
"tailwind-merge": "^1.14.0",
@@ -34,8 +35,8 @@
},
"devDependencies": {
"@playwright/test": "^1.50.1",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.27",

View File

@@ -7,11 +7,11 @@ import { RouterProvider, createHashRouter } from "react-router-dom";
import { HomePage } from "./3_HomePage";
import { useMediaPlayer } from "./5_useMediaPlayer";
import { InvitePage } from "./6_InvitePage";
import { PlayerControls } from "./components/PlayerControls";
import "./index.css";
import { MusicaAccount } from "@/1_schema";
import { apiKey } from "@/apiKey.ts";
import { SidebarProvider } from "@/components/ui/sidebar";
import { JazzProvider } from "jazz-react";
import { onAnonymousAccountDiscarded } from "./4_actions";
import { useUploadExampleData } from "./lib/useUploadExampleData";
@@ -50,7 +50,7 @@ function Main() {
return (
<>
<RouterProvider router={router} />
<PlayerControls mediaPlayer={mediaPlayer} />
{/* <PlayerControls mediaPlayer={mediaPlayer} /> */}
<Toaster />
</>
);
@@ -72,8 +72,10 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
defaultProfileName="Anonymous unicorn"
onAnonymousAccountDiscarded={onAnonymousAccountDiscarded}
>
<Main />
<JazzInspector />
<SidebarProvider>
<Main />
<JazzInspector />
</SidebarProvider>
</JazzProvider>
</React.StrictMode>,
);

View File

@@ -5,16 +5,16 @@ import {
useCoState,
useIsAuthenticated,
} from "jazz-react";
import { useNavigate, useParams } from "react-router";
import { useParams } from "react-router";
import { MusicaAccount, Playlist } from "./1_schema";
import { createNewPlaylist, uploadMusicTracks } from "./4_actions";
import { uploadMusicTracks } from "./4_actions";
import { MediaPlayer } from "./5_useMediaPlayer";
import { AuthButton } from "./components/AuthButton";
import { FileUploadButton } from "./components/FileUploadButton";
import { MusicTrackRow } from "./components/MusicTrackRow";
import { PlaylistTitleInput } from "./components/PlaylistTitleInput";
import { SidePanel } from "./components/SidePanel";
import { Button } from "./components/ui/button";
import { SidebarInset, SidebarTrigger } from "./components/ui/sidebar";
import { usePlayState } from "./lib/audio/usePlayState";
export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
@@ -26,7 +26,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
resolve: { root: { rootPlaylist: true, playlists: true } },
});
const navigate = useNavigate();
const playState = usePlayState();
const isPlaying = playState.value === "play";
const { toast } = useToast();
@@ -39,12 +38,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
await uploadMusicTracks(files);
}
async function handleCreatePlaylist() {
const playlist = await createNewPlaylist();
navigate(`/playlist/${playlist.id}`);
}
const params = useParams<{ playlistId: string }>();
const playlistId = params.playlistId ?? me?.root._refs.rootPlaylist.id;
@@ -71,10 +64,11 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
const isAuthenticated = useIsAuthenticated();
return (
<div className="flex flex-col h-screen text-gray-800 bg-blue-50">
<SidebarInset className="flex flex-col h-screen text-gray-800 bg-blue-50">
<div className="flex flex-1 overflow-hidden">
<SidePanel />
<SidePanel mediaPlayer={mediaPlayer} />
<main className="flex-1 p-6 overflow-y-auto">
<SidebarTrigger />
<div className="flex items-center justify-between mb-6">
{isRootPlaylist ? (
<h1 className="text-2xl font-bold text-blue-800">All tracks</h1>
@@ -87,7 +81,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
<FileUploadButton onFileLoad={handleFileLoad}>
Add file
</FileUploadButton>
<Button onClick={handleCreatePlaylist}>New playlist</Button>
</>
)}
{!isRootPlaylist && isAuthenticated && (
@@ -95,7 +88,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
Share playlist
</Button>
)}
<AuthButton />
</div>
</div>
<ul className="flex flex-col">
@@ -121,6 +113,6 @@ export function HomePage({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
</ul>
</main>
</div>
</div>
</SidebarInset>
);
}

View File

@@ -20,7 +20,7 @@ export function AuthButton() {
if (isAuthenticated) {
return (
<Button variant="outline" onClick={handleSignOut}>
<Button variant="ghost" onClick={handleSignOut}>
Sign out
</Button>
);
@@ -28,10 +28,7 @@ export function AuthButton() {
return (
<>
<Button
onClick={() => setOpen(true)}
className="bg-white text-black hover:bg-gray-100"
>
<Button onClick={() => setOpen(true)} variant="ghost">
Sign up
</Button>
<AuthModal open={open} onOpenChange={setOpen} />

View File

@@ -1,27 +1,40 @@
import { MusicaAccount } from "@/1_schema";
import { deletePlaylist } from "@/4_actions";
import { useAccount } from "jazz-react";
import { Trash2 } from "lucide-react";
import { MusicTrack, MusicaAccount } from "@/1_schema";
import { createNewPlaylist, deletePlaylist } from "@/4_actions";
import { MediaPlayer } from "@/5_useMediaPlayer";
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuAction,
SidebarMenuButton,
SidebarMenuItem,
} from "@/components/ui/sidebar";
import { usePlayState } from "@/lib/audio/usePlayState";
import { useAccount, useCoState } from "jazz-react";
import { Home, Music, Pause, Play, Plus, Trash2 } from "lucide-react";
import { useNavigate, useParams } from "react-router";
import { LocalOnlyTag } from "./LocalOnlyTag";
import { AuthButton } from "./AuthButton";
export function SidePanel() {
export function SidePanel({ mediaPlayer }: { mediaPlayer: MediaPlayer }) {
const { playlistId } = useParams();
const navigate = useNavigate();
const { me } = useAccount(MusicaAccount, {
resolve: { root: { playlists: { $each: true } } },
});
function handleAllTracksClick(evt: React.MouseEvent<HTMLAnchorElement>) {
evt.preventDefault();
const playState = usePlayState();
const isPlaying = playState.value === "play";
function handleAllTracksClick() {
navigate(`/`);
}
function handlePlaylistClick(
evt: React.MouseEvent<HTMLAnchorElement>,
playlistId: string,
) {
evt.preventDefault();
function handlePlaylistClick(playlistId: string) {
navigate(`/playlist/${playlistId}`);
}
@@ -32,73 +45,121 @@ export function SidePanel() {
}
}
async function handleCreatePlaylist() {
const playlist = await createNewPlaylist();
navigate(`/playlist/${playlist.id}`);
}
const activeTrack = useCoState(MusicTrack, mediaPlayer.activeTrackId, {
resolve: { waveform: true },
});
const activeTrackTitle = activeTrack?.title;
return (
<aside className="w-64 p-6 bg-white overflow-y-auto">
<div className="flex items-center mb-1">
<svg
className="w-8 h-8 mr-2"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9 18V5l12-2v13"
stroke="#3b82f6"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M6 15H3c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h3c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zM18 13h-3c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h3c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2z"
fill="#3b82f6"
/>
</svg>
<span className="text-xl font-bold text-blue-600">Music Player</span>
</div>
<div className="mb-6">
<LocalOnlyTag />
</div>
<nav>
<h2 className="mb-2 text-sm font-semibold text-gray-600">Playlists</h2>
<ul className="space-y-1">
<li>
<a
href="#"
className={`block px-2 py-1 text-sm rounded ${
!playlistId ? "bg-blue-100 text-blue-600" : "hover:bg-blue-100"
}`}
onClick={handleAllTracksClick}
>
All tracks
</a>
</li>
{me?.root.playlists.map((playlist, index) => (
<li
key={index}
className={`px-2 py-1 flex transition-all duration-300 rounded items-center justify-between ${
playlist.id === playlistId ? "bg-blue-100" : ""
}`}
>
<a
href="#"
className={`w-full text-sm`}
onClick={(evt) => handlePlaylistClick(evt, playlist.id)}
<Sidebar>
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem className="flex items-center gap-2">
<div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-blue-600 text-white">
<svg
className="size-4"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
{playlist.title}
</a>
{playlist.id === playlistId && (
<button
onClick={() => handleDeletePlaylist(playlist.id)}
className="ml-2 text-red-600 hover:text-red-800 animate-in fade-in scale-in duration-200"
aria-label={`Delete ${playlist.title}`}
>
<Trash2 size={16} />
</button>
)}
</li>
))}
</ul>
</nav>
</aside>
<path
d="M9 18V5l12-2v13"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M6 15H3c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h3c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zM18 13h-3c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h3c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2z"
fill="currentColor"
/>
</svg>
</div>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">Music Player</span>
</div>
<AuthButton />
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
<SidebarContent>
<SidebarGroup>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton onClick={handleAllTracksClick}>
<Home className="size-4" />
<span>Go to all tracks</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
<SidebarGroup>
<SidebarGroupLabel>Playlists</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton onClick={handleCreatePlaylist}>
<Plus className="size-4" />
<span>Add a new playlist</span>
</SidebarMenuButton>
</SidebarMenuItem>
{me?.root.playlists.map((playlist) => (
<SidebarMenuItem key={playlist.id}>
<SidebarMenuButton
onClick={() => handlePlaylistClick(playlist.id)}
isActive={playlist.id === playlistId}
>
<div className="flex items-center gap-2">
<Music className="size-4" />
<span>{playlist.title}</span>
</div>
</SidebarMenuButton>
{playlist.id === playlistId && (
<SidebarMenuAction
onClick={() => handleDeletePlaylist(playlist.id)}
className="text-red-600 hover:text-red-800"
>
<Trash2 className="size-4" />
<span className="sr-only">Delete {playlist.title}</span>
</SidebarMenuAction>
)}
</SidebarMenuItem>
))}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
{activeTrack && (
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem className="flex justify-end">
<SidebarMenuButton
onClick={playState.toggle}
aria-label={
isPlaying ? "Pause active track" : "Play active track"
}
>
<div className="w-[28px] h-[28px] flex items-center justify-center bg-blue-600 rounded-full text-white hover:bg-blue-700">
{isPlaying ? (
<Pause size={16} fill="currentColor" />
) : (
<Play size={16} fill="currentColor" />
)}
</div>
<span>{activeTrackTitle}</span>
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
)}
</Sidebar>
);
}

View File

@@ -5,7 +5,7 @@ import * as React from "react";
import { cn } from "@/lib/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
@@ -53,5 +53,4 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
);
Button.displayName = "Button";
// eslint-disable-next-line react-refresh/only-export-components
export { Button, buttonVariants };

View File

@@ -0,0 +1,29 @@
import * as SeparatorPrimitive from "@radix-ui/react-separator";
import * as React from "react";
import { cn } from "@/lib/utils";
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
>(
(
{ className, orientation = "horizontal", decorative = true, ...props },
ref,
) => (
<SeparatorPrimitive.Root
ref={ref}
decorative={decorative}
orientation={orientation}
className={cn(
"shrink-0 bg-border",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className,
)}
{...props}
/>
),
);
Separator.displayName = SeparatorPrimitive.Root.displayName;
export { Separator };

View File

@@ -0,0 +1,140 @@
"use client";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { type VariantProps, cva } from "class-variance-authority";
import { X } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
ref={ref}
/>
));
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
{
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
},
);
interface SheetContentProps
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
VariantProps<typeof sheetVariants> {}
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
SheetContentProps
>(({ side = "right", className, children, ...props }, ref) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
ref={ref}
className={cn(sheetVariants({ side }), className)}
{...props}
>
{children}
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
));
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetPortal,
SheetOverlay,
SheetTrigger,
SheetClose,
SheetContent,
SheetHeader,
SheetFooter,
SheetTitle,
SheetDescription,
};

View File

@@ -0,0 +1,779 @@
import { Slot } from "@radix-ui/react-slot";
import { VariantProps, cva } from "class-variance-authority";
import { PanelLeft } from "lucide-react";
import * as React from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
} from "@/components/ui/sheet";
import { Skeleton } from "@/components/ui/skeleton";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { useIsMobile } from "@/hooks/use-mobile";
import { cn } from "@/lib/utils";
const SIDEBAR_COOKIE_NAME = "sidebar_state";
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
const SIDEBAR_WIDTH = "16rem";
const SIDEBAR_WIDTH_MOBILE = "18rem";
const SIDEBAR_WIDTH_ICON = "3rem";
const SIDEBAR_KEYBOARD_SHORTCUT = "b";
type SidebarContextProps = {
state: "expanded" | "collapsed";
open: boolean;
setOpen: (open: boolean) => void;
openMobile: boolean;
setOpenMobile: (open: boolean) => void;
isMobile: boolean;
toggleSidebar: () => void;
};
const SidebarContext = React.createContext<SidebarContextProps | null>(null);
function useSidebar() {
const context = React.useContext(SidebarContext);
if (!context) {
throw new Error("useSidebar must be used within a SidebarProvider.");
}
return context;
}
const SidebarProvider = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
defaultOpen?: boolean;
open?: boolean;
onOpenChange?: (open: boolean) => void;
}
>(
(
{
defaultOpen = true,
open: openProp,
onOpenChange: setOpenProp,
className,
style,
children,
...props
},
ref,
) => {
const isMobile = useIsMobile();
const [openMobile, setOpenMobile] = React.useState(false);
// This is the internal state of the sidebar.
// We use openProp and setOpenProp for control from outside the component.
const [_open, _setOpen] = React.useState(defaultOpen);
const open = openProp ?? _open;
const setOpen = React.useCallback(
(value: boolean | ((value: boolean) => boolean)) => {
const openState = typeof value === "function" ? value(open) : value;
if (setOpenProp) {
setOpenProp(openState);
} else {
_setOpen(openState);
}
// This sets the cookie to keep the sidebar state.
document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
},
[setOpenProp, open],
);
// Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => {
return isMobile
? setOpenMobile((open) => !open)
: setOpen((open) => !open);
}, [isMobile, setOpen, setOpenMobile]);
// Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (
event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
(event.metaKey || event.ctrlKey)
) {
event.preventDefault();
toggleSidebar();
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [toggleSidebar]);
// We add a state so that we can do data-state="expanded" or "collapsed".
// This makes it easier to style the sidebar with Tailwind classes.
const state = open ? "expanded" : "collapsed";
const contextValue = React.useMemo<SidebarContextProps>(
() => ({
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
}),
[
state,
open,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
],
);
return (
<SidebarContext.Provider value={contextValue}>
<TooltipProvider delayDuration={0}>
<div
style={
{
"--sidebar-width": SIDEBAR_WIDTH,
"--sidebar-width-icon": SIDEBAR_WIDTH_ICON,
...style,
} as React.CSSProperties
}
className={cn(
"group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar",
className,
)}
ref={ref}
{...props}
>
{children}
</div>
</TooltipProvider>
</SidebarContext.Provider>
);
},
);
SidebarProvider.displayName = "SidebarProvider";
const Sidebar = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
side?: "left" | "right";
variant?: "sidebar" | "floating" | "inset";
collapsible?: "offcanvas" | "icon" | "none";
}
>(
(
{
side = "left",
variant = "sidebar",
collapsible = "offcanvas",
className,
children,
...props
},
ref,
) => {
const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
if (collapsible === "none") {
return (
<div
className={cn(
"flex h-full w-[--sidebar-width] flex-col bg-sidebar text-sidebar-foreground",
className,
)}
ref={ref}
{...props}
>
{children}
</div>
);
}
if (isMobile) {
return (
<Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
<SheetContent
data-sidebar="sidebar"
data-mobile="true"
className="w-[--sidebar-width] bg-sidebar p-0 text-sidebar-foreground [&>button]:hidden"
style={
{
"--sidebar-width": SIDEBAR_WIDTH_MOBILE,
} as React.CSSProperties
}
side={side}
>
<SheetHeader className="sr-only">
<SheetTitle>Sidebar</SheetTitle>
<SheetDescription>Displays the mobile sidebar.</SheetDescription>
</SheetHeader>
<div className="flex h-full w-full flex-col">{children}</div>
</SheetContent>
</Sheet>
);
}
return (
<div
ref={ref}
className="group peer hidden text-sidebar-foreground md:block"
data-state={state}
data-collapsible={state === "collapsed" ? collapsible : ""}
data-variant={variant}
data-side={side}
>
{/* This is what handles the sidebar gap on desktop */}
<div
className={cn(
"relative w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear",
"group-data-[collapsible=offcanvas]:w-0",
"group-data-[side=right]:rotate-180",
variant === "floating" || variant === "inset"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]"
: "group-data-[collapsible=icon]:w-[--sidebar-width-icon]",
)}
/>
<div
className={cn(
"fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex",
side === "left"
? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
: "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
// Adjust the padding for floating and inset variants.
variant === "floating" || variant === "inset"
? "p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]"
: "group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l",
className,
)}
{...props}
>
<div
data-sidebar="sidebar"
className="flex h-full w-full flex-col bg-sidebar group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:border-sidebar-border group-data-[variant=floating]:shadow"
>
{children}
</div>
</div>
</div>
);
},
);
Sidebar.displayName = "Sidebar";
const SidebarTrigger = React.forwardRef<
React.ElementRef<typeof Button>,
React.ComponentProps<typeof Button>
>(({ className, onClick, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<Button
ref={ref}
data-sidebar="trigger"
variant="ghost"
size="icon"
className={cn("h-7 w-7", className)}
onClick={(event) => {
onClick?.(event);
toggleSidebar();
}}
{...props}
>
<PanelLeft />
<span className="sr-only">Toggle Sidebar</span>
</Button>
);
});
SidebarTrigger.displayName = "SidebarTrigger";
const SidebarRail = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button">
>(({ className, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
return (
<button
ref={ref}
data-sidebar="rail"
aria-label="Toggle Sidebar"
tabIndex={-1}
onClick={toggleSidebar}
title="Toggle Sidebar"
className={cn(
"absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] hover:after:bg-sidebar-border group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex",
"[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize",
"[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
"group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full group-data-[collapsible=offcanvas]:hover:bg-sidebar",
"[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
"[[data-side=right][data-collapsible=offcanvas]_&]:-left-2",
className,
)}
{...props}
/>
);
});
SidebarRail.displayName = "SidebarRail";
const SidebarInset = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"main">
>(({ className, ...props }, ref) => {
return (
<main
ref={ref}
className={cn(
"relative flex w-full flex-1 flex-col bg-background",
"md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",
className,
)}
{...props}
/>
);
});
SidebarInset.displayName = "SidebarInset";
const SidebarInput = React.forwardRef<
React.ElementRef<typeof Input>,
React.ComponentProps<typeof Input>
>(({ className, ...props }, ref) => {
return (
<Input
ref={ref}
data-sidebar="input"
className={cn(
"h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring",
className,
)}
{...props}
/>
);
});
SidebarInput.displayName = "SidebarInput";
const SidebarHeader = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-sidebar="header"
className={cn("flex flex-col gap-2 p-2", className)}
{...props}
/>
);
});
SidebarHeader.displayName = "SidebarHeader";
const SidebarFooter = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-sidebar="footer"
className={cn("flex flex-col gap-2 p-2", className)}
{...props}
/>
);
});
SidebarFooter.displayName = "SidebarFooter";
const SidebarSeparator = React.forwardRef<
React.ElementRef<typeof Separator>,
React.ComponentProps<typeof Separator>
>(({ className, ...props }, ref) => {
return (
<Separator
ref={ref}
data-sidebar="separator"
className={cn("mx-2 w-auto bg-sidebar-border", className)}
{...props}
/>
);
});
SidebarSeparator.displayName = "SidebarSeparator";
const SidebarContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-sidebar="content"
className={cn(
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
className,
)}
{...props}
/>
);
});
SidebarContent.displayName = "SidebarContent";
const SidebarGroup = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => {
return (
<div
ref={ref}
data-sidebar="group"
className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
{...props}
/>
);
});
SidebarGroup.displayName = "SidebarGroup";
const SidebarGroupLabel = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & { asChild?: boolean }
>(({ className, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "div";
return (
<Comp
ref={ref}
data-sidebar="group-label"
className={cn(
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium text-sidebar-foreground/70 outline-none ring-sidebar-ring transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
className,
)}
{...props}
/>
);
});
SidebarGroupLabel.displayName = "SidebarGroupLabel";
const SidebarGroupAction = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & { asChild?: boolean }
>(({ className, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
ref={ref}
data-sidebar="group-action"
className={cn(
"absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
// Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 after:md:hidden",
"group-data-[collapsible=icon]:hidden",
className,
)}
{...props}
/>
);
});
SidebarGroupAction.displayName = "SidebarGroupAction";
const SidebarGroupContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => (
<div
ref={ref}
data-sidebar="group-content"
className={cn("w-full text-sm", className)}
{...props}
/>
));
SidebarGroupContent.displayName = "SidebarGroupContent";
const SidebarMenu = React.forwardRef<
HTMLUListElement,
React.ComponentProps<"ul">
>(({ className, ...props }, ref) => (
<ul
ref={ref}
data-sidebar="menu"
className={cn("flex w-full min-w-0 flex-col gap-1", className)}
{...props}
/>
));
SidebarMenu.displayName = "SidebarMenu";
const SidebarMenuItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
>(({ className, ...props }, ref) => (
<li
ref={ref}
data-sidebar="menu-item"
className={cn("group/menu-item relative", className)}
{...props}
/>
));
SidebarMenuItem.displayName = "SidebarMenuItem";
const sidebarMenuButtonVariants = cva(
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
{
variants: {
variant: {
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
outline:
"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]",
},
size: {
default: "h-8 text-sm",
sm: "h-7 text-xs",
lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
},
);
const SidebarMenuButton = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & {
asChild?: boolean;
isActive?: boolean;
tooltip?: string | React.ComponentProps<typeof TooltipContent>;
} & VariantProps<typeof sidebarMenuButtonVariants>
>(
(
{
asChild = false,
isActive = false,
variant = "default",
size = "default",
tooltip,
className,
...props
},
ref,
) => {
const Comp = asChild ? Slot : "button";
const { isMobile, state } = useSidebar();
const button = (
<Comp
ref={ref}
data-sidebar="menu-button"
data-size={size}
data-active={isActive}
className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
{...props}
/>
);
if (!tooltip) {
return button;
}
if (typeof tooltip === "string") {
tooltip = {
children: tooltip,
};
}
return (
<Tooltip>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent
side="right"
align="center"
hidden={state !== "collapsed" || isMobile}
{...tooltip}
/>
</Tooltip>
);
},
);
SidebarMenuButton.displayName = "SidebarMenuButton";
const SidebarMenuAction = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & {
asChild?: boolean;
showOnHover?: boolean;
}
>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
ref={ref}
data-sidebar="menu-action"
className={cn(
"absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 text-sidebar-foreground outline-none ring-sidebar-ring transition-transform hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 peer-hover/menu-button:text-sidebar-accent-foreground [&>svg]:size-4 [&>svg]:shrink-0",
// Increases the hit area of the button on mobile.
"after:absolute after:-inset-2 after:md:hidden",
"peer-data-[size=sm]/menu-button:top-1",
"peer-data-[size=default]/menu-button:top-1.5",
"peer-data-[size=lg]/menu-button:top-2.5",
"group-data-[collapsible=icon]:hidden",
showOnHover &&
"group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0",
className,
)}
{...props}
/>
);
});
SidebarMenuAction.displayName = "SidebarMenuAction";
const SidebarMenuBadge = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div">
>(({ className, ...props }, ref) => (
<div
ref={ref}
data-sidebar="menu-badge"
className={cn(
"pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums text-sidebar-foreground",
"peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
"peer-data-[size=sm]/menu-button:top-1",
"peer-data-[size=default]/menu-button:top-1.5",
"peer-data-[size=lg]/menu-button:top-2.5",
"group-data-[collapsible=icon]:hidden",
className,
)}
{...props}
/>
));
SidebarMenuBadge.displayName = "SidebarMenuBadge";
const SidebarMenuSkeleton = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
showIcon?: boolean;
}
>(({ className, showIcon = false, ...props }, ref) => {
// Random width between 50 to 90%.
const width = React.useMemo(() => {
return `${Math.floor(Math.random() * 40) + 50}%`;
}, []);
return (
<div
ref={ref}
data-sidebar="menu-skeleton"
className={cn("flex h-8 items-center gap-2 rounded-md px-2", className)}
{...props}
>
{showIcon && (
<Skeleton
className="size-4 rounded-md"
data-sidebar="menu-skeleton-icon"
/>
)}
<Skeleton
className="h-4 max-w-[--skeleton-width] flex-1"
data-sidebar="menu-skeleton-text"
style={
{
"--skeleton-width": width,
} as React.CSSProperties
}
/>
</div>
);
});
SidebarMenuSkeleton.displayName = "SidebarMenuSkeleton";
const SidebarMenuSub = React.forwardRef<
HTMLUListElement,
React.ComponentProps<"ul">
>(({ className, ...props }, ref) => (
<ul
ref={ref}
data-sidebar="menu-sub"
className={cn(
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5",
"group-data-[collapsible=icon]:hidden",
className,
)}
{...props}
/>
));
SidebarMenuSub.displayName = "SidebarMenuSub";
const SidebarMenuSubItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
>(({ ...props }, ref) => <li ref={ref} {...props} />);
SidebarMenuSubItem.displayName = "SidebarMenuSubItem";
const SidebarMenuSubButton = React.forwardRef<
HTMLAnchorElement,
React.ComponentProps<"a"> & {
asChild?: boolean;
size?: "sm" | "md";
isActive?: boolean;
}
>(({ asChild = false, size = "md", isActive, className, ...props }, ref) => {
const Comp = asChild ? Slot : "a";
return (
<Comp
ref={ref}
data-sidebar="menu-sub-button"
data-size={size}
data-active={isActive}
className={cn(
"flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 text-sidebar-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-sidebar-accent-foreground",
"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
size === "sm" && "text-xs",
size === "md" && "text-sm",
"group-data-[collapsible=icon]:hidden",
className,
)}
{...props}
/>
);
});
SidebarMenuSubButton.displayName = "SidebarMenuSubButton";
export {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupAction,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarInput,
SidebarInset,
SidebarMenu,
SidebarMenuAction,
SidebarMenuBadge,
SidebarMenuButton,
SidebarMenuItem,
SidebarMenuSkeleton,
SidebarMenuSub,
SidebarMenuSubButton,
SidebarMenuSubItem,
SidebarProvider,
SidebarRail,
SidebarSeparator,
SidebarTrigger,
useSidebar,
};

View File

@@ -0,0 +1,15 @@
import { cn } from "@/lib/utils";
function Skeleton({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn("animate-pulse rounded-md bg-muted", className)}
{...props}
/>
);
}
export { Skeleton };

View File

@@ -1,5 +1,3 @@
"use client";
import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import * as React from "react";
@@ -19,7 +17,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
className,
)}
{...props}

View File

@@ -0,0 +1,21 @@
import * as React from "react";
const MOBILE_BREAKPOINT = 768;
export function useIsMobile() {
const [isMobile, setIsMobile] = React.useState<boolean | undefined>(
undefined,
);
React.useEffect(() => {
const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => {
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
};
mql.addEventListener("change", onChange);
setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
return () => mql.removeEventListener("change", onChange);
}, []);
return !!isMobile;
}

View File

@@ -33,6 +33,22 @@
--ring: 20 14.3% 4.1%;
--radius: 0.5rem;
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
@@ -63,6 +79,14 @@
--border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%;
--ring: 24 5.7% 82.9%;
--sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 224.3 76.3% 48%;
--sidebar-primary-foreground: 0 0% 100%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
}

View File

@@ -4,7 +4,7 @@ import { useAudioManager } from "./AudioManager";
export function usePlayMedia() {
const audioManager = useAudioManager();
const previousMediaLoad = useRef<Promise<unknown>>();
const previousMediaLoad = useRef<Promise<unknown> | undefined>(undefined);
async function playMedia(file: Blob) {
// Wait for the previous load to finish

View File

@@ -52,6 +52,16 @@ const config: Config = {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
sidebar: {
DEFAULT: "hsl(var(--sidebar-background))",
foreground: "hsl(var(--sidebar-foreground))",
primary: "hsl(var(--sidebar-primary))",
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
accent: "hsl(var(--sidebar-accent))",
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
border: "hsl(var(--sidebar-border))",
ring: "hsl(var(--sidebar-ring))",
},
},
borderRadius: {
lg: "var(--radius)",
@@ -60,12 +70,20 @@ const config: Config = {
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
from: {
height: "0",
},
to: {
height: "var(--radix-accordion-content-height)",
},
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
from: {
height: "var(--radix-accordion-content-height)",
},
to: {
height: "0",
},
},
},
animation: {

View File

@@ -71,7 +71,7 @@ export class HomePage {
async navigateToPlaylist(playlistTitle: string) {
await this.page
.getByRole("link", {
.getByRole("button", {
name: playlistTitle,
})
.click();
@@ -79,7 +79,7 @@ export class HomePage {
async navigateToHome() {
await this.page
.getByRole("link", {
.getByRole("button", {
name: "All tracks",
})
.click();

View File

@@ -1,5 +1,66 @@
# organization
## 0.0.106
### Patch Changes
- jazz-react@0.14.16
- jazz-tools@0.14.16
## 0.0.105
### Patch Changes
- Updated dependencies [f9590f9]
- jazz-react@0.14.15
- jazz-tools@0.14.15
## 0.0.104
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-react@0.14.14
## 0.0.103
### Patch Changes
- jazz-react@0.14.13
## 0.0.102
### Patch Changes
- jazz-react@0.14.12
## 0.0.101
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-react@0.14.10
- jazz-tools@0.14.10
## 0.0.100
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-react@0.14.9
## 0.0.99
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-react@0.14.8
## 0.0.98
### Patch Changes

View File

@@ -2,7 +2,7 @@
This is an example of how to share a set of data between users through a CoMap called Organization.
Different apps have different names for this concept, such as "teams" or "workspaces".
Live version: [https://jazz-organization.vercel.app/](https://jazz-organization.vercel.app/)
Refer to the [documentation](https://jazz.tools/docs/react/design-patterns/organization) for more information.
## Getting started

View File

@@ -1,7 +1,7 @@
{
"name": "organization",
"private": true,
"version": "0.0.98",
"version": "0.0.106",
"type": "module",
"scripts": {
"dev": "vite",
@@ -16,8 +16,8 @@
"jazz-react": "workspace:*",
"jazz-tools": "workspace:*",
"lucide-react": "^0.274.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react": "19.0.0",
"react-dom": "19.0.0",
"react-router": "^6.16.0",
"react-router-dom": "^6.16.0"
},
@@ -25,8 +25,8 @@
"@playwright/test": "^1.50.1",
"@biomejs/biome": "1.9.4",
"@tailwindcss/forms": "^0.5.9",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react": "19.0.0",
"@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"globals": "^15.11.0",

View File

@@ -1,5 +1,53 @@
# passkey-svelte
## 0.0.100
### Patch Changes
- jazz-svelte@0.14.16
- jazz-tools@0.14.16
## 0.0.99
### Patch Changes
- jazz-svelte@0.14.15
- jazz-tools@0.14.15
## 0.0.98
### Patch Changes
- Updated dependencies [e32a1f7]
- jazz-tools@0.14.14
- jazz-svelte@0.14.14
## 0.0.97
### Patch Changes
- Updated dependencies [dc746a2]
- Updated dependencies [f869d9a]
- Updated dependencies [3fe6832]
- jazz-tools@0.14.10
- jazz-svelte@0.14.10
## 0.0.96
### Patch Changes
- Updated dependencies [22c2600]
- jazz-tools@0.14.9
- jazz-svelte@0.14.9
## 0.0.95
### Patch Changes
- Updated dependencies [637ae13]
- jazz-tools@0.14.8
- jazz-svelte@0.14.8
## 0.0.94
### Patch Changes

View File

@@ -5,6 +5,7 @@ This example app demonstrates how to implement passkey authentication in a Svelt
## Features
This example showcases how to:
- Set up passkey authentication in a Svelte application
- Handle user registration with passkeys
- Manage authentication state
@@ -13,23 +14,26 @@ This example showcases how to:
## Getting started
You can either
1. Clone the jazz repository, and run the app within the monorepo.
2. Or create a new Jazz project using this example as a template.
### Using the example as a template
Create a new Jazz project, and use this example as a template.
```bash
npx create-jazz-app@latest passkey-svelte-app --example passkey-svelte
```
Go to the new project directory.
```bash
cd passkey-svelte-app
```
Run the dev server.
```bash
npm run dev
```
@@ -39,21 +43,25 @@ npm run dev
This requires `pnpm` to be installed, see [https://pnpm.io/installation](https://pnpm.io/installation).
Clone the jazz repository.
```bash
git clone https://github.com/garden-co/jazz.git
```
Install and build dependencies.
```bash
pnpm i && npx turbo build
```
Go to the example directory.
```bash
cd jazz/examples/passkey-svelte/
```
Start the dev server.
```bash
pnpm dev
```

View File

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

View File

@@ -1 +1 @@
export const apiKey = "minimal-svelte-auth-passkey@garden.co"
export const apiKey = 'minimal-svelte-auth-passkey@garden.co';

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