camox 0.71.0 → 0.74.1
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/createApp.d.ts +4 -103
- package/dist/core/createApp.js +3 -24
- package/dist/core/createBlock.d.ts +2 -2
- package/dist/core/createBlock.js +41 -185
- package/dist/core/createLayout.d.ts +6 -77
- package/dist/core/createLayout.js +12 -50
- package/dist/core/editing/createEditableBlock.d.ts +9 -75
- package/dist/core/editing/createEditableBlock.js +258 -640
- package/dist/core/hooks/useIsEditable.js +2 -2
- package/dist/core/lib/artifactData.js +8 -3
- package/dist/core/lib/contentType.d.ts +23 -38
- package/dist/core/lib/contentType.js +34 -62
- package/dist/core/lib/iconTypes.d.ts +0 -3
- package/dist/core/lib/icons.js +63 -51
- package/dist/core/lib/recordScope.js +1 -1
- package/dist/features/canvas/CanvasOverlays.js +94 -176
- package/dist/features/canvas/CanvasPageFrame.js +62 -68
- package/dist/features/canvas/CanvasPreviewPageSlot.js +1 -3
- package/dist/features/canvas/canvasOverlayGeometry.js +1 -7
- package/dist/features/canvas/sidebar/CuratedPageInspector.js +3 -21
- package/dist/features/canvas/sidebar/LayoutPageBlocks.js +1 -2
- package/dist/features/canvas/useCanvasCamera.js +1 -1
- package/dist/features/canvas/useCanvasFrame.js +1 -1
- package/dist/features/content/ContentCollection.js +2 -2
- package/dist/features/content/collection-form.js +6 -7
- package/dist/features/page/CuratedPageContent.js +15 -24
- package/dist/features/page/UnplacedBlockContent.js +1 -6
- package/dist/features/preview/CamoxPreview.js +30 -33
- package/dist/features/preview/EditablePageContent.js +131 -151
- package/dist/features/preview/components/BlockActionsPopover.js +43 -152
- package/dist/features/preview/components/CanvasPreview.js +2 -2
- package/dist/features/preview/components/Frame.js +3 -3
- package/dist/features/preview/components/IconFieldEditor.js +1 -1
- package/dist/features/preview/components/ItemFieldsEditor.js +1 -3
- package/dist/features/preview/components/Overlays.js +18 -84
- package/dist/features/preview/components/PageInfo.js +121 -98
- package/dist/features/preview/components/PageTree.js +57 -103
- package/dist/features/preview/components/PreviewPanel.js +8 -11
- package/dist/features/preview/components/RecordCombobox.js +65 -78
- package/dist/features/preview/components/ReferenceFieldEditor.js +1 -19
- package/dist/features/preview/components/ReferenceListFieldEditor.js +1 -19
- package/dist/features/preview/components/RemovedBlockPlaceholder.js +2 -2
- package/dist/features/preview/components/SelectionEditor.js +6 -5
- package/dist/features/preview/components/useRepeatableItemActions.js +18 -24
- package/dist/features/preview/components/useUpdateBlockPosition.js +1 -1
- package/dist/features/preview/overlayMessages.js +1 -4
- package/dist/features/preview/previewStore.js +3 -23
- package/dist/features/renderer/RendererApp.js +17 -141
- package/dist/features/renderer/definitionAnswers.js +1 -8
- package/dist/features/renderer/rendererHost.js +1 -31
- package/dist/features/renderer/studioConnection.js +1 -25
- package/dist/features/routes/pageRuntime.js +15 -4
- package/dist/features/runtime/ClaimCard.js +192 -0
- package/dist/features/runtime/pageApp.js +5 -4
- package/dist/features/runtime/runtime.js +29 -8
- package/dist/features/runtime/worker.js +2 -2
- package/dist/features/runtime/workerRequest.d.ts +6 -0
- package/dist/features/runtime/workerRequest.js +13 -1
- package/dist/features/runtime/workerRuntime.d.ts +2 -2
- package/dist/features/runtime/workerRuntime.js +2 -2
- package/dist/features/studio/components/AgentSidebar.js +7 -7
- package/dist/features/studio/components/ChatWidget.js +142 -106
- package/dist/features/studio/components/ContentFindings.js +127 -230
- package/dist/features/studio/components/DeleteDraftDialog.js +112 -0
- package/dist/features/studio/components/DraftBar.js +98 -53
- package/dist/features/studio/components/DraftsControl.js +203 -190
- package/dist/features/studio/components/ReviewDraftDialog.js +670 -0
- package/dist/features/studio/components/{Patrol.js → Specialists.js} +291 -330
- package/dist/features/studio/components/Squareling.js +5 -5
- package/dist/features/studio/components/ThreadComposer.js +106 -127
- package/dist/features/studio/components/ThreadMessages.js +137 -45
- package/dist/features/studio/findingSentence.js +14 -12
- package/dist/features/studio/fixMessage.js +23 -0
- package/dist/features/studio/reportSentence.js +1 -1
- package/dist/features/studio/{patrollerBio.js → specialistBio.js} +8 -5
- package/dist/features/studio/studioStore.js +29 -15
- package/dist/features/studio/workingSentence.js +1 -1
- package/dist/features/vite/blockBoilerplate.js +1 -1
- package/dist/features/vite/definitionsSync.js +1 -8
- package/dist/lib/api-client.js +5 -1
- package/dist/lib/queries.js +5 -6
- package/dist/lib/studio-definitions.js +0 -2
- package/dist/lib/studio-reads.d.ts +1 -1
- package/dist/lib/studio-reads.js +5 -10
- package/dist/lib/use-thread.js +196 -138
- package/dist/package.js +1 -1
- package/dist/studio-overlays.css +0 -29
- package/dist/studio.css +1 -1
- package/package.json +4 -4
- package/skills/camox/SKILL.md +1 -1
- package/skills/camox/references/artifacts.md +4 -4
- package/skills/camox/references/block-definitions.md +21 -25
- package/skills/camox/references/dom-integrations.md +1 -1
- package/skills/camox/references/layout-definitions.md +3 -12
- package/skills/camox/references/routed-layouts.md +2 -2
- package/skills/camox-expand/SKILL.md +5 -5
- package/skills/camoxify/SKILL.md +4 -4
- package/dist/features/canvas/canvasInsertionSeams.js +0 -44
- package/dist/features/preview/components/AddBlockSheet.js +0 -314
- package/dist/features/preview/components/BlockPeek.js +0 -66
- package/dist/features/preview/components/BlockThumbnail.js +0 -281
- package/dist/features/preview/components/blockGridNavigation.js +0 -15
- package/dist/features/preview/referencePickerFocus.js +0 -29
- package/dist/features/studio/components/ReviewDraftSheet.js +0 -1587
|
@@ -10,11 +10,11 @@ import { useSelector } from "@xstate/store-react";
|
|
|
10
10
|
* the Page. Frames keep the editing runtime either way, so toggling never remounts the page.
|
|
11
11
|
*/
|
|
12
12
|
const EditableSurfaceContext = React.createContext(true);
|
|
13
|
-
function useIsEditable(
|
|
13
|
+
function useIsEditable() {
|
|
14
14
|
const isAuthenticated = useIsAuthenticated();
|
|
15
15
|
const isCanvasShown = useSelector(previewStore, selectIsCanvasShown);
|
|
16
16
|
const surface = React.use(EditableSurfaceContext);
|
|
17
|
-
return isAuthenticated &&
|
|
17
|
+
return isAuthenticated && isCanvasShown && surface;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
//#endregion
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { emptyFieldValue } from "@camox/api-contract";
|
|
2
|
+
|
|
1
3
|
//#region src/core/lib/artifactData.ts
|
|
2
4
|
const DATA_SOURCES = Symbol("camox.artifactDataSources");
|
|
3
5
|
/** Content fields that can't be Artifact Data. */
|
|
@@ -38,7 +40,10 @@ function valueSchema(schema) {
|
|
|
38
40
|
newTab: { type: "boolean" }
|
|
39
41
|
}, title);
|
|
40
42
|
case "Image":
|
|
41
|
-
case "File": return
|
|
43
|
+
case "File": return {
|
|
44
|
+
...titled,
|
|
45
|
+
anyOf: [objectSchema(assetProperties[schema.fieldType]), { type: "null" }]
|
|
46
|
+
};
|
|
42
47
|
case "ImageList":
|
|
43
48
|
case "FileList": {
|
|
44
49
|
const single = schema.fieldType === "ImageList" ? "Image" : "File";
|
|
@@ -111,10 +116,10 @@ function normalizeValue(schema, value, resolve) {
|
|
|
111
116
|
};
|
|
112
117
|
}
|
|
113
118
|
case "Image":
|
|
114
|
-
case "File": return normalizeAsset(schema.fieldType, resolve.asset(value)
|
|
119
|
+
case "File": return normalizeAsset(schema.fieldType, resolve.asset(value));
|
|
115
120
|
case "ImageList":
|
|
116
121
|
case "FileList": return (Array.isArray(value) ? value : []).map((item) => normalizeAsset(schema.fieldType, resolve.asset(item))).filter(Boolean);
|
|
117
|
-
default: return value ?? schema
|
|
122
|
+
default: return value ?? emptyFieldValue(schema);
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
125
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BlockStructuredData, KnownNodesOnly, RepeatedNodes } from "../structuredData.js";
|
|
2
2
|
import { Collection } from "../createCollection.js";
|
|
3
|
-
import {
|
|
3
|
+
import { IconValue } from "./iconTypes.js";
|
|
4
4
|
import { SystemOrderKey } from "@camox/api-contract";
|
|
5
5
|
import { Static, TArray, TBoolean, TObject, TSchema, TUnsafe } from "@sinclair/typebox";
|
|
6
6
|
//#region src/core/lib/contentType.d.ts
|
|
@@ -208,29 +208,23 @@ type StringOptions = {
|
|
|
208
208
|
/**
|
|
209
209
|
* Builds the fields of a block or repeatable item's content.
|
|
210
210
|
* `enum` and `boolean` are not content: declare them in `settings` instead.
|
|
211
|
+
* Fields have no default: an unset field holds the empty value of its kind.
|
|
211
212
|
*/
|
|
212
213
|
export interface ContentFieldBuilder {
|
|
213
214
|
/**
|
|
214
215
|
* An inline-editable text field.
|
|
215
216
|
*
|
|
216
217
|
* @example
|
|
217
|
-
* field.string({
|
|
218
|
+
* field.string({ maxLength: 100, title: "Title" })
|
|
218
219
|
*/
|
|
219
|
-
string: (options
|
|
220
|
-
default: string;
|
|
221
|
-
}) => StringField;
|
|
220
|
+
string: (options?: StringOptions) => StringField;
|
|
222
221
|
/**
|
|
223
222
|
* A link with text, a target (external URL or internal page) and a new-tab flag.
|
|
224
223
|
*
|
|
225
224
|
* @example
|
|
226
|
-
* field.link({
|
|
225
|
+
* field.link({ title: "CTA" })
|
|
227
226
|
*/
|
|
228
|
-
link: (options
|
|
229
|
-
default: {
|
|
230
|
-
text: string;
|
|
231
|
-
href: string;
|
|
232
|
-
newTab: boolean;
|
|
233
|
-
};
|
|
227
|
+
link: (options?: {
|
|
234
228
|
title?: string;
|
|
235
229
|
}) => LinkField;
|
|
236
230
|
/**
|
|
@@ -247,11 +241,10 @@ export interface ContentFieldBuilder {
|
|
|
247
241
|
* A list of image assets.
|
|
248
242
|
*
|
|
249
243
|
* @example
|
|
250
|
-
* field.imageList({ title: "Gallery"
|
|
244
|
+
* field.imageList({ title: "Gallery" })
|
|
251
245
|
*/
|
|
252
246
|
imageList: (options?: {
|
|
253
247
|
title?: string;
|
|
254
|
-
defaultItems?: number;
|
|
255
248
|
}) => ImageListField;
|
|
256
249
|
/**
|
|
257
250
|
* A file asset.
|
|
@@ -273,7 +266,6 @@ export interface ContentFieldBuilder {
|
|
|
273
266
|
fileList: (options: {
|
|
274
267
|
accept: string[];
|
|
275
268
|
title?: string;
|
|
276
|
-
defaultItems?: number;
|
|
277
269
|
}) => FileListField;
|
|
278
270
|
/**
|
|
279
271
|
* A URL that must match `pattern`, rendered as an embed.
|
|
@@ -281,13 +273,11 @@ export interface ContentFieldBuilder {
|
|
|
281
273
|
* @example
|
|
282
274
|
* field.embed({
|
|
283
275
|
* pattern: "https:\\/\\/(www\\.)?youtube\\.com\\/watch\\?v=.+",
|
|
284
|
-
* default: "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
|
|
285
276
|
* title: "YouTube URL",
|
|
286
277
|
* })
|
|
287
278
|
*/
|
|
288
279
|
embed: (options: {
|
|
289
280
|
pattern: string;
|
|
290
|
-
default: string;
|
|
291
281
|
title?: string;
|
|
292
282
|
}) => EmbedField;
|
|
293
283
|
/**
|
|
@@ -305,17 +295,15 @@ export interface ContentFieldBuilder {
|
|
|
305
295
|
* repeater, the siblings are the item's own fields and settings.
|
|
306
296
|
*/
|
|
307
297
|
data?: readonly D[];
|
|
308
|
-
default?: string;
|
|
309
298
|
title?: string;
|
|
310
299
|
}) => ArtifactField<NoInfer<D>>;
|
|
311
300
|
/**
|
|
312
301
|
* An icon from the set configured in `camox()`.
|
|
313
302
|
*
|
|
314
303
|
* @example
|
|
315
|
-
* field.icon({
|
|
304
|
+
* field.icon({ title: "Icon" })
|
|
316
305
|
*/
|
|
317
|
-
icon: (options
|
|
318
|
-
default: IconId;
|
|
306
|
+
icon: (options?: {
|
|
319
307
|
title?: string;
|
|
320
308
|
}) => IconField;
|
|
321
309
|
/**
|
|
@@ -355,11 +343,11 @@ export interface ContentFieldBuilder {
|
|
|
355
343
|
* @example
|
|
356
344
|
* field.repeater({
|
|
357
345
|
* content: (field) => ({
|
|
358
|
-
* title: field.string(
|
|
359
|
-
* description: field.string(
|
|
346
|
+
* title: field.string(),
|
|
347
|
+
* description: field.string(),
|
|
360
348
|
* }),
|
|
361
349
|
* settings: (setting) => ({
|
|
362
|
-
* highlighted: setting.boolean({
|
|
350
|
+
* highlighted: setting.boolean({ title: "Highlighted" }),
|
|
363
351
|
* }),
|
|
364
352
|
* minItems: 1,
|
|
365
353
|
* maxItems: 10,
|
|
@@ -416,30 +404,29 @@ type ArtifactKey<T extends Record<string, TSchema>> = { [K in keyof T & string]-
|
|
|
416
404
|
*/
|
|
417
405
|
export interface SettingBuilder {
|
|
418
406
|
/**
|
|
419
|
-
* One of a fixed set of options; keys are stored, values are editor labels.
|
|
407
|
+
* One of a fixed set of options; keys are stored, values are editor labels. Unset, it holds
|
|
408
|
+
* the first option.
|
|
420
409
|
*
|
|
421
410
|
* @example
|
|
422
|
-
* setting.enum({
|
|
411
|
+
* setting.enum({ options: { left: "Left", right: "Right" }, title: "Alignment" })
|
|
423
412
|
*/
|
|
424
413
|
enum: <const O extends Record<string, string>>(options: {
|
|
425
|
-
default: keyof O & string;
|
|
426
414
|
options: O;
|
|
427
415
|
title?: string;
|
|
428
416
|
}) => EnumSetting<O>;
|
|
429
417
|
/**
|
|
430
|
-
* A toggle.
|
|
418
|
+
* A toggle. Unset, it's off.
|
|
431
419
|
*
|
|
432
420
|
* @example
|
|
433
|
-
* setting.boolean({
|
|
421
|
+
* setting.boolean({ title: "Show background" })
|
|
434
422
|
*/
|
|
435
|
-
boolean: (options
|
|
436
|
-
default: boolean;
|
|
423
|
+
boolean: (options?: {
|
|
437
424
|
title?: string;
|
|
438
425
|
}) => BooleanSetting;
|
|
439
426
|
}
|
|
440
427
|
/**
|
|
441
|
-
* Builds the fields of a collection record.
|
|
442
|
-
*
|
|
428
|
+
* Builds the fields of a collection record. Collections have no settings: `enum` and `boolean`
|
|
429
|
+
* are content here.
|
|
443
430
|
*/
|
|
444
431
|
export interface CollectionFieldBuilder extends Pick<ContentFieldBuilder, "imageList" | "fileList" | "embed"> {
|
|
445
432
|
/**
|
|
@@ -490,21 +477,19 @@ export interface CollectionFieldBuilder extends Pick<ContentFieldBuilder, "image
|
|
|
490
477
|
* @example
|
|
491
478
|
* field.string({ minLength: 1, title: "Name" })
|
|
492
479
|
*/
|
|
493
|
-
string: (options?: StringOptions
|
|
494
|
-
default?: string;
|
|
495
|
-
}) => StringField;
|
|
480
|
+
string: (options?: StringOptions) => StringField;
|
|
496
481
|
/**
|
|
497
482
|
* One of a fixed set of options; keys are stored, values are editor labels.
|
|
498
483
|
*
|
|
499
484
|
* @example
|
|
500
|
-
* field.enum({
|
|
485
|
+
* field.enum({ options: { draft: "Draft", final: "Final" } })
|
|
501
486
|
*/
|
|
502
487
|
enum: SettingBuilder["enum"];
|
|
503
488
|
/**
|
|
504
489
|
* A toggle.
|
|
505
490
|
*
|
|
506
491
|
* @example
|
|
507
|
-
* field.boolean({
|
|
492
|
+
* field.boolean({ title: "Featured" })
|
|
508
493
|
*/
|
|
509
494
|
boolean: SettingBuilder["boolean"];
|
|
510
495
|
}
|
|
@@ -156,6 +156,20 @@ function resolveRecordStructuredData(builder, contentShape) {
|
|
|
156
156
|
/** The longest artifact source content writes accept (256 KB). */
|
|
157
157
|
const ARTIFACT_MAX_LENGTH = 262144;
|
|
158
158
|
const IMAGE_PLACEHOLDER = Symbol("camox.imagePlaceholder");
|
|
159
|
+
/**
|
|
160
|
+
* What an empty image field renders in a block: an illustrated placeholder labeled with the
|
|
161
|
+
* field's title. Its URL is the fallback for callbacks that don't render a plain `<img>`.
|
|
162
|
+
*/
|
|
163
|
+
function placeholderImage(title) {
|
|
164
|
+
const label = title || "image";
|
|
165
|
+
return {
|
|
166
|
+
url: `https://placehold.co/1200x800/f4f4f5/a1a1aa.png?text=${encodeURIComponent(label)}`,
|
|
167
|
+
alt: "",
|
|
168
|
+
filename: "placeholder.png",
|
|
169
|
+
mimeType: "image/png",
|
|
170
|
+
[IMAGE_PLACEHOLDER]: label
|
|
171
|
+
};
|
|
172
|
+
}
|
|
159
173
|
function isImagePlaceholder(value) {
|
|
160
174
|
return typeof value[IMAGE_PLACEHOLDER] === "string" && !value._fileId;
|
|
161
175
|
}
|
|
@@ -173,13 +187,6 @@ function _imageSingle(options) {
|
|
|
173
187
|
},
|
|
174
188
|
accept: ["image/*"],
|
|
175
189
|
required: options.required ?? false,
|
|
176
|
-
default: {
|
|
177
|
-
url: `https://placehold.co/1200x800/f4f4f5/a1a1aa.png?text=${options?.title || "image"}`,
|
|
178
|
-
alt: "",
|
|
179
|
-
filename: "placeholder.png",
|
|
180
|
-
mimeType: "image/png",
|
|
181
|
-
[IMAGE_PLACEHOLDER]: options.title || "image"
|
|
182
|
-
},
|
|
183
190
|
title: options.title,
|
|
184
191
|
fieldType: "Image"
|
|
185
192
|
});
|
|
@@ -188,8 +195,6 @@ function _imageList(options) {
|
|
|
188
195
|
return Type.Array(_imageSingle({ title: options.title }), {
|
|
189
196
|
minItems: 0,
|
|
190
197
|
maxItems: 100,
|
|
191
|
-
default: [],
|
|
192
|
-
defaultItems: options.defaultItems ?? 0,
|
|
193
198
|
title: options.title,
|
|
194
199
|
fieldType: "ImageList"
|
|
195
200
|
});
|
|
@@ -205,12 +210,6 @@ function _fileSingle(options) {
|
|
|
205
210
|
},
|
|
206
211
|
accept: options.accept,
|
|
207
212
|
required: options.required ?? false,
|
|
208
|
-
default: {
|
|
209
|
-
url: "https://placehold.co/file-placeholder",
|
|
210
|
-
alt: "",
|
|
211
|
-
filename: "placeholder",
|
|
212
|
-
mimeType: "application/octet-stream"
|
|
213
|
-
},
|
|
214
213
|
title: options.title,
|
|
215
214
|
fieldType: "File"
|
|
216
215
|
});
|
|
@@ -222,8 +221,6 @@ function _fileList(options) {
|
|
|
222
221
|
}), {
|
|
223
222
|
minItems: 0,
|
|
224
223
|
maxItems: 100,
|
|
225
|
-
default: [],
|
|
226
|
-
defaultItems: options.defaultItems ?? 0,
|
|
227
224
|
title: options.title,
|
|
228
225
|
fieldType: "FileList"
|
|
229
226
|
});
|
|
@@ -246,21 +243,14 @@ function assertFieldKinds(shape, context, owner) {
|
|
|
246
243
|
if (context === "content" && isSetting) throw new Error(`${owner} field "${key}": ${field.fieldType} is a setting, not content`);
|
|
247
244
|
}
|
|
248
245
|
}
|
|
249
|
-
function collectSchemaDefaults(properties) {
|
|
250
|
-
const defaults = {};
|
|
251
|
-
for (const [key, prop] of Object.entries(properties)) if ("default" in prop) defaults[key] = prop.default;
|
|
252
|
-
return defaults;
|
|
253
|
-
}
|
|
254
246
|
const enumSetting = (options) => Type.Unsafe({
|
|
255
247
|
type: "string",
|
|
256
248
|
enum: Object.keys(options.options),
|
|
257
|
-
default: options.default,
|
|
258
249
|
title: options.title,
|
|
259
250
|
enumLabels: options.options,
|
|
260
251
|
fieldType: "Enum"
|
|
261
252
|
});
|
|
262
|
-
const booleanSetting = (options) => Type.Boolean({
|
|
263
|
-
default: options.default,
|
|
253
|
+
const booleanSetting = (options = {}) => Type.Boolean({
|
|
264
254
|
title: options.title,
|
|
265
255
|
fieldType: "Boolean"
|
|
266
256
|
});
|
|
@@ -268,13 +258,14 @@ const settingBuilder = {
|
|
|
268
258
|
enum: enumSetting,
|
|
269
259
|
boolean: booleanSetting
|
|
270
260
|
};
|
|
261
|
+
const stringField = (options = {}) => Type.Unsafe({
|
|
262
|
+
type: "string",
|
|
263
|
+
...options,
|
|
264
|
+
fieldType: "String"
|
|
265
|
+
});
|
|
271
266
|
const contentFieldBuilder = {
|
|
272
|
-
string:
|
|
273
|
-
|
|
274
|
-
...options,
|
|
275
|
-
fieldType: "String"
|
|
276
|
-
}),
|
|
277
|
-
link: (options) => Type.Unsafe({
|
|
267
|
+
string: stringField,
|
|
268
|
+
link: (options = {}) => Type.Unsafe({
|
|
278
269
|
type: "object",
|
|
279
270
|
properties: {
|
|
280
271
|
type: {
|
|
@@ -286,10 +277,6 @@ const contentFieldBuilder = {
|
|
|
286
277
|
pageId: { anyOf: [{ const: "" }, uuidv7JsonSchema] },
|
|
287
278
|
newTab: { type: "boolean" }
|
|
288
279
|
},
|
|
289
|
-
default: {
|
|
290
|
-
...options.default,
|
|
291
|
-
type: "external"
|
|
292
|
-
},
|
|
293
280
|
title: options.title,
|
|
294
281
|
fieldType: "Link"
|
|
295
282
|
}),
|
|
@@ -297,33 +284,27 @@ const contentFieldBuilder = {
|
|
|
297
284
|
imageList: (options = {}) => _imageList(options),
|
|
298
285
|
file: (options) => _fileSingle(options),
|
|
299
286
|
fileList: (options) => _fileList(options),
|
|
300
|
-
embed: (options) => {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
title: options.title,
|
|
307
|
-
fieldType: "Embed"
|
|
308
|
-
});
|
|
309
|
-
},
|
|
287
|
+
embed: (options) => Type.Unsafe({
|
|
288
|
+
type: "string",
|
|
289
|
+
pattern: options.pattern,
|
|
290
|
+
title: options.title,
|
|
291
|
+
fieldType: "Embed"
|
|
292
|
+
}),
|
|
310
293
|
artifact: (options) => Type.Unsafe({
|
|
311
294
|
type: "string",
|
|
312
295
|
maxLength: ARTIFACT_MAX_LENGTH,
|
|
313
296
|
size: options.size,
|
|
314
297
|
...options.data?.length ? { data: [...options.data] } : {},
|
|
315
|
-
default: options.default ?? "",
|
|
316
298
|
title: options.title,
|
|
317
299
|
fieldType: "Artifact"
|
|
318
300
|
}),
|
|
319
|
-
icon: (options) => {
|
|
301
|
+
icon: (options = {}) => {
|
|
320
302
|
const ids = typeof __CAMOX_ICON_IDS__ === "undefined" ? [] : __CAMOX_ICON_IDS__;
|
|
321
|
-
if (
|
|
303
|
+
if (ids.length === 0) throw new Error("Icon fields need icons: configure them in camox() first.");
|
|
322
304
|
return Type.Unsafe({
|
|
323
305
|
type: "string",
|
|
324
306
|
fieldType: "Icon",
|
|
325
307
|
enum: [...ids],
|
|
326
|
-
default: options.default,
|
|
327
308
|
title: options.title
|
|
328
309
|
});
|
|
329
310
|
},
|
|
@@ -336,7 +317,6 @@ const contentFieldBuilder = {
|
|
|
336
317
|
collectionId: collection._internal.id,
|
|
337
318
|
required: options.required ?? false,
|
|
338
319
|
title: options.title ?? collection._internal.title,
|
|
339
|
-
default: null,
|
|
340
320
|
referenceSchema: collection._internal.contentSchema
|
|
341
321
|
}),
|
|
342
322
|
referenceList: (collection, options = {}) => Type.Unsafe({
|
|
@@ -350,7 +330,7 @@ const contentFieldBuilder = {
|
|
|
350
330
|
title: options.title ?? collection._internal.title,
|
|
351
331
|
...options.description === void 0 ? {} : { description: options.description },
|
|
352
332
|
...options.maxItems === void 0 ? {} : { maxItems: options.maxItems },
|
|
353
|
-
...options.query === void 0 ? {
|
|
333
|
+
...options.query === void 0 ? {} : { query: validateQuery(options.query, collection) },
|
|
354
334
|
...options.toMarkdown === void 0 ? {} : { toMarkdown: resolveToMarkdown(options.toMarkdown, void 0, "item", collection._internal.contentSchema.properties) },
|
|
355
335
|
referenceSchema: collection._internal.contentSchema
|
|
356
336
|
}),
|
|
@@ -363,8 +343,6 @@ const contentFieldBuilder = {
|
|
|
363
343
|
if (settings) assertFieldKinds(settings, "settings", owner);
|
|
364
344
|
attachArtifactData(content, settings, owner);
|
|
365
345
|
const objectSchema = Type.Object(content);
|
|
366
|
-
const defaultItem = collectSchemaDefaults(objectSchema.properties);
|
|
367
|
-
const defaultArray = Array(options.minItems).fill(null).map(() => ({ ...defaultItem }));
|
|
368
346
|
const settingsObjectSchema = settings ? Type.Object(settings) : null;
|
|
369
347
|
const itemSettingsSchema = settingsObjectSchema ? {
|
|
370
348
|
type: "object",
|
|
@@ -374,23 +352,17 @@ const contentFieldBuilder = {
|
|
|
374
352
|
return Type.Array(objectSchema, {
|
|
375
353
|
minItems: options.minItems,
|
|
376
354
|
...Number.isFinite(options.maxItems) ? { maxItems: options.maxItems } : {},
|
|
377
|
-
default: defaultArray,
|
|
378
355
|
title: options.title,
|
|
379
356
|
fieldType: "Repeater",
|
|
380
357
|
toTitle: resolveToTitle(options.toTitle, settings, "item", content),
|
|
381
358
|
toMarkdown: resolveToMarkdown(options.toMarkdown, settings, "item", content),
|
|
382
359
|
...options.toStructuredData && { toStructuredData: resolveToStructuredData(options.toStructuredData, settings, "item", content) },
|
|
383
|
-
itemSettingsSchema
|
|
384
|
-
defaultItemSettings: settingsObjectSchema ? collectSchemaDefaults(settingsObjectSchema.properties) : void 0
|
|
360
|
+
itemSettingsSchema
|
|
385
361
|
});
|
|
386
362
|
}
|
|
387
363
|
};
|
|
388
364
|
const collectionFieldBuilder = {
|
|
389
|
-
string:
|
|
390
|
-
type: "string",
|
|
391
|
-
...options,
|
|
392
|
-
fieldType: "String"
|
|
393
|
-
}),
|
|
365
|
+
string: stringField,
|
|
394
366
|
enum: enumSetting,
|
|
395
367
|
boolean: booleanSetting,
|
|
396
368
|
image: (options = {}) => contentFieldBuilder.image({ title: options.title }),
|
|
@@ -422,4 +394,4 @@ function resolveBlockFields(options) {
|
|
|
422
394
|
}
|
|
423
395
|
|
|
424
396
|
//#endregion
|
|
425
|
-
export { ARTIFACT_MAX_LENGTH, Conditional, FieldToken, assertFieldKinds, collectionField, collectionFieldBuilder, contentFieldBuilder, getImagePlaceholderTitle, isImagePlaceholder, resolveBlockFields, resolveRecordStructuredData, resolveRecordTemplate, resolveToMarkdown, resolveToStructuredData, resolveToTitle, settingBuilder };
|
|
397
|
+
export { ARTIFACT_MAX_LENGTH, Conditional, FieldToken, assertFieldKinds, collectionField, collectionFieldBuilder, contentFieldBuilder, getImagePlaceholderTitle, isImagePlaceholder, placeholderImage, resolveBlockFields, resolveRecordStructuredData, resolveRecordTemplate, resolveToMarkdown, resolveToStructuredData, resolveToTitle, settingBuilder };
|
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
declare global {
|
|
3
3
|
interface CamoxIconRegistry {}
|
|
4
4
|
}
|
|
5
|
-
export type IconId = CamoxIconRegistry extends {
|
|
6
|
-
ids: infer IDs extends string;
|
|
7
|
-
} ? IDs : never;
|
|
8
5
|
declare const iconBrand: unique symbol;
|
|
9
6
|
export type IconValue = string & {
|
|
10
7
|
readonly [iconBrand]: true;
|
package/dist/core/lib/icons.js
CHANGED
|
@@ -19,8 +19,9 @@ const iconQuery = (id) => ({
|
|
|
19
19
|
return response.json();
|
|
20
20
|
}
|
|
21
21
|
});
|
|
22
|
+
/** An icon by ID; an unset icon field (`""`) renders an empty SVG without fetching. */
|
|
22
23
|
function IconSvg(t0) {
|
|
23
|
-
const $ = c(
|
|
24
|
+
const $ = c(24);
|
|
24
25
|
let iconId;
|
|
25
26
|
let props;
|
|
26
27
|
if ($[0] !== t0) {
|
|
@@ -38,64 +39,75 @@ function IconSvg(t0) {
|
|
|
38
39
|
$[3] = iconId;
|
|
39
40
|
$[4] = t1;
|
|
40
41
|
} else t1 = $[4];
|
|
41
|
-
const
|
|
42
|
-
const t2 = useId();
|
|
42
|
+
const t2 = iconId !== "";
|
|
43
43
|
let t3;
|
|
44
|
-
if ($[5] !== t2) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
$[
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
44
|
+
if ($[5] !== t1 || $[6] !== t2) {
|
|
45
|
+
t3 = {
|
|
46
|
+
...t1,
|
|
47
|
+
enabled: t2
|
|
48
|
+
};
|
|
49
|
+
$[5] = t1;
|
|
50
|
+
$[6] = t2;
|
|
51
|
+
$[7] = t3;
|
|
52
|
+
} else t3 = $[7];
|
|
53
|
+
const { data } = useQuery(t3);
|
|
54
|
+
const t4 = useId();
|
|
55
|
+
let t5;
|
|
56
|
+
if ($[8] !== t4) {
|
|
57
|
+
let t6;
|
|
58
|
+
if ($[10] === Symbol.for("react.memo_cache_sentinel")) {
|
|
59
|
+
t6 = /[^a-zA-Z0-9_-]/g;
|
|
60
|
+
$[10] = t6;
|
|
61
|
+
} else t6 = $[10];
|
|
62
|
+
t5 = t4.replace(t6, "");
|
|
60
63
|
$[8] = t4;
|
|
61
64
|
$[9] = t5;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
+
} else t5 = $[9];
|
|
66
|
+
const instance = t5;
|
|
67
|
+
const t6 = data?.body ?? "";
|
|
68
|
+
const t7 = `camox-${instance}-`;
|
|
69
|
+
let t8;
|
|
70
|
+
if ($[11] !== t6 || $[12] !== t7) {
|
|
71
|
+
t8 = scopeIconSvgIds(t6, t7);
|
|
72
|
+
$[11] = t6;
|
|
73
|
+
$[12] = t7;
|
|
74
|
+
$[13] = t8;
|
|
75
|
+
} else t8 = $[13];
|
|
76
|
+
const body = t8;
|
|
65
77
|
const labeled = !!(props["aria-label"] || props["aria-labelledby"]);
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
let
|
|
72
|
-
if ($[
|
|
73
|
-
|
|
74
|
-
$[
|
|
75
|
-
$[
|
|
76
|
-
} else
|
|
77
|
-
let
|
|
78
|
-
if ($[
|
|
79
|
-
|
|
80
|
-
...
|
|
81
|
-
"aria-hidden":
|
|
82
|
-
role:
|
|
78
|
+
const t9 = data?.attributes;
|
|
79
|
+
const t10 = labeled ? void 0 : true;
|
|
80
|
+
const t11 = labeled ? "img" : void 0;
|
|
81
|
+
const t12 = data?.attribution?.url ?? data?.attribution?.license;
|
|
82
|
+
const t13 = data?.attribution?.author;
|
|
83
|
+
let t14;
|
|
84
|
+
if ($[14] !== body) {
|
|
85
|
+
t14 = { __html: body };
|
|
86
|
+
$[14] = body;
|
|
87
|
+
$[15] = t14;
|
|
88
|
+
} else t14 = $[15];
|
|
89
|
+
let t15;
|
|
90
|
+
if ($[16] !== props || $[17] !== t10 || $[18] !== t11 || $[19] !== t12 || $[20] !== t13 || $[21] !== t14 || $[22] !== t9) {
|
|
91
|
+
t15 = /* @__PURE__ */ jsx("svg", {
|
|
92
|
+
...t9,
|
|
93
|
+
"aria-hidden": t10,
|
|
94
|
+
role: t11,
|
|
83
95
|
focusable: "false",
|
|
84
|
-
"data-icon-license":
|
|
85
|
-
"data-icon-author":
|
|
96
|
+
"data-icon-license": t12,
|
|
97
|
+
"data-icon-author": t13,
|
|
86
98
|
...props,
|
|
87
|
-
dangerouslySetInnerHTML:
|
|
99
|
+
dangerouslySetInnerHTML: t14
|
|
88
100
|
});
|
|
89
|
-
$[
|
|
90
|
-
$[
|
|
91
|
-
$[
|
|
92
|
-
$[
|
|
93
|
-
$[17] = t7;
|
|
94
|
-
$[18] = t8;
|
|
95
|
-
$[19] = t9;
|
|
101
|
+
$[16] = props;
|
|
102
|
+
$[17] = t10;
|
|
103
|
+
$[18] = t11;
|
|
104
|
+
$[19] = t12;
|
|
96
105
|
$[20] = t13;
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
$[21] = t14;
|
|
107
|
+
$[22] = t9;
|
|
108
|
+
$[23] = t15;
|
|
109
|
+
} else t15 = $[23];
|
|
110
|
+
return t15;
|
|
99
111
|
}
|
|
100
112
|
async function prefetchIcons(client, ...sources) {
|
|
101
113
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -64,7 +64,7 @@ function renderFile(value, children) {
|
|
|
64
64
|
download: value.filename
|
|
65
65
|
}, value);
|
|
66
66
|
}
|
|
67
|
-
/** An asset field's value
|
|
67
|
+
/** An asset field's value, or null: an unset asset renders nothing in a record. */
|
|
68
68
|
function useAsset(name) {
|
|
69
69
|
const $ = c(3);
|
|
70
70
|
const { filesMap } = useNormalizedData();
|