camox 0.69.0 → 0.72.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/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 +55 -192
- 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/useArtifactHost.js +56 -46
- package/dist/core/hooks/useIsEditable.js +2 -2
- package/dist/core/lib/artifact.d.ts +4 -0
- package/dist/core/lib/artifactData.js +8 -3
- package/dist/core/lib/artifactHost.js +40 -0
- package/dist/core/lib/artifactRuntime.js +20 -1
- 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/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 +5 -4
- 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/runtime/pageApp.js +8 -4
- package/dist/features/runtime/runtime.js +3 -3
- package/dist/features/studio/agentRunToast.js +71 -0
- package/dist/features/studio/components/ChatWidget.js +2 -0
- package/dist/features/studio/components/DraftBar.js +2 -3
- package/dist/features/studio/components/DraftsControl.js +150 -176
- package/dist/features/studio/components/ReviewDraftSheet.js +344 -548
- package/dist/features/studio/components/ThreadMessages.js +89 -22
- package/dist/features/studio/draftLabel.js +1 -1
- package/dist/features/studio/studioStore.js +5 -17
- package/dist/features/studio/viewSwitch.js +2 -4
- package/dist/features/vite/blockBoilerplate.js +1 -1
- package/dist/features/vite/definitionsSync.js +1 -8
- package/dist/lib/queries.js +0 -1
- package/dist/lib/studio-definitions.js +0 -2
- package/dist/lib/studio-reads.js +0 -5
- 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 +6 -4
- package/skills/camox/SKILL.md +1 -1
- package/skills/camox/references/artifacts.md +89 -5
- 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
|
@@ -15,37 +15,43 @@ const ArtifactStudioContext = React.createContext(null);
|
|
|
15
15
|
*/
|
|
16
16
|
const ArtifactsRunContext = React.createContext(true);
|
|
17
17
|
/**
|
|
18
|
+
* Whether artifacts run in capture mode: in the look document (ADR 0032), where their Timeline's
|
|
19
|
+
* time only moves when the browser `look` drives seeks it.
|
|
20
|
+
*/
|
|
21
|
+
const ArtifactCaptureContext = React.createContext(false);
|
|
22
|
+
/**
|
|
18
23
|
* Connects an artifact's `<iframe>` to the `camox` runtime inside it: keeps sharing `studio` and
|
|
19
24
|
* its Artifact Data as they change, sizes frames sized to their content, and routes the
|
|
20
25
|
* artifact's navigation.
|
|
21
26
|
*/
|
|
22
27
|
function useArtifactHost(t0) {
|
|
23
|
-
const $ = c(
|
|
24
|
-
const { studio, data: t1, size, navigate } = t0;
|
|
25
|
-
let
|
|
28
|
+
const $ = c(19);
|
|
29
|
+
const { studio, data: t1, size, navigate, capture: t2 } = t0;
|
|
30
|
+
let t3;
|
|
26
31
|
if ($[0] !== t1) {
|
|
27
|
-
|
|
32
|
+
t3 = t1 === void 0 ? {} : t1;
|
|
28
33
|
$[0] = t1;
|
|
29
|
-
$[1] =
|
|
30
|
-
} else
|
|
31
|
-
const data =
|
|
34
|
+
$[1] = t3;
|
|
35
|
+
} else t3 = $[1];
|
|
36
|
+
const data = t3;
|
|
37
|
+
const capture = t2 === void 0 ? false : t2;
|
|
32
38
|
const host = React.useRef(null);
|
|
33
|
-
let
|
|
39
|
+
let t4;
|
|
34
40
|
if ($[2] !== data || $[3] !== studio) {
|
|
35
|
-
|
|
41
|
+
t4 = {
|
|
36
42
|
studio,
|
|
37
43
|
data
|
|
38
44
|
};
|
|
39
45
|
$[2] = data;
|
|
40
46
|
$[3] = studio;
|
|
41
|
-
$[4] =
|
|
42
|
-
} else
|
|
43
|
-
const latest = React.useRef(
|
|
47
|
+
$[4] = t4;
|
|
48
|
+
} else t4 = $[4];
|
|
49
|
+
const latest = React.useRef(t4);
|
|
44
50
|
const latestNavigate = React.useRef(navigate);
|
|
45
51
|
const [height, setHeight] = React.useState(null);
|
|
46
|
-
let
|
|
52
|
+
let t5;
|
|
47
53
|
if ($[5] !== data || $[6] !== navigate || $[7] !== studio) {
|
|
48
|
-
|
|
54
|
+
t5 = () => {
|
|
49
55
|
latest.current = {
|
|
50
56
|
studio,
|
|
51
57
|
data
|
|
@@ -59,55 +65,59 @@ function useArtifactHost(t0) {
|
|
|
59
65
|
$[5] = data;
|
|
60
66
|
$[6] = navigate;
|
|
61
67
|
$[7] = studio;
|
|
62
|
-
$[8] =
|
|
63
|
-
} else
|
|
64
|
-
React.useEffect(
|
|
65
|
-
let
|
|
66
|
-
if ($[9] !== size) {
|
|
67
|
-
|
|
68
|
+
$[8] = t5;
|
|
69
|
+
} else t5 = $[8];
|
|
70
|
+
React.useEffect(t5);
|
|
71
|
+
let t6;
|
|
72
|
+
if ($[9] !== capture || $[10] !== size) {
|
|
73
|
+
t6 = (frame) => {
|
|
68
74
|
if (!frame) return;
|
|
69
75
|
const options = {
|
|
70
76
|
size,
|
|
71
77
|
onHeight: setHeight,
|
|
72
78
|
navigate: (path) => void latestNavigate.current({ to: path })
|
|
73
79
|
};
|
|
74
|
-
const connected = connectArtifactHost(frame,
|
|
80
|
+
const connected = connectArtifactHost(frame, {
|
|
81
|
+
...latest.current,
|
|
82
|
+
capture
|
|
83
|
+
}, options);
|
|
75
84
|
host.current = connected;
|
|
76
85
|
return () => {
|
|
77
86
|
connected.disconnect();
|
|
78
87
|
if (host.current === connected) host.current = null;
|
|
79
88
|
};
|
|
80
89
|
};
|
|
81
|
-
$[9] =
|
|
82
|
-
$[10] =
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
$[9] = capture;
|
|
91
|
+
$[10] = size;
|
|
92
|
+
$[11] = t6;
|
|
93
|
+
} else t6 = $[11];
|
|
94
|
+
const ref = t6;
|
|
85
95
|
if (size !== "content" || height === null) {
|
|
86
|
-
let
|
|
87
|
-
if ($[
|
|
88
|
-
|
|
89
|
-
$[
|
|
90
|
-
$[
|
|
91
|
-
} else
|
|
92
|
-
return
|
|
96
|
+
let t7;
|
|
97
|
+
if ($[12] !== ref) {
|
|
98
|
+
t7 = { ref };
|
|
99
|
+
$[12] = ref;
|
|
100
|
+
$[13] = t7;
|
|
101
|
+
} else t7 = $[13];
|
|
102
|
+
return t7;
|
|
93
103
|
}
|
|
94
|
-
let t6;
|
|
95
|
-
if ($[13] !== height) {
|
|
96
|
-
t6 = { height };
|
|
97
|
-
$[13] = height;
|
|
98
|
-
$[14] = t6;
|
|
99
|
-
} else t6 = $[14];
|
|
100
104
|
let t7;
|
|
101
|
-
if ($[
|
|
102
|
-
t7 = {
|
|
105
|
+
if ($[14] !== height) {
|
|
106
|
+
t7 = { height };
|
|
107
|
+
$[14] = height;
|
|
108
|
+
$[15] = t7;
|
|
109
|
+
} else t7 = $[15];
|
|
110
|
+
let t8;
|
|
111
|
+
if ($[16] !== ref || $[17] !== t7) {
|
|
112
|
+
t8 = {
|
|
103
113
|
ref,
|
|
104
|
-
style:
|
|
114
|
+
style: t7
|
|
105
115
|
};
|
|
106
|
-
$[
|
|
107
|
-
$[16] = t6;
|
|
116
|
+
$[16] = ref;
|
|
108
117
|
$[17] = t7;
|
|
109
|
-
|
|
110
|
-
|
|
118
|
+
$[18] = t8;
|
|
119
|
+
} else t8 = $[18];
|
|
120
|
+
return t8;
|
|
111
121
|
}
|
|
112
122
|
/**
|
|
113
123
|
* The Artifact Data to inline in an artifact's `srcDoc`: the data its source first rendered
|
|
@@ -136,4 +146,4 @@ function useInitialArtifactData(source, data) {
|
|
|
136
146
|
}
|
|
137
147
|
|
|
138
148
|
//#endregion
|
|
139
|
-
export { ArtifactStudioContext, ArtifactsRunContext, useArtifactHost, useInitialArtifactData };
|
|
149
|
+
export { ArtifactCaptureContext, ArtifactStudioContext, ArtifactsRunContext, useArtifactHost, useInitialArtifactData };
|
|
@@ -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
|
|
@@ -26,6 +26,10 @@ export type ArtifactRenderProps = ArtifactFrameProps & {
|
|
|
26
26
|
ref: React.RefCallback<HTMLIFrameElement>;
|
|
27
27
|
/** For `size: "content"`, the height the artifact's content needs, once it reports it. */
|
|
28
28
|
style?: React.CSSProperties;
|
|
29
|
+
/** The artifact field's name, so the look document's browser finds the frame. */
|
|
30
|
+
"data-camox-artifact"?: string;
|
|
31
|
+
/** The id of the Repeatable Item holding the artifact field, when an item's. */
|
|
32
|
+
"data-camox-item"?: string;
|
|
29
33
|
};
|
|
30
34
|
//#endregion
|
|
31
35
|
export {};
|
|
@@ -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,5 +1,6 @@
|
|
|
1
1
|
import { artifactThemeColors } from "./artifactColors.js";
|
|
2
2
|
import { observeArtifactTheme, readArtifactTheme } from "./artifactTheme.js";
|
|
3
|
+
import { LOOK_ARTIFACT_CAPTURE } from "@camox/api-contract/drafts";
|
|
3
4
|
|
|
4
5
|
//#region src/core/lib/artifactHost.ts
|
|
5
6
|
function isRuntimeMessage(data) {
|
|
@@ -134,6 +135,34 @@ function connectArtifactHost(frame, initialState, options = {}) {
|
|
|
134
135
|
channel
|
|
135
136
|
}, "*");
|
|
136
137
|
};
|
|
138
|
+
const answers = /* @__PURE__ */ new Map();
|
|
139
|
+
let lastRequest = 0;
|
|
140
|
+
let whenReady = [];
|
|
141
|
+
const ask = (type, payload = {}) => new Promise((resolve) => {
|
|
142
|
+
const id = ++lastRequest;
|
|
143
|
+
answers.set(id, resolve);
|
|
144
|
+
const send = () => post(type, {
|
|
145
|
+
...payload,
|
|
146
|
+
id
|
|
147
|
+
});
|
|
148
|
+
if (ready) send();
|
|
149
|
+
else whenReady.push(send);
|
|
150
|
+
});
|
|
151
|
+
const capture = {
|
|
152
|
+
timeline: async () => (await ask("timeline")).timeline ?? null,
|
|
153
|
+
seek: async (t) => {
|
|
154
|
+
const { error } = await ask("seek", { t });
|
|
155
|
+
return typeof error === "string" ? { error } : {};
|
|
156
|
+
},
|
|
157
|
+
guardrail: async () => {
|
|
158
|
+
const { findings } = await ask("guardrail");
|
|
159
|
+
return Array.isArray(findings) ? findings : [];
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
if (initialState.capture) Object.defineProperty(frame, LOOK_ARTIFACT_CAPTURE, {
|
|
163
|
+
value: capture,
|
|
164
|
+
configurable: true
|
|
165
|
+
});
|
|
137
166
|
const sendStudio = () => post("studio", { studio: state.studio });
|
|
138
167
|
const sendData = () => post("data", { data: state.data ?? {} });
|
|
139
168
|
let sentTheme = null;
|
|
@@ -163,10 +192,20 @@ function connectArtifactHost(frame, initialState, options = {}) {
|
|
|
163
192
|
if (message.camox === "ready") {
|
|
164
193
|
ready = true;
|
|
165
194
|
observeViewport(false);
|
|
195
|
+
if (initialState.capture) post("capture");
|
|
166
196
|
sendStudio();
|
|
167
197
|
sendData();
|
|
168
198
|
sendTheme(true);
|
|
169
199
|
if (options.size === "content") post("measure");
|
|
200
|
+
for (const send of whenReady) send();
|
|
201
|
+
whenReady = [];
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (message.camox === "timeline" || message.camox === "seeked" || message.camox === "guardrail") {
|
|
205
|
+
const answer = typeof message.id === "number" ? answers.get(message.id) : void 0;
|
|
206
|
+
if (!answer) return;
|
|
207
|
+
answers.delete(message.id);
|
|
208
|
+
answer(message);
|
|
170
209
|
return;
|
|
171
210
|
}
|
|
172
211
|
if (message.camox === "height") {
|
|
@@ -197,6 +236,7 @@ function connectArtifactHost(frame, initialState, options = {}) {
|
|
|
197
236
|
page.removeEventListener("message", onMessage);
|
|
198
237
|
observeViewport(false);
|
|
199
238
|
stopObservingTheme();
|
|
239
|
+
if (initialState.capture) Reflect.deleteProperty(frame, LOOK_ARTIFACT_CAPTURE);
|
|
200
240
|
}
|
|
201
241
|
};
|
|
202
242
|
}
|
|
@@ -22,6 +22,25 @@
|
|
|
22
22
|
* - host → frame: `measure`, for frames sized to their content. The runtime then reports the
|
|
23
23
|
* document's `height` whenever it changes.
|
|
24
24
|
* - runtime → page: `navigate` with an `href`. The host acts only with transient user activation.
|
|
25
|
+
* - host → frame: `capture`, from the look document's hosts only: the runtime enters capture mode,
|
|
26
|
+
* where real time never advances and the Timeline only moves when seeked. Only in capture mode
|
|
27
|
+
* does it answer `timeline` (→ `timeline` with the same `id` and the declared `timeline`, or
|
|
28
|
+
* `null` without one) and `seek` with `t` in ms (→ `seeked` with the same `id`, once the frame at
|
|
29
|
+
* that time painted, and an `error` when `render` threw) and `guardrail` (→ `guardrail` with the
|
|
30
|
+
* same `id` and its `findings`, see `LookGuardrailFinding`). On the website and in the studio
|
|
31
|
+
* they go unanswered.
|
|
32
|
+
*
|
|
33
|
+
* The Timeline (`camox.timeline`) is declared once, synchronously, by the source, which draws its
|
|
34
|
+
* first frame at once, before the body is revealed. On the website its clock calls `render(t)` in
|
|
35
|
+
* `requestAnimationFrame` with real time, wrapped at `duration` when looping and held at the end
|
|
36
|
+
* otherwise. A looping Timeline plays from load, a non-looping one from when its frame is first
|
|
37
|
+
* visible; both pause while the frame is out of the viewport (the runtime observes it as
|
|
38
|
+
* `onViewport` does) and resume where they were. With `prefers-reduced-motion: reduce`, it shows
|
|
39
|
+
* its poster's frame and never plays. Its Tracks are compiled to Web Animations, one per
|
|
40
|
+
* element and property, which play on the compositor from the same start time and loop with it;
|
|
41
|
+
* in capture mode they're paused, and seeking sets their `currentTime`. The `type` and `count`
|
|
42
|
+
* helpers register with it and are drawn from the same `t`, before `render`, so they restart with
|
|
43
|
+
* each loop and seek exactly.
|
|
25
44
|
*
|
|
26
45
|
* The theme part applies the tokens to the artifact's `:root` and keeps the body hidden until the
|
|
27
46
|
* first theme arrives, so the artifact never paints in the wrong colors, or until a short fallback
|
|
@@ -32,7 +51,7 @@
|
|
|
32
51
|
* `plugins/minifyArtifactRuntime.ts`), so it must stay one template literal without
|
|
33
52
|
* interpolations or backslashes.
|
|
34
53
|
*/
|
|
35
|
-
const ARTIFACT_RUNTIME = "(()=>{\"use strict\";let e=window.parent,t=null,n=null,r,i,a=new Set,o=location.hash.slice(1),s=()=>{if(i!==void 0)return r;let e=document.querySelector(`script[data-camox-data]`);try{r=JSON.parse(e?e.textContent:decodeURIComponent(o)),(!r||typeof r!=`object`||Array.isArray(r))&&(r={})}catch{r={}}return i=JSON.stringify(r),r},c=(()=>{let e=new Set,t=[],n=Object.freeze({tokens:Object.freeze({}),colors:Object.freeze({})}),r=document.createElement(`style`);r.textContent=`body { visibility: hidden !important; }`,document.head.append(r);let i=()=>r.remove();setTimeout(i,300);let a=e=>Number.isFinite(e)?Math.min(255,Math.max(0,Math.round(e))):0;return{get current(){return n},receive(r){let o={},s={},c=r.colors||{};for(let[e,t]of Object.entries(r.tokens||{})){if(!e.startsWith(`--`)||typeof t!=`string`)continue;o[e]=t;let n=Object.hasOwn(c,e)?c[e]:null;n&&typeof n==`object`&&(s[e]=Object.freeze({r:a(n.r),g:a(n.g),b:a(n.b)}))}let l=document.documentElement.style;for(let e of t)Object.hasOwn(o,e)||l.removeProperty(e);for(let[e,t]of Object.entries(o))l.setProperty(e,t);t=Object.keys(o),i(),n=Object.freeze({tokens:Object.freeze(o),colors:Object.freeze(s)});for(let t of[...e])t(n)},subscribe(t){return e.add(t),()=>{e.delete(t)}}}})(),l=new Set,u=null,d=null,f=null,p=()=>{let e=Math.ceil(document.documentElement.getBoundingClientRect().height);e!==f&&(f=e,m(`height`,{height:f}))},m=(n,r)=>{t&&e.postMessage({...r,camox:n,channel:t},`*`)},h=()=>m(`observe-viewport`,{observe:l.size>0}),g={studio(e){let t=e.studio;n=t?Object.freeze({editing:!!t.editing,canvas:!!t.canvas}):null},data(e){s();let t=JSON.stringify(e.data??{});if(t!==i){r=JSON.parse(t),i=t;for(let e of[...a])e(r)}},theme:c.receive,measure(){f=null,d||(d=new ResizeObserver(p),d.observe(document.documentElement)),p()},viewport(e){let{progress:t,visibleRatio:n}=e;if(typeof t==`number`&&typeof n==`number`){u=Object.freeze({progress:t,visibleRatio:n}),document.documentElement.style.setProperty(`--camox-progress`,String(t));for(let e of l)e(u)}}};window.addEventListener(`message`,e=>{let n=e.data;if(n&&typeof n.camox==`string`){if(n.camox===`connect`){if(typeof n.channel!=`string`||n.channel===t)return;t=n.channel,m(`ready`),l.size>0&&h()}else t&&n.channel===t&&Object.hasOwn(g,n.camox)&&g[n.camox](n)}});let _=Object.freeze({get studio(){return n},get data(){return s()},onData(e){return a.add(e),()=>{a.delete(e)}},get theme(){return c.current},onTheme:c.subscribe,navigate(e){m(`navigate`,{href:String(e)})},onViewport(e){if(typeof e!=`function`)throw TypeError(`camox.onViewport needs a callback`);let t=t=>e(t);return l.add(t),l.size===1?h():u&&queueMicrotask(()=>l.has(t)&&e(u)),()=>{l.delete(t)&&l.size===0&&h()}}});Object.defineProperty(window,\"camox\",{value:_,enumerable:!0}),e!==window&&e.postMessage({camox:`hello`},`*`)})();";
|
|
54
|
+
const ARTIFACT_RUNTIME = "(()=>{\"use strict\";let e=window.parent,t=null,n=null,r,i,a=new Set,o=location.hash.slice(1),s=()=>{if(i!==void 0)return r;let e=document.querySelector(`script[data-camox-data]`);try{r=JSON.parse(e?e.textContent:decodeURIComponent(o)),(!r||typeof r!=`object`||Array.isArray(r))&&(r={})}catch{r={}}return i=JSON.stringify(r),r},c=(()=>{let e={setTimeout:window.setTimeout.bind(window),setInterval:window.setInterval.bind(window),clearTimeout:window.clearTimeout.bind(window)},t=new Map;window.setTimeout=function(n,r,...i){if(typeof n!=`function`)return e.setTimeout(n,r,...i);let a=e.setTimeout(function(){return t.delete(a),n.apply(this,arguments)},r,...i);return t.set(a,{kind:`setTimeout`,delay:Number(r)||0}),a},window.setInterval=function(n,r,...i){let a=e.setInterval(n,r,...i);return typeof n==`function`&&t.set(a,{kind:`setInterval`,delay:Number(r)||0}),a};let n=function(n){t.delete(n),e.clearTimeout(n)};return window.clearTimeout=n,window.clearInterval=n,{later:e.setTimeout,get live(){return[...t.values()]}}})(),l=(()=>{let e=new Set,t=[],n=Object.freeze({tokens:Object.freeze({}),colors:Object.freeze({})}),r=document.createElement(`style`);r.textContent=`body { visibility: hidden !important; }`,document.head.append(r);let i=()=>r.remove();c.later(i,300);let a=e=>Number.isFinite(e)?Math.min(255,Math.max(0,Math.round(e))):0;return{get current(){return n},receive(r){let o={},s={},c=r.colors||{};for(let[e,t]of Object.entries(r.tokens||{})){if(!e.startsWith(`--`)||typeof t!=`string`)continue;o[e]=t;let n=Object.hasOwn(c,e)?c[e]:null;n&&typeof n==`object`&&(s[e]=Object.freeze({r:a(n.r),g:a(n.g),b:a(n.b)}))}let l=document.documentElement.style;for(let e of t)Object.hasOwn(o,e)||l.removeProperty(e);for(let[e,t]of Object.entries(o))l.setProperty(e,t);t=Object.keys(o),i(),n=Object.freeze({tokens:Object.freeze(o),colors:Object.freeze(s)});for(let t of[...e])t(n)},subscribe(t){return e.add(t),()=>{e.delete(t)}}}})(),u=new Set,d=null,f=null,p=null,m=()=>{let e=Math.ceil(document.documentElement.getBoundingClientRect().height);e!==p&&(p=e,h(`height`,{height:p}))},h=(n,r)=>{t&&e.postMessage({...r,camox:n,channel:t},`*`)},g=()=>h(`observe-viewport`,{observe:u.size>0}),_=(e,t,n,r)=>{let i=(e,t,n)=>3*(1-n)*(1-n)*n*e+3*(1-n)*n*n*t+n*n*n,a=(e,t,n)=>3*(1-n)*(1-n)*e+6*(1-n)*n*(t-e)+3*n*n*(1-t);return o=>{if(o<=0)return 0;if(o>=1)return 1;let s=o;for(let c=0;c<8;c++){let c=i(e,n,s)-o;if(Math.abs(c)<1e-7)return i(t,r,s);let l=a(e,n,s);if(Math.abs(l)<1e-6)break;s-=c/l}let c=0,l=1;s=o;for(let t=0;t<40;t++){let t=i(e,n,s);if(Math.abs(t-o)<1e-7)break;t<o?c=s:l=s,s=(c+l)/2}return i(t,r,s)}},v=Object.freeze({travel:[.45,0,.1,1],arrive:[.25,.8,.25,1]}),y=Object.freeze({linear:e=>Math.min(1,Math.max(0,e)),travel:_(...v.travel),arrive:_(...v.arrive)}),b=e=>typeof e==`string`&&Object.hasOwn(y,e),x=e=>{if(e===void 0)return y.linear;if(typeof e==`function`)return e;if(b(e))return y[e];throw TypeError(`Unknown easing `+String(e)+`: use travel, arrive, linear or a function`)},S=(()=>{let e=[`transform`,`opacity`],t=e=>e===`linear`?`linear`:`cubic-bezier(`+v[e].join(`, `)+`)`,n=()=>Object.freeze({width:window.innerWidth,height:window.innerHeight}),r=(e,t)=>({index:e.index,text:e.name+` is skipped, so nothing it animates moves: `+t+`.`}),i=(e,t)=>{if(!e||typeof e!=`object`)return`a Track is an object`;let{el:n,at:r,keyframes:i}=e;if(!n||typeof n.animate!=`function`)return`it needs an el, the element it moves`;if(typeof r!=`number`||!(r>=0))return`it needs an at, when it starts in ms`;let a=e.duration;if(typeof a!=`number`||!(a>=0)||!(r+a<=t))return`it needs a duration in ms, and must end by the Timeline's duration (`+t+` ms)`;if(e.ease!==void 0&&!b(e.ease))return`it has an unknown easing `+String(e.ease)+`: use travel, arrive or linear`;if(typeof i!=`function`&&(!i||typeof i!=`object`))return`it needs keyframes, or a function of the artifact's size giving them`},a=(e,t)=>{if(e===void 0)return{tracks:[],skipped:[]};if(!Array.isArray(e))throw TypeError(`A Timeline's tracks must be an array of Tracks`);let n=[],a=[];return e.forEach((e,o)=>{let s=`Track `+o,c=i(e,t);if(c){a.push(r({index:o,name:s},c));return}let{el:l,at:u,keyframes:d}=e,f=e.ease===void 0?`linear`:e.ease;n.push({name:s,index:o,el:l,at:u,end:u+e.duration,ease:f,keyframes:d})}),{tracks:n,skipped:a}},o=(t,n)=>{let r=typeof t.keyframes==`function`?t.keyframes(n):t.keyframes;if(!r||typeof r!=`object`)return{problem:`its keyframes must be an object`};let i={};for(let[t,n]of Object.entries(r)){if(!e.includes(t))return{problem:`Tracks animate transform and opacity only, not `+t+`: draw it from render(t)`};if(!Array.isArray(n)||n.length!==2)return{problem:`its `+t+` needs two values, [from, to]`};i[t]=n}return{frames:i}},s=(e,i,a)=>{let s=new Map,c=[],l=n();for(let t of[...e].sort((e,t)=>e.at-t.at||e.index-t.index)){let{frames:e,problem:n}=o(t,l);if(n)c.push(r(t,n));else for(let[n,[r,i]]of Object.entries(e)){s.has(t.el)||s.set(t.el,new Map);let e=s.get(t.el);e.has(n)||e.set(n,[]),e.get(n).push({track:t,from:r,to:i})}}let u=[],d=[];for(let[e,n]of s)for(let[r,o]of n){let n=(e,n,a)=>({offset:e/i,[r]:n,easing:t(a)}),s=[n(0,o[0].from,`linear`)],c=0,l=null,f=null;for(let{track:t,from:i,to:a}of o){if(f&&t.at<f.end){let n=Math.min(f.end,t.end);d.push({el:e,property:r,tracks:[f.index,t.index],from:t.at,to:n})}(!f||t.end>f.end)&&(f=t);let o=Math.max(t.at,c),u=Math.max(t.end,o);l&&s.push(n(o,l.to,`linear`)),s.push(n(o,i,t.ease),n(u,a,`linear`)),c=u,l={track:t,to:a}}s.push(n(i,l.to,`linear`)),u.push(e.animate(s,{duration:i,iterations:a?1/0:1,fill:`both`}))}return{animations:u,overlaps:d,skipped:c}};return(e,t,n)=>{let{tracks:r,skipped:i}=a(e,t),o=s(r,t,n),c=null,l=0,u=()=>{for(let e of o.animations)c===null?(e.pause(),e.currentTime=Math.min(t,Math.max(0,l))):e.startTime=c};return r.some(e=>typeof e.keyframes==`function`)&&window.addEventListener(`resize`,()=>{for(let e of o.animations)e.cancel();o=s(r,t,n),u()}),{get animations(){return o.animations},get overlaps(){return o.overlaps},get skipped(){return[...i,...o.skipped].sort((e,t)=>e.index-t.index)},play(e){c=e,u()},seek(e){c=null,l=e,u()}}}})(),C=(()=>{let e=null,t=null,n=!1,r=0,i=null,a=0,o=null,s=!1,l=t=>{let{duration:n,loop:r}=e;return r?(t%n+n)%n:Math.min(n,Math.max(0,t))},d=[],f=0,p=t=>{f=t;for(let e of d)e(t);e.render&&e.render(t)},m=e=>{t.seek(e),p(e)},_=()=>{let e=document.timeline?document.timeline.currentTime:null;return typeof e==`number`?e:performance.now()},v=()=>{r&&cancelAnimationFrame(r),r=0},y=t=>{r=0;let n=l(t-i);p(n),e.loop||n<e.duration?r=requestAnimationFrame(y):(a=e.duration,i=null)},b=()=>{v(),i=_()-a,t.play(i),r=requestAnimationFrame(y)},x=()=>{i!==null&&(a=_()-i,i=null,v(),m(l(a)))},C=()=>{if(n||s)return;let{loop:t,duration:r}=e;(o===null?t:o)&&(t||a<r)?i===null&&b():x()},w=e=>{o=e.visibleRatio>0,C()},T=()=>{let{poster:t,marks:n,loop:r,duration:i}=e;return t===null?r?0:i:n[t]},E=e=>{let t=!1,n=()=>{t||(t=!0,e())};requestAnimationFrame(()=>requestAnimationFrame(n)),c.later(n,200)};return{inspect(n){if(!e)return{animations:[],skipped:[],overlaps:[],ends:null};let{animations:r,skipped:i,overlaps:a}=t;if(!e.loop||!n)return{animations:r,skipped:i,overlaps:a,ends:null};let o=f,s=e.duration-1;try{m(0);let e=n();return m(s),{animations:r,skipped:i,overlaps:a,ends:{first:e,last:n(),at:s}}}finally{m(o)}},register(t,n){if(!e)throw Error(`camox.`+t+` needs a Timeline: call camox.timeline first`);d.push(n),n(f)},declare(r){if(e)throw Error(`camox.timeline can be called once per artifact`);if(!r||typeof r!=`object`)throw TypeError(`camox.timeline needs its options: duration, marks, render`);let{duration:i}=r;if(typeof i!=`number`||!Number.isFinite(i)||i<=0)throw TypeError(`camox.timeline needs a duration: a positive number of milliseconds`);let a={};for(let[e,t]of Object.entries(r.marks||{})){if(typeof t!=`number`||!(t>=0&&t<=i))throw RangeError(`The Mark `+e+` must be a time from 0 to the duration`);a[e]=t}let o=r.poster===void 0?null:String(r.poster);if(o!==null&&!Object.hasOwn(a,o))throw RangeError(`The poster `+o+` must name a Mark`);let{render:c}=r;if(c!==void 0&&typeof c!=`function`)throw TypeError(`A Timeline's render must be a function of the time`);let l=r.loop===!0;t=S(r.tracks,i,l),e=Object.freeze({duration:i,loop:l,marks:Object.freeze(a),poster:o,render:c}),s=!n&&typeof matchMedia==`function`&&matchMedia(`(prefers-reduced-motion: reduce)`).matches,m(s?T():0),!(n||s)&&(u.add(w),u.size===1&&g(),C())},capture(){n=!0,e&&(v(),i=null,u.delete(w)&&u.size===0&&g(),m(0))},describe(t){if(!n)return;let{duration:r,loop:i,marks:a,poster:o}=e||{};h(`timeline`,{id:t.id,timeline:e?{duration:r,loop:i,marks:a,poster:o}:null})},seek(t){if(!n)return;let r=Number(t.t),i;if(e&&Number.isFinite(r))try{m(l(r))}catch(e){i=`render(`+r+`) threw: `+String(e&&e.message?e.message:e)}E(()=>h(`seeked`,i===void 0?{id:t.id}:{id:t.id,error:i}))}}})(),w=(()=>{let e=(e,t)=>{if(!(t instanceof Element))throw TypeError(`camox.`+e+` needs an element to write in`);return t},t=(e,t,n,r,i)=>{if(n===void 0&&r!==void 0)return r;if(typeof n!=`number`||!Number.isFinite(n)||n<0||i&&n===0)throw TypeError(`camox.`+e+`'s `+t+` must be a `+(i?`positive `:``)+`number`);return n},n=e=>{let[,t=``]=String(e).split(`.`);return/^[0-9]+$/.test(t)?Math.min(20,t.length):0};return{type(n,r,i={}){let a=e(`type`,n),o=t(`type`,`at`,i.at,0),s=t(`type`,`cps`,i.cps,20,!0),c=typeof Intl.Segmenter==`function`?Array.from(new Intl.Segmenter().segment(String(r)),e=>e.segment):Array.from(String(r)),l=o+c.length*1e3/s,u=document.createElement(`span`),d=document.createTextNode(``),f=document.createElement(`span`);f.setAttribute(`aria-hidden`,`true`),f.setAttribute(`data-camox-caret`,``),f.style.cssText=`border-left: max(1px, 0.07em) solid currentColor; margin-right: calc(-1 * max(1px, 0.07em));`,u.append(d,f),a.replaceChildren(u);let p=!0;C.register(`type`,e=>{let t=e<o?0:Math.min(c.length,Math.floor((e-o)*s/1e3)+1),n=c.slice(0,t).join(``);d.data!==n&&(d.data=n);let r=e<o?o-e:e-l,i=r<0||Math.floor(r/530)%2==0;i!==p&&(p=i,f.style.visibility=i?``:`hidden`)})},count(r,i){let a=e(`count`,r);if(!i||typeof i.to!=`number`||!Number.isFinite(i.to))throw TypeError(`camox.count needs the number to count to`);let{to:o}=i,s=i.from===void 0?0:i.from;if(typeof s!=`number`||!Number.isFinite(s))throw TypeError(`camox.count's from must be a number`);let c=t(`count`,`at`,i.at,0),l=t(`count`,`duration`,i.duration,1e3,!0),u=x(i.ease===void 0?`arrive`:i.ease),d=i.format;if(d===void 0){let e=Math.max(n(s),n(o)),t=new Intl.NumberFormat(void 0,{minimumFractionDigits:e,maximumFractionDigits:e});d=e=>t.format(e)}else if(typeof d!=`function`)throw TypeError(`camox.count's format must be a function of the value`);let f=null;C.register(`count`,e=>{let t=e>=c+l?o:s+(o-s)*u(Math.max(0,e-c)/l),n=String(d(t));n!==f&&(f=n,a.textContent=n)})}}})(),T=(()=>{let e=!1,t=new Set,n=/-?(?:[0-9]+[.]?[0-9]*|[.][0-9]+)(?:e[-+]?[0-9]+)?/g,r=e=>{if(!e||!e.tagName)return`an element`;let t=e.tagName.toLowerCase();if(e.id)return t+`#`+e.id;let n=Array.from(e.classList).slice(0,2);if(n.length)return t+`.`+n.join(`.`);let i=e.parentElement;return!i||i===document.documentElement?t:r(i)+` > `+t+`:nth-child(`+(Array.from(i.children).indexOf(e)+1)+`)`},i=e=>{let t=e.effect,n=t&&t.target,i=(n?r(n):`no element`)+(t&&t.pseudoElement||``);return typeof CSSAnimation==`function`&&e instanceof CSSAnimation?`The CSS animation `+e.animationName+` on `+i+` plays on its own, outside the Timeline, so captures can't seek it: make it a Track, or draw it from render(t).`:typeof CSSTransition==`function`&&e instanceof CSSTransition?`A CSS transition of `+e.transitionProperty+` on `+i+` ran without a visitor's hover or press: motion that plays on its own goes through the Timeline, as a Track or from render(t).`:`A Web Animation on `+i+` was made by the source and plays outside the Timeline: declare it as a Track, or pause it and set its currentTime from render(t).`},a=()=>{if(!e||typeof document.getAnimations!=`function`)return;let n=new Set(C.inspect().animations);for(let e of document.getAnimations())n.has(e)||e.playState===`paused`||e.playState===`idle`||t.add(i(e))},o=()=>{let e=new Map;for(let{kind:t,delay:n}of c.live){let r=t+` `+n;e.has(r)||e.set(r,{kind:t,delay:n,count:0}),e.get(r).count++}return[...e.values()].map(({kind:e,delay:t,count:n})=>({kind:`timer`,text:(e===`setInterval`?`A setInterval every `+t+` ms is still running`:`A setTimeout of `+t+` ms is still pending`)+(n>1?` (`+n+` of them)`:``)+`: time stands still in captures, so what timers move never shows there, and they don't follow the Timeline's loop. Draw it from render(t) instead.`}))},s=e=>{let t=new Map,n=(r,i,a)=>{let o=getComputedStyle(r),s=a&&o.display!==`none`,c=i*Number(o.opacity),l=s&&o.visibility!==`hidden`&&c>.01;if(!r.hasAttribute(`data-camox-caret`)){let n={};for(let e of r.attributes)n[e.name+` attribute`]=e.value;let i=``;for(let e of r.childNodes)e.nodeType===Node.TEXT_NODE&&(i+=e.data);if(i&&(n.text=i),e.has(r)&&(n.transform=new DOMMatrix(o.transform).toString(),n.opacity=o.opacity),r instanceof HTMLCanvasElement)try{n[`canvas drawing`]=r.toDataURL()}catch{}t.set(r,{visible:l,values:n})}for(let e of r.children)n(e,c,s)};return n(document.documentElement,1,!0),t},l=(e,t)=>{if(e===t)return!0;if(typeof e!=`string`||typeof t!=`string`||e.replace(n,`0`)!==t.replace(n,`0`))return!1;let r=t.match(n)||[];return(e.match(n)||[]).every((e,t)=>{let n=Number(e),i=Number(r[t]);return Math.abs(n-i)<=.01*Math.max(1,Math.abs(n),Math.abs(i))})},u=e=>JSON.stringify(e.length>40?e.slice(0,39)+`…`:e),d=()=>{let e=new Set(C.inspect().animations.map(e=>e.effect&&e.effect.target)),t;try{t=C.inspect(()=>s(e)).ends}catch{return null}if(!t)return null;let{first:n,last:i,at:a}=t,o=[];for(let e of new Set([...n.keys(),...i.keys()])){let t=n.get(e),s=i.get(e);if(!t||!s)(t||s).visible&&o.push(r(e)+` is there at only one end`);else if(t.visible||s.visible)for(let n of new Set([...Object.keys(t.values),...Object.keys(s.values)])){let i=t.values[n],c=s.values[n];l(i,c)||o.push(n===`canvas drawing`?r(e)+`'s canvas drawing`:r(e)+`'s `+n+` (`+(i===void 0?`none`:u(i))+` at 0 ms, `+(c===void 0?`none`:u(c))+` at `+a+` ms)`)}}if(!o.length)return null;let c=o.slice(0,4).join(`; `)+(o.length>4?`; and `+(o.length-4)+` more`:``);return{kind:`loop-cut`,text:`Loop cut: the last frame (`+a+` ms) differs from the first (0 ms), so the loop jumps at its restart: `+c+`. Bring them back to how they start before the end, or hide them while they reset.`}};return{get watching(){return e},watch(){e=!0,a()},sample:a,report(){let e=d();a();let n=[...t].map(e=>({kind:`animation`,text:e}));n.push(...o());let{skipped:i,overlaps:s}=C.inspect();for(let{text:e}of i)n.push({kind:`track`,text:e});for(let{el:e,property:t,tracks:i,from:a,to:o}of s)n.push({kind:`overlap`,text:`Tracks `+i[0]+` and `+i[1]+` both animate the `+t+` of `+r(e)+`, from `+a+` to `+o+` ms: the later one waits for the earlier to end, so it jumps. Start it once the earlier one ends.`});return e&&n.push(e),n}}})(),E={studio(e){let t=e.studio;n=t?Object.freeze({editing:!!t.editing,canvas:!!t.canvas}):null},data(e){s();let t=JSON.stringify(e.data??{});if(t!==i){r=JSON.parse(t),i=t;for(let e of[...a])e(r)}},theme:l.receive,measure(){p=null,f||(f=new ResizeObserver(m),f.observe(document.documentElement)),m()},viewport(e){let{progress:t,visibleRatio:n}=e;if(typeof t==`number`&&typeof n==`number`){d=Object.freeze({progress:t,visibleRatio:n}),document.documentElement.style.setProperty(`--camox-progress`,String(t));for(let e of u)e(d)}},capture(e){C.capture(e),T.watch()},timeline:C.describe,seek(e){C.seek(e),T.sample()},guardrail(e){T.watching&&h(`guardrail`,{id:e.id,findings:T.report()})}};window.addEventListener(`message`,e=>{let n=e.data;if(n&&typeof n.camox==`string`){if(n.camox===`connect`){if(typeof n.channel!=`string`||n.channel===t)return;t=n.channel,h(`ready`),u.size>0&&g()}else t&&n.channel===t&&Object.hasOwn(E,n.camox)&&E[n.camox](n)}});let D=Object.freeze({get studio(){return n},get data(){return s()},onData(e){return a.add(e),()=>{a.delete(e)}},get theme(){return l.current},onTheme:l.subscribe,navigate(e){h(`navigate`,{href:String(e)})},onViewport(e){if(typeof e!=`function`)throw TypeError(`camox.onViewport needs a callback`);let t=t=>e(t);return u.add(t),u.size===1?g():d&&queueMicrotask(()=>u.has(t)&&e(d)),()=>{u.delete(t)&&u.size===0&&g()}},timeline:C.declare,interpolate(e,t,n,r){let[i,a]=t,[o,s]=n,c=x(r&&r.ease),l=a===i?e<i?0:1:(e-i)/(a-i);return o+(s-o)*c(Math.min(1,Math.max(0,l)))},random(e){let t=String(e),n=2166136261;for(let e=0;e<t.length;e++)n=Math.imul(n^t.charCodeAt(e),16777619);return n=Math.imul(n^n>>>16,2246822507),n=Math.imul(n^n>>>13,3266489909),((n^n>>>16)>>>0)/4294967296},type:w.type,count:w.count});Object.defineProperty(window,\"camox\",{value:D,enumerable:!0}),e!==window&&e.postMessage({camox:`hello`},`*`)})();";
|
|
36
55
|
|
|
37
56
|
//#endregion
|
|
38
57
|
export { ARTIFACT_RUNTIME };
|
|
@@ -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
|
}
|