@artkit-ai/react 0.1.0 → 0.2.0

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.
Files changed (89) hide show
  1. package/dist/cache.d.ts +7 -11
  2. package/dist/cache.d.ts.map +1 -1
  3. package/dist/cache.js +32 -53
  4. package/dist/cache.js.map +1 -1
  5. package/dist/client.d.ts +4 -15
  6. package/dist/client.d.ts.map +1 -1
  7. package/dist/client.js +2 -29
  8. package/dist/client.js.map +1 -1
  9. package/dist/components/card.d.ts +2 -2
  10. package/dist/components/card.d.ts.map +1 -1
  11. package/dist/components/card.js +3 -3
  12. package/dist/components/card.js.map +1 -1
  13. package/dist/components/editor.d.ts +31 -18
  14. package/dist/components/editor.d.ts.map +1 -1
  15. package/dist/components/editor.js +81 -131
  16. package/dist/components/editor.js.map +1 -1
  17. package/dist/components/icons.d.ts +2 -2
  18. package/dist/components/icons.d.ts.map +1 -1
  19. package/dist/components/icons.js +2 -2
  20. package/dist/components/icons.js.map +1 -1
  21. package/dist/components/panel.d.ts +13 -16
  22. package/dist/components/panel.d.ts.map +1 -1
  23. package/dist/components/panel.js +13 -97
  24. package/dist/components/panel.js.map +1 -1
  25. package/dist/components/shared.d.ts +2 -6
  26. package/dist/components/shared.d.ts.map +1 -1
  27. package/dist/components/shared.js +2 -6
  28. package/dist/components/shared.js.map +1 -1
  29. package/dist/components/view.d.ts +7 -8
  30. package/dist/components/view.d.ts.map +1 -1
  31. package/dist/components/view.js +16 -15
  32. package/dist/components/view.js.map +1 -1
  33. package/dist/context.d.ts +14 -9
  34. package/dist/context.d.ts.map +1 -1
  35. package/dist/context.js.map +1 -1
  36. package/dist/editor-session.d.ts +77 -165
  37. package/dist/editor-session.d.ts.map +1 -1
  38. package/dist/editor-session.js +164 -586
  39. package/dist/editor-session.js.map +1 -1
  40. package/dist/hooks.d.ts +2 -23
  41. package/dist/hooks.d.ts.map +1 -1
  42. package/dist/hooks.js +24 -116
  43. package/dist/hooks.js.map +1 -1
  44. package/dist/i18n.d.ts +4 -66
  45. package/dist/i18n.d.ts.map +1 -1
  46. package/dist/i18n.js +6 -68
  47. package/dist/i18n.js.map +1 -1
  48. package/dist/index.d.ts +6 -9
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +4 -8
  51. package/dist/index.js.map +1 -1
  52. package/dist/provider.d.ts +1 -1
  53. package/dist/provider.d.ts.map +1 -1
  54. package/dist/provider.js +12 -12
  55. package/dist/provider.js.map +1 -1
  56. package/dist/styles.d.ts +1 -1
  57. package/dist/styles.d.ts.map +1 -1
  58. package/dist/styles.js +4 -4
  59. package/package.json +2 -2
  60. package/src/cache.ts +32 -55
  61. package/src/client.ts +7 -55
  62. package/src/components/card.tsx +6 -7
  63. package/src/components/editor.tsx +208 -308
  64. package/src/components/icons.tsx +2 -2
  65. package/src/components/panel.tsx +43 -300
  66. package/src/components/shared.tsx +3 -12
  67. package/src/components/view.tsx +26 -29
  68. package/src/context.ts +16 -11
  69. package/src/editor-session.ts +197 -675
  70. package/src/hooks.ts +25 -140
  71. package/src/i18n.ts +6 -68
  72. package/src/index.ts +7 -39
  73. package/src/provider.tsx +13 -13
  74. package/src/styles.ts +4 -4
  75. package/dist/components/approval.d.ts +0 -34
  76. package/dist/components/approval.d.ts.map +0 -1
  77. package/dist/components/approval.js +0 -80
  78. package/dist/components/approval.js.map +0 -1
  79. package/dist/components/version-diff.d.ts +0 -35
  80. package/dist/components/version-diff.d.ts.map +0 -1
  81. package/dist/components/version-diff.js +0 -85
  82. package/dist/components/version-diff.js.map +0 -1
  83. package/dist/line-diff.d.ts +0 -25
  84. package/dist/line-diff.d.ts.map +0 -1
  85. package/dist/line-diff.js +0 -96
  86. package/dist/line-diff.js.map +0 -1
  87. package/src/components/approval.tsx +0 -219
  88. package/src/components/version-diff.tsx +0 -266
  89. package/src/line-diff.ts +0 -111
package/src/hooks.ts CHANGED
@@ -2,12 +2,10 @@ import {
2
2
  type AnyArtifactExporter,
3
3
  type Artifact,
4
4
  ArtifactError,
5
- type ChangeSummary,
6
5
  type CommitResult,
7
6
  isArtifactError,
8
7
  silentLogger,
9
8
  slugify,
10
- type VersionEntry,
11
9
  } from '@artkit-ai/core';
