camox 0.12.1 → 0.14.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/InlineLexicalEditor.js +24 -1
- package/dist/core/components/lexical/SidebarLexicalEditor.js +25 -1
- package/dist/core/createApp.d.ts +4 -0
- package/dist/core/createBlock.d.ts +32 -5
- package/dist/core/createBlock.js +129 -74
- package/dist/core/lib/contentType.d.ts +46 -10
- package/dist/core/lib/contentType.js +56 -3
- package/dist/core/lib/lexicalReact.js +8 -2
- package/dist/core/lib/lexicalState.js +13 -1
- package/dist/features/preview/components/AddBlockSheet.js +8 -5
- package/dist/features/preview/components/{TextFormatToolbar.js → FieldToolbar.js} +73 -44
- package/dist/features/preview/components/PageContentSheet.js +135 -48
- package/dist/features/preview/components/PreviewPanel.js +3 -3
- package/dist/features/preview/components/RepeatableItemsList.js +4 -0
- package/dist/features/studio/components/EnvironmentMenu.js +18 -26
- package/dist/features/studio/components/Navbar.js +1 -1
- package/dist/features/vite/routeGeneration.js +8 -8
- package/dist/features/vite/vite.js +2 -8
- package/dist/lib/queries.js +1 -0
- package/dist/studio-overlays.css +39 -17
- package/dist/studio.css +1 -1
- package/package.json +5 -5
- package/skills/camox-block/SKILL.md +41 -11
|
@@ -10,7 +10,7 @@ import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
|
10
10
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
11
11
|
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
|
|
12
12
|
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
13
|
-
import { COMMAND_PRIORITY_LOW, KEY_ESCAPE_COMMAND } from "lexical";
|
|
13
|
+
import { COMMAND_PRIORITY_LOW, INSERT_LINE_BREAK_COMMAND, KEY_ENTER_COMMAND, KEY_ESCAPE_COMMAND } from "lexical";
|
|
14
14
|
|
|
15
15
|
//#region src/core/components/lexical/InlineLexicalEditor.tsx
|
|
16
16
|
function ExternalStateSync(t0) {
|
|
@@ -89,6 +89,28 @@ function EscapeHandler() {
|
|
|
89
89
|
React.useEffect(t0, t1);
|
|
90
90
|
return null;
|
|
91
91
|
}
|
|
92
|
+
function EnterAsLineBreakHandler() {
|
|
93
|
+
const $ = c(3);
|
|
94
|
+
const [editor] = useLexicalComposerContext();
|
|
95
|
+
let t0;
|
|
96
|
+
let t1;
|
|
97
|
+
if ($[0] !== editor) {
|
|
98
|
+
t0 = () => editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
|
|
99
|
+
event?.preventDefault();
|
|
100
|
+
editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND, false);
|
|
101
|
+
return true;
|
|
102
|
+
}, COMMAND_PRIORITY_LOW);
|
|
103
|
+
t1 = [editor];
|
|
104
|
+
$[0] = editor;
|
|
105
|
+
$[1] = t0;
|
|
106
|
+
$[2] = t1;
|
|
107
|
+
} else {
|
|
108
|
+
t0 = $[1];
|
|
109
|
+
t1 = $[2];
|
|
110
|
+
}
|
|
111
|
+
React.useEffect(t0, t1);
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
92
114
|
function FocusBlurHandler(t0) {
|
|
93
115
|
const $ = c(5);
|
|
94
116
|
const { onFocus, onBlur } = t0;
|
|
@@ -157,6 +179,7 @@ function InlineLexicalEditor({ initialState, externalState, onChange, onFocus, o
|
|
|
157
179
|
/* @__PURE__ */ jsx(OnChangePlugin, { onChange: handleChange }),
|
|
158
180
|
/* @__PURE__ */ jsx(ExternalStateSync, { externalState }),
|
|
159
181
|
/* @__PURE__ */ jsx(EscapeHandler, {}),
|
|
182
|
+
/* @__PURE__ */ jsx(EnterAsLineBreakHandler, {}),
|
|
160
183
|
/* @__PURE__ */ jsx(FocusBlurHandler, {
|
|
161
184
|
onFocus: handleFocus,
|
|
162
185
|
onBlur: handleBlur
|
|
@@ -8,9 +8,32 @@ import { LexicalComposer } from "@lexical/react/LexicalComposer";
|
|
|
8
8
|
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
|
|
9
9
|
import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
|
|
10
10
|
import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
|
|
11
|
+
import { COMMAND_PRIORITY_LOW, INSERT_LINE_BREAK_COMMAND, KEY_ENTER_COMMAND } from "lexical";
|
|
11
12
|
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
|
|
12
13
|
|
|
13
14
|
//#region src/core/components/lexical/SidebarLexicalEditor.tsx
|
|
15
|
+
function EnterAsLineBreakHandler() {
|
|
16
|
+
const $ = c(3);
|
|
17
|
+
const [editor] = useLexicalComposerContext();
|
|
18
|
+
let t0;
|
|
19
|
+
let t1;
|
|
20
|
+
if ($[0] !== editor) {
|
|
21
|
+
t0 = () => editor.registerCommand(KEY_ENTER_COMMAND, (event) => {
|
|
22
|
+
event?.preventDefault();
|
|
23
|
+
editor.dispatchCommand(INSERT_LINE_BREAK_COMMAND, false);
|
|
24
|
+
return true;
|
|
25
|
+
}, COMMAND_PRIORITY_LOW);
|
|
26
|
+
t1 = [editor];
|
|
27
|
+
$[0] = editor;
|
|
28
|
+
$[1] = t0;
|
|
29
|
+
$[2] = t1;
|
|
30
|
+
} else {
|
|
31
|
+
t0 = $[1];
|
|
32
|
+
t1 = $[2];
|
|
33
|
+
}
|
|
34
|
+
React.useEffect(t0, t1);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
14
37
|
function ExternalStateSync(t0) {
|
|
15
38
|
const $ = c(5);
|
|
16
39
|
const { value, isSyncingRef } = t0;
|
|
@@ -82,7 +105,8 @@ function SidebarLexicalEditor({ id, value, onChange, onFocus, onBlur }) {
|
|
|
82
105
|
/* @__PURE__ */ jsx(ExternalStateSync, {
|
|
83
106
|
value,
|
|
84
107
|
isSyncingRef
|
|
85
|
-
})
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ jsx(EnterAsLineBreakHandler, {})
|
|
86
110
|
]
|
|
87
111
|
});
|
|
88
112
|
}
|
package/dist/core/createApp.d.ts
CHANGED
|
@@ -271,8 +271,10 @@ declare function createApp({
|
|
|
271
271
|
name: string;
|
|
272
272
|
children: (item: any, index: number) => React.ReactNode;
|
|
273
273
|
}) => React.ReactNode;
|
|
274
|
+
useSetting: (name: string) => unknown;
|
|
274
275
|
}, index: number) => React.ReactNode;
|
|
275
276
|
}) => React.ReactNode;
|
|
277
|
+
useSetting: <F extends string>(name: F) => never;
|
|
276
278
|
}, index: number) => React.ReactNode;
|
|
277
279
|
}) => _$react_jsx_runtime0.JSX.Element;
|
|
278
280
|
useSetting: <K extends string>(name: K) => unknown;
|
|
@@ -593,8 +595,10 @@ declare function createApp({
|
|
|
593
595
|
name: string;
|
|
594
596
|
children: (item: any, index: number) => React.ReactNode;
|
|
595
597
|
}) => React.ReactNode;
|
|
598
|
+
useSetting: (name: string) => unknown;
|
|
596
599
|
}, index: number) => React.ReactNode;
|
|
597
600
|
}) => React.ReactNode;
|
|
601
|
+
useSetting: <F extends string>(name: F) => never;
|
|
598
602
|
}, index: number) => React.ReactNode;
|
|
599
603
|
}) => _$react_jsx_runtime0.JSX.Element;
|
|
600
604
|
useSetting: <K extends string>(name: K) => unknown;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { EmbedURL, FileValue, ImageValue, LinkValue, ToMarkdownBuilder, Type } from "./lib/contentType.js";
|
|
1
|
+
import { EmbedURL, FileValue, ImageValue, ItemSettingsBrand, 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";
|
|
@@ -61,13 +61,16 @@ interface CreateBlockOptions<TSchemaShape extends Record<string, TSchema> = Reco
|
|
|
61
61
|
/**
|
|
62
62
|
* Builder for rendering block content as markdown.
|
|
63
63
|
* `c` is a proxy typed on `content` keys — `c.title`, `c.description`, etc.
|
|
64
|
-
*
|
|
65
|
-
*
|
|
64
|
+
* `s` is a proxy typed on `settings` keys — call a boolean setting with a line
|
|
65
|
+
* (`s.showCta(c.cta)`) or an enum with a value (`s.variant("banner", [...])`)
|
|
66
|
+
* to wrap lines in a conditional. Each returned entry becomes a paragraph
|
|
67
|
+
* (joined with `\n\n`). Lines where all referenced fields resolve to empty
|
|
68
|
+
* (or whose condition is false) are omitted at render time.
|
|
66
69
|
*
|
|
67
70
|
* @example
|
|
68
|
-
* toMarkdown: (c) => [`# ${c.title}`, c.description,
|
|
71
|
+
* toMarkdown: (c, s) => [`# ${c.title}`, c.description, s.showCta(c.cta)]
|
|
69
72
|
*/
|
|
70
|
-
toMarkdown: ToMarkdownBuilder<TSchemaShape>;
|
|
73
|
+
toMarkdown: ToMarkdownBuilder<TSchemaShape, TSettingsShape>;
|
|
71
74
|
}
|
|
72
75
|
interface BlockData<TContent> {
|
|
73
76
|
_id: number;
|
|
@@ -90,6 +93,7 @@ interface PeekItem {
|
|
|
90
93
|
parentItemId: number | null;
|
|
91
94
|
fieldName: string;
|
|
92
95
|
content: unknown;
|
|
96
|
+
settings: Record<string, unknown> | null;
|
|
93
97
|
summary: string;
|
|
94
98
|
position: string;
|
|
95
99
|
createdAt: number;
|
|
@@ -100,6 +104,7 @@ interface RepeatableItemSeed {
|
|
|
100
104
|
parentTempId: string | null;
|
|
101
105
|
fieldName: string;
|
|
102
106
|
content: Record<string, unknown>;
|
|
107
|
+
settings?: Record<string, unknown>;
|
|
103
108
|
position: string;
|
|
104
109
|
}
|
|
105
110
|
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>): {
|
|
@@ -1055,8 +1060,30 @@ declare function createBlock<TSchemaShape extends Record<string, TSchema>, TSett
|
|
|
1055
1060
|
name: string;
|
|
1056
1061
|
children: (item: any, index: number) => React.ReactNode;
|
|
1057
1062
|
}) => React.ReactNode;
|
|
1063
|
+
useSetting: (name: string) => unknown;
|
|
1058
1064
|
}, index: number) => React.ReactNode;
|
|
1059
1065
|
}) => React.ReactNode;
|
|
1066
|
+
useSetting: <F extends keyof (TSchemaShape[K] extends {
|
|
1067
|
+
readonly [ItemSettingsBrand]?: infer S;
|
|
1068
|
+
} ? S extends Record<string, TSchema> ? _$_sinclair_typebox0.Evaluate<Readonly<Partial<Pick<{ [K_6 in keyof S]: (S[K_6] & {
|
|
1069
|
+
params: unknown[] & [];
|
|
1070
|
+
})["static"] }, { [K_7 in keyof S]: S[K_7] extends _$_sinclair_typebox0.TReadonly<TSchema> ? S[K_7] extends _$_sinclair_typebox0.TOptional<S[K_7]> ? K_7 : never : never }[keyof S]>>> & Readonly<Pick<{ [K_6 in keyof S]: (S[K_6] & {
|
|
1071
|
+
params: unknown[] & [];
|
|
1072
|
+
})["static"] }, { [K_8 in keyof S]: S[K_8] extends _$_sinclair_typebox0.TReadonly<TSchema> ? S[K_8] extends _$_sinclair_typebox0.TOptional<S[K_8]> ? never : K_8 : never }[keyof S]>> & Partial<Pick<{ [K_6 in keyof S]: (S[K_6] & {
|
|
1073
|
+
params: unknown[] & [];
|
|
1074
|
+
})["static"] }, { [K_9 in keyof S]: S[K_9] extends _$_sinclair_typebox0.TOptional<TSchema> ? S[K_9] extends _$_sinclair_typebox0.TReadonly<S[K_9]> ? never : K_9 : never }[keyof S]>> & Required<Pick<{ [K_6 in keyof S]: (S[K_6] & {
|
|
1075
|
+
params: unknown[] & [];
|
|
1076
|
+
})["static"] }, Exclude<keyof S, { [K_7 in keyof S]: S[K_7] extends _$_sinclair_typebox0.TReadonly<TSchema> ? S[K_7] extends _$_sinclair_typebox0.TOptional<S[K_7]> ? K_7 : never : never }[keyof S] | { [K_8 in keyof S]: S[K_8] extends _$_sinclair_typebox0.TReadonly<TSchema> ? S[K_8] extends _$_sinclair_typebox0.TOptional<S[K_8]> ? never : K_8 : never }[keyof S] | { [K_9 in keyof S]: S[K_9] extends _$_sinclair_typebox0.TOptional<TSchema> ? S[K_9] extends _$_sinclair_typebox0.TReadonly<S[K_9]> ? never : K_9 : never }[keyof S]>>>> : Record<string, never> : Record<string, never>)>(name: F) => (TSchemaShape[K] extends {
|
|
1077
|
+
readonly [ItemSettingsBrand]?: infer S;
|
|
1078
|
+
} ? S extends Record<string, TSchema> ? _$_sinclair_typebox0.Evaluate<Readonly<Partial<Pick<{ [K_6 in keyof S]: (S[K_6] & {
|
|
1079
|
+
params: unknown[] & [];
|
|
1080
|
+
})["static"] }, { [K_7 in keyof S]: S[K_7] extends _$_sinclair_typebox0.TReadonly<TSchema> ? S[K_7] extends _$_sinclair_typebox0.TOptional<S[K_7]> ? K_7 : never : never }[keyof S]>>> & Readonly<Pick<{ [K_6 in keyof S]: (S[K_6] & {
|
|
1081
|
+
params: unknown[] & [];
|
|
1082
|
+
})["static"] }, { [K_8 in keyof S]: S[K_8] extends _$_sinclair_typebox0.TReadonly<TSchema> ? S[K_8] extends _$_sinclair_typebox0.TOptional<S[K_8]> ? never : K_8 : never }[keyof S]>> & Partial<Pick<{ [K_6 in keyof S]: (S[K_6] & {
|
|
1083
|
+
params: unknown[] & [];
|
|
1084
|
+
})["static"] }, { [K_9 in keyof S]: S[K_9] extends _$_sinclair_typebox0.TOptional<TSchema> ? S[K_9] extends _$_sinclair_typebox0.TReadonly<S[K_9]> ? never : K_9 : never }[keyof S]>> & Required<Pick<{ [K_6 in keyof S]: (S[K_6] & {
|
|
1085
|
+
params: unknown[] & [];
|
|
1086
|
+
})["static"] }, Exclude<keyof S, { [K_7 in keyof S]: S[K_7] extends _$_sinclair_typebox0.TReadonly<TSchema> ? S[K_7] extends _$_sinclair_typebox0.TOptional<S[K_7]> ? K_7 : never : never }[keyof S] | { [K_8 in keyof S]: S[K_8] extends _$_sinclair_typebox0.TReadonly<TSchema> ? S[K_8] extends _$_sinclair_typebox0.TOptional<S[K_8]> ? never : K_8 : never }[keyof S] | { [K_9 in keyof S]: S[K_9] extends _$_sinclair_typebox0.TOptional<TSchema> ? S[K_9] extends _$_sinclair_typebox0.TReadonly<S[K_9]> ? never : K_9 : never }[keyof S]>>>> : Record<string, never> : Record<string, never>)[F];
|
|
1060
1087
|
}, index: number) => React.ReactNode;
|
|
1061
1088
|
}) => _$react_jsx_runtime0.JSX.Element;
|
|
1062
1089
|
useSetting: <K extends keyof (TSettingsShape extends Record<string, never> ? Record<string, never> : _$_sinclair_typebox0.Evaluate<Readonly<Partial<Pick<{ [K_1 in keyof TSettingsShape]: (TSettingsShape[K_1] & {
|
package/dist/core/createBlock.js
CHANGED
|
@@ -67,6 +67,7 @@ function buildInitialSeeds(properties, parentTempId, content, allSeeds, counter)
|
|
|
67
67
|
if (propSchema.type === "array" && propSchema.items?.properties) continue;
|
|
68
68
|
if ("default" in propSchema) itemContent[propName] = propSchema.default;
|
|
69
69
|
}
|
|
70
|
+
const itemSettingsDefaults = fieldSchema.defaultItemSettings;
|
|
70
71
|
const markers = [];
|
|
71
72
|
let prevPosition = null;
|
|
72
73
|
for (let i = 0; i < defaultCount; i++) {
|
|
@@ -78,6 +79,7 @@ function buildInitialSeeds(properties, parentTempId, content, allSeeds, counter)
|
|
|
78
79
|
parentTempId,
|
|
79
80
|
fieldName,
|
|
80
81
|
content: { ...itemContent },
|
|
82
|
+
settings: itemSettingsDefaults ? { ...itemSettingsDefaults } : void 0,
|
|
81
83
|
position
|
|
82
84
|
});
|
|
83
85
|
markers.push({ _itemId: tempId });
|
|
@@ -102,6 +104,7 @@ function buildPeekItems(properties, blockId, parentItemId, content, allItems, co
|
|
|
102
104
|
if (propSchema.type === "array" && propSchema.items?.properties) continue;
|
|
103
105
|
if ("default" in propSchema) itemContent[propName] = propSchema.default;
|
|
104
106
|
}
|
|
107
|
+
const itemSettingsDefaults = fieldSchema.defaultItemSettings;
|
|
105
108
|
const markers = [];
|
|
106
109
|
let prevPosition = null;
|
|
107
110
|
for (let i = 0; i < defaultCount; i++) {
|
|
@@ -114,6 +117,7 @@ function buildPeekItems(properties, blockId, parentItemId, content, allItems, co
|
|
|
114
117
|
parentItemId,
|
|
115
118
|
fieldName,
|
|
116
119
|
content: { ...itemContent },
|
|
120
|
+
settings: itemSettingsDefaults ? { ...itemSettingsDefaults } : null,
|
|
117
121
|
summary: "",
|
|
118
122
|
position,
|
|
119
123
|
createdAt: 0,
|
|
@@ -139,7 +143,7 @@ function createBlock(options) {
|
|
|
139
143
|
description: options.description,
|
|
140
144
|
properties: typeboxSchema.properties,
|
|
141
145
|
required: Object.keys(options.content),
|
|
142
|
-
toMarkdown: resolveToMarkdown(options.toMarkdown)
|
|
146
|
+
toMarkdown: resolveToMarkdown(options.toMarkdown, options.settings, "block")
|
|
143
147
|
};
|
|
144
148
|
const settingsTypeboxSchema = options.settings ? Type$1.Object(options.settings) : null;
|
|
145
149
|
const settingsSchema = settingsTypeboxSchema ? {
|
|
@@ -157,12 +161,14 @@ function createBlock(options) {
|
|
|
157
161
|
contentDefaultsForStorage[key] = prop.default;
|
|
158
162
|
}
|
|
159
163
|
const repeatableItemDefaults = {};
|
|
164
|
+
const repeatableItemSettingsDefaults = {};
|
|
160
165
|
for (const [key, prop] of Object.entries(typeboxSchema.properties)) {
|
|
161
166
|
const p = prop;
|
|
162
167
|
if (p.type === "array" && p.items?.properties) {
|
|
163
168
|
const itemDefaults = {};
|
|
164
169
|
for (const [itemKey, itemProp] of Object.entries(p.items.properties)) if (itemProp && typeof itemProp === "object" && "default" in itemProp) itemDefaults[itemKey] = itemProp.default;
|
|
165
170
|
if (Object.keys(itemDefaults).length > 0) repeatableItemDefaults[key] = itemDefaults;
|
|
171
|
+
if (p.defaultItemSettings && typeof p.defaultItemSettings === "object") repeatableItemSettingsDefaults[key] = p.defaultItemSettings;
|
|
166
172
|
}
|
|
167
173
|
}
|
|
168
174
|
const settingsDefaults = {};
|
|
@@ -968,92 +974,141 @@ function createBlock(options) {
|
|
|
968
974
|
return t3;
|
|
969
975
|
};
|
|
970
976
|
const Repeater = (t0) => {
|
|
971
|
-
const $ = c(
|
|
977
|
+
const $ = c(28);
|
|
972
978
|
const { name, children } = t0;
|
|
973
979
|
const blockContext = React.use(Context);
|
|
974
980
|
if (!blockContext) throw new Error("Repeater must be used within a Block Component");
|
|
975
981
|
const { blockId, content, mode } = blockContext;
|
|
976
982
|
const parentRepeaterContext = React.use(RepeaterItemContext);
|
|
977
983
|
const fieldName = String(name);
|
|
978
|
-
const
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
Repeater
|
|
985
|
-
};
|
|
984
|
+
const ItemField = Field;
|
|
985
|
+
const ItemLink = Link;
|
|
986
|
+
const ItemEmbed = Embed;
|
|
987
|
+
const ItemImage = Image;
|
|
988
|
+
const ItemFile = File;
|
|
989
|
+
const ItemRepeater = Repeater;
|
|
986
990
|
const source = parentRepeaterContext ? parentRepeaterContext.itemContent[name] : content[name];
|
|
987
991
|
const { itemsMap } = useNormalizedData();
|
|
988
|
-
let
|
|
989
|
-
if (!Array.isArray(arrayValue)) throw new Error(`Field "${String(name)}" is not an array`);
|
|
992
|
+
let T0;
|
|
990
993
|
let t1;
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
};
|
|
996
|
-
|
|
997
|
-
$[
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
$[
|
|
1015
|
-
|
|
1016
|
-
|
|
994
|
+
let t2;
|
|
995
|
+
let t3;
|
|
996
|
+
if ($[0] !== blockId || $[1] !== children || $[2] !== fieldName || $[3] !== itemsMap || $[4] !== mode || $[5] !== name || $[6] !== parentRepeaterContext || $[7] !== source) {
|
|
997
|
+
let arrayValue = source ?? [];
|
|
998
|
+
if (!Array.isArray(arrayValue)) throw new Error(`Field "${String(name)}" is not an array`);
|
|
999
|
+
let t4;
|
|
1000
|
+
if ($[12] !== itemsMap) {
|
|
1001
|
+
t4 = (item) => {
|
|
1002
|
+
if (isItemMarker(item)) return itemsMap.get(item._itemId) ?? null;
|
|
1003
|
+
return item;
|
|
1004
|
+
};
|
|
1005
|
+
$[12] = itemsMap;
|
|
1006
|
+
$[13] = t4;
|
|
1007
|
+
} else t4 = $[13];
|
|
1008
|
+
arrayValue = arrayValue.map(t4).filter(Boolean);
|
|
1009
|
+
if (arrayValue.length === 0) {
|
|
1010
|
+
const fieldSchema = parentRepeaterContext ? typeboxSchema.properties[parentRepeaterContext.arrayFieldName]?.items?.properties?.[fieldName] : typeboxSchema.properties[fieldName];
|
|
1011
|
+
const ait = fieldSchema?.arrayItemType;
|
|
1012
|
+
if (ait === "Image" || ait === "File") {
|
|
1013
|
+
const defaultCount = fieldSchema.defaultItems ?? 0;
|
|
1014
|
+
const itemProps = fieldSchema.items?.properties;
|
|
1015
|
+
if (defaultCount > 0 && itemProps) {
|
|
1016
|
+
let t5;
|
|
1017
|
+
if ($[14] !== defaultCount || $[15] !== itemProps) {
|
|
1018
|
+
const itemContent = {};
|
|
1019
|
+
for (const [propName, propSchema] of Object.entries(itemProps)) if (propSchema && typeof propSchema === "object" && "default" in propSchema) itemContent[propName] = propSchema.default;
|
|
1020
|
+
t5 = Array.from({ length: defaultCount }, () => ({ ...itemContent }));
|
|
1021
|
+
$[14] = defaultCount;
|
|
1022
|
+
$[15] = itemProps;
|
|
1023
|
+
$[16] = t5;
|
|
1024
|
+
} else t5 = $[16];
|
|
1025
|
+
arrayValue = t5;
|
|
1026
|
+
}
|
|
1017
1027
|
}
|
|
1018
1028
|
}
|
|
1029
|
+
const settingsDefaultsForField = repeatableItemSettingsDefaults[fieldName];
|
|
1030
|
+
T0 = RepeaterHoverProvider;
|
|
1031
|
+
t1 = blockId;
|
|
1032
|
+
t2 = fieldName;
|
|
1033
|
+
let t5;
|
|
1034
|
+
if ($[17] !== blockId || $[18] !== children || $[19] !== fieldName || $[20] !== mode || $[21] !== settingsDefaultsForField) {
|
|
1035
|
+
t5 = (item_0, index) => {
|
|
1036
|
+
const isDbItem = item_0.content !== void 0 && item_0.id != null;
|
|
1037
|
+
const itemContent_0 = {
|
|
1038
|
+
...repeatableItemDefaults[fieldName],
|
|
1039
|
+
...isDbItem ? item_0.content : item_0
|
|
1040
|
+
};
|
|
1041
|
+
const itemSettings = {
|
|
1042
|
+
...settingsDefaultsForField,
|
|
1043
|
+
...(isDbItem ? item_0.settings : null) ?? {}
|
|
1044
|
+
};
|
|
1045
|
+
const itemId = isDbItem ? item_0.id : void 0;
|
|
1046
|
+
const useItemSetting = (settingName) => itemSettings[settingName];
|
|
1047
|
+
const itemApi = {
|
|
1048
|
+
Field: ItemField,
|
|
1049
|
+
Link: ItemLink,
|
|
1050
|
+
Embed: ItemEmbed,
|
|
1051
|
+
Image: ItemImage,
|
|
1052
|
+
File: ItemFile,
|
|
1053
|
+
Repeater: ItemRepeater,
|
|
1054
|
+
useSetting: useItemSetting
|
|
1055
|
+
};
|
|
1056
|
+
return /* @__PURE__ */ jsx(RepeaterItemContext.Provider, {
|
|
1057
|
+
value: {
|
|
1058
|
+
arrayFieldName: fieldName,
|
|
1059
|
+
itemIndex: index,
|
|
1060
|
+
itemContent: itemContent_0,
|
|
1061
|
+
itemSettings,
|
|
1062
|
+
itemId
|
|
1063
|
+
},
|
|
1064
|
+
children: /* @__PURE__ */ jsx(RepeaterItemWrapper, {
|
|
1065
|
+
itemId,
|
|
1066
|
+
blockId,
|
|
1067
|
+
mode,
|
|
1068
|
+
children: children(itemApi, index)
|
|
1069
|
+
})
|
|
1070
|
+
}, itemId ?? index);
|
|
1071
|
+
};
|
|
1072
|
+
$[17] = blockId;
|
|
1073
|
+
$[18] = children;
|
|
1074
|
+
$[19] = fieldName;
|
|
1075
|
+
$[20] = mode;
|
|
1076
|
+
$[21] = settingsDefaultsForField;
|
|
1077
|
+
$[22] = t5;
|
|
1078
|
+
} else t5 = $[22];
|
|
1079
|
+
t3 = arrayValue.map(t5);
|
|
1080
|
+
$[0] = blockId;
|
|
1081
|
+
$[1] = children;
|
|
1082
|
+
$[2] = fieldName;
|
|
1083
|
+
$[3] = itemsMap;
|
|
1084
|
+
$[4] = mode;
|
|
1085
|
+
$[5] = name;
|
|
1086
|
+
$[6] = parentRepeaterContext;
|
|
1087
|
+
$[7] = source;
|
|
1088
|
+
$[8] = T0;
|
|
1089
|
+
$[9] = t1;
|
|
1090
|
+
$[10] = t2;
|
|
1091
|
+
$[11] = t3;
|
|
1092
|
+
} else {
|
|
1093
|
+
T0 = $[8];
|
|
1094
|
+
t1 = $[9];
|
|
1095
|
+
t2 = $[10];
|
|
1096
|
+
t3 = $[11];
|
|
1019
1097
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
};
|
|
1027
|
-
const itemId = isDbItem ? item_0.id : void 0;
|
|
1028
|
-
return /* @__PURE__ */ jsx(RepeaterItemContext.Provider, {
|
|
1029
|
-
value: {
|
|
1030
|
-
arrayFieldName: fieldName,
|
|
1031
|
-
itemIndex: index,
|
|
1032
|
-
itemContent: itemContent_0,
|
|
1033
|
-
itemId
|
|
1034
|
-
},
|
|
1035
|
-
children: /* @__PURE__ */ jsx(RepeaterItemWrapper, {
|
|
1036
|
-
itemId,
|
|
1037
|
-
blockId,
|
|
1038
|
-
mode,
|
|
1039
|
-
children: children(itemComponents, index)
|
|
1040
|
-
})
|
|
1041
|
-
}, itemId ?? index);
|
|
1042
|
-
});
|
|
1043
|
-
let t3;
|
|
1044
|
-
if ($[5] !== T0 || $[6] !== blockId || $[7] !== fieldName || $[8] !== t2) {
|
|
1045
|
-
t3 = /* @__PURE__ */ jsx(T0, {
|
|
1046
|
-
blockId,
|
|
1047
|
-
fieldName,
|
|
1048
|
-
children: t2
|
|
1098
|
+
let t4;
|
|
1099
|
+
if ($[23] !== T0 || $[24] !== t1 || $[25] !== t2 || $[26] !== t3) {
|
|
1100
|
+
t4 = /* @__PURE__ */ jsx(T0, {
|
|
1101
|
+
blockId: t1,
|
|
1102
|
+
fieldName: t2,
|
|
1103
|
+
children: t3
|
|
1049
1104
|
});
|
|
1050
|
-
$[
|
|
1051
|
-
$[
|
|
1052
|
-
$[
|
|
1053
|
-
$[
|
|
1054
|
-
$[
|
|
1055
|
-
} else
|
|
1056
|
-
return
|
|
1105
|
+
$[23] = T0;
|
|
1106
|
+
$[24] = t1;
|
|
1107
|
+
$[25] = t2;
|
|
1108
|
+
$[26] = t3;
|
|
1109
|
+
$[27] = t4;
|
|
1110
|
+
} else t4 = $[27];
|
|
1111
|
+
return t4;
|
|
1057
1112
|
};
|
|
1058
1113
|
const BlockComponent = (t0) => {
|
|
1059
1114
|
const $ = c(69);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _$_sinclair_typebox0 from "@sinclair/typebox";
|
|
2
|
-
import { TArray, TObject, TSchema, TUnsafe } from "@sinclair/typebox";
|
|
2
|
+
import { Static, TArray, TObject, TSchema, TUnsafe } from "@sinclair/typebox";
|
|
3
3
|
|
|
4
4
|
//#region src/core/lib/contentType.d.ts
|
|
5
5
|
declare class FieldToken {
|
|
@@ -7,12 +7,40 @@ declare class FieldToken {
|
|
|
7
7
|
constructor(fieldName: string);
|
|
8
8
|
toString(): string;
|
|
9
9
|
}
|
|
10
|
+
type SettingsScope = "block" | "item";
|
|
11
|
+
/**
|
|
12
|
+
* Serializable conditional block produced by the settings proxy. Emits Handlebars-style
|
|
13
|
+
* `{{#if ...}}...{{/if}}` syntax wrapping each child line, tagged with its scope so the
|
|
14
|
+
* server-side resolver knows whether to read from `settings` or `itemSettings`.
|
|
15
|
+
*/
|
|
16
|
+
declare class Conditional {
|
|
17
|
+
readonly scope: SettingsScope;
|
|
18
|
+
readonly settingName: string;
|
|
19
|
+
readonly enumValue: string | null;
|
|
20
|
+
readonly children: ReadonlyArray<string | FieldToken | Conditional>;
|
|
21
|
+
constructor(scope: SettingsScope, settingName: string, enumValue: string | null, children: ReadonlyArray<string | FieldToken | Conditional>);
|
|
22
|
+
get openTag(): string;
|
|
23
|
+
get closeTag(): string;
|
|
24
|
+
}
|
|
25
|
+
type ConditionalChild = string | FieldToken | Conditional;
|
|
26
|
+
type ConditionalLines = ConditionalChild | ReadonlyArray<ConditionalChild>;
|
|
10
27
|
type ContentProxy<TShape extends Record<string, TSchema>> = { [K in keyof TShape & string]: FieldToken };
|
|
11
|
-
|
|
28
|
+
/**
|
|
29
|
+
* Callable shape for one entry on the settings proxy. Booleans take a single `lines`
|
|
30
|
+
* argument; enums take `(value, lines)`. Settings of other shapes are disallowed — they
|
|
31
|
+
* don't make sense as conditions.
|
|
32
|
+
*/
|
|
33
|
+
type SettingCallable<T extends TSchema> = Static<T> extends boolean ? (lines: ConditionalLines) => Conditional : Static<T> extends string ? (value: Static<T>, lines: ConditionalLines) => Conditional : never;
|
|
34
|
+
type SettingsProxy<TShape extends Record<string, TSchema>> = { [K in keyof TShape & string]: SettingCallable<TShape[K]> };
|
|
35
|
+
type ToMarkdownBuilder<TContent extends Record<string, TSchema>, TSettings extends Record<string, TSchema> = Record<string, never>> = (c: ContentProxy<TContent>, s: SettingsProxy<TSettings>) => ReadonlyArray<string | FieldToken | Conditional>;
|
|
12
36
|
declare const EmbedURLBrand: unique symbol;
|
|
13
37
|
type EmbedURL = string & {
|
|
14
38
|
readonly [EmbedURLBrand]: true;
|
|
15
39
|
};
|
|
40
|
+
declare const ItemSettingsBrand: unique symbol;
|
|
41
|
+
type WithItemSettings<S extends Record<string, TSchema>> = {
|
|
42
|
+
readonly [ItemSettingsBrand]?: S;
|
|
43
|
+
};
|
|
16
44
|
declare const LinkBrand: unique symbol;
|
|
17
45
|
type LinkValue = ({
|
|
18
46
|
type: "external";
|
|
@@ -91,25 +119,33 @@ declare const Type$1: {
|
|
|
91
119
|
* Creates a repeatable array of object items.
|
|
92
120
|
* The default array is auto-generated based on minItems.
|
|
93
121
|
*
|
|
122
|
+
* Items may also declare per-item `settings` (Enum/Boolean only) — not
|
|
123
|
+
* inline-editable; they appear in the sidebar when the item is selected,
|
|
124
|
+
* similar to block-level settings.
|
|
125
|
+
*
|
|
94
126
|
* @example
|
|
95
127
|
* Type.RepeatableItem({
|
|
96
128
|
* content: {
|
|
97
129
|
* title: Type.String({ default: 'Item' }),
|
|
98
130
|
* description: Type.String({ default: 'Description' }),
|
|
99
131
|
* },
|
|
132
|
+
* settings: {
|
|
133
|
+
* highlighted: Type.Boolean({ default: false, title: 'Highlighted' }),
|
|
134
|
+
* },
|
|
100
135
|
* minItems: 1,
|
|
101
136
|
* maxItems: 10,
|
|
102
137
|
* title: 'Items',
|
|
103
138
|
* toMarkdown: (c) => [`### ${c.title}`, c.description],
|
|
104
139
|
* })
|
|
105
140
|
*/
|
|
106
|
-
RepeatableItem: <T extends Record<string, TSchema>>(options: {
|
|
141
|
+
RepeatableItem: <T extends Record<string, TSchema>, S extends Record<string, TSchema> = Record<string, never>>(options: {
|
|
107
142
|
content: T;
|
|
143
|
+
settings?: S;
|
|
108
144
|
minItems: number;
|
|
109
145
|
maxItems: number;
|
|
110
146
|
title?: string;
|
|
111
|
-
toMarkdown: ToMarkdownBuilder<T>;
|
|
112
|
-
}) => TArray<TObject<T
|
|
147
|
+
toMarkdown: ToMarkdownBuilder<T, S>;
|
|
148
|
+
}) => TArray<TObject<T>> & WithItemSettings<S>;
|
|
113
149
|
/**
|
|
114
150
|
* Creates an enum field with a set of predefined options.
|
|
115
151
|
*
|
|
@@ -120,11 +156,11 @@ declare const Type$1: {
|
|
|
120
156
|
* title: 'Alignment'
|
|
121
157
|
* })
|
|
122
158
|
*/
|
|
123
|
-
Enum: (options: {
|
|
124
|
-
default: string;
|
|
125
|
-
options:
|
|
159
|
+
Enum: <const O extends Record<string, string>>(options: {
|
|
160
|
+
default: keyof O & string;
|
|
161
|
+
options: O;
|
|
126
162
|
title?: string;
|
|
127
|
-
}) => TUnsafe<string>;
|
|
163
|
+
}) => TUnsafe<keyof O & string>;
|
|
128
164
|
/**
|
|
129
165
|
* Creates a boolean toggle field.
|
|
130
166
|
*
|
|
@@ -169,4 +205,4 @@ declare const Type$1: {
|
|
|
169
205
|
File: typeof _fileType;
|
|
170
206
|
};
|
|
171
207
|
//#endregion
|
|
172
|
-
export { EmbedURL, FileValue, ImageValue, LinkValue, ToMarkdownBuilder, Type$1 as Type };
|
|
208
|
+
export { EmbedURL, FileValue, ImageValue, ItemSettingsBrand, LinkValue, ToMarkdownBuilder, Type$1 as Type };
|
|
@@ -9,14 +9,55 @@ var FieldToken = class {
|
|
|
9
9
|
return `{{${this.fieldName}}}`;
|
|
10
10
|
}
|
|
11
11
|
};
|
|
12
|
+
/**
|
|
13
|
+
* Serializable conditional block produced by the settings proxy. Emits Handlebars-style
|
|
14
|
+
* `{{#if ...}}...{{/if}}` syntax wrapping each child line, tagged with its scope so the
|
|
15
|
+
* server-side resolver knows whether to read from `settings` or `itemSettings`.
|
|
16
|
+
*/
|
|
17
|
+
var Conditional = class {
|
|
18
|
+
constructor(scope, settingName, enumValue, children) {
|
|
19
|
+
this.scope = scope;
|
|
20
|
+
this.settingName = settingName;
|
|
21
|
+
this.enumValue = enumValue;
|
|
22
|
+
this.children = children;
|
|
23
|
+
}
|
|
24
|
+
get openTag() {
|
|
25
|
+
const root = this.scope === "block" ? "settings" : "itemSettings";
|
|
26
|
+
if (this.enumValue === null) return `{{#if ${root}.${this.settingName}}}`;
|
|
27
|
+
return `{{#if (eq ${root}.${this.settingName} "${this.enumValue}")}}`;
|
|
28
|
+
}
|
|
29
|
+
get closeTag() {
|
|
30
|
+
return "{{/if}}";
|
|
31
|
+
}
|
|
32
|
+
};
|
|
12
33
|
function createContentProxy() {
|
|
13
34
|
return new Proxy({}, { get(_target, prop) {
|
|
14
35
|
if (typeof prop !== "string") return void 0;
|
|
15
36
|
return new FieldToken(prop);
|
|
16
37
|
} });
|
|
17
38
|
}
|
|
18
|
-
function
|
|
19
|
-
return
|
|
39
|
+
function createSettingsProxy(settingsShape, scope) {
|
|
40
|
+
return new Proxy({}, { get(_target, prop) {
|
|
41
|
+
if (typeof prop !== "string") return void 0;
|
|
42
|
+
const fieldType = (settingsShape?.[prop])?.fieldType;
|
|
43
|
+
if (fieldType === "Boolean") return (lines) => new Conditional(scope, prop, null, Array.isArray(lines) ? lines : [lines]);
|
|
44
|
+
if (fieldType === "Enum") return (value, lines) => new Conditional(scope, prop, value, Array.isArray(lines) ? lines : [lines]);
|
|
45
|
+
throw new Error(`toMarkdown settings proxy: "${prop}" is not a Boolean or Enum setting on this ${scope}.`);
|
|
46
|
+
} });
|
|
47
|
+
}
|
|
48
|
+
/** Flatten a `Conditional`'s children into wrapped lines, recursing into nested Conditionals. */
|
|
49
|
+
function serializeConditional(cond) {
|
|
50
|
+
const out = [];
|
|
51
|
+
for (const child of cond.children) if (child instanceof Conditional) for (const nested of serializeConditional(child)) out.push(`${cond.openTag}${nested}${cond.closeTag}`);
|
|
52
|
+
else out.push(`${cond.openTag}${String(child)}${cond.closeTag}`);
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
function resolveToMarkdown(builder, settingsShape, scope) {
|
|
56
|
+
const entries = builder(createContentProxy(), createSettingsProxy(settingsShape, scope));
|
|
57
|
+
const out = [];
|
|
58
|
+
for (const entry of entries) if (entry instanceof Conditional) out.push(...serializeConditional(entry));
|
|
59
|
+
else out.push(entry instanceof FieldToken ? entry.toString() : String(entry));
|
|
60
|
+
return out;
|
|
20
61
|
}
|
|
21
62
|
function _imageType(options) {
|
|
22
63
|
const imageDefault = {
|
|
@@ -102,13 +143,25 @@ const Type$1 = {
|
|
|
102
143
|
const defaultItem = {};
|
|
103
144
|
for (const [key, prop] of Object.entries(objectSchema.properties)) if ("default" in prop) defaultItem[key] = prop.default;
|
|
104
145
|
const defaultArray = Array(options.minItems).fill(null).map(() => ({ ...defaultItem }));
|
|
146
|
+
const settingsTypeboxSchema = options.settings ? Type.Object(options.settings) : null;
|
|
147
|
+
const itemSettingsSchema = settingsTypeboxSchema ? {
|
|
148
|
+
type: "object",
|
|
149
|
+
properties: settingsTypeboxSchema.properties,
|
|
150
|
+
required: Object.keys(options.settings)
|
|
151
|
+
} : void 0;
|
|
152
|
+
const defaultItemSettings = {};
|
|
153
|
+
if (settingsTypeboxSchema) {
|
|
154
|
+
for (const [key, prop] of Object.entries(settingsTypeboxSchema.properties)) if ("default" in prop) defaultItemSettings[key] = prop.default;
|
|
155
|
+
}
|
|
105
156
|
return Type.Array(objectSchema, {
|
|
106
157
|
minItems: options.minItems,
|
|
107
158
|
maxItems: options.maxItems,
|
|
108
159
|
default: defaultArray,
|
|
109
160
|
title: options.title,
|
|
110
161
|
fieldType: "RepeatableItem",
|
|
111
|
-
toMarkdown: resolveToMarkdown(options.toMarkdown)
|
|
162
|
+
toMarkdown: resolveToMarkdown(options.toMarkdown, options.settings, "item"),
|
|
163
|
+
itemSettingsSchema,
|
|
164
|
+
defaultItemSettings: settingsTypeboxSchema ? defaultItemSettings : void 0
|
|
112
165
|
});
|
|
113
166
|
},
|
|
114
167
|
Enum: (options) => {
|