Compare commits

..

60 Commits

Author SHA1 Message Date
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
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
Guido D'Orsi
fa3cf6d0c1 Merge pull request #2331 from garden-co/changeset-release/main
Version Packages
2025-05-22 14:26:58 +02:00
github-actions[bot]
d823700a7c Version Packages 2025-05-22 12:23:10 +00:00
Guido D'Orsi
ed472e834a Merge pull request #2329 from garden-co/fix-z-create
fix: reduce the z exported APIs to the ones we support and fix compatible types
2025-05-22 14:18:56 +02:00
Guido D'Orsi
365b0ea3a9 fix: reduce the z exported APIs to the ones we support and fix compatible types 2025-05-22 14:14:39 +02:00
Benjamin S. Leveritt
43c831167f Merge pull request #2328 from garden-co/2327-remove-auto-generated-api-reference-content
Hides the API Ref links
2025-05-22 12:48:00 +01:00
Benjamin S. Leveritt
cac0f1ad2b Hides the API Ref links 2025-05-22 11:10:46 +01:00
Guido D'Orsi
f66b7c1a5a Merge pull request #2326 from garden-co/changeset-release/main
Version Packages
2025-05-22 11:49:26 +02:00
github-actions[bot]
1b57cfc3f6 Version Packages 2025-05-22 09:45:36 +00:00
Guido D'Orsi
a805e27b0a Merge pull request #2322 from garden-co/fix-z-create
fix: fixes create types for CoList, CoRecord, CoFeed and CoFileStream
2025-05-22 11:42:24 +02:00
Guido D'Orsi
9d6d9fe7a5 fix: fixes create types for CoList, CoRecord, CoFeed and CoFileStream 2025-05-22 11:33:03 +02:00
Benjamin S. Leveritt
409758afd0 Adds tests for co.fileStream()'s this 2025-05-22 10:53:46 +02:00
227 changed files with 8511 additions and 3890 deletions

View File

@@ -1,5 +1,96 @@
# betterauth # betterauth
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-betterauth-server-plugin@0.14.7
- jazz-inspector@0.14.7
- jazz-react@0.14.7
- jazz-react-auth-betterauth@0.14.7
- jazz-betterauth-client-plugin@0.14.7
## 0.1.10
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-betterauth-server-plugin@0.14.6
- jazz-inspector@0.14.6
- jazz-react@0.14.6
- jazz-react-auth-betterauth@0.14.6
- jazz-betterauth-client-plugin@0.14.6
## 0.1.9 ## 0.1.9
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,81 @@
# chat-rn-expo-clerk # chat-rn-expo-clerk
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-expo@0.14.7
- jazz-react-native-media-images@0.14.7
## 1.0.129
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-expo@0.14.6
- jazz-react-native-media-images@0.14.6
## 1.0.128 ## 1.0.128
### Patch Changes ### Patch Changes

View File

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

View File

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

View File

