@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.
- package/dist/cache.d.ts +7 -11
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +32 -53
- package/dist/cache.js.map +1 -1
- package/dist/client.d.ts +4 -15
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +2 -29
- package/dist/client.js.map +1 -1
- package/dist/components/card.d.ts +2 -2
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +3 -3
- package/dist/components/card.js.map +1 -1
- package/dist/components/editor.d.ts +31 -18
- package/dist/components/editor.d.ts.map +1 -1
- package/dist/components/editor.js +81 -131
- package/dist/components/editor.js.map +1 -1
- package/dist/components/icons.d.ts +2 -2
- package/dist/components/icons.d.ts.map +1 -1
- package/dist/components/icons.js +2 -2
- package/dist/components/icons.js.map +1 -1
- package/dist/components/panel.d.ts +13 -16
- package/dist/components/panel.d.ts.map +1 -1
- package/dist/components/panel.js +13 -97
- package/dist/components/panel.js.map +1 -1
- package/dist/components/shared.d.ts +2 -6
- package/dist/components/shared.d.ts.map +1 -1
- package/dist/components/shared.js +2 -6
- package/dist/components/shared.js.map +1 -1
- package/dist/components/view.d.ts +7 -8
- package/dist/components/view.d.ts.map +1 -1
- package/dist/components/view.js +16 -15
- package/dist/components/view.js.map +1 -1
- package/dist/context.d.ts +14 -9
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/editor-session.d.ts +77 -165
- package/dist/editor-session.d.ts.map +1 -1
- package/dist/editor-session.js +164 -586
- package/dist/editor-session.js.map +1 -1
- package/dist/hooks.d.ts +2 -23
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +24 -116
- package/dist/hooks.js.map +1 -1
- package/dist/i18n.d.ts +4 -66
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +6 -68
- package/dist/i18n.js.map +1 -1
- package/dist/index.d.ts +6 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -8
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +12 -12
- package/dist/provider.js.map +1 -1
- package/dist/styles.d.ts +1 -1
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +4 -4
- package/package.json +2 -2
- package/src/cache.ts +32 -55
- package/src/client.ts +7 -55
- package/src/components/card.tsx +6 -7
- package/src/components/editor.tsx +208 -308
- package/src/components/icons.tsx +2 -2
- package/src/components/panel.tsx +43 -300
- package/src/components/shared.tsx +3 -12
- package/src/components/view.tsx +26 -29
- package/src/context.ts +16 -11
- package/src/editor-session.ts +197 -675
- package/src/hooks.ts +25 -140
- package/src/i18n.ts +6 -68
- package/src/index.ts +7 -39
- package/src/provider.tsx +13 -13
- package/src/styles.ts +4 -4
- package/dist/components/approval.d.ts +0 -34
- package/dist/components/approval.d.ts.map +0 -1
- package/dist/components/approval.js +0 -80
- package/dist/components/approval.js.map +0 -1
- package/dist/components/version-diff.d.ts +0 -35
- package/dist/components/version-diff.d.ts.map +0 -1
- package/dist/components/version-diff.js +0 -85
- package/dist/components/version-diff.js.map +0 -1
- package/dist/line-diff.d.ts +0 -25
- package/dist/line-diff.d.ts.map +0 -1
- package/dist/line-diff.js +0 -96
- package/dist/line-diff.js.map +0 -1
- package/src/components/approval.tsx +0 -219
- package/src/components/version-diff.tsx +0 -266
- 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 {
|
|
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
|
|
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,
|
|
71
|
-
}, [cache, id,
|
|
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,
|
|
84
|
-
}, [cache, id
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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.
|
|
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 (!
|
|
213
|
+
if (!knownFormat) return;
|
|
325
214
|
try {
|
|
326
|
-
setLoaded(await browserExporters(
|
|
215
|
+
setLoaded(await browserExporters(knownFormat));
|
|
327
216
|
} catch {
|
|
328
217
|
// Without browser exporters the server formats still work.
|
|
329
218
|
}
|
|
330
|
-
}, [browserExporters,
|
|
219
|
+
}, [browserExporters, knownFormat]);
|
|
331
220
|
|
|
332
221
|
const formats = useMemo(() => {
|
|
333
|
-
if (!
|
|
334
|
-
const set = new Set<string>(ctx.exportFormats[
|
|
335
|
-
for (const exporter of registry.exporters(
|
|
336
|
-
if (exporter.runtime !== 'node') set.add(exporter.
|
|
337
|
-
for (const exporter of loaded) set.add(exporter.
|
|
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,
|
|
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.
|
|
354
|
-
(candidate) => candidate.
|
|
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 "{
|
|
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
|
-
|
|
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 "{
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
96
|
-
|
|
97
|
-
type
|
|
98
|
-
type
|
|
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
|
|
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',
|
|
96
|
-
const key: LoadKey = `${type}:${
|
|
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?.[
|
|
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 "${
|
|
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: (
|
|
126
|
-
hasEditor: (
|
|
127
|
-
hasExporters: (
|
|
128
|
-
loadRenderer: (
|
|
129
|
-
loadEditor: (
|
|
130
|
-
loadExporters: (
|
|
131
|
-
resetLoad: (type,
|
|
132
|
-
loads.current.delete(`${type}:${
|
|
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
|