@joai/core 4.5.0 → 4.7.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/index.d.mts +652 -530
- package/dist/index.mjs +34 -2
- package/dist/react/index.d.mts +258 -2
- package/dist/react/index.mjs +435 -2
- package/package.json +1 -1
- package/dist/types-CWSaEVa7.d.mts +0 -32
package/dist/react/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
2
3
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
4
|
//#region src/react/guest.ts
|
|
4
5
|
function safeGet(key) {
|
|
@@ -288,4 +289,436 @@ function useEmbedChat({ agentUuid, http, cortexBaseUrl, guestId, roomStorageKey,
|
|
|
288
289
|
};
|
|
289
290
|
}
|
|
290
291
|
//#endregion
|
|
291
|
-
|
|
292
|
+
//#region src/react/content/context.ts
|
|
293
|
+
const ContentContext = createContext(null);
|
|
294
|
+
function useContent() {
|
|
295
|
+
const context = useContext(ContentContext);
|
|
296
|
+
if (!context) throw new Error("useContent must be used within a ContentProvider.");
|
|
297
|
+
return context;
|
|
298
|
+
}
|
|
299
|
+
//#endregion
|
|
300
|
+
//#region src/react/content/content-cache.ts
|
|
301
|
+
const contentCache = /* @__PURE__ */ new Map();
|
|
302
|
+
const pendingLoads = /* @__PURE__ */ new Map();
|
|
303
|
+
function cacheContent(content) {
|
|
304
|
+
contentCache.set(`id:${content.id}`, content);
|
|
305
|
+
contentCache.set(`slug:${content.slug}`, content);
|
|
306
|
+
}
|
|
307
|
+
async function loadContent(client, contentId, publicSlug) {
|
|
308
|
+
const target = contentId ?? publicSlug;
|
|
309
|
+
if (!target) return null;
|
|
310
|
+
const key = contentId ? `id:${contentId}` : `slug:${publicSlug}`;
|
|
311
|
+
const cached = contentCache.get(key);
|
|
312
|
+
if (cached) return cached;
|
|
313
|
+
const pending = pendingLoads.get(key);
|
|
314
|
+
if (pending) return pending;
|
|
315
|
+
const request = (contentId ? client.content.get(target) : client.content.getPublic(target)).then((result) => result.ok && result.data ? result.data : null).then((content) => {
|
|
316
|
+
if (content) cacheContent(content);
|
|
317
|
+
return content;
|
|
318
|
+
}).finally(() => pendingLoads.delete(key));
|
|
319
|
+
pendingLoads.set(key, request);
|
|
320
|
+
return request;
|
|
321
|
+
}
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/react/content/state.ts
|
|
324
|
+
function contentValues(content) {
|
|
325
|
+
return Object.fromEntries(content?.version?.entries.map((entry) => [entry.key, entry.value]) ?? []);
|
|
326
|
+
}
|
|
327
|
+
function contentPatches(content, values) {
|
|
328
|
+
const original = contentValues(content);
|
|
329
|
+
return Object.entries(values).filter(([key, value]) => JSON.stringify(value) !== JSON.stringify(original[key])).map(([key, value]) => ({
|
|
330
|
+
key,
|
|
331
|
+
value
|
|
332
|
+
}));
|
|
333
|
+
}
|
|
334
|
+
//#endregion
|
|
335
|
+
//#region src/react/content/provider.tsx
|
|
336
|
+
function ContentProvider({ children, client, contentId, publicSlug, initialContent, canEdit = false, canPublish = false, teamSlug }) {
|
|
337
|
+
const [content, setContent] = useState(initialContent ?? null);
|
|
338
|
+
const [values, setValues] = useState(() => contentValues(initialContent ?? null));
|
|
339
|
+
const [isLoading, setIsLoading] = useState(!initialContent && Boolean(contentId || publicSlug));
|
|
340
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
341
|
+
const [isEditing, setEditing] = useState(false);
|
|
342
|
+
const [error, setError] = useState(null);
|
|
343
|
+
useEffect(() => {
|
|
344
|
+
if (initialContent && !contentId) {
|
|
345
|
+
cacheContent(initialContent);
|
|
346
|
+
setContent(initialContent);
|
|
347
|
+
setValues(contentValues(initialContent));
|
|
348
|
+
setIsLoading(false);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const load = async () => {
|
|
352
|
+
if (!contentId && !publicSlug) return;
|
|
353
|
+
setIsLoading(true);
|
|
354
|
+
setError(null);
|
|
355
|
+
const nextContent = await loadContent(client, contentId, publicSlug);
|
|
356
|
+
if (!nextContent) setError("Content could not be loaded.");
|
|
357
|
+
else {
|
|
358
|
+
setContent(nextContent);
|
|
359
|
+
setValues(contentValues(nextContent));
|
|
360
|
+
}
|
|
361
|
+
setIsLoading(false);
|
|
362
|
+
};
|
|
363
|
+
load();
|
|
364
|
+
}, [
|
|
365
|
+
client,
|
|
366
|
+
contentId,
|
|
367
|
+
initialContent,
|
|
368
|
+
publicSlug
|
|
369
|
+
]);
|
|
370
|
+
const setValue = useCallback((key, value) => {
|
|
371
|
+
setValues((current) => ({
|
|
372
|
+
...current,
|
|
373
|
+
[key]: value
|
|
374
|
+
}));
|
|
375
|
+
}, []);
|
|
376
|
+
const isDirty = contentPatches(content, values).length > 0;
|
|
377
|
+
const save = useCallback(async () => {
|
|
378
|
+
if (!content?.version || !contentId || !canEdit) return false;
|
|
379
|
+
const patches = contentPatches(content, values);
|
|
380
|
+
if (patches.length === 0) return true;
|
|
381
|
+
setIsSaving(true);
|
|
382
|
+
setError(null);
|
|
383
|
+
const result = await client.content.patch(contentId, {
|
|
384
|
+
expectedVersion: content.version.number,
|
|
385
|
+
patches,
|
|
386
|
+
origin: "inlineEditor"
|
|
387
|
+
});
|
|
388
|
+
setIsSaving(false);
|
|
389
|
+
if (!result.ok || !result.data) {
|
|
390
|
+
setError("Changes could not be saved. Refresh and try again.");
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
const nextContent = {
|
|
394
|
+
...content,
|
|
395
|
+
version: result.data,
|
|
396
|
+
updatedAt: result.data.updatedAt
|
|
397
|
+
};
|
|
398
|
+
cacheContent(nextContent);
|
|
399
|
+
setContent(nextContent);
|
|
400
|
+
setValues(contentValues(nextContent));
|
|
401
|
+
return true;
|
|
402
|
+
}, [
|
|
403
|
+
canEdit,
|
|
404
|
+
client,
|
|
405
|
+
content,
|
|
406
|
+
contentId,
|
|
407
|
+
values
|
|
408
|
+
]);
|
|
409
|
+
const publish = useCallback(async () => {
|
|
410
|
+
if (!content?.version || !contentId || !canPublish) return false;
|
|
411
|
+
if (!await save()) return false;
|
|
412
|
+
const expectedVersion = content.version.number + (contentPatches(content, values).length > 0 ? 1 : 0);
|
|
413
|
+
setIsSaving(true);
|
|
414
|
+
const result = await client.content.publish(contentId, expectedVersion);
|
|
415
|
+
setIsSaving(false);
|
|
416
|
+
if (!result.ok || !result.data) {
|
|
417
|
+
setError("Changes could not be published. Refresh and try again.");
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
const nextContent = {
|
|
421
|
+
...content,
|
|
422
|
+
version: result.data,
|
|
423
|
+
updatedAt: result.data.updatedAt
|
|
424
|
+
};
|
|
425
|
+
cacheContent(nextContent);
|
|
426
|
+
setContent(nextContent);
|
|
427
|
+
setValues(contentValues(nextContent));
|
|
428
|
+
setEditing(false);
|
|
429
|
+
return true;
|
|
430
|
+
}, [
|
|
431
|
+
canPublish,
|
|
432
|
+
client,
|
|
433
|
+
content,
|
|
434
|
+
contentId,
|
|
435
|
+
save,
|
|
436
|
+
values
|
|
437
|
+
]);
|
|
438
|
+
const context = useMemo(() => ({
|
|
439
|
+
content,
|
|
440
|
+
values,
|
|
441
|
+
isLoading,
|
|
442
|
+
isSaving,
|
|
443
|
+
isEditing,
|
|
444
|
+
isDirty,
|
|
445
|
+
canEdit,
|
|
446
|
+
canPublish,
|
|
447
|
+
teamSlug,
|
|
448
|
+
media: client.media,
|
|
449
|
+
error,
|
|
450
|
+
setEditing,
|
|
451
|
+
setValue,
|
|
452
|
+
save,
|
|
453
|
+
publish
|
|
454
|
+
}), [
|
|
455
|
+
canEdit,
|
|
456
|
+
canPublish,
|
|
457
|
+
client.media,
|
|
458
|
+
content,
|
|
459
|
+
error,
|
|
460
|
+
isDirty,
|
|
461
|
+
isEditing,
|
|
462
|
+
isLoading,
|
|
463
|
+
isSaving,
|
|
464
|
+
publish,
|
|
465
|
+
save,
|
|
466
|
+
setValue,
|
|
467
|
+
teamSlug,
|
|
468
|
+
values
|
|
469
|
+
]);
|
|
470
|
+
return /* @__PURE__ */ jsx(ContentContext.Provider, {
|
|
471
|
+
value: context,
|
|
472
|
+
children
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
//#endregion
|
|
476
|
+
//#region src/react/content/editable-content.tsx
|
|
477
|
+
function EditableContent({ field, as: Tag = "span", className, placeholder = "Add text", multiline = false }) {
|
|
478
|
+
const { values, isEditing, canEdit, setValue } = useContent();
|
|
479
|
+
const value = values[field];
|
|
480
|
+
const text = typeof value === "string" || typeof value === "number" ? String(value) : "";
|
|
481
|
+
if (!canEdit || !isEditing) return /* @__PURE__ */ jsx(Tag, {
|
|
482
|
+
className,
|
|
483
|
+
children: text
|
|
484
|
+
});
|
|
485
|
+
if (multiline) return /* @__PURE__ */ jsx("textarea", {
|
|
486
|
+
"aria-label": field,
|
|
487
|
+
className,
|
|
488
|
+
placeholder,
|
|
489
|
+
value: text,
|
|
490
|
+
onChange: (event) => setValue(field, event.target.value)
|
|
491
|
+
});
|
|
492
|
+
return /* @__PURE__ */ jsx("input", {
|
|
493
|
+
"aria-label": field,
|
|
494
|
+
className,
|
|
495
|
+
placeholder,
|
|
496
|
+
value: text,
|
|
497
|
+
onChange: (event) => setValue(field, event.target.value)
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
function useContentValue(key) {
|
|
501
|
+
return useContent().values[key];
|
|
502
|
+
}
|
|
503
|
+
//#endregion
|
|
504
|
+
//#region src/react/content/editable-image.tsx
|
|
505
|
+
function EditableImage({ field, alt = "", className, inputClassName, placeholder = "Image URL", onSelect }) {
|
|
506
|
+
const { values, isEditing, canEdit, media, setValue, teamSlug } = useContent();
|
|
507
|
+
const source = typeof values[field] === "string" ? values[field] : "";
|
|
508
|
+
const [isPickerOpen, setPickerOpen] = useState(false);
|
|
509
|
+
const [images, setImages] = useState([]);
|
|
510
|
+
const [isUploading, setUploading] = useState(false);
|
|
511
|
+
useEffect(() => {
|
|
512
|
+
if (!isPickerOpen || !media || !teamSlug) return;
|
|
513
|
+
media.list(teamSlug, { mime: "image/" }).then((result) => setImages(result.ok ? result.data ?? [] : []));
|
|
514
|
+
}, [
|
|
515
|
+
isPickerOpen,
|
|
516
|
+
media,
|
|
517
|
+
teamSlug
|
|
518
|
+
]);
|
|
519
|
+
const upload = async (file) => {
|
|
520
|
+
if (!media || !teamSlug || !file.type.startsWith("image/")) return;
|
|
521
|
+
setUploading(true);
|
|
522
|
+
const result = await media.upload({
|
|
523
|
+
team: teamSlug,
|
|
524
|
+
file,
|
|
525
|
+
type: "output",
|
|
526
|
+
label: file.name
|
|
527
|
+
});
|
|
528
|
+
setUploading(false);
|
|
529
|
+
if (!result.ok || !result.data) return;
|
|
530
|
+
setImages((current) => [result.data, ...current]);
|
|
531
|
+
setValue(field, result.data.url);
|
|
532
|
+
setPickerOpen(false);
|
|
533
|
+
};
|
|
534
|
+
if (!canEdit || !isEditing) return source ? /* @__PURE__ */ jsx("img", {
|
|
535
|
+
src: source,
|
|
536
|
+
alt,
|
|
537
|
+
className
|
|
538
|
+
}) : null;
|
|
539
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
540
|
+
className,
|
|
541
|
+
children: [
|
|
542
|
+
source && /* @__PURE__ */ jsx("img", {
|
|
543
|
+
src: source,
|
|
544
|
+
alt
|
|
545
|
+
}),
|
|
546
|
+
onSelect && /* @__PURE__ */ jsx("button", {
|
|
547
|
+
className: "rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-blue-500",
|
|
548
|
+
type: "button",
|
|
549
|
+
onClick: onSelect,
|
|
550
|
+
children: "Choose image"
|
|
551
|
+
}),
|
|
552
|
+
!onSelect && media && teamSlug && /* @__PURE__ */ jsx("button", {
|
|
553
|
+
className: "rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-blue-500",
|
|
554
|
+
type: "button",
|
|
555
|
+
onClick: () => setPickerOpen(true),
|
|
556
|
+
children: "Choose image"
|
|
557
|
+
}),
|
|
558
|
+
/* @__PURE__ */ jsx(ImagePicker, {
|
|
559
|
+
open: isPickerOpen,
|
|
560
|
+
onClose: () => setPickerOpen(false),
|
|
561
|
+
images,
|
|
562
|
+
isUploading,
|
|
563
|
+
onUpload: upload,
|
|
564
|
+
onSelect: (url) => {
|
|
565
|
+
setValue(field, url);
|
|
566
|
+
setPickerOpen(false);
|
|
567
|
+
}
|
|
568
|
+
}),
|
|
569
|
+
/* @__PURE__ */ jsx("input", {
|
|
570
|
+
"aria-label": field,
|
|
571
|
+
className: inputClassName,
|
|
572
|
+
type: "url",
|
|
573
|
+
placeholder,
|
|
574
|
+
value: source,
|
|
575
|
+
onChange: (event) => setValue(field, event.target.value)
|
|
576
|
+
})
|
|
577
|
+
]
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
function ImagePicker({ open, onClose, images, isUploading, onUpload, onSelect }) {
|
|
581
|
+
if (!open) return null;
|
|
582
|
+
return /* @__PURE__ */ jsx("div", {
|
|
583
|
+
className: "fixed inset-0 z-[1100] grid place-items-center bg-slate-950/45 p-4",
|
|
584
|
+
role: "dialog",
|
|
585
|
+
"aria-modal": "true",
|
|
586
|
+
"aria-label": "Image library",
|
|
587
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
588
|
+
className: "max-h-[min(44rem,calc(100vh-2rem))] w-full max-w-2xl overflow-y-auto rounded-xl bg-white p-5 shadow-2xl",
|
|
589
|
+
children: [
|
|
590
|
+
/* @__PURE__ */ jsxs("div", {
|
|
591
|
+
className: "flex items-start justify-between gap-4",
|
|
592
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
|
|
593
|
+
className: "text-lg font-semibold text-slate-950",
|
|
594
|
+
children: "Image library"
|
|
595
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
596
|
+
className: "mt-1 text-sm text-slate-500",
|
|
597
|
+
children: "Choose an existing image or upload a new one."
|
|
598
|
+
})] }), /* @__PURE__ */ jsx("button", {
|
|
599
|
+
className: "rounded-lg px-3 py-2 text-sm font-medium text-slate-700 transition hover:bg-slate-100",
|
|
600
|
+
type: "button",
|
|
601
|
+
onClick: onClose,
|
|
602
|
+
children: "Close"
|
|
603
|
+
})]
|
|
604
|
+
}),
|
|
605
|
+
/* @__PURE__ */ jsxs("label", {
|
|
606
|
+
className: "mt-5 flex cursor-pointer items-center justify-center rounded-lg border border-dashed border-slate-300 px-4 py-6 text-sm font-medium text-slate-600 transition hover:border-blue-400 hover:text-blue-600",
|
|
607
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
608
|
+
className: "sr-only",
|
|
609
|
+
type: "file",
|
|
610
|
+
accept: "image/*",
|
|
611
|
+
onChange: (event) => {
|
|
612
|
+
const file = event.target.files?.[0];
|
|
613
|
+
if (file) onUpload(file);
|
|
614
|
+
}
|
|
615
|
+
}), "Upload image"]
|
|
616
|
+
}),
|
|
617
|
+
isUploading && /* @__PURE__ */ jsx("span", {
|
|
618
|
+
className: "mt-3 block text-sm text-slate-500",
|
|
619
|
+
children: "Uploading…"
|
|
620
|
+
}),
|
|
621
|
+
/* @__PURE__ */ jsx("div", {
|
|
622
|
+
className: "mt-5 grid grid-cols-2 gap-3 sm:grid-cols-3",
|
|
623
|
+
role: "list",
|
|
624
|
+
children: images.map((image) => /* @__PURE__ */ jsxs("button", {
|
|
625
|
+
className: "overflow-hidden rounded-lg border border-slate-200 text-left transition-opacity hover:opacity-75",
|
|
626
|
+
type: "button",
|
|
627
|
+
onClick: () => onSelect(image.url),
|
|
628
|
+
children: [/* @__PURE__ */ jsx("img", {
|
|
629
|
+
className: "aspect-square w-full object-cover",
|
|
630
|
+
src: image.url,
|
|
631
|
+
alt: image.name
|
|
632
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
633
|
+
className: "block truncate p-2 text-xs text-slate-700",
|
|
634
|
+
children: image.name
|
|
635
|
+
})]
|
|
636
|
+
}, image.id))
|
|
637
|
+
})
|
|
638
|
+
]
|
|
639
|
+
})
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
//#endregion
|
|
643
|
+
//#region src/react/content/toolbar.tsx
|
|
644
|
+
function ContentToolbar({ className, labels = {}, confirmPublish }) {
|
|
645
|
+
const { canEdit, canPublish, isDirty, isEditing, isSaving, error, setEditing, save, publish } = useContent();
|
|
646
|
+
if (!canEdit) return null;
|
|
647
|
+
const edit = labels.edit ?? "Edit";
|
|
648
|
+
const saveLabel = labels.save ?? "Save draft";
|
|
649
|
+
const publishLabel = labels.publish ?? "Publish";
|
|
650
|
+
const cancel = labels.cancel ?? "Cancel";
|
|
651
|
+
const handlePublish = async () => {
|
|
652
|
+
if (confirmPublish && !await confirmPublish()) return;
|
|
653
|
+
await publish();
|
|
654
|
+
};
|
|
655
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
656
|
+
className: `flex flex-wrap items-center gap-2 ${className ?? ""}`,
|
|
657
|
+
role: "toolbar",
|
|
658
|
+
"aria-label": "Content editor",
|
|
659
|
+
children: [
|
|
660
|
+
!isEditing ? /* @__PURE__ */ jsx("button", {
|
|
661
|
+
className: "rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-blue-500",
|
|
662
|
+
type: "button",
|
|
663
|
+
onClick: () => setEditing(true),
|
|
664
|
+
children: edit
|
|
665
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
666
|
+
/* @__PURE__ */ jsx("button", {
|
|
667
|
+
className: "rounded-lg bg-blue-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-blue-500 disabled:opacity-60",
|
|
668
|
+
type: "button",
|
|
669
|
+
disabled: isSaving,
|
|
670
|
+
onClick: () => void save(),
|
|
671
|
+
children: isSaving ? "Saving…" : saveLabel
|
|
672
|
+
}),
|
|
673
|
+
canPublish && /* @__PURE__ */ jsx("button", {
|
|
674
|
+
className: "rounded-lg bg-emerald-600 px-3 py-2 text-sm font-medium text-white transition hover:bg-emerald-500 disabled:opacity-60",
|
|
675
|
+
type: "button",
|
|
676
|
+
disabled: isSaving,
|
|
677
|
+
onClick: () => void handlePublish(),
|
|
678
|
+
children: publishLabel
|
|
679
|
+
}),
|
|
680
|
+
/* @__PURE__ */ jsx("button", {
|
|
681
|
+
className: "rounded-lg px-3 py-2 text-sm font-medium text-slate-700 transition hover:bg-slate-100 disabled:opacity-60",
|
|
682
|
+
type: "button",
|
|
683
|
+
disabled: isSaving,
|
|
684
|
+
onClick: () => setEditing(false),
|
|
685
|
+
children: cancel
|
|
686
|
+
})
|
|
687
|
+
] }),
|
|
688
|
+
error && /* @__PURE__ */ jsx("span", {
|
|
689
|
+
className: "w-full text-sm text-red-600 dark:text-red-400",
|
|
690
|
+
role: "alert",
|
|
691
|
+
children: error
|
|
692
|
+
}),
|
|
693
|
+
isEditing && isDirty && /* @__PURE__ */ jsx("span", {
|
|
694
|
+
className: "w-full text-xs text-slate-500",
|
|
695
|
+
"aria-live": "polite",
|
|
696
|
+
children: "Unsaved changes"
|
|
697
|
+
})
|
|
698
|
+
]
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
//#endregion
|
|
702
|
+
//#region src/react/content/content-editor.tsx
|
|
703
|
+
function ContentEditor({ children, title = "JoAi Content", ...provider }) {
|
|
704
|
+
return /* @__PURE__ */ jsx(ContentProvider, {
|
|
705
|
+
...provider,
|
|
706
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
707
|
+
"data-joai-content-editor": "true",
|
|
708
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
709
|
+
className: "fixed right-4 bottom-4 z-[1000] w-[min(24rem,calc(100vw-2rem))] rounded-xl border border-slate-200 bg-white p-3 text-slate-950 shadow-xl",
|
|
710
|
+
children: [/* @__PURE__ */ jsx("strong", {
|
|
711
|
+
className: "mb-2 block text-sm font-semibold",
|
|
712
|
+
children: title
|
|
713
|
+
}), /* @__PURE__ */ jsx(ContentToolbar, { labels: {
|
|
714
|
+
edit: "Edit",
|
|
715
|
+
save: "Save draft",
|
|
716
|
+
publish: "Publish",
|
|
717
|
+
cancel: "Cancel"
|
|
718
|
+
} })]
|
|
719
|
+
}), children]
|
|
720
|
+
})
|
|
721
|
+
});
|
|
722
|
+
}
|
|
723
|
+
//#endregion
|
|
724
|
+
export { ContentEditor, ContentProvider, ContentToolbar, EditableContent, EditableImage, EmbedChatInput, EmbedChatList, clearRoom, getOrCreateGuestId, loadRoom, openEventSourceStream, saveRoom, useContentValue, useEmbedChat };
|
package/package.json
CHANGED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
//#region src/http/types.d.ts
|
|
2
|
-
interface IHttpService {
|
|
3
|
-
readonly baseUrl: string;
|
|
4
|
-
readonly authToken: string | null;
|
|
5
|
-
onNetworkError: (error: Error) => void;
|
|
6
|
-
onUnauthorized: (response: IAppResponse<any>) => void;
|
|
7
|
-
onSuccessfulResponse: (response: IAppResponse<any>) => void;
|
|
8
|
-
onMaintenanceMode: (response: IAppResponse<any>) => void;
|
|
9
|
-
get: <T>(url: string, options?: IRequestOptions) => Promise<IAppResponse<T>>;
|
|
10
|
-
post: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
|
|
11
|
-
put: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
|
|
12
|
-
patch: <T>(url: string, data?: any, options?: IRequestOptions) => Promise<IAppResponse<T>>;
|
|
13
|
-
delete: <T>(url: string, options?: IRequestOptions) => Promise<IAppResponse<T>>;
|
|
14
|
-
}
|
|
15
|
-
interface IAppResponse<T> {
|
|
16
|
-
data: T;
|
|
17
|
-
meta?: any;
|
|
18
|
-
body: any;
|
|
19
|
-
errors: any;
|
|
20
|
-
ok: boolean;
|
|
21
|
-
paymentRequired: boolean;
|
|
22
|
-
noContent: boolean;
|
|
23
|
-
original: Response;
|
|
24
|
-
}
|
|
25
|
-
interface IRequestOptions {
|
|
26
|
-
isJson?: boolean;
|
|
27
|
-
headers?: {
|
|
28
|
-
[name: string]: string;
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
//#endregion
|
|
32
|
-
export { IHttpService as n, IRequestOptions as r, IAppResponse as t };
|