@@ -1,960 +1,38 @@
# chat-rn-expo # chat-rn-expo
## 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
## 1.0.6
### Patch Changes
- jazz-react-native@0.8.11
- jazz-tools@0.8.11
## 1.0.5 ## 1.0.5
### Patch Changes ### 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 [e32a1f7]
- Updated dependencies [b7639cf] - jazz-tools@0.14.14
- jazz-react-native@0.8.8 - jazz-expo@0.14.14
## 1.0.4 ## 1.0.4
### Patch Changes ### Patch Changes
- Updated dependencies [32b05b6] - jazz-expo@0.14.13
- jazz-react-native@0.8.7
## 1.0.3 ## 1.0.3
### Patch Changes ### Patch Changes
- jazz-react-native@0.8.6 - jazz-expo@0.14.12
## 1.0.2 ## 1.0.2
### Patch Changes ### Patch Changes
- Updated dependencies [c3f4e6b] - Updated dependencies [98d697f]
- Updated dependencies [d9152ed] - jazz-expo@0.14.11
- jazz-react-native@0.8.5
- jazz-tools@0.8.5
## 1.0.1 ## 1.0.1
### Patch Changes ### Patch Changes
- Updated dependencies - Updated dependencies [dc746a2]
- jazz-react-native@0.8.3 - Updated dependencies [f869d9a]
- jazz-tools@0.8.3 - 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": { "expo": {
"name": "jazz-chat-rn-expo", "name": "chat-rn-expo",
"scheme": "jazz-chat-rn-expo", "slug": "chat-rn-expo",
"slug": "jazz-chat-rn-expo",
"version": "1.0.0", "version": "1.0.0",
"orientation": "portrait", "orientation": "portrait",
"icon": "./assets/icon.png", "icon": "./assets/icon.png",
"userInterfaceStyle": "light", "userInterfaceStyle": "light",
"newArchEnabled": true,
"splash": { "splash": {
"image": "./assets/splash.png", "image": "./assets/splash-icon.png",
"resizeMode": "contain", "resizeMode": "contain",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"ios": { "ios": {
"supportsTablet": true, "supportsTablet": true,
"bundleIdentifier": "com.jazz.chatrn" "bundleIdentifier": "com.anonymous.chatrnexpo"
}, },
"android": { "android": {
"adaptiveIcon": { "adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png", "foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff" "backgroundColor": "#ffffff"
}, },
"package": "com.jazz.chatrn" "edgeToEdgeEnabled": true,
"package": "com.anonymous.chatrnexpo"
}, },
"plugins": [ "web": {
"expo-secure-store", "favicon": "./assets/favicon.png"
"expo-sqlite",
"expo-build-properties",
"expo-web-browser"
],
"extra": {
"eas": {
"projectId": "e0e61872-1906-4c84-b9d8-9be77355cad0"
}
}, },
"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", "name": "chat-rn-expo",
"version": "1.0.115", "version": "1.0.5",
"main": "index.js", "main": "index.ts",
"scripts": { "scripts": {
"build": "tsc --noEmit && expo export -p ios", "build": "expo prebuild",
"start": "expo start", "start": "expo start",
"format-and-lint": "biome check .",
"format-and-lint:fix": "biome check . --write",
"android": "expo run:android", "android": "expo run:android",
"ios": "expo prebuild && pnpx pod-install && expo run:ios", "ios": "expo run:ios",
"web": "expo start --web" "web": "expo start --web"
}, },
"dependencies": { "dependencies": {
"@azure/core-asynciterator-polyfill": "^1.0.2", "@azure/core-asynciterator-polyfill": "^1.0.2",
"@bacons/text-decoder": "0.0.0", "@bacons/text-decoder": "^0.0.0",
"@craftzdog/react-native-buffer": "6.0.5", "@craftzdog/react-native-buffer": "^6.0.5",
"@react-native-community/netinfo": "11.4.1", "@react-native-community/netinfo": "11.4.1",
"@react-navigation/native": "7.0.19", "expo": "~53.0.9",
"@react-navigation/native-stack": "7.2.1", "expo-clipboard": "^7.1.4",
"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-secure-store": "~14.2.3", "expo-secure-store": "~14.2.3",
"expo-sqlite": "15.2.9", "expo-sqlite": "~15.2.10",
"expo-status-bar": "~2.2.3", "expo-status-bar": "~2.2.3",
"expo-web-browser": "~14.1.6",
"jazz-expo": "workspace:*", "jazz-expo": "workspace:*",
"jazz-tools": "workspace:*", "jazz-tools": "workspace:*",
"nativewind": "^4.1.21",
"react": "19.0.0", "react": "19.0.0",
"react-dom": "19.0.0",
"react-native": "0.79.2", "react-native": "0.79.2",
"react-native-get-random-values": "^1.11.0", "react-native-get-random-values": "^1.11.0",
"react-native-safe-area-context": "5.4.0", "readable-stream": "^4.7.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"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.25.2", "@babel/core": "^7.25.2",
"@types/react": "~19.0.14", "@types/react": "~19.0.10",
"tailwindcss": "^3.4.17", "typescript": "~5.8.3"
"typescript": "5.8.3"
}, },
"private": true "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 { JazzProvider } from "jazz-expo";
import React, { StrictMode } from "react";
import { apiKey } from "./apiKey"; import { apiKey } from "./apiKey";
import ChatScreen from "./chat"; import ChatScreen from "./chat";
const Stack = createNativeStackNavigator(); export default function App() {
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");
}
}
});
}, []);
return ( return (
<StrictMode> <StrictMode>
<JazzProvider <JazzProvider
CryptoProvider={RNQuickCrypto}
sync={{ sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`, peer: `wss://cloud.jazz.tools/?key=${apiKey}`,
}} }}
> >
<NavigationContainer linking={linking} ref={navigationRef}> <ChatScreen />
<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>
</JazzProvider> </JazzProvider>
</StrictMode> </StrictMode>
); );
} }
export default App;