12
10
  import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react';
13
11
  import type { CacheEntry } from './cache.js';
@@ -26,16 +24,7 @@ function toArtifactError(error: unknown): ArtifactError {
26
24
  });
27
25
  }
28
26
 
29
- function newKey(): string {
30
- const cryptoApi = (globalThis as { crypto?: { randomUUID?: () => string } }).crypto;
31
- return (
32
- cryptoApi?.randomUUID?.() ?? `ak-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`
33
- );
34
- }
35
-
36
27
  export interface UseArtifactOptions {
37
- /** A specific (immutable) version; omit for the latest. */
38
- version?: number;
39
28
  /** Already-known artifact (e.g. from a chat message), shown immediately and cached. */
40
29
  initial?: Artifact;
41
30
  /** Revalidate the latest version on mount (default true). */
@@ -53,12 +42,12 @@ export interface UseArtifactResult {
53
42
  /** Loads an artifact through the client with a shared cache (spec §13.2). Pass undefined to skip. */
54
43
  export function useArtifact(id: string | undefined, options: UseArtifactOptions = {}): UseArtifactResult {
55
44
  const { cache } = useArtkit();
56
- const { version, initial, revalidate = true } = options;
45
+ const { initial, revalidate = true } = options;
57
46
  const subscribe = useCallback(
58
47
  (listener: () => void) => (id ? cache.subscribe(id, listener) : noop),
59
48
  [cache, id],
60
49
  );
61
- const read = () => (id ? cache.entry(id, version) : NO_ENTRY);
50
+ const read = () => (id ? cache.entry(id) : NO_ENTRY);
62
51
  const entry = useSyncExternalStore(id ? subscribe : noSubscription, read, read);
63
52
 
64
53
  useEffect(() => {
@@ -67,21 +56,18 @@ export function useArtifact(id: string | undefined, options: UseArtifactOptions
67
56
 
68
57
  useEffect(() => {
69
58
  if (!id) return;
70
- cache.load(id, version, version === undefined && revalidate).catch(noop);
71
- }, [cache, id, version, revalidate]);
59
+ cache.load(id, revalidate).catch(noop);
60
+ }, [cache, id, revalidate]);
72
61
 
73
- const usableInitial =
74
- initial && initial.id === id && (version === undefined || initial.version === version)
75
- ? initial
76
- : undefined;
62
+ const usableInitial = initial && initial.id === id ? initial : undefined;
77
63
  const artifact =
78
64
  entry.artifact && (!usableInitial || entry.artifact.version >= usableInitial.version)
79
65
  ? entry.artifact
80
66
  : (usableInitial ?? entry.artifact);
81
67
  const refresh = useCallback(async () => {
82
68
  if (!id) return undefined;
83
- return cache.load(id, version, true);
84
- }, [cache, id, version]);
69
+ return cache.load(id, true);
70
+ }, [cache, id]);
85
71
 
86
72
  return {
87
73
  artifact,
@@ -102,104 +88,15 @@ export function useLatestVersion(id: string | undefined): number | undefined {
102
88
  return useSyncExternalStore(subscribe, read, read);
103
89
  }
104
90
 
105
- export interface UseArtifactHistoryResult {
106
- entries: VersionEntry[];
107
- loading: boolean;
108
- error: unknown;
109
- hasMore: boolean;
110
- loadMore(): Promise<void>;
111
- refresh(): Promise<void>;
112
- /** Creates a new version with the content of `version` (spec §8.5). */
113
- restore(version: number, message?: string): Promise<CommitResult>;
114
- restoring: number | undefined;
115
- }
116
-
117
- /** Version list with pagination and restore (spec §13.2). Refetches when a newer version is known. */
118
- export function useArtifactHistory(
119
- id: string | undefined,
120
- options: { pageSize?: number } = {},
121
- ): UseArtifactHistoryResult {
122
- const { client, cache } = useArtkit();
123
- const pageSize = options.pageSize ?? 20;
124
- const latest = useLatestVersion(id);
125
- const [entries, setEntries] = useState<VersionEntry[]>([]);
126
- const [cursor, setCursor] = useState<string | undefined>(undefined);
127
- const [loading, setLoading] = useState(Boolean(id));
128
- const [error, setError] = useState<unknown>(undefined);
129
- const [restoring, setRestoring] = useState<number | undefined>(undefined);
130
- const request = useRef(0);
131
-
132
- const refresh = useCallback(async () => {
133
- if (!id) return;
134
- const ticket = ++request.current;
135
- setLoading(true);
136
- try {
137
- const page = await client.history(id, { limit: pageSize });
138
- if (ticket !== request.current) return;
139
- setEntries(page.items);
140
- setCursor(page.nextCursor);
141
- setError(undefined);
142
- } catch (caught) {
143
- if (ticket === request.current) setError(caught);
144
- } finally {
145
- if (ticket === request.current) setLoading(false);
146
- }
147
- }, [client, id, pageSize]);
148
-
149
- // biome-ignore lint/correctness/useExhaustiveDependencies: `latest` is the revalidation trigger.
150
- useEffect(() => {
151
- void refresh();
152
- }, [refresh, latest]);
153
-
154
- const loadMore = useCallback(async () => {
155
- if (!id || !cursor) return;
156
- const ticket = ++request.current;
157
- setLoading(true);
158
- try {
159
- const page = await client.history(id, { limit: pageSize, cursor });
160
- if (ticket !== request.current) return;
161
- setEntries((previous) => {
162
- const seen = new Set(previous.map((entry) => entry.version));
163
- return [...previous, ...page.items.filter((entry) => !seen.has(entry.version))];
164
- });
165
- setCursor(page.nextCursor);
166
- } catch (caught) {
167
- if (ticket === request.current) setError(caught);
168
- } finally {
169
- if (ticket === request.current) setLoading(false);
170
- }
171
- }, [client, id, cursor, pageSize]);
172
-
173
- const restore = useCallback(
174
- async (version: number, message?: string) => {
175
- if (!id) throw new ArtifactError('NOT_FOUND', 'No artifact id.');
176
- setRestoring(version);
177
- try {
178
- const result = await client.restore(id, version, message);
179
- cache.put(result.artifact);
180
- return result;
181
- } finally {
182
- setRestoring(undefined);
183
- }
184
- },
185
- [client, cache, id],
186
- );
187
-
188
- return { entries, loading, error, hasMore: cursor !== undefined, loadMore, refresh, restore, restoring };
189
- }
190
-
191
91
  export interface ApplyConflict {
192
92
  operations: unknown[];
193
93
  baseVersion: number;
194
94
  currentVersion?: number;
195
- changes: ChangeSummary[];
196
95
  }
197
96
 
198
97
  export interface ApplyOptions {
199
98
  /** Defaults to the latest cached version (loaded when unknown). */
200
99
  baseVersion?: number;
201
- idempotencyKey?: string;
202
- message?: string;
203
100
  }
204
101
 
205
102
  export interface UseApplyOperationsResult {
@@ -227,12 +124,7 @@ export function useApplyOperations(id: string): UseApplyOperationsResult {
227
124
  let baseVersion = options.baseVersion;
228
125
  try {
229
126
  baseVersion ??= cache.latest(id)?.version ?? (await cache.load(id)).version;
230
- const result = await client.apply(id, {
231
- baseVersion,
232
- operations,
233
- idempotencyKey: options.idempotencyKey ?? newKey(),
234
- ...(options.message ? { message: options.message } : {}),
235
- });
127
+ const result = await client.apply(id, { baseVersion, operations });
236
128
  cache.put(result.artifact);
237
129
  conflictRef.current = undefined;
238
130
  setState({ pending: false });
@@ -241,15 +133,13 @@ export function useApplyOperations(id: string): UseApplyOperationsResult {
241
133
  const error = toArtifactError(caught);
242
134
  let conflict: ApplyConflict | undefined;
243
135
  if (error.code === 'VERSION_CONFLICT') {
244
- const changes = error.details.changesSinceBase;
245
136
  const current = error.details.currentVersion;
246
137
  conflict = {
247
138
  operations,
248
139
  baseVersion: baseVersion ?? 0,
249
140
  ...(typeof current === 'number' ? { currentVersion: current } : {}),
250
- changes: Array.isArray(changes) ? (changes as ChangeSummary[]) : [],
251
141
  };
252
- cache.load(id, undefined, true).catch(noop);
142
+ cache.load(id, true).catch(noop);
253
143
  }
254
144
  conflictRef.current = conflict;
255
145
  setState({ pending: false, error, ...(conflict ? { conflict } : {}) });
@@ -262,7 +152,7 @@ export function useApplyOperations(id: string): UseApplyOperationsResult {
262
152
  const retry = useCallback(async () => {
263
153
  const conflict = conflictRef.current;
264
154
  if (!conflict) throw new ArtifactError('NOT_FOUND', 'There is no conflicting batch to retry.');
265
- const latest = await cache.load(id, undefined, true);
155
+ const latest = await cache.load(id, true);
266
156
  return apply(conflict.operations, { baseVersion: latest.version });
267
157
  }, [apply, cache, id]);
268
158
 
@@ -275,7 +165,6 @@ export function useApplyOperations(id: string): UseApplyOperationsResult {
275
165
  }
276
166
 
277
167
  export interface ExportOptions {
278
- version?: number;
279
168
  /** Triggers a browser download (default true). */
280
169
  download?: boolean;
281
170
  options?: Record<string, unknown>;
@@ -299,21 +188,21 @@ export interface UseArtifactExportResult {
299
188
  * Exports in the browser when a loaded exporter with runtime `any`/`browser` handles the format, else
300
189
  * through the client (spec §13.2), and triggers a download.
301
190
  */
302
- export function useArtifactExport(id: string, kind?: string): UseArtifactExportResult {
191
+ export function useArtifactExport(id: string, format?: string): UseArtifactExportResult {
303
192
  const ctx = useArtkit();
304
193
  const { client, cache, registry } = ctx;
305
194
  const [pending, setPending] = useState<string | undefined>(undefined);
306
195
  const [error, setError] = useState<ArtifactError | undefined>(undefined);
307
196
  const [warnings, setWarnings] = useState<string[]>([]);
308
197
  const [loaded, setLoaded] = useState<AnyArtifactExporter[]>([]);
309
- const knownKind = kind ?? cache.latest(id)?.kind;
198
+ const knownFormat = format ?? cache.latest(id)?.format;
310
199
 
311
200
  const browserExporters = useCallback(
312
201
  async (artifactKind: string): Promise<AnyArtifactExporter[]> => {
313
202
  const fromRegistry = registry.exporters(artifactKind).filter((exporter) => exporter.runtime !== 'node');
314
203
  if (!ctx.hasExporters(artifactKind)) return fromRegistry;
315
204
  const lazy = (await ctx.loadExporters(artifactKind)).filter(
316
- (exporter) => exporter.kind === artifactKind && exporter.runtime !== 'node',
205
+ (exporter) => exporter.format === artifactKind && exporter.runtime !== 'node',
317
206
  );
318
207
  return [...lazy, ...fromRegistry];
319
208
  },
@@ -321,22 +210,22 @@ export function useArtifactExport(id: string, kind?: string): UseArtifactExportR
321
210
  );
322
211
 
323
212
  const loadFormats = useCallback(async () => {
324
- if (!knownKind) return;
213
+ if (!knownFormat) return;
325
214
  try {
326
- setLoaded(await browserExporters(knownKind));
215
+ setLoaded(await browserExporters(knownFormat));
327
216
  } catch {
328
217
  // Without browser exporters the server formats still work.
329
218
  }
330
- }, [browserExporters, knownKind]);
219
+ }, [browserExporters, knownFormat]);
331
220
 
332
221
  const formats = useMemo(() => {
333
- if (!knownKind) return [];
334
- const set = new Set<string>(ctx.exportFormats[knownKind] ?? []);
335
- for (const exporter of registry.exporters(knownKind))
336
- if (exporter.runtime !== 'node') set.add(exporter.format);
337
- for (const exporter of loaded) set.add(exporter.format);
222
+ if (!knownFormat) return [];
223
+ const set = new Set<string>(ctx.exportFormats[knownFormat] ?? []);
224
+ for (const exporter of registry.exporters(knownFormat))
225
+ if (exporter.runtime !== 'node') set.add(exporter.target);
226
+ for (const exporter of loaded) set.add(exporter.target);
338
227
  return [...set];
339
- }, [ctx.exportFormats, knownKind, loaded, registry]);
228
+ }, [ctx.exportFormats, knownFormat, loaded, registry]);
340
229
 
341
230
  const exportArtifact = useCallback(
342
231
  async (format: string, options: ExportOptions = {}) => {
@@ -344,14 +233,11 @@ export function useArtifactExport(id: string, kind?: string): UseArtifactExportR
344
233
  setError(undefined);
345
234
  setWarnings([]);
346
235
  try {
347
- const artifact =
348
- options.version === undefined
349
- ? (cache.latest(id) ?? (await cache.load(id)))
350
- : await cache.load(id, options.version);
236
+ const artifact = cache.latest(id) ?? (await cache.load(id));
351
237
  let result: ClientExportResult | undefined;
352
238
  if (options.prefer !== 'server') {
353
- const exporter = (await browserExporters(artifact.kind).catch(() => [])).find(
354
- (candidate) => candidate.format === format,
239
+ const exporter = (await browserExporters(artifact.format).catch(() => [])).find(
240
+ (candidate) => candidate.target === format,
355
241
  );
356
242
  if (exporter) {
357
243
  const collected: string[] = [];
@@ -389,7 +275,6 @@ export function useArtifactExport(id: string, kind?: string): UseArtifactExportR
389
275
  }
390
276
  result ??= await client.export(id, {
391
277
  format,
392
- ...(options.version === undefined ? {} : { version: options.version }),
393
278
  ...(options.options ? { options: options.options } : {}),
394
279
  ...(options.signal ? { signal: options.signal } : {}),
395
280
  });
package/src/i18n.ts CHANGED
@@ -4,7 +4,7 @@ export const uiMessages = {
4
4
  loading: 'Loading…',
5
5
  generating: 'Generating…',
6
6
  provisional: 'Preview — not saved yet',
7
- noRenderer: 'No renderer is registered for kind "{kind}". Showing the raw content.',
7
+ noRenderer: 'No renderer is registered for kind "{format}". Showing the raw content.',
8
8
  loadFailed: 'Could not load this artifact.',
9
9
  retry: 'Retry',
10
10
  close: 'Close',
@@ -15,7 +15,8 @@ export const uiMessages = {
15
15
  latest: 'latest',
16
16
  tabView: 'View',
17
17
  tabCode: 'Code',
18
- tabHistory: 'History',
18
+ tabEdit: 'Edit',
19
+ save: 'Save',
19
20
  tabsLabel: 'Artifact sections',
20
21
  copy: 'Copy',
21
22
  copied: 'Copied',
@@ -25,34 +26,10 @@ export const uiMessages = {
25
26
  exported: 'Exported {filename}',
26
27
  exportWarnings: 'Export finished with warnings:',
27
28
  noExportFormats: 'No export formats available',
28
- status: 'Status',
29
- status_draft: 'Draft',
30
- status_pending_approval: 'Pending approval',
31
- status_published: 'Published',
32
- status_archived: 'Archived',
33
- action_submit: 'Submit for approval',
34
- action_approve: 'Approve',
35
- action_reject: 'Reject',
36
- action_publish: 'Publish',
37
- action_archive: 'Archive',
38
- statusChanged: 'Status changed to {status}',
39
29
  rejectReason: 'Reason for rejection',
40
- rejectReasonRequired: 'Explain why the version is being rejected.',
41
30
  confirmReject: 'Confirm rejection',
42
31
  cancel: 'Cancel',
43
- approvalTitle: 'Review version {version}',
44
- approvalComparedTo: 'Compared with version {version}',
45
- approvalFirstVersion: 'First version: nothing to compare with.',
46
- notPending: 'This artifact is not waiting for approval.',
47
- approved: 'Version {version} approved',
48
- rejected: 'Version {version} rejected',
49
- historyEmpty: 'No versions yet.',
50
32
  loadMore: 'Load more',
51
- restore: 'Restore',
52
- restoreVersion: 'Restore version {version}',
53
- restored: 'Version {version} restored as version {newVersion}',
54
- viewVersion: 'View version {version}',
55
- restoredFrom: 'restored from v{version}',
56
33
  by: 'by {actor}',
57
34
  actor_agent: 'agent',
58
35
  actor_user: 'user',
@@ -66,8 +43,6 @@ export const uiMessages = {
66
43
  diffUnified: 'Highlighted',
67
44
  diffSplit: 'Side by side',
68
45
  diffViewLabel: 'Diff layout',
69
- diffBefore: 'Version {version}',
70
- diffAfter: 'Version {version}',
71
46
  lineAdded: 'added',
72
47
  lineRemoved: 'removed',
73
48
  undo: 'Undo',
@@ -76,18 +51,12 @@ export const uiMessages = {
76
51
  redone: 'Change redone',
77
52
  saving: 'Saving…',
78
53
  saved: 'Saved',
79
- savedVersion: 'Saved version {version}',
80
54
  unsaved: 'Unsaved changes',
81
55
  rolledBack: 'Change rejected: {message}',
82
56
  dismiss: 'Dismiss',
83
57
  readOnly: 'Read only',
84
58
  lockedBy: 'Locked by the {actor} — editing is disabled.',
85
59
  lockedUntil: 'Locked until {time} — editing is disabled.',
86
- agentUpdated: 'The artifact was updated to version {version}',
87
- conflictTitle: 'Your edit conflicts with a newer version',
88
- conflictBody: 'Version {version} changed the same items you edited.',
89
- conflictUndoBody: 'The artifact changed after your edit, so undoing it would also discard those changes.',
90
- keepTheirs: 'Keep agent version',
91
60
  reapplyMine: 'Reapply my edit',
92
61
  editorLabel: 'Editor for {title}',
93
62
  lintWarnings: '{count} lint warnings',
@@ -96,7 +65,7 @@ export const uiMessages = {
96
65
  loading: 'Carregando…',
97
66
  generating: 'Gerando…',
98
67
  provisional: 'Prévia — ainda não salva',
99
- noRenderer: 'Não há renderer registrado para o tipo "{kind}". Exibindo o conteúdo bruto.',
68
+ noRenderer: 'Não há renderer registrado para o tipo "{format}". Exibindo o conteúdo bruto.',
100
69
  loadFailed: 'Não foi possível carregar este artefato.',
101
70
  retry: 'Tentar novamente',
102
71
  close: 'Fechar',
@@ -107,7 +76,8 @@ export const uiMessages = {
107
76
  latest: 'atual',
108
77
  tabView: 'Visualização',
109
78
  tabCode: 'Código',
110
- tabHistory: 'Histórico',
79
+ tabEdit: 'Editar',
80
+ save: 'Salvar',
111
81
  tabsLabel: 'Seções do artefato',
112
82
  copy: 'Copiar',
113
83
  copied: 'Copiado',
@@ -117,34 +87,10 @@ export const uiMessages = {
117
87
  exported: '{filename} exportado',
118
88
  exportWarnings: 'Exportação concluída com avisos:',
119
89
  noExportFormats: 'Nenhum formato de exportação disponível',
120
- status: 'Status',
121
- status_draft: 'Rascunho',
122
- status_pending_approval: 'Aguardando aprovação',
123
- status_published: 'Publicado',
124
- status_archived: 'Arquivado',
125
- action_submit: 'Enviar para aprovação',
126
- action_approve: 'Aprovar',
127
- action_reject: 'Rejeitar',
128
- action_publish: 'Publicar',
129
- action_archive: 'Arquivar',
130
- statusChanged: 'Status alterado para {status}',
131
90
  rejectReason: 'Motivo da rejeição',
132
- rejectReasonRequired: 'Explique por que a versão está sendo rejeitada.',
133
91
  confirmReject: 'Confirmar rejeição',
134
92
  cancel: 'Cancelar',
135
- approvalTitle: 'Revisar versão {version}',
136
- approvalComparedTo: 'Comparada com a versão {version}',
137
- approvalFirstVersion: 'Primeira versão: não há com o que comparar.',
138
- notPending: 'Este artefato não está aguardando aprovação.',
139
- approved: 'Versão {version} aprovada',
140
- rejected: 'Versão {version} rejeitada',
141
- historyEmpty: 'Ainda não há versões.',
142
93
  loadMore: 'Carregar mais',
143
- restore: 'Restaurar',
144
- restoreVersion: 'Restaurar versão {version}',
145
- restored: 'Versão {version} restaurada como versão {newVersion}',
146
- viewVersion: 'Ver versão {version}',
147
- restoredFrom: 'restaurada da v{version}',
148
94
  by: 'por {actor}',
149
95
  actor_agent: 'agente',
150
96
  actor_user: 'usuário',
@@ -158,8 +104,6 @@ export const uiMessages = {
158
104
  diffUnified: 'Destacado',
159
105
  diffSplit: 'Lado a lado',
160
106
  diffViewLabel: 'Layout do diff',
161
- diffBefore: 'Versão {version}',
162
- diffAfter: 'Versão {version}',
163
107
  lineAdded: 'inserida',
164
108
  lineRemoved: 'removida',
165
109
  undo: 'Desfazer',
@@ -168,18 +112,12 @@ export const uiMessages = {
168
112
  redone: 'Alteração refeita',
169
113
  saving: 'Salvando…',
170
114
  saved: 'Salvo',
171
- savedVersion: 'Versão {version} salva',
172
115
  unsaved: 'Alterações não salvas',
173
116
  rolledBack: 'Alteração rejeitada: {message}',
174
117
  dismiss: 'Dispensar',
175
118
  readOnly: 'Somente leitura',
176
119
  lockedBy: 'Bloqueado pelo {actor} — edição desativada.',
177
120
  lockedUntil: 'Bloqueado até {time} — edição desativada.',
178
- agentUpdated: 'O artefato foi atualizado para a versão {version}',
179
- conflictTitle: 'Sua edição conflita com uma versão mais nova',
180
- conflictBody: 'A versão {version} alterou os mesmos itens que você editou.',
181
- conflictUndoBody: 'O artefato mudou depois da sua edição; desfazê-la também descartaria essas mudanças.',
182
- keepTheirs: 'Manter versão do agente',
183
121
  reapplyMine: 'Reaplicar minha edição',
184
122
  editorLabel: 'Editor de {title}',
185
123
  lintWarnings: '{count} avisos de lint',
package/src/index.ts CHANGED
@@ -11,20 +11,13 @@ export {
11
11
  type HttpClientOptions,
12
12
  type ReadOptions,
13
13
  type RequestOptions,
14
- STATUS_ACTIONS,
15
- type StatusAction,
16
14
  } from './client.js';
17
- export {
18
- ArtifactApproval,
19
- type ArtifactApprovalPart,
20
- type ArtifactApprovalProps,
21
- } from './components/approval.js';
22
15
  export { ArtifactCard, type ArtifactCardPart, type ArtifactCardProps } from './components/card.js';
23
16
  export {
24
17
  ArtifactEditor,
25
18
  type ArtifactEditorPart,
26
19
  type ArtifactEditorProps,
27
- type EditorPermission,
20
+ type SaveEvent,
28
21
  } from './components/editor.js';
29
22
  export {
30
23
  ArtifactPanel,
@@ -32,20 +25,12 @@ export {
32
25
  type ArtifactPanelProps,
33
26
  type PanelTab,
34
27
  } from './components/panel.js';
35
- export { type Slots, StatusBadge } from './components/shared.js';
36
- export {
37
- ArtifactVersionDiff,
38
- type ArtifactVersionDiffPart,
39
- type ArtifactVersionDiffProps,
40
- compareVersions,
41
- type DiffLayout,
42
- type VersionComparison,
43
- } from './components/version-diff.js';
28
+ export type { Slots } from './components/shared.js';
44
29
  export {
45
30
  ArtifactView,
46
31
  type ArtifactViewPart,
47
32
  type ArtifactViewProps,
48
- KindRenderer,
33
+ FormatRenderer,
49
34
  previewContent,
50
35
  } from './components/view.js';
51
36
  export {
@@ -92,17 +77,10 @@ export {
92
77
  } from './controls.js';
93
78
  export { triggerDownload } from './download.js';
94
79
  export {
95
- type ConflictChoice,
96
- EditorSession,
97
- type EditorSessionOptions,
98
- type EditorSessionState,
99
- type EnvelopeState,
100
- envelopeOf,
101
- operationsBetween,
102
- type SendRequest,
103
- type SessionConflict,
104
- type SessionEvent,
105
- type SessionStatus,
80
+ DraftSession,
81
+ type DraftSessionOptions,
82
+ type DraftSnapshot,
83
+ type EmitOptions,
106
84
  } from './editor-session.js';
107
85
  export {
108
86
  type ApplyConflict,
@@ -110,13 +88,11 @@ export {
110
88
  type ExportOptions,
111
89
  type UseApplyOperationsResult,
112
90
  type UseArtifactExportResult,
113
- type UseArtifactHistoryResult,
114
91
  type UseArtifactOptions,
115
92
  type UseArtifactResult,
116
93
  useApplyOperations,
117
94
  useArtifact,
118
95
  useArtifactExport,
119
- useArtifactHistory,
120
96
  useLatestVersion,
121
97
  } from './hooks.js';
122
98
  export {
@@ -128,14 +104,6 @@ export {
128
104
  uiMessages,
129
105
  } from './i18n.js';
130
106
  export { kitCss } from './kit-css.js';
131
- export {
132
- diffLines,
133
- type LineDiffEntry,
134
- type LineDiffOptions,
135
- type LineDiffType,
136
- type SplitRow,
137
- toSplitRows,
138
- } from './line-diff.js';
139
107
  export { parsePartialJson } from './partial-json.js';
140
108
  export { ArtifactProvider, type ArtifactProviderProps } from './provider.js';
141
109
  export { artkitCss, darkTheme, mixColors, themeStyles } from './styles.js';
package/src/provider.tsx CHANGED
@@ -18,7 +18,7 @@ export interface ArtifactProviderProps {
18
18
  /** Core registry with the kinds the app shows (parsePartial, apply, project, diff, lint). */
19
19
  registry: ArtifactRegistry;
20
20
  client: ArtifactClient;
21
- /** Lazy renderers, editors and exporters per kind. Read once per kind: later changes are ignored. */
21
+ /** Lazy renderers, editors and exporters per format. Read once per format: later changes are ignored. */
22
22
  loaders?: ArtifactLoaders;
23
23
  /** UI locale (pt-BR or en built in). Artifacts keep their own locale for content formatting. */
24
24
  locale?: string;
@@ -92,8 +92,8 @@ export function ArtifactProvider(props: ArtifactProviderProps) {
92
92
 
93
93
  const value = useMemo<ArtkitContextValue>(() => {
94
94
  const byId = new Map(themeList.map((theme) => [theme.id, theme]));
95
- function load<T>(type: 'renderer' | 'editor' | 'exporters', kind: string): Promise<T> {
96
- const key: LoadKey = `${type}:${kind}`;
95
+ function load<T>(type: 'renderer' | 'editor' | 'exporters', format: string): Promise<T> {
96
+ const key: LoadKey = `${type}:${format}`;
97
97
  let promise = loads.current.get(key) as Promise<T> | undefined;
98
98
  if (!promise) {
99
99
  const group =
@@ -102,10 +102,10 @@ export function ArtifactProvider(props: ArtifactProviderProps) {
102
102
  : type === 'editor'
103
103
  ? loadersRef.current?.editors
104
104
  : loadersRef.current?.exporters;
105
- const loader = group?.[kind];
105
+ const loader = group?.[format];
106
106
  promise = loader
107
107
  ? (loader() as Promise<T>)
108
- : Promise.reject(new Error(`No ${type} loader registered for kind "${kind}".`));
108
+ : Promise.reject(new Error(`No ${type} loader registered for kind "${format}".`));
109
109
  loads.current.set(key, promise);
110
110
  }
111
111
  return promise;
@@ -122,14 +122,14 @@ export function ArtifactProvider(props: ArtifactProviderProps) {
122
122
  ...(props.resolveAssetUrl ? { resolveAssetUrl: props.resolveAssetUrl } : {}),
123
123
  ...(props.assets ? { assets: props.assets } : {}),
124
124
  exportFormats: props.exportFormats ?? {},
125
- hasRenderer: (kind) => Boolean(loadersRef.current?.renderers?.[kind]),
126
- hasEditor: (kind) => Boolean(loadersRef.current?.editors?.[kind]),
127
- hasExporters: (kind) => Boolean(loadersRef.current?.exporters?.[kind]),
128
- loadRenderer: (kind) => load<RendererModule>('renderer', kind),
129
- loadEditor: (kind) => load<EditorModule>('editor', kind),
130
- loadExporters: (kind) => load('exporters', kind),
131
- resetLoad: (type, kind) => {
132
- loads.current.delete(`${type}:${kind}`);
125
+ hasRenderer: (format) => Boolean(loadersRef.current?.renderers?.[format]),
126
+ hasEditor: (format) => Boolean(loadersRef.current?.editors?.[format]),
127
+ hasExporters: (format) => Boolean(loadersRef.current?.exporters?.[format]),
128
+ loadRenderer: (format) => load<RendererModule>('renderer', format),
129
+ loadEditor: (format) => load<EditorModule>('editor', format),
130
+ loadExporters: (format) => load('exporters', format),
131
+ resetLoad: (type, format) => {
132
+ loads.current.delete(`${type}:${format}`);
133
133
  },
134
134
  ...(nonce ? { nonce } : {}),
135
135
  };
package/src/styles.ts CHANGED
@@ -139,7 +139,7 @@ export const artkitCss = `
139
139
  .ak-button:hover:not(:disabled){background:var(--ak-color-hover);border-color:var(--ak-color-border-strong)}
140
140
  .ak-button:active:not(:disabled){background:var(--ak-color-active)}
141
141
  .ak-button:disabled{opacity:.4;cursor:not-allowed}
142
- .ak-button[data-variant="primary"]{border-color:transparent;background:var(--ak-gradient-button);color:var(--ak-color-on-primary)}
142
+ .ak-button[data-variant="primary"]{border-color:transparent;background:var(--ak-gradient-button);color:var(--ak-color-on-primary);border-radius:var(--ak-radius-pill)}
143
143
  .ak-button[data-variant="primary"]:hover:not(:disabled){background:var(--ak-gradient-button-hover);border-color:transparent}
144
144
  .ak-button[data-variant="primary"]:active:not(:disabled){background:var(--ak-gradient-button-active)}
145
145
  .ak-button[data-variant="quiet"]{border-color:transparent;background:transparent;color:var(--ak-color-muted)}
@@ -172,11 +172,11 @@ export const artkitCss = `
172
172
  .ak-card-title{font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin:0 0 4px;font-size:14px;font-family:var(--ak-font-heading)}
173
173
  .ak-card-meta{display:flex;flex-wrap:wrap;gap:6px;align-items:center;color:var(--ak-color-muted);font-size:12px}
174
174
  .ak-panel{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--ak-color-background);border:1px solid var(--ak-color-border);border-radius:var(--ak-radius);overflow:hidden}
175
- .ak-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:16px;border-bottom:1px solid var(--ak-color-border)}
175
+ .ak-panel-header{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:16px;border-bottom:1px solid var(--ak-color-border-soft)}
176
176
  .ak-panel-title{flex:1;min-width:120px;margin:0;font-size:16px;line-height:22px;font-weight:700;font-family:var(--ak-font-heading)}
177
- .ak-panel-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--ak-color-border)}
177
+ .ak-panel-toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px;padding:12px 16px;border-bottom:1px solid var(--ak-color-border-soft)}
178
178
  .ak-panel-body{flex:1;min-height:0;overflow:auto;padding:16px}
179
- .ak-tabs{display:flex;gap:4px;padding:0 16px;border-bottom:1px solid var(--ak-color-border);overflow-x:auto;scrollbar-width:none}
179
+ .ak-tabs{display:flex;gap:4px;padding:0 16px;border-bottom:1px solid var(--ak-color-border-soft);overflow-x:auto;scrollbar-width:none}
180
180
  .ak-tab{display:inline-flex;align-items:center;gap:8px;height:36px;padding:0 12px;font:inherit;font-size:14px;font-weight:600;border:0;border-bottom:2px solid transparent;background:none;color:var(--ak-color-muted);cursor:pointer;white-space:nowrap}
181
181
  .ak-tab:hover{color:var(--ak-color-text)}
182
182
  .ak-tab[aria-selected="true"]{color:var(--ak-color-text);border-bottom-color:var(--ak-color-primary)}
@@ -1,34 +0,0 @@
1
- import type { Artifact } from '@artkit-ai/core';
2
- import { type CSSProperties } from 'react';
3
- import { type Slots } from './shared.js';
4
- export type ArtifactApprovalPart = 'header' | 'diff' | 'actions' | 'reason';
5
- export interface ArtifactApprovalProps {
6
- id?: string;
7
- artifact?: Artifact;
8
- /** Require a reason to reject (default true). */
9
- requireReason?: boolean;
10
- onApproved?(artifact: Artifact): void;
11
- onRejected?(artifact: Artifact, reason: string): void;
12
- className?: string;
13
- slots?: Slots<ArtifactApprovalPart>;
14
- }
15
- /**
16
- * Review of the version waiting for approval (spec §13.1, §15.3): diff against the last published
17
- * version (`meta.publishedVersion`) or the previous one, plus approve and reject with a reason.
18
- */
19
- export declare function ArtifactApproval(props: ArtifactApprovalProps): import("react").JSX.Element;
20
- export interface RejectFormProps {
21
- busy: boolean;
22
- requireReason: boolean;
23
- reason: string;
24
- onReasonChange(reason: string): void;
25
- onSubmit(): void;
26
- onCancel(): void;
27
- textareaProps?: {
28
- className?: string;
29
- style?: CSSProperties;
30
- };
31
- }
32
- /** Inline rejection form shared by the approval view and the panel. Escape cancels. */
33
- export declare function RejectForm(props: RejectFormProps): import("react").JSX.Element;
34
- //# sourceMappingURL=approval.d.ts.map