promptslide 0.3.16 → 0.3.18

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.
package/package.json CHANGED
@@ -1,16 +1,20 @@
1
1
  {
2
2
  "name": "promptslide",
3
- "version": "0.3.16",
3
+ "version": "0.3.18",
4
4
  "description": "CLI and slide engine for PromptSlide presentations",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js"
12
- },
13
- "./src/commands/*": "./src/commands/*"
5
+ "keywords": [
6
+ "cli",
7
+ "presentations",
8
+ "promptslide",
9
+ "react",
10
+ "slides",
11
+ "vite"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "prompticeu",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/prompticeu/promptslide.git"
14
18
  },
15
19
  "bin": {
16
20
  "promptslide": "src/index.mjs"
@@ -22,47 +26,43 @@
22
26
  "CHANGELOG.md",
23
27
  "README.md"
24
28
  ],
29
+ "type": "module",
30
+ "main": "./dist/index.js",
31
+ "types": "./dist/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js"
36
+ },
37
+ "./src/commands/*": "./src/commands/*"
38
+ },
25
39
  "scripts": {
26
40
  "build": "tsup",
27
41
  "test": "node --test test/*.test.mjs",
28
42
  "prepublishOnly": "npm run build"
29
43
  },
30
- "license": "MIT",
31
- "repository": {
32
- "type": "git",
33
- "url": "git+https://github.com/prompticeu/promptslide.git"
34
- },
35
- "author": "prompticeu",
36
- "keywords": [
37
- "slides",
38
- "presentations",
39
- "cli",
40
- "react",
41
- "promptslide",
42
- "vite"
43
- ],
44
44
  "dependencies": {
45
45
  "@tailwindcss/postcss": "^4.1.13",
46
46
  "@vitejs/plugin-react": "^4.5.2",
47
47
  "clsx": "^2.1.1",
48
48
  "lucide-react": "^0.552.0",
49
+ "playwright": "^1.50.0",
49
50
  "postcss": "^8.5.6",
50
51
  "tailwind-merge": "^3.3.1",
51
52
  "tailwindcss": "^4.1.13",
52
- "playwright": "^1.50.0",
53
+ "typescript": "^5.9.3",
53
54
  "vite": "^6.3.5"
54
55
  },
56
+ "devDependencies": {
57
+ "@types/react": "^19.2.14",
58
+ "@types/react-dom": "^19.2.3",
59
+ "tsup": "^8.5.1"
60
+ },
55
61
  "peerDependencies": {
56
62
  "framer-motion": "^12.0.0",
57
63
  "react": "^19.0.0",
58
64
  "react-dom": "^19.0.0"
59
65
  },
60
- "devDependencies": {
61
- "@types/react": "^19.2.14",
62
- "@types/react-dom": "^19.2.3",
63
- "tsup": "^8.5.1",
64
- "typescript": "^5.9.3"
65
- },
66
66
  "engines": {
67
67
  "node": ">=18.0.0"
68
68
  }
@@ -5,10 +5,14 @@ import { fileURLToPath } from "node:url"
5
5
  import { bold, green, cyan, red, dim, yellow } from "../utils/ansi.mjs"
6
6
  import { requireAuth } from "../utils/auth.mjs"
7
7
  import { hexToOklch } from "../utils/colors.mjs"
8
- import { closePrompts } from "../utils/prompts.mjs"
9
- import { fetchRegistryItem, resolveRegistryDependencies, writeLockfile } from "../utils/registry.mjs"
10
8
  import { toPascalCase, replaceDeckConfig } from "../utils/deck-config.mjs"
11
9
  import { collectRegistrySlideSlugs, partitionDeckSlides } from "../utils/deck-sync.mjs"
10
+ import { closePrompts } from "../utils/prompts.mjs"
11
+ import {
12
+ fetchRegistryItem,
13
+ resolveRegistryDependencies,
14
+ writeLockfile
15
+ } from "../utils/registry.mjs"
12
16
  import { ensureTsConfig } from "../utils/tsconfig.mjs"
13
17
 
14
18
  const __filename = fileURLToPath(import.meta.url)
@@ -63,7 +67,9 @@ export async function clone(args) {
63
67
  }
64
68
 
