deepspace 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@ import { useUser } from 'deepspace'
13
13
  import { useUsers } from 'deepspace'
14
14
  import { useQuery } from 'deepspace'
15
15
  import { useMutations } from 'deepspace'
16
- import { Button, Badge, Avatar, AvatarFallback, useToast } from 'deepspace'
16
+ import { Button, Badge, Avatar, AvatarFallback, useToast } from '@/components/ui'
17
17
  import { ROLES, ROLE_CONFIG, type Role } from 'deepspace'
18
18
 
19
19
  // ============================================================================
@@ -12,7 +12,7 @@ import { useNavigate } from 'react-router-dom'
12
12
  import { useUser } from 'deepspace'
13
13
  import { useQuery } from 'deepspace'
14
14
  import { useMutations } from 'deepspace'
15
- import { Button, Modal, EmptyState } from 'deepspace'
15
+ import { Button, Modal, EmptyState } from '@/components/ui'
16
16
  import { ROLES, type Role } from 'deepspace'
17
17
 
18
18
  // ============================================================================
@@ -6,7 +6,7 @@ import { useState, useRef, useCallback, useEffect } from 'react'
6
6
  import { useCanvas, type CanvasShapeClient } from 'deepspace'
7
7
  import { CanvasToolbar, type CanvasTool } from './CanvasToolbar'
8
8
  import { ShapeRenderer } from './ShapeRenderer'
9
- import { Badge } from 'deepspace'
9
+ import { Badge } from '@/components/ui'
10
10
 
