camox 0.10.0 → 0.11.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/core/components/lexical/SidebarLexicalEditor.js +14 -41
- package/dist/core/createApp.d.ts +3 -3
- package/dist/core/createBlock.d.ts +14 -13
- package/dist/core/createBlock.js +114 -98
- package/dist/core/lib/contentType.d.ts +11 -9
- package/dist/core/lib/contentType.js +19 -2
- package/dist/features/content/CamoxContent.js +1 -1
- package/dist/features/preview/CamoxPreview.js +1 -1
- package/dist/features/preview/components/AddBlockSheet.js +1 -1
- package/dist/features/preview/components/AssetFieldEditor.js +1 -1
- package/dist/features/preview/components/CreatePageModal.js +1 -1
- package/dist/features/preview/components/EditPageModal.js +1 -1
- package/dist/features/preview/components/PagePicker.js +1 -1
- package/dist/features/preview/components/useUpdateBlockPosition.js +1 -1
- package/dist/features/provider/CamoxProvider.js +1 -1
- package/dist/features/routes/pageRoute.js +4 -3
- package/dist/features/studio/CamoxStudio.js +1 -1
- package/dist/features/studio/components/Navbar.js +1 -1
- package/dist/features/studio/components/ProjectMenu.js +1 -1
- package/dist/features/vite/blockBoilerplate.js +1 -1
- package/dist/features/vite/vite.js +45 -42
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- package/skills/camox-block/SKILL.md +30 -24
|
@@ -12,42 +12,15 @@ import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
|
12
12
|
|
|
13
13
|
//#region src/core/components/lexical/SidebarLexicalEditor.tsx
|
|
14
14
|
function ExternalStateSync(t0) {
|
|
15
|
-
const $ = c(
|
|
15
|
+
const $ = c(5);
|
|
16
16
|
const { value, isSyncingRef } = t0;
|
|
17
17
|
const [editor] = useLexicalComposerContext();
|
|
18
|
-
const isFocusedRef = React.useRef(false);
|
|
19
18
|
let t1;
|
|
20
19
|
let t2;
|
|
21
|
-
if ($[0] !== editor) {
|
|
22
|
-
t1 = () =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
isFocusedRef.current = true;
|
|
26
|
-
};
|
|
27
|
-
const handleBlur = () => {
|
|
28
|
-
isFocusedRef.current = false;
|
|
29
|
-
};
|
|
30
|
-
root.addEventListener("focus", handleFocus);
|
|
31
|
-
root.addEventListener("blur", handleBlur);
|
|
32
|
-
return () => {
|
|
33
|
-
root.removeEventListener("focus", handleFocus);
|
|
34
|
-
root.removeEventListener("blur", handleBlur);
|
|
35
|
-
};
|
|
36
|
-
});
|
|
37
|
-
t2 = [editor];
|
|
38
|
-
$[0] = editor;
|
|
39
|
-
$[1] = t1;
|
|
40
|
-
$[2] = t2;
|
|
41
|
-
} else {
|
|
42
|
-
t1 = $[1];
|
|
43
|
-
t2 = $[2];
|
|
44
|
-
}
|
|
45
|
-
React.useEffect(t1, t2);
|
|
46
|
-
let t3;
|
|
47
|
-
let t4;
|
|
48
|
-
if ($[3] !== editor || $[4] !== isSyncingRef || $[5] !== value) {
|
|
49
|
-
t3 = () => {
|
|
50
|
-
if (isFocusedRef.current) return;
|
|
20
|
+
if ($[0] !== editor || $[1] !== isSyncingRef || $[2] !== value) {
|
|
21
|
+
t1 = () => {
|
|
22
|
+
const root = editor.getRootElement();
|
|
23
|
+
if (root !== null && root === document.activeElement) return;
|
|
51
24
|
try {
|
|
52
25
|
const normalized = normalizeLexicalState(value);
|
|
53
26
|
const newState = editor.parseEditorState(normalized);
|
|
@@ -55,21 +28,21 @@ function ExternalStateSync(t0) {
|
|
|
55
28
|
editor.setEditorState(newState);
|
|
56
29
|
} catch {}
|
|
57
30
|
};
|
|
58
|
-
|
|
31
|
+
t2 = [
|
|
59
32
|
editor,
|
|
60
33
|
value,
|
|
61
34
|
isSyncingRef
|
|
62
35
|
];
|
|
63
|
-
$[
|
|
64
|
-
$[
|
|
65
|
-
$[
|
|
66
|
-
$[
|
|
67
|
-
$[
|
|
36
|
+
$[0] = editor;
|
|
37
|
+
$[1] = isSyncingRef;
|
|
38
|
+
$[2] = value;
|
|
39
|
+
$[3] = t1;
|
|
40
|
+
$[4] = t2;
|
|
68
41
|
} else {
|
|
69
|
-
|
|
70
|
-
|
|
42
|
+
t1 = $[3];
|
|
43
|
+
t2 = $[4];
|
|
71
44
|
}
|
|
72
|
-
React.useEffect(
|
|
45
|
+
React.useEffect(t1, t2);
|
|
73
46
|
return null;
|
|
74
47
|
}
|
|
75
48
|
function SidebarLexicalEditor({ id, value, onChange, onFocus, onBlur }) {
|
package/dist/core/createApp.d.ts
CHANGED
|
@@ -296,7 +296,7 @@ declare function createApp({
|
|
|
296
296
|
description: string;
|
|
297
297
|
properties: Record<string, _$_sinclair_typebox0.TSchema>;
|
|
298
298
|
required: string[];
|
|
299
|
-
toMarkdown:
|
|
299
|
+
toMarkdown: string[];
|
|
300
300
|
};
|
|
301
301
|
settingsSchema: {
|
|
302
302
|
type: "object";
|
|
@@ -618,7 +618,7 @@ declare function createApp({
|
|
|
618
618
|
description: string;
|
|
619
619
|
properties: Record<string, _$_sinclair_typebox0.TSchema>;
|
|
620
620
|
required: string[];
|
|
621
|
-
toMarkdown:
|
|
621
|
+
toMarkdown: string[];
|
|
622
622
|
};
|
|
623
623
|
settingsSchema: {
|
|
624
624
|
type: "object";
|
|
@@ -804,7 +804,7 @@ declare function createApp({
|
|
|
804
804
|
description: string;
|
|
805
805
|
properties: Record<string, _$_sinclair_typebox0.TSchema>;
|
|
806
806
|
required: string[];
|
|
807
|
-
toMarkdown:
|
|
807
|
+
toMarkdown: string[];
|
|
808
808
|
};
|
|
809
809
|
settingsSchema: {
|
|
810
810
|
type: "object";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { EmbedURL,
|
|
1
|
+
import { EmbedURL, FileValue, ImageValue, LinkValue, ToMarkdownBuilder, Type } from "./lib/contentType.js";
|
|
2
2
|
import * as _$_sinclair_typebox0 from "@sinclair/typebox";
|
|
3
3
|
import { Static, TSchema, Type as Type$1 } from "@sinclair/typebox";
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import * as _$react_jsx_runtime0 from "react/jsx-runtime";
|
|
6
6
|
|
|
7
7
|
//#region src/core/createBlock.d.ts
|
|
8
|
-
interface CreateBlockOptions<TSchemaShape extends Record<string, TSchema> = Record<string, TSchema>, TSettingsShape extends Record<string, TSchema> = Record<string, TSchema>,
|
|
8
|
+
interface CreateBlockOptions<TSchemaShape extends Record<string, TSchema> = Record<string, TSchema>, TSettingsShape extends Record<string, TSchema> = Record<string, TSchema>, TLayoutOnly extends boolean = false> {
|
|
9
9
|
id: string;
|
|
10
10
|
/**
|
|
11
11
|
* Human-readable title for the block (JSON Schema `title`).
|
|
@@ -31,15 +31,6 @@ interface CreateBlockOptions<TSchemaShape extends Record<string, TSchema> = Reco
|
|
|
31
31
|
* }
|
|
32
32
|
*/
|
|
33
33
|
content: TSchemaShape;
|
|
34
|
-
/**
|
|
35
|
-
* Template for rendering block content as markdown.
|
|
36
|
-
* Each line is joined with `\n\n`. Use `{{fieldName}}` placeholders for field values.
|
|
37
|
-
* Lines where all placeholders resolve to empty are omitted.
|
|
38
|
-
*
|
|
39
|
-
* @example
|
|
40
|
-
* toMarkdown: ["# {{title}}", "{{description}}", "{{illustration}}", "{{cta}}"]
|
|
41
|
-
*/
|
|
42
|
-
toMarkdown: [ExtractAllPlaceholders<TMarkdown>] extends [Extract<keyof TSchemaShape, string>] ? TMarkdown : readonly [`Invalid toMarkdown placeholder {{${Exclude<ExtractAllPlaceholders<TMarkdown>, Extract<keyof TSchemaShape, string>>}}}`];
|
|
43
34
|
/**
|
|
44
35
|
* Optional schema defining block-level settings (e.g. layout variant, toggles).
|
|
45
36
|
* Settings are not inline-editable; they use Type.Enum() and Type.Boolean().
|
|
@@ -64,6 +55,16 @@ interface CreateBlockOptions<TSchemaShape extends Record<string, TSchema> = Reco
|
|
|
64
55
|
component: React.ComponentType<{
|
|
65
56
|
content: Static<ReturnType<typeof Type$1.Object<TSchemaShape>>>;
|
|
66
57
|
}>;
|
|
58
|
+
/**
|
|
59
|
+
* Builder for rendering block content as markdown.
|
|
60
|
+
* `c` is a proxy typed on `content` keys — `c.title`, `c.description`, etc.
|
|
61
|
+
* Each returned entry becomes a paragraph (joined with `\n\n`).
|
|
62
|
+
* Lines where all referenced fields resolve to empty are omitted at render time.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* toMarkdown: (c) => [`# ${c.title}`, c.description, c.illustration, c.cta]
|
|
66
|
+
*/
|
|
67
|
+
toMarkdown: ToMarkdownBuilder<TSchemaShape>;
|
|
67
68
|
}
|
|
68
69
|
interface BlockData<TContent> {
|
|
69
70
|
_id: number;
|
|
@@ -98,7 +99,7 @@ interface RepeatableItemSeed {
|
|
|
98
99
|
content: Record<string, unknown>;
|
|
99
100
|
position: string;
|
|
100
101
|
}
|
|
101
|
-
declare function createBlock<TSchemaShape extends Record<string, TSchema>, TSettingsShape extends Record<string, TSchema> = Record<string, never>,
|
|
102
|
+
declare function createBlock<TSchemaShape extends Record<string, TSchema>, TSettingsShape extends Record<string, TSchema> = Record<string, never>, TLayoutOnly extends boolean = false>(options: CreateBlockOptions<TSchemaShape, TSettingsShape, TLayoutOnly>): {
|
|
102
103
|
Detached: ({
|
|
103
104
|
children
|
|
104
105
|
}: {
|
|
@@ -1103,7 +1104,7 @@ declare function createBlock<TSchemaShape extends Record<string, TSchema>, TSett
|
|
|
1103
1104
|
description: string;
|
|
1104
1105
|
properties: TSchemaShape;
|
|
1105
1106
|
required: string[];
|
|
1106
|
-
toMarkdown:
|
|
1107
|
+
toMarkdown: string[];
|
|
1107
1108
|
};
|
|
1108
1109
|
settingsSchema: {
|
|
1109
1110
|
type: "object";
|
package/dist/core/createBlock.js
CHANGED
|
@@ -10,7 +10,7 @@ import { InlineLexicalEditor } from "./components/lexical/InlineLexicalEditor.js
|
|
|
10
10
|
import { useFieldSelection } from "./hooks/useFieldSelection.js";
|
|
11
11
|
import { useIsEditable } from "./hooks/useIsEditable.js";
|
|
12
12
|
import { useOverlayMessage } from "./hooks/useOverlayMessage.js";
|
|
13
|
-
import { Type } from "./lib/contentType.js";
|
|
13
|
+
import { Type, resolveToMarkdown } from "./lib/contentType.js";
|
|
14
14
|
import { markdownToReactNodes } from "./lib/lexicalReact.js";
|
|
15
15
|
import { c } from "react/compiler-runtime";
|
|
16
16
|
import { Input } from "@camox/ui/input";
|
|
@@ -20,6 +20,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "@camox/ui/popover";
|
|
|
20
20
|
import { toast } from "@camox/ui/toaster";
|
|
21
21
|
import { Type as Type$1 } from "@sinclair/typebox";
|
|
22
22
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
23
|
+
import { useLocation } from "@tanstack/react-router";
|
|
23
24
|
import { useSelector } from "@xstate/store/react";
|
|
24
25
|
import { generateKeyBetween } from "fractional-indexing";
|
|
25
26
|
import * as React from "react";
|
|
@@ -35,9 +36,16 @@ const normalizeLinkValue = (value) => {
|
|
|
35
36
|
};
|
|
36
37
|
return value;
|
|
37
38
|
};
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a LinkValue to an href string.
|
|
41
|
+
*
|
|
42
|
+
* Hash-only and empty hrefs are anchored to `currentPathname` so TanStack Router's
|
|
43
|
+
* `<Link to>` builds the same `href` on SSR and client — bare `"#"` otherwise
|
|
44
|
+
* resolves inconsistently across environments, causing hydration mismatches.
|
|
45
|
+
*/
|
|
46
|
+
const resolveLinkHref = (link, pages, currentPathname) => {
|
|
47
|
+
if (link.type === "page") return (pages?.find((p) => String(p.id) === link.pageId))?.fullPath ?? currentPathname;
|
|
48
|
+
if (!link.href || link.href.startsWith("#")) return `${currentPathname}${link.href ?? ""}`;
|
|
41
49
|
return link.href;
|
|
42
50
|
};
|
|
43
51
|
let hasShownEmbedLockToast = false;
|
|
@@ -131,7 +139,7 @@ function createBlock(options) {
|
|
|
131
139
|
description: options.description,
|
|
132
140
|
properties: typeboxSchema.properties,
|
|
133
141
|
required: Object.keys(options.content),
|
|
134
|
-
toMarkdown: options.toMarkdown
|
|
142
|
+
toMarkdown: resolveToMarkdown(options.toMarkdown)
|
|
135
143
|
};
|
|
136
144
|
const settingsTypeboxSchema = options.settings ? Type$1.Object(options.settings) : null;
|
|
137
145
|
const settingsSchema = settingsTypeboxSchema ? {
|
|
@@ -506,7 +514,7 @@ function createBlock(options) {
|
|
|
506
514
|
return t28;
|
|
507
515
|
};
|
|
508
516
|
const Link = (t0) => {
|
|
509
|
-
const $ = c(
|
|
517
|
+
const $ = c(37);
|
|
510
518
|
const { name, children } = t0;
|
|
511
519
|
const blockContext = React.use(Context);
|
|
512
520
|
if (!blockContext) throw new Error("Link must be used within a Block Component");
|
|
@@ -554,7 +562,12 @@ function createBlock(options) {
|
|
|
554
562
|
$[8] = t6;
|
|
555
563
|
} else t6 = $[8];
|
|
556
564
|
const { data: pages } = useQuery(t6);
|
|
557
|
-
|
|
565
|
+
let t7;
|
|
566
|
+
if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
|
|
567
|
+
t7 = { select: _temp2 };
|
|
568
|
+
$[9] = t7;
|
|
569
|
+
} else t7 = $[9];
|
|
570
|
+
const resolvedHref = resolveLinkHref(fieldValue, pages, useLocation(t7));
|
|
558
571
|
const fieldId = getOverlayFieldId(blockId, repeaterContext, String(name));
|
|
559
572
|
const [isEditing, setIsEditing] = React.useState(false);
|
|
560
573
|
const [displayText, setDisplayText] = React.useState(fieldValue.text);
|
|
@@ -566,24 +579,24 @@ function createBlock(options) {
|
|
|
566
579
|
if (!isEditing) setDisplayText(fieldValue.text);
|
|
567
580
|
}, [fieldValue.text, isEditing]);
|
|
568
581
|
const isHoveredFromSidebar = useOverlayMessage(iframeWindow, isContentEditable, "CAMOX_HOVER_FIELD", "CAMOX_HOVER_FIELD_END", { fieldId });
|
|
569
|
-
let t7;
|
|
570
582
|
let t8;
|
|
571
|
-
|
|
572
|
-
|
|
583
|
+
let t9;
|
|
584
|
+
if ($[10] !== isHoveredFromSidebar) {
|
|
585
|
+
t8 = () => {
|
|
573
586
|
setIsHovered(isHoveredFromSidebar);
|
|
574
587
|
};
|
|
575
|
-
|
|
576
|
-
$[
|
|
577
|
-
$[10] = t7;
|
|
588
|
+
t9 = [isHoveredFromSidebar];
|
|
589
|
+
$[10] = isHoveredFromSidebar;
|
|
578
590
|
$[11] = t8;
|
|
591
|
+
$[12] = t9;
|
|
579
592
|
} else {
|
|
580
|
-
t7 = $[10];
|
|
581
593
|
t8 = $[11];
|
|
594
|
+
t9 = $[12];
|
|
582
595
|
}
|
|
583
|
-
React.useEffect(
|
|
584
|
-
let
|
|
585
|
-
if ($[
|
|
586
|
-
|
|
596
|
+
React.useEffect(t8, t9);
|
|
597
|
+
let t10;
|
|
598
|
+
if ($[13] !== blockId || $[14] !== name || $[15] !== repeaterContext || $[16] !== updateBlockContent || $[17] !== updateRepeatableContent) {
|
|
599
|
+
t10 = (newLinkValue) => {
|
|
587
600
|
if (repeaterContext?.itemId != null) updateRepeatableContent.mutate({
|
|
588
601
|
id: repeaterContext.itemId,
|
|
589
602
|
content: { [name]: newLinkValue }
|
|
@@ -593,14 +606,14 @@ function createBlock(options) {
|
|
|
593
606
|
content: { [name]: newLinkValue }
|
|
594
607
|
});
|
|
595
608
|
};
|
|
596
|
-
$[
|
|
597
|
-
$[
|
|
598
|
-
$[
|
|
599
|
-
$[
|
|
600
|
-
$[
|
|
601
|
-
$[
|
|
602
|
-
} else
|
|
603
|
-
const saveLinkValue =
|
|
609
|
+
$[13] = blockId;
|
|
610
|
+
$[14] = name;
|
|
611
|
+
$[15] = repeaterContext;
|
|
612
|
+
$[16] = updateBlockContent;
|
|
613
|
+
$[17] = updateRepeatableContent;
|
|
614
|
+
$[18] = t10;
|
|
615
|
+
} else t10 = $[18];
|
|
616
|
+
const saveLinkValue = t10;
|
|
604
617
|
const handleInput = (e) => {
|
|
605
618
|
const newText = e.target.textContent || "";
|
|
606
619
|
saveLinkValue({
|
|
@@ -608,9 +621,9 @@ function createBlock(options) {
|
|
|
608
621
|
text: newText
|
|
609
622
|
});
|
|
610
623
|
};
|
|
611
|
-
let
|
|
612
|
-
if ($[
|
|
613
|
-
|
|
624
|
+
let t11;
|
|
625
|
+
if ($[19] !== blockId || $[20] !== name || $[21] !== repeaterContext) {
|
|
626
|
+
t11 = () => {
|
|
614
627
|
setIsEditing(true);
|
|
615
628
|
setIsEditorFocused(true);
|
|
616
629
|
if (repeaterContext?.itemId != null) previewStore.send({
|
|
@@ -627,32 +640,32 @@ function createBlock(options) {
|
|
|
627
640
|
fieldType: "Link"
|
|
628
641
|
});
|
|
629
642
|
};
|
|
630
|
-
$[
|
|
631
|
-
$[
|
|
632
|
-
$[
|
|
633
|
-
$[21] = t10;
|
|
634
|
-
} else t10 = $[21];
|
|
635
|
-
const handleFocus = t10;
|
|
636
|
-
let t11;
|
|
637
|
-
if ($[22] === Symbol.for("react.memo_cache_sentinel")) {
|
|
638
|
-
t11 = () => {
|
|
639
|
-
setIsEditing(false);
|
|
640
|
-
setIsEditorFocused(false);
|
|
641
|
-
};
|
|
643
|
+
$[19] = blockId;
|
|
644
|
+
$[20] = name;
|
|
645
|
+
$[21] = repeaterContext;
|
|
642
646
|
$[22] = t11;
|
|
643
647
|
} else t11 = $[22];
|
|
644
|
-
const
|
|
648
|
+
const handleFocus = t11;
|
|
645
649
|
let t12;
|
|
646
650
|
if ($[23] === Symbol.for("react.memo_cache_sentinel")) {
|
|
647
|
-
t12 = (
|
|
651
|
+
t12 = () => {
|
|
652
|
+
setIsEditing(false);
|
|
653
|
+
setIsEditorFocused(false);
|
|
654
|
+
};
|
|
655
|
+
$[23] = t12;
|
|
656
|
+
} else t12 = $[23];
|
|
657
|
+
const handleBlur = t12;
|
|
658
|
+
let t13;
|
|
659
|
+
if ($[24] === Symbol.for("react.memo_cache_sentinel")) {
|
|
660
|
+
t13 = (e_0) => {
|
|
648
661
|
e_0.stopPropagation();
|
|
649
662
|
previewStore.send({ type: "toggleContentSheet" });
|
|
650
663
|
setIsEditorFocused(false);
|
|
651
664
|
setIsEditing(false);
|
|
652
665
|
};
|
|
653
|
-
$[
|
|
654
|
-
} else
|
|
655
|
-
const handleEditLink =
|
|
666
|
+
$[24] = t13;
|
|
667
|
+
} else t13 = $[24];
|
|
668
|
+
const handleEditLink = t13;
|
|
656
669
|
const linkData = {
|
|
657
670
|
text: displayText,
|
|
658
671
|
href: resolvedHref,
|
|
@@ -664,16 +677,16 @@ function createBlock(options) {
|
|
|
664
677
|
rel: fieldValue.newTab ? "noreferrer" : void 0,
|
|
665
678
|
children: fieldValue.text
|
|
666
679
|
}, linkData) });
|
|
667
|
-
let t13;
|
|
668
680
|
let t14;
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
t14 = () => setIsHovered(
|
|
672
|
-
|
|
681
|
+
let t15;
|
|
682
|
+
if ($[25] === Symbol.for("react.memo_cache_sentinel")) {
|
|
683
|
+
t14 = () => setIsHovered(true);
|
|
684
|
+
t15 = () => setIsHovered(false);
|
|
673
685
|
$[25] = t14;
|
|
686
|
+
$[26] = t15;
|
|
674
687
|
} else {
|
|
675
|
-
t13 = $[24];
|
|
676
688
|
t14 = $[25];
|
|
689
|
+
t15 = $[26];
|
|
677
690
|
}
|
|
678
691
|
const linkProps = {
|
|
679
692
|
ref: elementRef,
|
|
@@ -686,56 +699,56 @@ function createBlock(options) {
|
|
|
686
699
|
"data-camox-focused": isFocused || void 0,
|
|
687
700
|
"data-camox-overlay-mode": mode === "layout" ? "layout" : void 0,
|
|
688
701
|
contentEditable: true,
|
|
689
|
-
onClick:
|
|
702
|
+
onClick: _temp3,
|
|
690
703
|
onInput: handleInput,
|
|
691
704
|
onFocus: handleFocus,
|
|
692
705
|
onBlur: handleBlur,
|
|
693
|
-
onMouseEnter:
|
|
694
|
-
onMouseLeave:
|
|
695
|
-
onKeyDown:
|
|
706
|
+
onMouseEnter: t14,
|
|
707
|
+
onMouseLeave: t15,
|
|
708
|
+
onKeyDown: _temp4,
|
|
696
709
|
spellCheck: false,
|
|
697
710
|
suppressContentEditableWarning: true
|
|
698
711
|
};
|
|
699
712
|
const T0 = Popover;
|
|
700
|
-
const
|
|
701
|
-
let
|
|
702
|
-
if ($[
|
|
703
|
-
|
|
713
|
+
const t16 = children(linkProps, linkData);
|
|
714
|
+
let t17;
|
|
715
|
+
if ($[27] !== handleEditLink) {
|
|
716
|
+
t17 = /* @__PURE__ */ jsx("button", {
|
|
704
717
|
type: "button",
|
|
705
718
|
className: "hover:bg-accent flex items-center gap-1.5 rounded-md px-2 py-1 text-sm transition-colors",
|
|
706
|
-
onMouseDown:
|
|
719
|
+
onMouseDown: _temp5,
|
|
707
720
|
onClick: handleEditLink,
|
|
708
721
|
children: "Edit link"
|
|
709
722
|
});
|
|
710
|
-
$[
|
|
711
|
-
$[
|
|
712
|
-
} else
|
|
713
|
-
let
|
|
714
|
-
if ($[
|
|
715
|
-
|
|
723
|
+
$[27] = handleEditLink;
|
|
724
|
+
$[28] = t17;
|
|
725
|
+
} else t17 = $[28];
|
|
726
|
+
let t18;
|
|
727
|
+
if ($[29] !== elementRef || $[30] !== t17) {
|
|
728
|
+
t18 = /* @__PURE__ */ jsx(PopoverContent, {
|
|
716
729
|
className: "w-auto p-2",
|
|
717
730
|
initialFocus: false,
|
|
718
731
|
anchor: elementRef,
|
|
719
732
|
align: "end",
|
|
720
|
-
children:
|
|
733
|
+
children: t17
|
|
721
734
|
});
|
|
722
|
-
$[
|
|
723
|
-
$[29] = t16;
|
|
735
|
+
$[29] = elementRef;
|
|
724
736
|
$[30] = t17;
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
737
|
+
$[31] = t18;
|
|
738
|
+
} else t18 = $[31];
|
|
739
|
+
let t19;
|
|
740
|
+
if ($[32] !== T0 || $[33] !== isEditorFocused || $[34] !== t16 || $[35] !== t18) {
|
|
741
|
+
t19 = /* @__PURE__ */ jsxs(T0, {
|
|
729
742
|
open: isEditorFocused,
|
|
730
|
-
children: [
|
|
743
|
+
children: [t16, t18]
|
|
731
744
|
});
|
|
732
|
-
$[
|
|
733
|
-
$[
|
|
734
|
-
$[
|
|
735
|
-
$[34] = t17;
|
|
745
|
+
$[32] = T0;
|
|
746
|
+
$[33] = isEditorFocused;
|
|
747
|
+
$[34] = t16;
|
|
736
748
|
$[35] = t18;
|
|
737
|
-
|
|
738
|
-
|
|
749
|
+
$[36] = t19;
|
|
750
|
+
} else t19 = $[36];
|
|
751
|
+
return t19;
|
|
739
752
|
};
|
|
740
753
|
const Image = (t0) => {
|
|
741
754
|
const $ = c(25);
|
|
@@ -1048,9 +1061,9 @@ function createBlock(options) {
|
|
|
1048
1061
|
const isContentEditable = useIsEditable(mode);
|
|
1049
1062
|
const { window: iframeWindow } = useFrame();
|
|
1050
1063
|
const [isHovered, setIsHovered] = React.useState(false);
|
|
1051
|
-
const selection = useSelector(previewStore,
|
|
1052
|
-
const isPageContentSheetOpen = useSelector(previewStore,
|
|
1053
|
-
const isAddBlockSheetOpen = useSelector(previewStore,
|
|
1064
|
+
const selection = useSelector(previewStore, _temp6);
|
|
1065
|
+
const isPageContentSheetOpen = useSelector(previewStore, _temp7);
|
|
1066
|
+
const isAddBlockSheetOpen = useSelector(previewStore, _temp8);
|
|
1054
1067
|
const isAnySideSheetOpen = useIsPreviewSheetOpen();
|
|
1055
1068
|
const isBlockSelected = selection?.blockId === blockData._id;
|
|
1056
1069
|
const ref = React.useRef(null);
|
|
@@ -1123,7 +1136,7 @@ function createBlock(options) {
|
|
|
1123
1136
|
result = { ...blockData.content };
|
|
1124
1137
|
for (const key in result) {
|
|
1125
1138
|
const value = result[key];
|
|
1126
|
-
if (Array.isArray(value) && value.length > 0 && value[0]?.content !== void 0) result[key] = value.map(
|
|
1139
|
+
if (Array.isArray(value) && value.length > 0 && value[0]?.content !== void 0) result[key] = value.map(_temp9);
|
|
1127
1140
|
}
|
|
1128
1141
|
$[15] = blockData.content;
|
|
1129
1142
|
$[16] = result;
|
|
@@ -1348,9 +1361,9 @@ function createBlock(options) {
|
|
|
1348
1361
|
const { blockId, mode, isHovered, setIsHovered } = ctx;
|
|
1349
1362
|
const isContentEditable = useIsEditable(mode);
|
|
1350
1363
|
const { window: iframeWindow } = useFrame();
|
|
1351
|
-
const selection = useSelector(previewStore,
|
|
1352
|
-
const isAddBlockSheetOpen = useSelector(previewStore,
|
|
1353
|
-
const isPageContentSheetOpen = useSelector(previewStore,
|
|
1364
|
+
const selection = useSelector(previewStore, _temp0);
|
|
1365
|
+
const isAddBlockSheetOpen = useSelector(previewStore, _temp1);
|
|
1366
|
+
const isPageContentSheetOpen = useSelector(previewStore, _temp10);
|
|
1354
1367
|
const isBlockSelected = selection?.blockId === blockId;
|
|
1355
1368
|
const t1 = String(blockId);
|
|
1356
1369
|
let t2;
|
|
@@ -1538,34 +1551,37 @@ function _temp() {
|
|
|
1538
1551
|
" to interact with the embed content"
|
|
1539
1552
|
] }));
|
|
1540
1553
|
}
|
|
1541
|
-
function _temp2(
|
|
1554
|
+
function _temp2(l) {
|
|
1555
|
+
return l.pathname;
|
|
1556
|
+
}
|
|
1557
|
+
function _temp3(e_1) {
|
|
1542
1558
|
return e_1.preventDefault();
|
|
1543
1559
|
}
|
|
1544
|
-
function
|
|
1560
|
+
function _temp4(e_2) {
|
|
1545
1561
|
if (e_2.key === "Escape") e_2.target.blur();
|
|
1546
1562
|
}
|
|
1547
|
-
function
|
|
1563
|
+
function _temp5(e_3) {
|
|
1548
1564
|
return e_3.preventDefault();
|
|
1549
1565
|
}
|
|
1550
|
-
function
|
|
1566
|
+
function _temp6(state) {
|
|
1551
1567
|
return state.context.selection;
|
|
1552
1568
|
}
|
|
1553
|
-
function
|
|
1569
|
+
function _temp7(state_0) {
|
|
1554
1570
|
return state_0.context.isPageContentSheetOpen;
|
|
1555
1571
|
}
|
|
1556
|
-
function
|
|
1572
|
+
function _temp8(state_1) {
|
|
1557
1573
|
return state_1.context.isAddBlockSheetOpen;
|
|
1558
1574
|
}
|
|
1559
|
-
function
|
|
1575
|
+
function _temp9(item) {
|
|
1560
1576
|
return item.content;
|
|
1561
1577
|
}
|
|
1562
|
-
function
|
|
1578
|
+
function _temp0(state) {
|
|
1563
1579
|
return state.context.selection;
|
|
1564
1580
|
}
|
|
1565
|
-
function
|
|
1581
|
+
function _temp1(state_0) {
|
|
1566
1582
|
return state_0.context.isAddBlockSheetOpen;
|
|
1567
1583
|
}
|
|
1568
|
-
function
|
|
1584
|
+
function _temp10(state_1) {
|
|
1569
1585
|
return state_1.context.isPageContentSheetOpen;
|
|
1570
1586
|
}
|
|
1571
1587
|
|
|
@@ -2,8 +2,13 @@ import * as _$_sinclair_typebox0 from "@sinclair/typebox";
|
|
|
2
2
|
import { TArray, TObject, TSchema, TUnsafe } from "@sinclair/typebox";
|
|
3
3
|
|
|
4
4
|
//#region src/core/lib/contentType.d.ts
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
declare class FieldToken {
|
|
6
|
+
readonly fieldName: string;
|
|
7
|
+
constructor(fieldName: string);
|
|
8
|
+
toString(): string;
|
|
9
|
+
}
|
|
10
|
+
type ContentProxy<TShape extends Record<string, TSchema>> = { [K in keyof TShape & string]: FieldToken };
|
|
11
|
+
type ToMarkdownBuilder<TShape extends Record<string, TSchema>> = (c: ContentProxy<TShape>) => ReadonlyArray<string | FieldToken>;
|
|
7
12
|
declare const EmbedURLBrand: unique symbol;
|
|
8
13
|
type EmbedURL = string & {
|
|
9
14
|
readonly [EmbedURLBrand]: true;
|
|
@@ -96,15 +101,12 @@ declare const Type$1: {
|
|
|
96
101
|
* title: 'Items'
|
|
97
102
|
* })
|
|
98
103
|
*/
|
|
99
|
-
RepeatableItem: <T extends Record<string, TSchema
|
|
104
|
+
RepeatableItem: <T extends Record<string, TSchema>>(shape: T, options: {
|
|
100
105
|
minItems: number;
|
|
101
106
|
maxItems: number;
|
|
102
107
|
title?: string;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
} : {
|
|
106
|
-
toMarkdown?: readonly [`Invalid toMarkdown placeholder: "{{${Exclude<ExtractAllPlaceholders<TMarkdown>, Extract<keyof T, string>>}}}"`];
|
|
107
|
-
})) => TArray<TObject<T>>;
|
|
108
|
+
toMarkdown: ToMarkdownBuilder<T>;
|
|
109
|
+
}) => TArray<TObject<T>>;
|
|
108
110
|
/**
|
|
109
111
|
* Creates an enum field with a set of predefined options.
|
|
110
112
|
*
|
|
@@ -164,4 +166,4 @@ declare const Type$1: {
|
|
|
164
166
|
File: typeof _fileType;
|
|
165
167
|
};
|
|
166
168
|
//#endregion
|
|
167
|
-
export { EmbedURL,
|
|
169
|
+
export { EmbedURL, FileValue, ImageValue, LinkValue, ToMarkdownBuilder, Type$1 as Type };
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
|
|
3
3
|
//#region src/core/lib/contentType.ts
|
|
4
|
+
var FieldToken = class {
|
|
5
|
+
constructor(fieldName) {
|
|
6
|
+
this.fieldName = fieldName;
|
|
7
|
+
}
|
|
8
|
+
toString() {
|
|
9
|
+
return `{{${this.fieldName}}}`;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
function createContentProxy() {
|
|
13
|
+
return new Proxy({}, { get(_target, prop) {
|
|
14
|
+
if (typeof prop !== "string") return void 0;
|
|
15
|
+
return new FieldToken(prop);
|
|
16
|
+
} });
|
|
17
|
+
}
|
|
18
|
+
function resolveToMarkdown(builder) {
|
|
19
|
+
return builder(createContentProxy()).map((entry) => entry instanceof FieldToken ? entry.toString() : String(entry));
|
|
20
|
+
}
|
|
4
21
|
function _imageType(options) {
|
|
5
22
|
const imageDefault = {
|
|
6
23
|
url: `https://placehold.co/1200x800/f4f4f5/a1a1aa.png?text=${options?.title || "image"}`,
|
|
@@ -91,7 +108,7 @@ const Type$1 = {
|
|
|
91
108
|
default: defaultArray,
|
|
92
109
|
title: options.title,
|
|
93
110
|
fieldType: "RepeatableItem",
|
|
94
|
-
|
|
111
|
+
toMarkdown: resolveToMarkdown(options.toMarkdown)
|
|
95
112
|
});
|
|
96
113
|
},
|
|
97
114
|
Enum: (options) => {
|
|
@@ -148,4 +165,4 @@ const Type$1 = {
|
|
|
148
165
|
};
|
|
149
166
|
|
|
150
167
|
//#endregion
|
|
151
|
-
export { Type$1 as Type };
|
|
168
|
+
export { Type$1 as Type, resolveToMarkdown };
|
|
@@ -203,7 +203,7 @@ const CamoxContent = () => {
|
|
|
203
203
|
let t18;
|
|
204
204
|
if ($[39] !== deleteFiles || $[40] !== selectedIds) {
|
|
205
205
|
t18 = selectedIds.size > 0 && /* @__PURE__ */ jsxs(FloatingToolbar, {
|
|
206
|
-
className: "bottom-4 min-w-xs justify-between gap-4",
|
|
206
|
+
className: "bottom-4 min-w-xs justify-between gap-4 pl-3",
|
|
207
207
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
208
208
|
className: "text-muted-foreground",
|
|
209
209
|
children: [
|
|
@@ -19,6 +19,7 @@ import { PeekedBlock } from "./components/PeekedBlock.js";
|
|
|
19
19
|
import { PreviewFrame, PreviewPanel } from "./components/PreviewPanel.js";
|
|
20
20
|
import { c } from "react/compiler-runtime";
|
|
21
21
|
import { keepPreviousData, useQuery, useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
|
|
22
|
+
import { useLocation, useNavigate } from "@tanstack/react-router";
|
|
22
23
|
import { useSelector } from "@xstate/store/react";
|
|
23
24
|
import * as React from "react";
|
|
24
25
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -26,7 +27,6 @@ import { queryKeys } from "@camox/api-contract/query-keys";
|
|
|
26
27
|
import { Button } from "@camox/ui/button";
|
|
27
28
|
import { PanelContent, PanelHeader } from "@camox/ui/panel";
|
|
28
29
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@camox/ui/tooltip";
|
|
29
|
-
import { useLocation, useNavigate } from "@tanstack/react-router";
|
|
30
30
|
import { Info } from "lucide-react";
|
|
31
31
|
|
|
32
32
|
//#region src/features/preview/CamoxPreview.tsx
|
|
@@ -8,13 +8,13 @@ import { trackClientEvent } from "../../../lib/analytics-client.js";
|
|
|
8
8
|
import { usePreviewedPage } from "../CamoxPreview.js";
|
|
9
9
|
import { c } from "react/compiler-runtime";
|
|
10
10
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
|
11
|
+
import { useLocation } from "@tanstack/react-router";
|
|
11
12
|
import { useSelector } from "@xstate/store/react";
|
|
12
13
|
import { generateKeyBetween } from "fractional-indexing";
|
|
13
14
|
import * as React from "react";
|
|
14
15
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
16
|
import { queryKeys } from "@camox/api-contract/query-keys";
|
|
16
17
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@camox/ui/tooltip";
|
|
17
|
-
import { useLocation } from "@tanstack/react-router";
|
|
18
18
|
import { InfoIcon } from "lucide-react";
|
|
19
19
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@camox/ui/command";
|
|
20
20
|
|