65
69
  if (item.type !== "deck") {
66
- console.error(` ${red("Error:")} "${slug}" is a ${item.type}, not a deck. Only decks can be cloned.`)
70
+ console.error(
71
+ ` ${red("Error:")} "${slug}" is a ${item.type}, not a deck. Only decks can be cloned.`
72
+ )
67
73
  process.exit(1)
68
74
  }
69
75
 
@@ -75,8 +81,12 @@ export async function clone(args) {
75
81
  const localParts = CLI_VERSION.match(/^(\d+)\.(\d+)/)
76
82
  if (pubParts && localParts && pubParts[2] !== localParts[2]) {
77
83
  console.log()
78
- console.log(` ${yellow("⚠")} This deck was published with promptslide ${bold(`v${item.promptslideVersion}`)}`)
79
- console.log(` You have ${bold(`v${CLI_VERSION}`)} installed — some slides may need updating.`)
84
+ console.log(
85
+ ` ${yellow("⚠")} This deck was published with promptslide ${bold(`v${item.promptslideVersion}`)}`
86
+ )
87
+ console.log(
88
+ ` You have ${bold(`v${CLI_VERSION}`)} installed — some slides may need updating.`
89
+ )
80
90
  }
81
91
  }
82
92
 
@@ -100,7 +110,11 @@ export async function clone(args) {
100
110
  const replacements = [
101
111
  {
102
112
  path: join(targetDir, "package.json"),
103
- values: { "{{PROJECT_SLUG}}": dirName, "{{PROJECT_NAME}}": projectName, "{{PROMPTSLIDE_VERSION}}": `^${CLI_VERSION}` }
113
+ values: {
114
+ "{{PROJECT_SLUG}}": dirName,
115
+ "{{PROJECT_NAME}}": projectName,
116
+ "{{PROMPTSLIDE_VERSION}}": `^${CLI_VERSION}`
117
+ }
104
118
  },
105
119
  {
106
120
  path: join(targetDir, "src", "theme.ts"),
@@ -149,7 +163,10 @@ export async function clone(args) {
149
163
 
150
164
  const dataUriPrefix = file.content.match(/^data:[^;]+;base64,/)
151
165
  if (dataUriPrefix) {
152
- writeFileSync(targetPath, Buffer.from(file.content.slice(dataUriPrefix[0].length), "base64"))
166
+ writeFileSync(
167
+ targetPath,
168
+ Buffer.from(file.content.slice(dataUriPrefix[0].length), "base64")
169
+ )
153
170
  } else {
154
171
  writeFileSync(targetPath, file.content, "utf-8")
155
172
  }
@@ -168,6 +185,7 @@ export async function clone(args) {
168
185
  const slides = available.map(s => ({
169
186
  componentName: s.componentName || toPascalCase(s.slug),
170
187
  importPath: `@/slides/${s.slug}`,
188
+ id: s.id,
171
189
  steps: s.steps,
172
190
  section: s.section
173
191
  }))
@@ -175,7 +193,9 @@ export async function clone(args) {
175
193
  transition: item.meta.transition,
176
194
  directionalTransition: item.meta.directionalTransition
177
195
  })
178
- console.log(` ${green("✓")} Generated ${cyan("deck-config.ts")} ${dim(`(${slides.length} slides)`)}`)
196
+ console.log(
197
+ ` ${green("✓")} Generated ${cyan("deck-config.ts")} ${dim(`(${slides.length} slides)`)}`
198
+ )
179
199
  }
180
200
 
181
201
  // 7. Add npm dependencies
@@ -195,24 +215,37 @@ export async function clone(args) {
195
215
  if (item.id) {
196
216
  try {
197
217
  const annotationsRes = await fetch(`${auth.registry}/api/items/${item.id}/annotations`, {
198
- headers: { Authorization: `Bearer ${auth.token}`, ...(auth.organizationId ? { "X-Organization-Id": auth.organizationId } : {}) }
218
+ headers: {
219
+ Authorization: `Bearer ${auth.token}`,
220
+ ...(auth.organizationId ? { "X-Organization-Id": auth.organizationId } : {})
221
+ }
199
222
  })
200
223
  if (annotationsRes.ok) {
201
224
  const data = await annotationsRes.json()
202
225
  const annotations = data.annotations ?? []
203
226
  if (annotations.length > 0) {
204
- const annotationsFile = { version: 1, annotations: annotations.map(a => ({
205
- id: a.id,
206
- slideIndex: a.slideIndex,
207
- slideTitle: a.slideTitle,
208
- target: a.target,
209
- body: a.body,
210
- createdAt: a.createdAt,
211
- status: a.status,
212
- ...(a.resolution ? { resolution: a.resolution } : {})
213
- })) }
214
- writeFileSync(join(targetDir, "annotations.json"), JSON.stringify(annotationsFile, null, 2) + "\n", "utf-8")
215
- console.log(` ${green("✓")} Pulled ${cyan("annotations.json")} ${dim(`(${annotations.length} annotation${annotations.length === 1 ? "" : "s"})`)}`)
227
+ const annotationsFile = {
228
+ version: 1,
229
+ annotations: annotations.map(a => ({
230
+ id: a.id,
231
+ slideIndex: a.slideIndex,
232
+ ...(a.slideId ? { slideId: a.slideId } : {}),
233
+ slideTitle: a.slideTitle,
234
+ target: a.target,
235
+ body: a.body,
236
+ createdAt: a.createdAt,
237
+ status: a.status,
238
+ ...(a.resolution ? { resolution: a.resolution } : {})
239
+ }))
240
+ }
241
+ writeFileSync(
242
+ join(targetDir, "annotations.json"),
243
+ JSON.stringify(annotationsFile, null, 2) + "\n",
244
+ "utf-8"
245
+ )
246
+ console.log(
247
+ ` ${green("✓")} Pulled ${cyan("annotations.json")} ${dim(`(${annotations.length} annotation${annotations.length === 1 ? "" : "s"})`)}`
248
+ )
216
249
  }
217
250
  }
218
251
  } catch {
@@ -1,9 +1,11 @@
1
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs"
2
1
  import { execFileSync } from "node:child_process"
2
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs"
3
3
  import { join, dirname, resolve, sep } from "node:path"
4
4
 
5
5
  import { bold, green, cyan, red, yellow, dim } from "../utils/ansi.mjs"
6
6
  import { requireAuth } from "../utils/auth.mjs"
7
+ import { toPascalCase, addSlideToDeckConfig, replaceDeckConfig } from "../utils/deck-config.mjs"
8
+ import { confirm, closePrompts } from "../utils/prompts.mjs"
7
9
  import {
8
10
  fetchRegistryItem,
9
11
  resolveRegistryDependencies,
@@ -15,13 +17,7 @@ import {
15
17
  hashFile,
16
18
  isFileDirty
17
19
  } from "../utils/registry.mjs"
18
- import {
19
- toPascalCase,
20
- addSlideToDeckConfig,
21
- replaceDeckConfig
22
- } from "../utils/deck-config.mjs"
23
20
  import { collectRegistrySlideSlugs, partitionDeckSlides } from "../utils/deck-sync.mjs"
24
- import { confirm, closePrompts } from "../utils/prompts.mjs"
25
21
 
26
22
  export async function pull(args) {
27
23
  const cwd = process.cwd()
@@ -51,7 +47,9 @@ export async function pull(args) {
51
47
 
52
48
  if (!deckSlug) {
53
49
  console.error(` ${red("Error:")} No deck slug found in lockfile.`)
54
- console.error(` ${dim("Run")} ${cyan("promptslide publish --type deck")} ${dim("first to set it.")}`)
50
+ console.error(
51
+ ` ${dim("Run")} ${cyan("promptslide publish --type deck")} ${dim("first to set it.")}`
52
+ )
55
53
  console.log()
56
54
  process.exit(1)
57
55
  }
@@ -69,7 +67,9 @@ export async function pull(args) {
69
67
  }
70
68
 
71
69
  const versionTag = deckItem.version ? ` ${dim(`v${deckItem.version}`)}` : ""
72
- console.log(` Found ${bold(deckItem.title || deckItem.name)} ${dim(`(${deckItem.type})`)}${versionTag}`)
70
+ console.log(
71
+ ` Found ${bold(deckItem.title || deckItem.name)} ${dim(`(${deckItem.type})`)}${versionTag}`
72
+ )
73
73
 
74
74
  // Resolve all dependencies (slides, layouts, themes, assets)
75
75
  let resolved
@@ -138,7 +138,10 @@ export async function pull(args) {
138
138
  }
139
139
  } else if (!storedHash) {
140
140
  // File exists but not in lockfile (first pull or untracked)
141
- const overwrite = await confirm(` Overwrite ${relativePath}? ${dim("(local changes will be lost)")}`, false)
141
+ const overwrite = await confirm(
142
+ ` Overwrite ${relativePath}? ${dim("(local changes will be lost)")}`,
143
+ false
144
+ )
142
145
  if (!overwrite) {
143
146
  console.log(` ${dim("Skipped")} ${relativePath}`)
144
147
  continue
@@ -151,7 +154,10 @@ export async function pull(args) {
151
154
  mkdirSync(targetDir, { recursive: true })
152
155
  const dataUriPrefix = file.content.match(/^data:[^;]+;base64,/)
153
156
  if (dataUriPrefix) {
154
- writeFileSync(targetPath, Buffer.from(file.content.slice(dataUriPrefix[0].length), "base64"))
157
+ writeFileSync(
158
+ targetPath,
159
+ Buffer.from(file.content.slice(dataUriPrefix[0].length), "base64")
160
+ )
155
161
  } else {
156
162
  writeFileSync(targetPath, file.content, "utf-8")
157
163
  }
@@ -186,6 +192,7 @@ export async function pull(args) {
186
192
  const slides = available.map(s => ({
187
193
  componentName: s.componentName || toPascalCase(s.slug),
188
194
  importPath: `@/slides/${s.slug}`,
195
+ id: s.id,
189
196
  steps: s.steps,
190
197
  section: s.section
191
198
  }))
@@ -193,13 +200,21 @@ export async function pull(args) {
193
200
  transition: deckItem.meta.transition,
194
201
  directionalTransition: deckItem.meta.directionalTransition
195
202
  })
196
- console.log(` ${green("+")} Replaced ${cyan("deck-config.ts")} ${dim(`(${slides.length} slides)`)}`)
203
+ console.log(
204
+ ` ${green("+")} Replaced ${cyan("deck-config.ts")} ${dim(`(${slides.length} slides)`)}`
205
+ )
197
206
  } else {
198
207
  // Append individual slides
199
208
  for (const s of available) {
200
209
  const componentName = s.componentName || toPascalCase(s.slug)
201
210
  const importPath = `@/slides/${s.slug}`
202
- const updated = addSlideToDeckConfig(cwd, { componentName, importPath, steps: s.steps, section: s.section })
211
+ const updated = addSlideToDeckConfig(cwd, {
212
+ componentName,
213
+ importPath,
214
+ steps: s.steps,
215
+ id: s.id,
216
+ section: s.section
217
+ })
203
218
  if (updated) {
204
219
  console.log(` ${green("+")} Added ${componentName} to ${cyan("deck-config.ts")}`)
205
220
  }
@@ -227,24 +242,37 @@ export async function pull(args) {
227
242
  if (deckItem.id) {
228
243
  try {
229
244
  const annotationsRes = await fetch(`${auth.registry}/api/items/${deckItem.id}/annotations`, {
230
- headers: { Authorization: `Bearer ${auth.token}`, ...(auth.organizationId ? { "X-Organization-Id": auth.organizationId } : {}) }
245
+ headers: {
246
+ Authorization: `Bearer ${auth.token}`,
247
+ ...(auth.organizationId ? { "X-Organization-Id": auth.organizationId } : {})
248
+ }
231
249
  })
232
250
  if (annotationsRes.ok) {
233
251
  const data = await annotationsRes.json()
234
252
  const annotations = data.annotations ?? []
235
253
  if (annotations.length > 0) {
236
- const annotationsFile = { version: 1, annotations: annotations.map(a => ({
237
- id: a.id,
238
- slideIndex: a.slideIndex,
239
- slideTitle: a.slideTitle,
240
- target: a.target,
241
- body: a.body,
242
- createdAt: a.createdAt,
243
- status: a.status,
244
- ...(a.resolution ? { resolution: a.resolution } : {})
245
- })) }
246
- writeFileSync(join(cwd, "annotations.json"), JSON.stringify(annotationsFile, null, 2) + "\n", "utf-8")
247
- console.log(` ${green("+")} ${cyan("annotations.json")} ${dim(`(${annotations.length} annotation${annotations.length === 1 ? "" : 's'})`)}`)
254
+ const annotationsFile = {
255
+ version: 1,
256
+ annotations: annotations.map(a => ({
257
+ id: a.id,
258
+ slideIndex: a.slideIndex,
259
+ ...(a.slideId ? { slideId: a.slideId } : {}),
260
+ slideTitle: a.slideTitle,
261
+ target: a.target,
262
+ body: a.body,
263
+ createdAt: a.createdAt,
264
+ status: a.status,
265
+ ...(a.resolution ? { resolution: a.resolution } : {})
266
+ }))
267
+ }
268
+ writeFileSync(
269
+ join(cwd, "annotations.json"),
270
+ JSON.stringify(annotationsFile, null, 2) + "\n",
271
+ "utf-8"
272
+ )
273
+ console.log(
274
+ ` ${green("+")} ${cyan("annotations.json")} ${dim(`(${annotations.length} annotation${annotations.length === 1 ? "" : "s"})`)}`
275
+ )
248
276
  }
249
277
  }
250
278
  } catch {
@@ -257,7 +285,9 @@ export async function pull(args) {
257
285
  if (written.length === 0) {
258
286
  console.log(` ${green("+")} Everything is up to date.`)
259
287
  } else {
260
- console.log(` ${green("+")} Pulled ${bold(String(written.length))} file(s) from ${bold(deckSlug)}`)
288
+ console.log(
289
+ ` ${green("+")} Pulled ${bold(String(written.length))} file(s) from ${bold(deckSlug)}`
290
+ )
261
291
  }
262
292
  console.log()
263
293
  closePrompts()
@@ -1,6 +1,7 @@
1
1
  import { createServer } from "vite"
2
2
 
3
3
  import { bold, dim } from "../utils/ansi.mjs"
4
+ import { registerStudioServer } from "../utils/studio-discovery.mjs"
4
5
  import { ensureTsConfig } from "../utils/tsconfig.mjs"
5
6
  import { createViteConfig } from "../vite/config.mjs"
6
7
 
@@ -10,7 +11,7 @@ export async function studio(args) {
10
11
  const port = portArg ? parseInt(portArg.split("=")[1], 10) : 5173
11
12
  const hasHost = args.includes("--host") || args.some(a => a.startsWith("--host="))
12
13
  const hostArg = args.find(a => a.startsWith("--host="))
13
- const host = hasHost ? (hostArg ? hostArg.split("=")[1] || "0.0.0.0" : "0.0.0.0") : undefined
14
+ const host = hasHost ? (hostArg ? hostArg.split("=")[1] || "0.0.0.0" : "0.0.0.0") : "127.0.0.1"
14
15
 
15
16
  ensureTsConfig(cwd)
16
17
 
@@ -18,17 +19,20 @@ export async function studio(args) {
18
19
  console.log(` ${bold("promptslide")} ${dim("studio")}`)
19
20
  console.log()
20
21
 
21
- const config = createViteConfig({ cwd, mode: "development" })
22
+ const config = createViteConfig({ cwd, mode: "development", editor: !hasHost })
22
23
  const server = await createServer({
23
24
  ...config,
24
25
  server: {
25
26
  port,
27
+ host,
26
28
  strictPort: false,
27
- ...(host && { host, allowedHosts: true })
29
+ ...(hasHost && { allowedHosts: true })
28
30
  }
29
31
  })
30
32
 
31
33
  await server.listen()
34
+ const baseUrl = server.resolvedUrls?.local[0]
35
+ if (baseUrl) registerStudioServer(cwd, baseUrl)
32
36
  server.printUrls()
33
37
  server.bindCLIShortcuts({ print: true })
34
38
  }
@@ -8,6 +8,8 @@ export async function toImage(args) {
8
8
  const slidePath = args[0]
9
9
  const outputIndex = args.indexOf("-o")
10
10
  const output = outputIndex !== -1 ? args[outputIndex + 1] : null
11
+ const portArg = args.find(arg => arg.startsWith("--port="))
12
+ const studioPort = portArg ? Number(portArg.slice(7)) : undefined
11
13
 
12
14
  if (!slidePath || slidePath === "--help" || slidePath === "-h") {
13
15
  console.log()
@@ -15,6 +17,7 @@ export async function toImage(args) {
15
17
  console.log()
16
18
  console.log(` ${bold("Options:")}`)
17
19
  console.log(` -o <file> Output file path (default: <slide-name>.png)`)
20
+ console.log(` --port=N Studio port to reuse (default: auto-discover)`)
18
21
  console.log()
19
22
  console.log(` ${bold("Examples:")}`)
20
23
  console.log(` ${dim("promptslide to-image src/slides/slide-title.tsx")}`)
@@ -26,7 +29,9 @@ export async function toImage(args) {
26
29
  if (!(await isPlaywrightAvailable())) {
27
30
  console.error()
28
31
  console.error(` ${red("Error:")} Playwright is required for image export.`)
29
- console.error(` Install it with: ${bold("npm install -D playwright && npx playwright install chromium")}`)
32
+ console.error(
33
+ ` Install it with: ${bold("npm install -D playwright && npx playwright install chromium")}`
34
+ )
30
35
  console.error()
31
36
  process.exit(1)
32
37
  }
@@ -36,10 +41,18 @@ export async function toImage(args) {
36
41
  console.log()
37
42
  console.log(` ${dim("Capturing screenshot...")}`)
38
43
 
39
- const buffer = await captureSlideScreenshot({
40
- cwd: process.cwd(),
41
- slidePath
42
- })
44
+ let buffer
45
+ try {
46
+ buffer = await captureSlideScreenshot({
47
+ cwd: process.cwd(),
48
+ slidePath,
49
+ studioPort
50
+ })
51
+ } catch (error) {
52
+ console.error(` ${red("Error:")} ${error.message}`)
53
+ process.exitCode = 1
54
+ return
55
+ }
43
56
 
44
57
  if (!buffer) {
45
58
  console.error(` ${red("Error:")} Failed to capture screenshot.`)
@@ -0,0 +1,27 @@
1
+ import { writeFileSync } from "node:fs"
2
+ import { resolve } from "node:path"
3
+
4
+ import { bold, green, dim, red } from "../utils/ansi.mjs"
5
+ import { captureDeckPdf } from "../utils/export.mjs"
6
+
7
+ export async function toPdf(args) {
8
+ if (args.includes("--help") || args.includes("-h")) {
9
+ console.log(` ${bold("Usage:")} promptslide to-pdf [-o slides.pdf] [--port=N]`)
10
+ return
11
+ }
12
+ const outputIndex = args.indexOf("-o")
13
+ const output = resolve(outputIndex >= 0 ? args[outputIndex + 1] : "slides.pdf")
14
+ const portArg = args.find(arg => arg.startsWith("--port="))
15
+ const studioPort = portArg ? Number(portArg.slice(7)) : undefined
16
+ console.log(` ${dim("Rendering deck PDF...")}`)
17
+ let pdf
18
+ try {
19
+ pdf = await captureDeckPdf({ cwd: process.cwd(), studioPort })
20
+ } catch (error) {
21
+ console.error(` ${red("Error:")} ${error.message}`)
22
+ process.exitCode = 1
23
+ return
24
+ }
25
+ writeFileSync(output, pdf)
26
+ console.log(` ${green("✓")} Saved to ${bold(output)}`)
27
+ }
@@ -48,7 +48,7 @@ const animationVariants: Record<AnimationType, Variants> = {
48
48
  }
49
49
 
50
50
  interface AnimatedProps {
51
- /** Which step reveals this content (1-indexed) */
51
+ /** Which step reveals this content (0 = visible from slide entry) */
52
52
  step: number
53
53
  /** Animation type */
54
54
  animation?: AnimationType
@@ -83,7 +83,7 @@ export function Animated({
83
83
 
84
84
  return (
85
85
  <motion.div
86
- initial="hidden"
86
+ initial={isVisible ? false : "hidden"}
87
87
  animate={isVisible ? "visible" : "hidden"}
88
88
  variants={animationVariants[animation]}
89
89
  transition={{
@@ -138,7 +138,7 @@ export function AnimatedGroup({
138
138
 
139
139
  return (
140
140
  <motion.div
141
- initial="hidden"
141
+ initial={isVisible ? false : "hidden"}
142
142
  animate={isVisible ? "visible" : "hidden"}
143
143
  variants={containerVariants}
144
144
  className={className}
@@ -38,6 +38,14 @@ export function createHttpAdapter(): AnnotationStorageAdapter {
38
38
  async remove(id) {
39
39
  cache = cache.filter(a => a.id !== id)
40
40
  await saveAll(cache)
41
+ },
42
+ async update(id, patch) {
43
+ cache = cache.map(a => (a.id === id ? { ...a, ...patch } : a))
44
+ await saveAll(cache)
45
+ },
46
+ async replaceAll(annotations) {
47
+ cache = annotations
48
+ await saveAll(cache)
41
49
  }
42
50
  }
43
51
  }