11
11
  interface CanvasViewProps {
12
12
  docId: string
@@ -24,7 +24,7 @@ import {
24
24
  type PresencePeerClient,
25
25
  } from 'deepspace'
26
26
  import { ArrowLeft, AlertTriangle, List as ListIcon, RefreshCw, Share2 } from 'lucide-react'
27
- import { Badge } from 'deepspace'
27
+ import { Badge } from '@/components/ui'
28
28
  import { type Editor, useEditorState } from '@tiptap/react'
29
29
  import { useYjsRoomWithAwareness } from './use-yjs-room-with-awareness'
30
30
  import { useDocEditor } from './editor/useDocEditor'
@@ -2,14 +2,7 @@ import { useMemo, useState } from 'react'
2
2
  import type { RecordData } from 'deepspace'
3
3
  import { useMutations, useQuery, useUser } from 'deepspace'
4
4
  import { Mail, ShieldCheck, UserMinus, Users } from 'lucide-react'
5
- import {
6
- Dialog,
7
- DialogContent,
8
- DialogDescription,
9
- DialogHeader,
10
- DialogTitle,
11
- useToast,
12
- } from '../../components/ui'
5
+ import { Modal, useToast } from '@/components/ui'
13
6
 
14
7
  export interface InviteDialogDocumentFields {
15
8
  title: string
@@ -187,150 +180,148 @@ export function InviteDialog({ open, onOpenChange, doc, isOwner, onAclChange }:
187
180
  'Owner'
188
181
 
189
182
  return (
190
- <Dialog open={open} onOpenChange={onOpenChange}>
191
- <DialogContent className="docs-feature-scope max-w-xl">
192
- <DialogHeader>
193
- <DialogTitle>Share document</DialogTitle>
194
- <DialogDescription>
195
- Invite DeepSpace users by the email address on their account.
196
- </DialogDescription>
197
- </DialogHeader>
183
+ <Modal open={open} onClose={() => onOpenChange(false)} size="lg" className="docs-feature-scope">
184
+ <Modal.Header onClose={() => onOpenChange(false)}>
185
+ <Modal.Title>Share document</Modal.Title>
186
+ <Modal.Description>
187
+ Invite DeepSpace users by the email address on their account.
188
+ </Modal.Description>
189
+ </Modal.Header>
198
190
 
199
- <div className="space-y-5">
200
- <div className="rounded-xl border p-3" style={{ borderColor: 'var(--docs-el-line)' }}>
201
- <label
202
- className="mb-2 block text-xs font-semibold uppercase tracking-wide"
203
- style={{ color: 'var(--docs-el-muted)' }}
204
- >
205
- Add people
206
- </label>
207
- <div className="flex flex-col gap-2 sm:flex-row">
208
- <div className="relative min-w-0 flex-1">
209
- <Mail
210
- className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2"
211
- style={{ color: 'var(--docs-el-muted)' }}
212
- />
213
- <input
214
- value={email}
215
- onChange={(e) => setEmail(e.target.value)}
216
- onKeyDown={(e) => {
217
- if (e.key === 'Enter') void addInvite()
218
- }}
219
- placeholder="person@gmail.com"
220
- className="h-10 w-full rounded-lg border bg-transparent pl-9 pr-3 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring/30"
221
- style={{ borderColor: 'var(--docs-el-line)', color: 'var(--docs-el-text)' }}
222
- />
223
- </div>
224
- <select
225
- value={role}
226
- onChange={(e) => setRole(e.target.value as InviteRole)}
227
- className="h-10 rounded-lg border bg-transparent px-3 text-sm font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring/30"
191
+ <Modal.Body className="space-y-5">
192
+ <div className="rounded-xl border p-3" style={{ borderColor: 'var(--docs-el-line)' }}>
193
+ <label
194
+ className="mb-2 block text-xs font-semibold uppercase tracking-wide"
195
+ style={{ color: 'var(--docs-el-muted)' }}
196
+ >
197
+ Add people
198
+ </label>
199
+ <div className="flex flex-col gap-2 sm:flex-row">
200
+ <div className="relative min-w-0 flex-1">
201
+ <Mail
202
+ className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2"
203
+ style={{ color: 'var(--docs-el-muted)' }}
204
+ />
205
+ <input
206
+ value={email}
207
+ onChange={(e) => setEmail(e.target.value)}
208
+ onKeyDown={(e) => {
209
+ if (e.key === 'Enter') void addInvite()
210
+ }}
211
+ placeholder="person@gmail.com"
212
+ className="h-10 w-full rounded-lg border bg-transparent pl-9 pr-3 text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring/30"
228
213
  style={{ borderColor: 'var(--docs-el-line)', color: 'var(--docs-el-text)' }}
229
- >
230
- <option value="editor">Editor</option>
231
- <option value="viewer">Viewer</option>
232
- </select>
233
- <button
234
- type="button"
235
- onClick={() => void addInvite()}
236
- disabled={saving || !email.trim()}
237
- className="h-10 rounded-lg px-4 text-sm font-semibold text-white transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50"
238
- style={{ backgroundColor: 'var(--docs-el-accent)' }}
239
- >
240
- Add
241
- </button>
214
+ />
242
215
  </div>
216
+ <select
217
+ value={role}
218
+ onChange={(e) => setRole(e.target.value as InviteRole)}
219
+ className="h-10 rounded-lg border bg-transparent px-3 text-sm font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring/30"
220
+ style={{ borderColor: 'var(--docs-el-line)', color: 'var(--docs-el-text)' }}
221
+ >
222
+ <option value="editor">Editor</option>
223
+ <option value="viewer">Viewer</option>
224
+ </select>
225
+ <button
226
+ type="button"
227
+ onClick={() => void addInvite()}
228
+ disabled={saving || !email.trim()}
229
+ className="h-10 rounded-lg px-4 text-sm font-semibold text-white transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50"
230
+ style={{ backgroundColor: 'var(--docs-el-accent)' }}
231
+ >
232
+ Add
233
+ </button>
243
234
  </div>
235
+ </div>
244
236
 
245
- <div>
246
- <div className="mb-3 flex items-center gap-2">
247
- <Users className="h-4 w-4" style={{ color: 'var(--docs-el-muted)' }} />
248
- <h3 className="text-sm font-semibold">People with access</h3>
249
- </div>
237
+ <div>
238
+ <div className="mb-3 flex items-center gap-2">
239
+ <Users className="h-4 w-4" style={{ color: 'var(--docs-el-muted)' }} />
240
+ <h3 className="text-sm font-semibold">People with access</h3>
241
+ </div>
250
242
 
251
- <div className="space-y-2">
252
- <div
253
- className="flex items-center gap-3 rounded-xl border p-3"
254
- style={{ borderColor: 'var(--docs-el-line)' }}
255
- >
256
- <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-black/5 text-xs font-bold dark:bg-white/10">
257
- {initialsFor(ownerName)}
258
- </div>
259
- <div className="min-w-0 flex-1">
260
- <div className="truncate text-sm font-medium">{ownerName}</div>
261
- <div className="truncate text-xs" style={{ color: 'var(--docs-el-muted)' }}>
262
- {ownerRecord?.data.email ?? user?.email ?? 'Owner'}
263
- </div>
243
+ <div className="space-y-2">
244
+ <div
245
+ className="flex items-center gap-3 rounded-xl border p-3"
246
+ style={{ borderColor: 'var(--docs-el-line)' }}
247
+ >
248
+ <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-black/5 text-xs font-bold dark:bg-white/10">
249
+ {initialsFor(ownerName)}
250
+ </div>
251
+ <div className="min-w-0 flex-1">
252
+ <div className="truncate text-sm font-medium">{ownerName}</div>
253
+ <div className="truncate text-xs" style={{ color: 'var(--docs-el-muted)' }}>
254
+ {ownerRecord?.data.email ?? user?.email ?? 'Owner'}
264
255
  </div>
265
- <span className="inline-flex items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-medium">
266
- <ShieldCheck className="h-3.5 w-3.5" />
267
- Owner
268
- </span>
269
256
  </div>
257
+ <span className="inline-flex items-center gap-1 rounded-full border px-2.5 py-1 text-xs font-medium">
258
+ <ShieldCheck className="h-3.5 w-3.5" />
259
+ Owner
260
+ </span>
261
+ </div>
270
262
 
271
- {collaboratorRecords.map((u) => {
272
- const name = u.data.name?.trim() || u.data.email?.trim() || 'Collaborator'
273
- const userRole: InviteRole = editors.includes(u.recordId) ? 'editor' : 'viewer'
274
- return (
275
- <div
276
- key={u.recordId}
277
- className="flex items-center gap-3 rounded-xl border p-3"
278
- style={{ borderColor: 'var(--docs-el-line)' }}
279
- >
280
- {u.data.imageUrl ? (
281
- <img
282
- src={u.data.imageUrl}
283
- alt=""
284
- className="h-9 w-9 shrink-0 rounded-full object-cover"
285
- />
286
- ) : (
287
- <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-black/5 text-xs font-bold dark:bg-white/10">
288
- {initialsFor(name)}
289
- </div>
290
- )}
291
- <div className="min-w-0 flex-1">
292
- <div className="truncate text-sm font-medium">{name}</div>
293
- <div className="truncate text-xs" style={{ color: 'var(--docs-el-muted)' }}>
294
- {u.data.email ?? 'No email'}
295
- </div>
263
+ {collaboratorRecords.map((u) => {
264
+ const name = u.data.name?.trim() || u.data.email?.trim() || 'Collaborator'
265
+ const userRole: InviteRole = editors.includes(u.recordId) ? 'editor' : 'viewer'
266
+ return (
267
+ <div
268
+ key={u.recordId}
269
+ className="flex items-center gap-3 rounded-xl border p-3"
270
+ style={{ borderColor: 'var(--docs-el-line)' }}
271
+ >
272
+ {u.data.imageUrl ? (
273
+ <img
274
+ src={u.data.imageUrl}
275
+ alt=""
276
+ className="h-9 w-9 shrink-0 rounded-full object-cover"
277
+ />
278
+ ) : (
279
+ <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-black/5 text-xs font-bold dark:bg-white/10">
280
+ {initialsFor(name)}
281
+ </div>
282
+ )}
283
+ <div className="min-w-0 flex-1">
284
+ <div className="truncate text-sm font-medium">{name}</div>
285
+ <div className="truncate text-xs" style={{ color: 'var(--docs-el-muted)' }}>
286
+ {u.data.email ?? 'No email'}
296
287
  </div>
297
- <select
298
- value={userRole}
299
- onChange={(e) =>
300
- void setCollaboratorRole(u.recordId, e.target.value as InviteRole)
301
- }
302
- disabled={saving}
303
- className="h-8 rounded-lg border bg-transparent px-2 text-xs font-medium outline-none"
304
- style={{ borderColor: 'var(--docs-el-line)', color: 'var(--docs-el-text)' }}
305
- >
306
- <option value="editor">Editor</option>
307
- <option value="viewer">Viewer</option>
308
- </select>
309
- <button
310
- type="button"
311
- onClick={() => void removeCollaborator(u.recordId)}
312
- disabled={saving}
313
- className="rounded-lg p-1.5 text-red-600 transition-colors hover:bg-red-500/10 disabled:opacity-50"
314
- title="Remove access"
315
- >
316
- <UserMinus className="h-4 w-4" />
317
- </button>
318
288
  </div>
319
- )
320
- })}
289
+ <select
290
+ value={userRole}
291
+ onChange={(e) =>
292
+ void setCollaboratorRole(u.recordId, e.target.value as InviteRole)
293
+ }
294
+ disabled={saving}
295
+ className="h-8 rounded-lg border bg-transparent px-2 text-xs font-medium outline-none"
296
+ style={{ borderColor: 'var(--docs-el-line)', color: 'var(--docs-el-text)' }}
297
+ >
298
+ <option value="editor">Editor</option>
299
+ <option value="viewer">Viewer</option>
300
+ </select>
301
+ <button
302
+ type="button"
303
+ onClick={() => void removeCollaborator(u.recordId)}
304
+ disabled={saving}
305
+ className="rounded-lg p-1.5 text-red-600 transition-colors hover:bg-red-500/10 disabled:opacity-50"
306
+ title="Remove access"
307
+ >
308
+ <UserMinus className="h-4 w-4" />
309
+ </button>
310
+ </div>
311
+ )
312
+ })}
321
313
 
322
- {collaboratorRecords.length === 0 ? (
323
- <p
324
- className="rounded-xl border p-3 text-sm"
325
- style={{ color: 'var(--docs-el-muted)' }}
326
- >
327
- Only the owner can access this document.
328
- </p>
329
- ) : null}
330
- </div>
314
+ {collaboratorRecords.length === 0 ? (
315
+ <p
316
+ className="rounded-xl border p-3 text-sm"
317
+ style={{ color: 'var(--docs-el-muted)' }}
318
+ >
319
+ Only the owner can access this document.
320
+ </p>
321
+ ) : null}
331
322
  </div>
332
323
  </div>
333
- </DialogContent>
334
- </Dialog>
324
+ </Modal.Body>
325
+ </Modal>
335
326
  )
336
327
  }
@@ -16,14 +16,11 @@ import {
16
16
  useQuery,
17
17
  useMutations,
18
18
  useR2Files,
19
- Button,
20
- Modal,
21
- EmptyState,
22
- Badge,
23
19
  ROLES,
24
20
  formatFileSize,
25
21
  type Role,
26
22
  } from 'deepspace'
23
+ import { Button, Modal, EmptyState, Badge } from '@/components/ui'
27
24
  import { useMimeTypeDetection, type FileCategory } from '../hooks/useMimeTypeDetection'
28
25
  import { useFilePreview } from '../hooks/useFilePreview'
29
26
  import { MAX_FILE_SIZE } from '../constants/attachments-constants'
@@ -9,7 +9,8 @@
9
9
  */
10
10
 
11
11
  import { useState, useEffect, useCallback, useRef } from 'react'
12
- import { useUser, useR2Files, Button, EmptyState, Badge, Modal } from 'deepspace'
12
+ import { useUser, useR2Files } from 'deepspace'
13
+ import { Button, EmptyState, Badge, Modal } from '@/components/ui'
13
14
  import type { R2FileInfo } from 'deepspace'
14
15
 
15
16
  // ============================================================================
@@ -12,7 +12,7 @@ import { useState, useMemo } from 'react'
12
12
  import { useUser } from 'deepspace'
13
13
  import { useQuery } from 'deepspace'
14
14
  import { useMutations } from 'deepspace'
15
- import { Button, Modal, EmptyState, Badge } from 'deepspace'
15
+ import { Button, Modal, EmptyState, Badge } from '@/components/ui'
16
16
  import { ROLES, type Role } from 'deepspace'
17
17
  import { ITEM_STATUS } from '../components/items/items-constants'
18
18
 
@@ -14,7 +14,7 @@ import {
14
14
  Github, Twitter, Linkedin, Mail, Sparkles, ChevronRight, Plus, Minus,
15
15
  } from 'lucide-react'
16
16
  import { useUser } from 'deepspace'
17
- import { Button, cn } from 'deepspace'
17
+ import { Button, cn } from '@/components/ui'
18
18
  import {
19
19
  Typewriter,
20
20
  ScrollReveal,
@@ -8,7 +8,7 @@
8
8
  import { useEffect, useState, useRef, type ReactNode } from 'react'
9
9
  import { motion, AnimatePresence, useInView } from 'framer-motion'
10
10
  import { ImageIcon, ChevronDown } from 'lucide-react'
11
- import { cn } from 'deepspace'
11
+ import { cn } from '@/components/ui'
12
12
 
13
13
  // ============================================================================
14
14
  // Smooth Typewriter
@@ -12,7 +12,7 @@ import { useState } from 'react'
12
12
  import { useUser } from 'deepspace'
13
13
  import { useQuery } from 'deepspace'
14
14
  import { useMutations } from 'deepspace'
15
- import { Button, Modal, EmptyState, Badge } from 'deepspace'
15
+ import { Button, Modal, EmptyState, Badge } from '@/components/ui'
16
16
  import { ROLES, type Role } from 'deepspace'
17
17
  import { LEADERBOARD_CATEGORY, CATEGORY_CONFIG, type LeaderboardCategory } from '../components/leaderboard/leaderboard-constants'
18
18
 
@@ -2,7 +2,7 @@
2
2
  * Leaderboard Feature - Constants
3
3
  */
4
4
 
5
- import type { BadgeProps } from 'deepspace'
5
+ import type { BadgeProps } from '@/components/ui'
6
6
 
7
7
  export type BadgeVariant = BadgeProps['variant']
8
8
 
@@ -1,5 +1,5 @@
1
1
  import { useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
2
- import { Badge, Button, EmptyState, SearchInput, cn } from 'deepspace'
2
+ import { Badge, Button, EmptyState, SearchInput, cn } from '@/components/ui'
3
3
  import { Loader2 } from 'lucide-react'
4
4
 
5
5
  export interface SearchItem {
@@ -13,7 +13,7 @@ import { useUser } from 'deepspace'
13
13
  import { useUsers } from 'deepspace'
14
14
  import { useQuery } from 'deepspace'
15
15
  import { useMutations } from 'deepspace'
16
- import { Button, Modal, Badge, EmptyState, type BadgeProps } from 'deepspace'
16
+ import { Button, Modal, Badge, EmptyState, type BadgeProps } from '@/components/ui'
17
17
  import { ROLES, type Role } from 'deepspace'
18
18
  import { DIFFICULTY, DIFFICULTY_CONFIG, GRADE, GRADE_CONFIG, type Difficulty, type Grade, type BadgeVariant } from '../components/tasks/tasks-constants'
19
19
 
@@ -2,7 +2,7 @@
2
2
  * Tasks/Challenges Feature - Constants
3
3
  */
4
4
 
5
- import type { BadgeProps } from 'deepspace'
5
+ import type { BadgeProps } from '@/components/ui'
6
6
 
7
7
  export type BadgeVariant = BadgeProps['variant']
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deepspace",
3
- "version": "0.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "DeepSpace SDK — build real-time collaborative apps on Cloudflare Workers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -56,7 +56,6 @@
56
56
  "@ai-sdk/openai-compatible": "^1.0.0",
57
57
  "@playwright/test": ">=1.40.0",
58
58
  "ai": "^5.0.0",
59
- "class-variance-authority": ">=0.7.0",
60
59
  "clsx": ">=2.0.0",
61
60
  "lucide-react": ">=0.400.0",
62
61
  "react": "^18.0.0 || ^19.0.0",
@@ -85,9 +84,6 @@
85
84
  "react-dom": {
86
85
  "optional": true
87
86
  },
88
- "class-variance-authority": {
89
- "optional": true
90
- },
91
87
  "clsx": {
92
88
  "optional": true
93
89
  },
@@ -104,24 +100,11 @@
104
100
  "@ai-sdk/openai-compatible": "^1.0.0",
105
101
  "@cloudflare/workers-types": "^4.20241205.0",
106
102
  "@playwright/test": "^1.59.1",
107
- "@radix-ui/react-avatar": "^1.1.11",
108
- "@radix-ui/react-checkbox": "^1.3.3",
109
- "@radix-ui/react-dialog": "^1.1.15",
110
- "@radix-ui/react-dropdown-menu": "^2.1.16",
111
- "@radix-ui/react-label": "^2.1.8",
112
- "@radix-ui/react-progress": "^1.1.8",
113
- "@radix-ui/react-select": "^2.2.6",
114
- "@radix-ui/react-separator": "^1.1.8",
115
- "@radix-ui/react-slot": "^1.2.4",
116
- "@radix-ui/react-switch": "^1.2.6",
117
- "@radix-ui/react-tabs": "^1.1.13",
118
- "@radix-ui/react-tooltip": "^1.2.8",
119
103
  "@types/better-sqlite3": "^7.6.12",
120
104
  "@types/cross-spawn": "^6.0.6",
121
105
  "@types/react": "^19.0.0",
122
106
  "@types/react-dom": "^19.0.0",
123
107
  "better-sqlite3": "^12.0.0",
124
- "class-variance-authority": "^0.7.1",
125
108
  "clsx": "^2.1.1",
126
109
  "framer-motion": "^12.38.0",
127
110
  "lucide-react": "^1.7.0",