View File

@@ -1,7 +1,6 @@
import clsx from "clsx";
import * as Clipboard from "expo-clipboard"; import * as Clipboard from "expo-clipboard";
import { Group, ID, Loaded, Profile } from "jazz-tools"; import { Account, Group } from "jazz-tools";
import { useEffect, useState } from "react"; import { useState } from "react";
import React, { import React, {
Button, Button,
FlatList, FlatList,
@@ -12,54 +11,38 @@ import React, {
TouchableOpacity, TouchableOpacity,
View, View,
Alert, Alert,
StyleSheet,
} from "react-native"; } from "react-native";
import { useAccount, useCoState } from "jazz-expo"; import { useAccount, useCoState } from "jazz-expo";
import { Chat, Message } from "./schema"; import { Chat, Message } from "./schema";
export default function ChatScreen({ navigation }: { navigation: any }) { export default function ChatScreen() {
const { me, logOut } = useAccount(); const { me, logOut } = useAccount(Account, { resolve: { profile: true } });
const [chatId, setChatId] = useState<string>(); const [chatId, setChatId] = useState<string>();
const [chatIdInput, setChatIdInput] = useState<string>(); const [chatIdInput, setChatIdInput] = useState<string>();
const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } }); const loadedChat = useCoState(Chat, chatId, { resolve: { $each: true } });
const [message, setMessage] = useState(""); const [message, setMessage] = useState("");
const profile = useCoState(Profile, me._refs.profile?.id, {});
function handleLogOut() { function handleLogOut() {
setChatId(undefined); setChatId(undefined);
logOut(); 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 createChat = () => {
const group = Group.create({ owner: me }); const group = Group.create();
group.addMember("everyone", "writer"); group.addMember("everyone", "writer");
const chat = Chat.create([], { owner: group }); const chat = Chat.create([], group);
setChatId(chat.id); setChatId(chat.id);
}; };
const joinChat = () => { const joinChat = () => {
if (chatIdInput) { if (chatIdInput) {
setChatId(chatIdInput); if (chatIdInput.startsWith("https://chat.jazz.tools/#/chat/")) {
setChatId(chatIdInput.split("/").pop());
} else {
setChatId(chatIdInput);
}
} else { } else {
Alert.alert("Error", "Chat ID cannot be empty."); 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; const isMe = item._edits?.text?.by?.isMe;
return ( return (
<View <View
className={clsx( style={[
`rounded-lg p-1 px-1.5 max-w-[80%] `, styles.messageContainer,
isMe ? styles.myMessage : styles.otherMessage,
isMe ? `bg-gray-200 self-end text-right` : `bg-gray-300 self-start `, ]}
)}
> >
{!isMe ? ( {!isMe ? (
<Text <Text
className={clsx( style={[
`text-xs text-gray-500`, styles.messageSender,
isMe ? "text-right" : "text-left", { textAlign: isMe ? "right" : "left" },
)} ]}
> >
{item?._edits?.text?.by?.profile?.name} {item?._edits?.text?.by?.profile?.name}
</Text> </Text>
) : null} ) : null}
<View <View style={styles.messageContent}>
className={clsx( <Text style={styles.messageText}>{item.text}</Text>
"flex relative items-end justify-between", <Text style={[styles.messageTime, { marginTop: !isMe ? 8 : 4 }]}>
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",
)}
>
{item?._edits?.text?.madeAt?.getHours().toString().padStart(2, "0")} {item?._edits?.text?.madeAt?.getHours().toString().padStart(2, "0")}
: :
{item?._edits?.text?.madeAt {item?._edits?.text?.madeAt
@@ -123,31 +93,28 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
}; };
return ( return (
<View className="flex flex-col h-full"> <View style={styles.container}>
{!loadedChat ? ( {!loadedChat ? (
<View className="flex flex-col h-full items-center justify-center"> <View style={styles.welcomeContainer}>
<Text className="text-m font-bold mb-6">Username</Text> <Text style={styles.usernameTitle}>Username</Text>
<TextInput <TextInput
className="rounded h-12 p-2 mb-12 w-40 border border-gray-200 block" style={styles.usernameInput}
value={profile?.name ?? ""} value={me?.profile.name ?? ""}
onChangeText={(value) => { onChangeText={(value) => {
if (profile) { if (me?.profile) {
profile.name = value; me.profile.name = value;
} }
}} }}
textAlignVertical="center" textAlignVertical="center"
onSubmitEditing={sendMessage} onSubmitEditing={sendMessage}
testID="username-input" testID="username-input"
/> />
<TouchableOpacity <TouchableOpacity onPress={createChat} style={styles.newChatButton}>
onPress={createChat} <Text style={styles.newChatButtonText}>Start new chat</Text>
className="bg-blue-500 p-4 rounded-md"
>
<Text className="text-white font-semibold">Start new chat</Text>
</TouchableOpacity> </TouchableOpacity>
<Text className="text-m font-bold mt-6">Join existing chat</Text> <Text style={styles.joinChatTitle}>Join existing chat</Text>
<TextInput <TextInput
className="rounded h-12 p-2 m-2 mt-4 w-80 border border-gray-200 block" style={styles.chatIdInput}
placeholder="Chat ID" placeholder="Chat ID"
value={chatIdInput ?? ""} value={chatIdInput ?? ""}
onChangeText={(value) => { onChangeText={(value) => {
@@ -161,22 +128,38 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
}} }}
testID="chat-id-input" testID="chat-id-input"
/> />
<TouchableOpacity <TouchableOpacity onPress={joinChat} style={styles.joinChatButton}>
onPress={joinChat} <Text style={styles.newChatButtonText}>Join chat</Text>
className="bg-green-500 p-4 rounded-md"
>
<Text className="text-white font-semibold">Join chat</Text>
</TouchableOpacity> </TouchableOpacity>
</View> </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 <FlatList
contentContainerStyle={{ contentContainerStyle={{
flexGrow: 1, flexGrow: 1,
gap: 6, gap: 6,
padding: 8, padding: 8,
justifyContent: "flex-end",
}} }}
className="flex" style={styles.messageList}
data={loadedChat} data={loadedChat}
keyExtractor={(item) => item.id} keyExtractor={(item) => item.id}
renderItem={renderMessageItem} renderItem={renderMessageItem}
@@ -185,11 +168,11 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
<KeyboardAvoidingView <KeyboardAvoidingView
keyboardVerticalOffset={110} keyboardVerticalOffset={110}
behavior="padding" 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 <TextInput
className="rounded-full h-8 py-0 px-2 border border-gray-200 block flex-1" style={styles.messageInput}
value={message} value={message}
onChangeText={setMessage} onChangeText={setMessage}
placeholder="Type a message..." placeholder="Type a message..."
@@ -199,7 +182,7 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
/> />
<TouchableOpacity <TouchableOpacity
onPress={sendMessage} onPress={sendMessage}
className="bg-gray-300 text-white rounded-full h-8 w-8 items-center justify-center" style={styles.sendButton}
testID="send-button" testID="send-button"
> >
<Text></Text> <Text></Text>
@@ -211,3 +194,133 @@ export default function ChatScreen({ navigation }: { navigation: any }) {
</View> </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({ export const Message = co.map({
text: z.string(), text: z.string(),
}); });
export type Message = co.loaded<typeof Message>;
export const Chat = co.list(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" # - assertVisible: "Reload"
# - tapOn: "Reload" # - tapOn: "Reload"
# login - assertVisible: "Username"
- assertVisible: "Logout"
- tapOn: "Logout"
- assertVisible: "Anonymous user"
- runFlow: - runFlow:
label: "Erase existing username" label: "Erase existing username"
file: erase_text.yml file: erase_text.yml
@@ -43,12 +40,13 @@ appId: com.jazz.chatrn
# logout # logout
- tapOn: "Logout" - tapOn: "Logout"
- assertVisible: "Username"
- assertVisible: "Anonymous user" - assertVisible: "Anonymous user"
# join chat # join chat
- tapOn: # - tapOn:
id: "chat-id-input" # id: "chat-id-input"
- inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard # - inputText: "co_zFs6KFyhxPw4xtw83tcEMzeHUNv" # Use a static id because maestro doesn't have access to the system clipboard
- tapOn: "Join chat" # - tapOn: "Join chat"
- assertVisible: "boorad" # - assertVisible: "boorad"
- assertVisible: "bro, low key, it do be like that tho" # - 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 # This script is necessary, because unlike ios, the android emulator action
# accepts a script, runs it as your tests, then terminates. # accepts a script, runs it as your tests, then terminates.
set -e # set -e
# build and install the app # # build and install the app
echo "Building and installing Android app." # echo "Building and installing Android app."
echo "If it fails, its output will be in artifact: android-install.log..." # echo "If it fails, its output will be in artifact: android-install.log..."
cd ./android/ # cd ./android/
./gradlew installRelease >> ~/output/android-install.log 2>&1 # ./gradlew installRelease >> ~/output/android-install.log 2>&1
cd .. # cd ..
# run the e2e tests # run the e2e tests
export PATH="$PATH":"$HOME/.maestro/bin" export PATH="$PATH":"$HOME/.maestro/bin"

View File

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

View File

@@ -1,5 +1,75 @@
# chat-rn # chat-rn
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-react-native@0.14.7
## 1.0.124
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-react-native@0.14.6
## 1.0.123 ## 1.0.123
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,62 @@
# chat-vue # chat-vue
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-browser@0.14.7
- jazz-vue@0.14.7
## 0.0.107
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-browser@0.14.6
- jazz-vue@0.14.6
## 0.0.106 ## 0.0.106
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,77 @@
# jazz-example-chat # jazz-example-chat
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-inspector@0.14.7
- jazz-react@0.14.7
## 0.0.205
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-inspector@0.14.6
- jazz-react@0.14.6
## 0.0.204 ## 0.0.204
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,76 @@
# minimal-auth-clerk # minimal-auth-clerk
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-react@0.14.7
- jazz-react-auth-clerk@0.14.7
## 0.0.104
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-react@0.14.6
- jazz-react-auth-clerk@0.14.6
## 0.0.103 ## 0.0.103
### Patch Changes ### Patch Changes

View File

@@ -2,7 +2,7 @@
This is an example of how to use clerk authentication with Jazz. 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 ## Getting started

View File

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

View File

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

View File

@@ -1,5 +1,74 @@
# file-share-svelte # file-share-svelte
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-inspector-element@0.14.7
- jazz-svelte@0.14.7
## 0.0.89
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-inspector-element@0.14.6
- jazz-svelte@0.14.6
## 0.0.88 ## 0.0.88
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,8 +1,8 @@
import { FileStream, Group, co, z } from 'jazz-tools'; import { Group, co, z } from 'jazz-tools';
export const SharedFile = co.map({ export const SharedFile = co.map({
name: z.string(), name: z.string(),
file: FileStream, file: co.fileStream(),
createdAt: z.date(), createdAt: z.date(),
uploadedAt: z.date(), uploadedAt: z.date(),
size: z.number(), size: z.number(),

View File

@@ -1,5 +1,76 @@
# jazz-tailwind-demo-auth-starter # jazz-tailwind-demo-auth-starter
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-inspector@0.14.7
- jazz-react@0.14.7
## 0.0.44
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-inspector@0.14.6
- jazz-react@0.14.6
## 0.0.43 ## 0.0.43
### Patch Changes ### Patch Changes

View File

@@ -2,7 +2,7 @@
This is an example of how to upload and render images with Jazz. 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 ## Getting started

View File

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

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useAccount } from "jazz-react"; import { useAccount } from "jazz-react";
import { FileStream, co } from "jazz-tools"; import { co } from "jazz-tools";
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { JazzAccount } from "./schema"; import { JazzAccount } from "./schema";
@@ -125,7 +125,7 @@ export function FileWidget() {
try { try {
setIsUploading(true); setIsUploading(true);
me.profile.file = await FileStream.createFromBlob(file, { me.profile.file = await co.fileStream().createFromBlob(file, {
onProgress: (p) => setProgress(Math.round(p * 100)), onProgress: (p) => setProgress(Math.round(p * 100)),
}); });
} catch (error) { } catch (error) {

View File

@@ -1,5 +1,69 @@
# form # form
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-react@0.14.7
## 0.1.45
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-react@0.14.6
## 0.1.44 ## 0.1.44
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,68 @@
# image-upload # image-upload
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-react@0.14.7
## 0.0.101
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-react@0.14.6
## 0.0.100 ## 0.0.100
### Patch Changes ### Patch Changes

View File

@@ -2,7 +2,7 @@
This is an example of how to upload and render images with Jazz. 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 ## Getting started

View File

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

View File

@@ -1,5 +1,55 @@
# jazz-example-inspector # jazz-example-inspector
## 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
- jazz-inspector@0.14.7
## 0.0.154
### Patch Changes
- jazz-inspector@0.14.6
## 0.0.153 ## 0.0.153
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
# Jazz Inspector # 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. Use this to visually inspect a Jazz account or other CoValue.

View File

@@ -1,7 +1,7 @@
{ {
"name": "jazz-inspector-app", "name": "jazz-inspector-app",
"private": true, "private": true,
"version": "0.0.153", "version": "0.0.161",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
@@ -17,15 +17,15 @@
"cojson-transport-ws": "workspace:*", "cojson-transport-ws": "workspace:*",
"hash-slash": "workspace:*", "hash-slash": "workspace:*",
"lucide-react": "^0.274.0", "lucide-react": "^0.274.0",
"react": "^18.3.1", "react": "19.0.0",
"react-dom": "^18.3.1", "react-dom": "19.0.0",
"react-router": "^6.16.0", "react-router": "^6.16.0",
"react-router-dom": "^6.16.0", "react-router-dom": "^6.16.0",
"react-use": "^17.4.0" "react-use": "^17.4.0"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.3.12", "@types/react": "19.0.0",
"@types/react-dom": "^18.3.1", "@types/react-dom": "19.0.0",
"@vitejs/plugin-react-swc": "^3.3.2", "@vitejs/plugin-react-swc": "^3.3.2",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"postcss": "^8.4.27", "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,9 @@
# jazz-nextjs
## 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.1",
"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,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,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,39 @@
"use client";
import { useAccount } from "jazz-react";
import { Account } from "jazz-tools";
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>
</div>
);
}

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-react": "workspace:*",
"jazz-tools": "workspace:*", "jazz-tools": "workspace:*",
"lucide-react": "^0.485.0", "lucide-react": "^0.485.0",
"react": "^18.3.1", "react": "19.0.0",
"react-dom": "^18.3.1", "react-dom": "19.0.0",
"tailwind-merge": "^3.0.2", "tailwind-merge": "^3.0.2",
"tailwindcss": "^4.0.17", "tailwindcss": "^4.0.17",
"tw-animate-css": "^1.2.5" "tw-animate-css": "^1.2.5"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.3.12", "@types/react": "19.0.0",
"@types/react-dom": "^18.3.1", "@types/react-dom": "19.0.0",
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
"jazz-run": "workspace:*", "jazz-run": "workspace:*",
"npm-run-all": "^4.1.5", "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 type JoinGameRequest = co.loaded<typeof JoinGameRequest>;
export const InboxMessage = z.discriminatedUnion([ export const InboxMessage = z.discriminatedUnion("type", [
PlayIntent, PlayIntent,
NewGameIntent, NewGameIntent,
CreateGameRequest, CreateGameRequest,

View File

@@ -1,5 +1,68 @@
# multi-cursors # multi-cursors
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-react@0.14.7
## 0.0.97
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-react@0.14.6
## 0.0.96 ## 0.0.96
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,7 @@
# Jazz Multi-Cursors Example # Jazz Multi-Cursors Example
Track user presence on a canvas with multiple cursors and out of bounds indicators. 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 ## Getting started

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,76 @@
# multiauth # multiauth
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-react@0.14.7
- jazz-react-auth-clerk@0.14.7
## 0.0.45
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-react@0.14.6
- jazz-react-auth-clerk@0.14.6
## 0.0.44 ## 0.0.44
### Patch Changes ### Patch Changes

View File

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

View File

@@ -1,5 +1,76 @@
# jazz-example-musicplayer # jazz-example-musicplayer
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-inspector@0.14.7
- jazz-react@0.14.7
## 0.0.126
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-inspector@0.14.6
- jazz-react@0.14.6
## 0.0.125 ## 0.0.125
### Patch Changes ### Patch Changes

View File

@@ -1,6 +1,6 @@
# Music player example with Jazz and React # 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 ## Getting started

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,27 +1,40 @@
import { MusicaAccount } from "@/1_schema"; import { MusicTrack, MusicaAccount } from "@/1_schema";
import { deletePlaylist } from "@/4_actions"; import { createNewPlaylist, deletePlaylist } from "@/4_actions";
import { useAccount } from "jazz-react"; import { MediaPlayer } from "@/5_useMediaPlayer";
import { Trash2 } from "lucide-react"; 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 { 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 { playlistId } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
const { me } = useAccount(MusicaAccount, { const { me } = useAccount(MusicaAccount, {
resolve: { root: { playlists: { $each: true } } }, resolve: { root: { playlists: { $each: true } } },
}); });
function handleAllTracksClick(evt: React.MouseEvent<HTMLAnchorElement>) { const playState = usePlayState();
evt.preventDefault(); const isPlaying = playState.value === "play";
function handleAllTracksClick() {
navigate(`/`); navigate(`/`);
} }
function handlePlaylistClick( function handlePlaylistClick(playlistId: string) {
evt: React.MouseEvent<HTMLAnchorElement>,
playlistId: string,
) {
evt.preventDefault();
navigate(`/playlist/${playlistId}`); 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 ( return (
<aside className="w-64 p-6 bg-white overflow-y-auto"> <Sidebar>
<div className="flex items-center mb-1"> <SidebarHeader>
<svg <SidebarMenu>
className="w-8 h-8 mr-2" <SidebarMenuItem className="flex items-center gap-2">
viewBox="0 0 24 24" <div className="flex aspect-square size-8 items-center justify-center rounded-lg bg-blue-600 text-white">
fill="none" <svg
xmlns="http://www.w3.org/2000/svg" className="size-4"
> viewBox="0 0 24 24"
<path fill="none"
d="M9 18V5l12-2v13" xmlns="http://www.w3.org/2000/svg"
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)}
> >
{playlist.title} <path
</a> d="M9 18V5l12-2v13"
{playlist.id === playlistId && ( stroke="currentColor"
<button strokeWidth="2"
onClick={() => handleDeletePlaylist(playlist.id)} strokeLinecap="round"
className="ml-2 text-red-600 hover:text-red-800 animate-in fade-in scale-in duration-200" strokeLinejoin="round"
aria-label={`Delete ${playlist.title}`} />
> <path
<Trash2 size={16} /> 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"
</button> fill="currentColor"
)} />
</li> </svg>
))} </div>
</ul> <div className="grid flex-1 text-left text-sm leading-tight">
</nav> <span className="truncate font-semibold">Music Player</span>
</aside> </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"; import { cn } from "@/lib/utils";
const buttonVariants = cva( 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: { variants: {
variant: { variant: {
@@ -53,5 +53,4 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
); );
Button.displayName = "Button"; Button.displayName = "Button";
// eslint-disable-next-line react-refresh/only-export-components
export { Button, buttonVariants }; 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 TooltipPrimitive from "@radix-ui/react-tooltip";
import * as React from "react"; import * as React from "react";
@@ -19,7 +17,7 @@ const TooltipContent = React.forwardRef<
ref={ref} ref={ref}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( 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, className,
)} )}
{...props} {...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%; --ring: 20 14.3% 4.1%;
--radius: 0.5rem; --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 { .dark {
@@ -63,6 +79,14 @@
--border: 12 6.5% 15.1%; --border: 12 6.5% 15.1%;
--input: 12 6.5% 15.1%; --input: 12 6.5% 15.1%;
--ring: 24 5.7% 82.9%; --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() { export function usePlayMedia() {
const audioManager = useAudioManager(); const audioManager = useAudioManager();
const previousMediaLoad = useRef<Promise<unknown>>(); const previousMediaLoad = useRef<Promise<unknown> | undefined>(undefined);
async function playMedia(file: Blob) { async function playMedia(file: Blob) {
// Wait for the previous load to finish // Wait for the previous load to finish

View File

@@ -52,6 +52,16 @@ const config: Config = {
DEFAULT: "hsl(var(--card))", DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))", 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: { borderRadius: {
lg: "var(--radius)", lg: "var(--radius)",
@@ -60,12 +70,20 @@ const config: Config = {
}, },
keyframes: { keyframes: {
"accordion-down": { "accordion-down": {
from: { height: "0" }, from: {
to: { height: "var(--radix-accordion-content-height)" }, height: "0",
},
to: {
height: "var(--radix-accordion-content-height)",
},
}, },
"accordion-up": { "accordion-up": {
from: { height: "var(--radix-accordion-content-height)" }, from: {
to: { height: "0" }, height: "var(--radix-accordion-content-height)",
},
to: {
height: "0",
},
}, },
}, },
animation: { animation: {

View File

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

View File

@@ -1,5 +1,68 @@
# organization # organization
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-react@0.14.7
## 0.0.97
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-react@0.14.6
## 0.0.96 ## 0.0.96
### Patch Changes ### 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. 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". 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. Refer to the [documentation](https://jazz.tools/docs/react/design-patterns/organization) for more information.
## Getting started ## Getting started

View File

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

View File

@@ -1,5 +1,56 @@
# passkey-svelte # passkey-svelte
## 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
- Updated dependencies [365b0ea]
- jazz-tools@0.14.7
- jazz-svelte@0.14.7
## 0.0.93
### Patch Changes
- Updated dependencies [9d6d9fe]
- Updated dependencies [9d6d9fe]
- jazz-tools@0.14.6
- jazz-svelte@0.14.6
## 0.0.92 ## 0.0.92
### Patch Changes ### Patch Changes

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,13 @@
<script lang="ts"> <script lang="ts">
import { JazzProvider, PasskeyAuthBasicUI } from 'jazz-svelte'; import { JazzProvider, PasskeyAuthBasicUI } from 'jazz-svelte';
import {apiKey} from '../apiKey'; import { apiKey } from '../apiKey';
let { children } = $props(); let { children } = $props();
</script> </script>
<JazzProvider <JazzProvider
sync={{ sync={{
peer: `wss://cloud.jazz.tools/?key=${apiKey}`, peer: `wss://cloud.jazz.tools/?key=${apiKey}`
}} }}
> >
<PasskeyAuthBasicUI appName="minimal-svelte-auth-passkey"> <PasskeyAuthBasicUI appName="minimal-svelte-auth-passkey">

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