@getquick/content 0.3.1 → 0.4.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/README.md +87 -0
- package/dist/consent-astro.js +2 -2
- package/dist/consent-client.js +19 -6
- package/dist/consent-server.js +4 -37
- package/dist/consent.js +2 -2
- package/dist/copy-DLto_bWj.js +163 -0
- package/dist/descriptor-B-e7gHi1.d.ts +143 -0
- package/dist/descriptor-x8kHFQ79.js +205 -0
- package/dist/design-client.d.ts +19 -0
- package/dist/design-client.js +519 -0
- package/dist/{dist-D4-CMkrf.js → dist-5jNKLmbn.js} +198 -3
- package/dist/{embeds-p9SyGNZI.js → embeds-CJJemAmE.js} +2 -2
- package/dist/forms-astro.d.ts +50 -0
- package/dist/forms-astro.js +193 -0
- package/dist/forms-server.d.ts +80 -0
- package/dist/forms-server.js +294 -0
- package/dist/forms-testing.d.ts +66 -0
- package/dist/forms-testing.js +334 -0
- package/dist/forms.d.ts +25 -0
- package/dist/forms.js +4 -0
- package/dist/index.d.ts +131 -12
- package/dist/index.js +9 -2
- package/dist/metadata-content.js +1 -1
- package/dist/metadata-testing.js +1 -1
- package/dist/request-guards-BUPr_vA4.js +46 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +281 -26
- package/dist/site-language-BCGjkpWY.js +169178 -0
- package/dist/state-CsMFLUUO.d.ts +66 -0
- package/dist/validate-wRgYUNxN.js +130 -0
- package/dist/{version-ChwS3fUu.js → version-D81MsCZU.js} +1 -1
- package/dist/video-hero-D8AcMR4q.js +69 -0
- package/dist/{wordpress-D_HG2rEt.d.ts → wordpress-BvkTDMA0.d.ts} +306 -3
- package/package.json +21 -1
- package/dist/site-language-BLA2mmOw.js +0 -565
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
//#region frontend/src/forms/copy.d.ts
|
|
2
|
+
type FormsCopyLanguage = "en" | "pt-PT";
|
|
3
|
+
type FormErrorCode = "required" | "email" | "email-mismatch" | "number" | "range" | "url" | "choice" | "too-long";
|
|
4
|
+
interface FormsCopy {
|
|
5
|
+
required: string;
|
|
6
|
+
requiredFields: string;
|
|
7
|
+
errorSummary: string;
|
|
8
|
+
errors: Record<FormErrorCode, string>;
|
|
9
|
+
/** The submission was refused before reaching the CMS, or the CMS failed. */
|
|
10
|
+
failed: string;
|
|
11
|
+
/** Turnstile failed or was missing. */
|
|
12
|
+
verification: string;
|
|
13
|
+
/** A submission arrived too fast or too often. */
|
|
14
|
+
tooMany: string;
|
|
15
|
+
sent: string;
|
|
16
|
+
unavailable: string;
|
|
17
|
+
submit: string;
|
|
18
|
+
privacyPolicy: string;
|
|
19
|
+
/** Visible to assistive technology only, on the honeypot (Gravity Forms' wording). */
|
|
20
|
+
honeypot: string;
|
|
21
|
+
/** With Turnstile and no JavaScript. */
|
|
22
|
+
needsJavaScript: string;
|
|
23
|
+
}
|
|
24
|
+
declare const FORMS_COPY: Record<FormsCopyLanguage, FormsCopy>;
|
|
25
|
+
/** The copy language for a page's `lang`: Portuguese for `pt*`, else English. */
|
|
26
|
+
declare function formsCopyLanguage(language: string | null | undefined): FormsCopyLanguage;
|
|
27
|
+
//#endregion
|
|
28
|
+
//#region frontend/src/forms/state.d.ts
|
|
29
|
+
type FormStatus = "sent" | "invalid" | "failed" | "verification" | "too-many";
|
|
30
|
+
interface FormState {
|
|
31
|
+
formId: number;
|
|
32
|
+
status: FormStatus;
|
|
33
|
+
/** Field errors by field id: the descriptor check's codes. */
|
|
34
|
+
errors: Record<number, FormErrorCode>;
|
|
35
|
+
/** Gravity Forms' own messages by field id, when it refused the submission. */
|
|
36
|
+
messages: Record<number, string>;
|
|
37
|
+
/** What the visitor typed, by input name (left out when too large to keep). */
|
|
38
|
+
values: Record<string, string>;
|
|
39
|
+
/** Gravity Forms' confirmation message as text, after a submission it accepted. */
|
|
40
|
+
confirmation?: string;
|
|
41
|
+
}
|
|
42
|
+
/** The query parameter that marks the redirect back after a post. */
|
|
43
|
+
declare const FORM_STATE_PARAM = "gq-form";
|
|
44
|
+
/** Seconds the outcome is kept for the page after the redirect. */
|
|
45
|
+
declare const FORM_STATE_MAX_AGE = 300;
|
|
46
|
+
declare const formStateCookieName: (formId: number) => string;
|
|
47
|
+
/** The Set-Cookie header that carries a form's outcome to the page. */
|
|
48
|
+
declare function formStateCookie(state: FormState, options: {
|
|
49
|
+
secure: boolean;
|
|
50
|
+
}): string;
|
|
51
|
+
/** The Set-Cookie header that removes a form's outcome once the page has shown it. */
|
|
52
|
+
declare function clearFormStateCookie(formId: number, options: {
|
|
53
|
+
secure: boolean;
|
|
54
|
+
}): string;
|
|
55
|
+
/**
|
|
56
|
+
* A form's outcome for the page: present only on the redirect back after a
|
|
57
|
+
* post to it (`?gq-form=<id>`), from its cookie. Null otherwise.
|
|
58
|
+
*/
|
|
59
|
+
declare function readFormState(request: {
|
|
60
|
+
url: string | URL;
|
|
61
|
+
cookie: string | null | undefined;
|
|
62
|
+
}, formId: number): FormState | null;
|
|
63
|
+
/** Where the handler sends the visitor back to: the page, marked for the form. */
|
|
64
|
+
declare function formStateLocation(source: string, formId: number): string;
|
|
65
|
+
//#endregion
|
|
66
|
+
export { clearFormStateCookie as a, formStateLocation as c, FormErrorCode as d, FormsCopy as f, FormStatus as i, readFormState as l, formsCopyLanguage as m, FORM_STATE_PARAM as n, formStateCookie as o, FormsCopyLanguage as p, FormState as r, formStateCookieName as s, FORM_STATE_MAX_AGE as t, FORMS_COPY as u };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
//#region frontend/src/forms/validate.ts
|
|
2
|
+
/** No single value is longer (characters). */
|
|
3
|
+
const MAX_VALUE_LENGTH = 1e4;
|
|
4
|
+
const EMAIL = /^[^\s@<>()[\]\\,;:"]+@[^\s@<>()[\]\\,;:"]+\.[^\s@<>()[\]\\,;:"]+$/;
|
|
5
|
+
function webAddress(value) {
|
|
6
|
+
try {
|
|
7
|
+
const url = new URL(value);
|
|
8
|
+
return (url.protocol === "https:" || url.protocol === "http:") && url.hostname.includes(".");
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* A number as visitors type it in either convention (1234.5, 1,234.5, 1.234,5,
|
|
15
|
+
* 1 234,5): the last separator is the decimal one when both appear. NaN when
|
|
16
|
+
* it isn't one; Gravity Forms checks its own number format again.
|
|
17
|
+
*/
|
|
18
|
+
function parseNumber(value) {
|
|
19
|
+
let text = value.replace(/[\s\u00a0']/g, "");
|
|
20
|
+
const dot = text.lastIndexOf(".");
|
|
21
|
+
const comma = text.lastIndexOf(",");
|
|
22
|
+
if (dot >= 0 && comma >= 0) text = dot > comma ? text.replaceAll(",", "") : text.replaceAll(".", "").replace(",", ".");
|
|
23
|
+
else if (comma >= 0) text = text.indexOf(",") === comma ? text.replace(",", ".") : text.replaceAll(",", "");
|
|
24
|
+
else if ((text.match(/\./g) ?? []).length > 1) text = text.replaceAll(".", "");
|
|
25
|
+
return /^-?\d+(\.\d+)?$/.test(text) ? Number(text) : NaN;
|
|
26
|
+
}
|
|
27
|
+
/** A posted value, without surrounding whitespace, bounded. */
|
|
28
|
+
function read(values, name) {
|
|
29
|
+
return (values.get(name) ?? "").trim().slice(0, MAX_VALUE_LENGTH);
|
|
30
|
+
}
|
|
31
|
+
function check(field, values, input, shown) {
|
|
32
|
+
const take = (name) => {
|
|
33
|
+
const value = read(values, name);
|
|
34
|
+
input[name] = value;
|
|
35
|
+
if (field.visibility === "visible" && field.type !== "hidden") shown[name] = value;
|
|
36
|
+
return value;
|
|
37
|
+
};
|
|
38
|
+
const first = field.inputs[0];
|
|
39
|
+
switch (field.type) {
|
|
40
|
+
case "html":
|
|
41
|
+
case "section": return null;
|
|
42
|
+
case "hidden": {
|
|
43
|
+
if (!first) return null;
|
|
44
|
+
const value = values.get(first.name) === null ? field.defaultValue ?? "" : take(first.name);
|
|
45
|
+
input[first.name] = value;
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
case "checkbox": {
|
|
49
|
+
const chosen = field.inputs.filter((each) => {
|
|
50
|
+
const value = read(values, each.name);
|
|
51
|
+
if (value === "") return false;
|
|
52
|
+
input[each.name] = value;
|
|
53
|
+
shown[each.name] = value;
|
|
54
|
+
return true;
|
|
55
|
+
});
|
|
56
|
+
if (chosen.some((each) => read(values, each.name) !== each.value)) return "choice";
|
|
57
|
+
return field.required && chosen.length === 0 ? "required" : null;
|
|
58
|
+
}
|
|
59
|
+
case "consent": {
|
|
60
|
+
if (!first) return null;
|
|
61
|
+
const checked = read(values, first.name) === "1";
|
|
62
|
+
if (field.required && !checked) return "required";
|
|
63
|
+
if (checked) {
|
|
64
|
+
input[first.name] = "1";
|
|
65
|
+
shown[first.name] = "1";
|
|
66
|
+
const [, label, revision] = field.inputs;
|
|
67
|
+
if (label) input[label.name] = field.consent?.checkboxLabel ?? "";
|
|
68
|
+
if (revision) input[revision.name] = field.consent?.revisionId ?? "";
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
case "name": {
|
|
73
|
+
const given = field.inputs.map((each) => ({
|
|
74
|
+
each,
|
|
75
|
+
value: take(each.name)
|
|
76
|
+
}));
|
|
77
|
+
if (!field.required) return null;
|
|
78
|
+
const essential = given.filter(({ each }) => given.length === 1 || /\.(3|6)$/.test(each.id));
|
|
79
|
+
return (essential.length ? essential : given).some(({ value }) => value === "") ? "required" : null;
|
|
80
|
+
}
|
|
81
|
+
default: {
|
|
82
|
+
if (!first) return null;
|
|
83
|
+
const value = take(first.name);
|
|
84
|
+
if (value === "") {
|
|
85
|
+
if (field.type === "email" && field.inputs[1]) take(field.inputs[1].name);
|
|
86
|
+
return field.required ? "required" : null;
|
|
87
|
+
}
|
|
88
|
+
if (field.maxLength !== void 0 && Array.from(value).length > field.maxLength) return "too-long";
|
|
89
|
+
if (field.type === "email") {
|
|
90
|
+
if (!EMAIL.test(value)) return "email";
|
|
91
|
+
const confirmation = field.inputs[1];
|
|
92
|
+
if (confirmation && take(confirmation.name) !== value) return "email-mismatch";
|
|
93
|
+
}
|
|
94
|
+
if (field.type === "website" && !webAddress(value)) return "url";
|
|
95
|
+
if (field.type === "number") {
|
|
96
|
+
const number = parseNumber(value);
|
|
97
|
+
if (!Number.isFinite(number)) return "number";
|
|
98
|
+
if (field.range?.min !== void 0 && number < field.range.min || field.range?.max !== void 0 && number > field.range.max) return "range";
|
|
99
|
+
}
|
|
100
|
+
if ((field.type === "select" || field.type === "radio") && !(field.choices ?? []).some((choice) => choice.value === value)) return "choice";
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Checks a submission against the descriptor: required fields, formats,
|
|
107
|
+
* choices and lengths. Only the descriptor's inputs are kept; the honeypot is
|
|
108
|
+
* passed through, empty, for Gravity Forms' own check.
|
|
109
|
+
*/
|
|
110
|
+
function validateSubmission(descriptor, values) {
|
|
111
|
+
const input = {};
|
|
112
|
+
const shown = {};
|
|
113
|
+
const errors = {};
|
|
114
|
+
for (const field of descriptor.fields) {
|
|
115
|
+
const error = check(field, values, input, shown);
|
|
116
|
+
if (error) errors[field.id] = error;
|
|
117
|
+
}
|
|
118
|
+
if (descriptor.honeypot) input[descriptor.honeypot.name] = "";
|
|
119
|
+
return {
|
|
120
|
+
input,
|
|
121
|
+
errors,
|
|
122
|
+
values: shown
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** Whether the honeypot was filled in: a bot. Such a submission never reaches the CMS. */
|
|
126
|
+
function honeypotFilled(descriptor, values) {
|
|
127
|
+
return descriptor.honeypot !== null && (values.get(descriptor.honeypot.name) ?? "") !== "";
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
export { honeypotFilled as n, validateSubmission as r, MAX_VALUE_LENGTH as t };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#endregion
|
|
2
2
|
//#region frontend/src/consent/version.ts
|
|
3
3
|
/** The UI/adapter version recorded with each decision (CN-R7). */
|
|
4
|
-
const CONSENT_UI_VERSION = `gq-content@0.
|
|
4
|
+
const CONSENT_UI_VERSION = `gq-content@0.4.0`;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { CONSENT_UI_VERSION as t };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/** Object-fit geometry for a 16:9 YouTube frame in the actual authored media box.
|
|
2
|
+
* Adapters must size the iframe itself; object-fit cannot crop its document.
|
|
3
|
+
* The intrinsic frame size matches the player's 560 × 315 embedding dimensions.
|
|
4
|
+
*/
|
|
5
|
+
function videoHeroFrameGeometry(box, fit = "cover", position = {
|
|
6
|
+
x: .5,
|
|
7
|
+
y: .5
|
|
8
|
+
}) {
|
|
9
|
+
const contain = Math.min(box.width / 560, box.height / 315);
|
|
10
|
+
const scale = fit === "cover" ? Math.max(box.width / 560, box.height / 315) : fit === "contain" ? contain : fit === "scale-down" ? Math.min(1, contain) : 1;
|
|
11
|
+
const width = fit === "fill" ? box.width : 560 * scale;
|
|
12
|
+
const height = fit === "fill" ? box.height : 315 * scale;
|
|
13
|
+
return {
|
|
14
|
+
width,
|
|
15
|
+
height,
|
|
16
|
+
left: (box.width - width) * position.x || 0,
|
|
17
|
+
top: (box.height - height) * position.y || 0
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Canonical structural CSS for every Video Hero adapter; presentation stays in the shared model. */
|
|
21
|
+
function videoHeroStyleSheet() {
|
|
22
|
+
return `.wp-block-getquick-design-video-hero {
|
|
23
|
+
position: relative;
|
|
24
|
+
display: grid;
|
|
25
|
+
box-sizing: border-box;
|
|
26
|
+
isolation: isolate;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.wp-block-getquick-design-video-hero > .gqd-video-hero__media {
|
|
30
|
+
position: absolute;
|
|
31
|
+
z-index: 0;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
inset: 0;
|
|
34
|
+
background: inherit;
|
|
35
|
+
pointer-events: none;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.wp-block-getquick-design-video-hero > .gqd-video-hero__media > .gqd-video-hero__video,
|
|
39
|
+
.wp-block-getquick-design-video-hero > .gqd-video-hero__media > .gqd-video-hero__poster {
|
|
40
|
+
position: absolute;
|
|
41
|
+
width: 100%;
|
|
42
|
+
height: 100%;
|
|
43
|
+
inset: 0;
|
|
44
|
+
object-fit: cover;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.wp-block-getquick-design-video-hero > .gqd-video-hero__media > iframe.gqd-video-hero__video {
|
|
48
|
+
inset: auto;
|
|
49
|
+
border: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.wp-block-getquick-design-video-hero > .gqd-video-hero__content {
|
|
53
|
+
position: relative;
|
|
54
|
+
z-index: 1;
|
|
55
|
+
display: flex;
|
|
56
|
+
min-width: 0;
|
|
57
|
+
box-sizing: border-box;
|
|
58
|
+
flex-direction: column;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
@media (prefers-reduced-motion: reduce) {
|
|
62
|
+
.wp-block-getquick-design-video-hero > .gqd-video-hero__media > .gqd-video-hero__video {
|
|
63
|
+
visibility: hidden;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { videoHeroStyleSheet as n, videoHeroFrameGeometry as t };
|
|
@@ -1,5 +1,232 @@
|
|
|
1
1
|
import { r as ConsentConfiguration, t as AnalyticsSettings } from "./configuration-C_JGygQI.js";
|
|
2
2
|
import { r as LegalLanguage } from "./legal-C5Xiq59W.js";
|
|
3
|
+
import { o as FormDescriptor } from "./descriptor-B-e7gHi1.js";
|
|
4
|
+
//#endregion
|
|
5
|
+
//#region frontend/src/design-text.d.ts
|
|
6
|
+
/** Already loaded, authorized values. No lookup, fetching or query selection.
|
|
7
|
+
* Site title and description are plain text, as returned by WP settings. */
|
|
8
|
+
interface DesignTextContext {
|
|
9
|
+
site?: {
|
|
10
|
+
title?: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
url?: string;
|
|
13
|
+
};
|
|
14
|
+
post?: {
|
|
15
|
+
uri?: string;
|
|
16
|
+
/** Caller selects/formats the requested date using the block's format,
|
|
17
|
+
* date source and Site timezone; this adapter never guesses them. */
|
|
18
|
+
date?: {
|
|
19
|
+
text: string;
|
|
20
|
+
dateTime: string;
|
|
21
|
+
};
|
|
22
|
+
/** Supplied inline rich text, not a generated/truncated post body. */
|
|
23
|
+
excerpt?: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** Restore source-only native text. Saved, producer-sanitized shells stay with
|
|
27
|
+
* the caller; childrenHtml contains HTML already rendered by that same caller.
|
|
28
|
+
* undefined means this adapter cannot supply the block, never placeholder text.
|
|
29
|
+
* Presentation validation and all styling belong to the shared renderer. */
|
|
30
|
+
declare function renderDesignText(name: string, attributes: Record<string, unknown>, childrenHtml?: string, context?: DesignTextContext): string | undefined;
|
|
31
|
+
/** Small shared source-rich-text boundary; also suitable for Image captions.
|
|
32
|
+
* Rebuild parsed HTML, preserving safe inline formatting without executable
|
|
33
|
+
* attributes, embedded documents, foreign namespaces or source CSS. */
|
|
34
|
+
declare function safeDesignRichText(value: string): string;
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region frontend/src/design-query.d.ts
|
|
37
|
+
/** Authorized, synchronously preloaded content; supplied by the caller's data layer. */
|
|
38
|
+
interface DesignPostContext {
|
|
39
|
+
id: number | string;
|
|
40
|
+
/** Plain text, escaped when rendered as a native Post Title. */
|
|
41
|
+
title: string;
|
|
42
|
+
blocks: DesignBlock[];
|
|
43
|
+
uri?: string;
|
|
44
|
+
featuredImage?: {
|
|
45
|
+
sourceUrl: string;
|
|
46
|
+
altText: string;
|
|
47
|
+
} | null;
|
|
48
|
+
}
|
|
49
|
+
/** A producer-selected identity, not permission to fetch an arbitrary post. */
|
|
50
|
+
interface DesignQueryItem {
|
|
51
|
+
id: number | string;
|
|
52
|
+
type?: string;
|
|
53
|
+
slug?: string;
|
|
54
|
+
uri?: string;
|
|
55
|
+
}
|
|
56
|
+
interface DesignQueryResolverOptions {
|
|
57
|
+
/** Map lookup or other synchronous lookup of already authorized, loaded posts. */
|
|
58
|
+
resolvePost?: (item: DesignQueryItem) => DesignPostContext | null | undefined;
|
|
59
|
+
}
|
|
60
|
+
interface DesignQueryRenderContext extends DesignQueryResolverOptions {
|
|
61
|
+
post?: DesignPostContext;
|
|
62
|
+
/** Use the same renderer and Site overrides recursively, under this post context. */
|
|
63
|
+
render: (blocks: DesignBlock[], post?: DesignPostContext) => string;
|
|
64
|
+
/** Optional Site URL normalization, followed by the shared safe-link boundary. */
|
|
65
|
+
href?: (url: unknown) => string;
|
|
66
|
+
}
|
|
67
|
+
/** Repeat the delivered template once per delivered item, without selecting again.
|
|
68
|
+
* Returns undefined for other blocks. No Query or synced-pattern shell is added.
|
|
69
|
+
*/
|
|
70
|
+
declare function renderDesignQuery(block: DesignBlock, context: DesignQueryRenderContext): string | undefined;
|
|
71
|
+
/** Native post-dependent blocks and already-resolved synced references.
|
|
72
|
+
* Call only after Site renderer overrides have had precedence.
|
|
73
|
+
*/
|
|
74
|
+
declare function renderDesignPostBlock(block: DesignBlock, context: DesignQueryRenderContext): string | undefined;
|
|
75
|
+
/** Find identities already selected by producers, including resolved patterns.
|
|
76
|
+
* This never interprets query arguments or requests content. */
|
|
77
|
+
declare function designQueryItems(pattern: {
|
|
78
|
+
blocks: DesignBlock[];
|
|
79
|
+
} | DesignBlock[] | null | undefined): DesignQueryItem[];
|
|
80
|
+
interface DesignPostRecord {
|
|
81
|
+
id: string | number;
|
|
82
|
+
databaseId?: number;
|
|
83
|
+
title: string;
|
|
84
|
+
uri: string;
|
|
85
|
+
designBlocks?: DesignBlock[];
|
|
86
|
+
featuredImage?: {
|
|
87
|
+
sourceUrl: string;
|
|
88
|
+
altText: string;
|
|
89
|
+
} | null;
|
|
90
|
+
}
|
|
91
|
+
/** Convert an existing authorized publication; absent neutral delivery is explicit. */
|
|
92
|
+
declare function designPostContext(record: DesignPostRecord): DesignPostContext | null;
|
|
93
|
+
interface DesignPreloadedPosts extends DesignQueryResolverOptions {
|
|
94
|
+
posts: ReadonlyMap<string, DesignPostContext>;
|
|
95
|
+
resolvePost: (item: DesignQueryItem) => DesignPostContext | null;
|
|
96
|
+
}
|
|
97
|
+
/** Preload producer-selected URIs through a caller's existing publication loader.
|
|
98
|
+
* Selection/order stay with the producer; nested contexts use the same boundary. */
|
|
99
|
+
declare function preloadDesignQueryPosts(pattern: {
|
|
100
|
+
blocks: DesignBlock[];
|
|
101
|
+
} | DesignBlock[] | null | undefined, load: (item: DesignQueryItem) => Promise<DesignPostRecord | null>): Promise<DesignPreloadedPosts>;
|
|
102
|
+
//#endregion
|
|
103
|
+
/** Neutral resolved dimensions; palette identities and dark governance stay in DesignTokens. */
|
|
104
|
+
interface DesignTheme {
|
|
105
|
+
spacing: string;
|
|
106
|
+
breakpoints: Record<"sm" | "md" | "lg" | "xl" | "2xl", string>;
|
|
107
|
+
colors: Record<string, string>;
|
|
108
|
+
fontFamilies: Record<string, string>;
|
|
109
|
+
fontSizes: Record<string, string>;
|
|
110
|
+
fontSizeLineHeights: Record<string, string>;
|
|
111
|
+
fontWeights: Record<string, string>;
|
|
112
|
+
letterSpacings: Record<string, string>;
|
|
113
|
+
lineHeights: Record<string, string>;
|
|
114
|
+
radii: Record<string, string>;
|
|
115
|
+
maxWidths: Record<string, string>;
|
|
116
|
+
}
|
|
117
|
+
type DesignThemeOverrides = { [K in keyof DesignTheme]?: DesignTheme[K] extends string ? string : Partial<DesignTheme[K]>; };
|
|
118
|
+
/** The same bounded override vocabulary PHP and JSON Schema validate. */
|
|
119
|
+
declare function resolveDesignTheme(overrides?: unknown): DesignTheme;
|
|
120
|
+
/** Complete theme declarations for every supported value, independent of CMS content scanning. */
|
|
121
|
+
declare function designThemeVariables(overrides?: DesignThemeOverrides): Record<string, string>;
|
|
122
|
+
/** Scoped Preflight; the Gutenberg canvas retains native and authored spacing. */
|
|
123
|
+
declare function designThemeStyleSheet(overrides?: DesignThemeOverrides, scope?: string): string;
|
|
124
|
+
/** Color/font extension for the shared presentation parser; never raw utility strings. */
|
|
125
|
+
declare function resolvePresentationToken(kind: string, value: unknown): string | undefined;
|
|
126
|
+
//#endregion
|
|
127
|
+
type PresentationBreakpoint = "base" | "sm" | "md" | "lg" | "xl" | "2xl";
|
|
128
|
+
interface PresentationModel {
|
|
129
|
+
baseline: string;
|
|
130
|
+
breakpoints: Record<PresentationBreakpoint, string | null>;
|
|
131
|
+
properties: Record<string, Property>;
|
|
132
|
+
capabilities: Record<string, string[]>;
|
|
133
|
+
targets?: Record<string, PresentationTargets>;
|
|
134
|
+
selectors?: Record<string, string>;
|
|
135
|
+
nativeSupports?: Record<string, string[][]>;
|
|
136
|
+
shorthands?: Record<string, string[]>;
|
|
137
|
+
defaultDisplay?: Record<string, string>;
|
|
138
|
+
variablesFrom?: Record<string, Record<string, {
|
|
139
|
+
path: string[];
|
|
140
|
+
values: Record<string, string>;
|
|
141
|
+
default?: string;
|
|
142
|
+
}>>;
|
|
143
|
+
defaults: Record<string, Record<string, string | number>>;
|
|
144
|
+
/**
|
|
145
|
+
* Frontend flow rhythm: listed blocks space themselves from a preceding
|
|
146
|
+
* sibling; layout blocks only from a preceding flow block in body content.
|
|
147
|
+
*/
|
|
148
|
+
flow?: {
|
|
149
|
+
blocks: string[];
|
|
150
|
+
layout?: string[];
|
|
151
|
+
gap: string;
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
interface PresentationTargets {
|
|
155
|
+
selector?: string;
|
|
156
|
+
elements?: Record<string, string[]>;
|
|
157
|
+
properties?: Record<string, string>;
|
|
158
|
+
cssProperties?: Record<string, string[]>;
|
|
159
|
+
styles?: Record<string, Record<string, string>>;
|
|
160
|
+
conditionalStyles?: {
|
|
161
|
+
property: string;
|
|
162
|
+
target: string;
|
|
163
|
+
declarations: Record<string, string>;
|
|
164
|
+
}[];
|
|
165
|
+
/** Native structural baselines; authored presentation has higher priority. */
|
|
166
|
+
rules?: {
|
|
167
|
+
target: string;
|
|
168
|
+
important?: boolean;
|
|
169
|
+
declarations: Record<string, string>;
|
|
170
|
+
media?: {
|
|
171
|
+
minWidth?: string;
|
|
172
|
+
maxWidth?: string;
|
|
173
|
+
};
|
|
174
|
+
}[];
|
|
175
|
+
}
|
|
176
|
+
interface PresentationExtension {
|
|
177
|
+
/** Existing canonical properties only; extensions never define CSS values. */
|
|
178
|
+
properties: readonly string[];
|
|
179
|
+
/** A single wrapper class. Defaults to the conventional WordPress block class. */
|
|
180
|
+
selector?: string;
|
|
181
|
+
/** Optional descendant/child class paths, keyed by declared property. */
|
|
182
|
+
targets?: Readonly<Record<string, string>>;
|
|
183
|
+
/** Native wrapper mode restored by Display Auto/reset and editor hidden preview. */
|
|
184
|
+
defaultDisplay?: string;
|
|
185
|
+
}
|
|
186
|
+
type PresentationExtensions = Readonly<Record<string, PresentationExtension>>;
|
|
187
|
+
/** Explicit Site additions reuse the canonical vocabulary without changing core capabilities. */
|
|
188
|
+
declare function createPresentationModel(extensions?: PresentationExtensions): PresentationModel;
|
|
189
|
+
/** One bounded catalog shared by controls, producers and Site adapters. */
|
|
190
|
+
declare const presentationModel: PresentationModel;
|
|
191
|
+
type Presentation = Partial<Record<PresentationBreakpoint, Record<string, string | number | {
|
|
192
|
+
x: number;
|
|
193
|
+
y: number;
|
|
194
|
+
} | {
|
|
195
|
+
palette: string;
|
|
196
|
+
} | {
|
|
197
|
+
theme: string;
|
|
198
|
+
} | {
|
|
199
|
+
literal: string;
|
|
200
|
+
}>>>;
|
|
201
|
+
type PresentationTheme = DesignThemeOverrides;
|
|
202
|
+
type Property = {
|
|
203
|
+
label: string;
|
|
204
|
+
valueType?: string;
|
|
205
|
+
scale?: string;
|
|
206
|
+
themeToken?: string;
|
|
207
|
+
valueSchema?: Record<string, unknown>;
|
|
208
|
+
cssProperty: string;
|
|
209
|
+
companionCssProperty?: string;
|
|
210
|
+
reset: string;
|
|
211
|
+
values: {
|
|
212
|
+
value: string | number;
|
|
213
|
+
css: string;
|
|
214
|
+
label: string;
|
|
215
|
+
editorCss?: string;
|
|
216
|
+
companionCss?: string;
|
|
217
|
+
}[];
|
|
218
|
+
};
|
|
219
|
+
/** Invalid or unsupported settings fail explicitly; omission never means Auto/reset. */
|
|
220
|
+
declare function presentationVariables(name: string, presentation?: unknown, options?: {
|
|
221
|
+
editor?: boolean;
|
|
222
|
+
attributes?: Record<string, unknown>;
|
|
223
|
+
model?: PresentationModel;
|
|
224
|
+
}): Record<string, string>;
|
|
225
|
+
/** Static, complete CSS: content first authored after a production build still works. */
|
|
226
|
+
declare function presentationStyleSheet(theme?: PresentationTheme, options?: {
|
|
227
|
+
model?: PresentationModel;
|
|
228
|
+
editor?: boolean;
|
|
229
|
+
}): string;
|
|
3
230
|
declare namespace content_types_d_exports {
|
|
4
231
|
export { Archives, CmsFailure, CmsFailureReason, CollectionMembership, CollectionTerm, Delivery, DesignPresets, EntryContent, Extended, Found, HomeContent, Missing, PublishedEntry, SiteChrome, Translation, Unavailable, WordPressImage, WordPressMenuItem, WordPressPost, WordPressSettings };
|
|
5
232
|
}
|
|
@@ -8,6 +235,13 @@ interface WordPressImage {
|
|
|
8
235
|
altText: string;
|
|
9
236
|
}
|
|
10
237
|
interface WordPressPost {
|
|
238
|
+
databaseId?: number;
|
|
239
|
+
designBlocks?: DesignBlock[];
|
|
240
|
+
/**
|
|
241
|
+
* The public descriptors of the Gravity Forms forms it references, on a
|
|
242
|
+
* Site with `forms` (ADR 0009): what `gravityforms/form` blocks render.
|
|
243
|
+
*/
|
|
244
|
+
forms?: FormDescriptor[];
|
|
11
245
|
id: string;
|
|
12
246
|
title: string;
|
|
13
247
|
excerpt: string;
|
|
@@ -29,6 +263,8 @@ interface WordPressSettings {
|
|
|
29
263
|
description: string;
|
|
30
264
|
}
|
|
31
265
|
interface DesignPresets {
|
|
266
|
+
/** Resolved CMS theme; absent in publications written before theme delivery. */
|
|
267
|
+
theme?: DesignTheme;
|
|
32
268
|
spacingSizes: Array<{
|
|
33
269
|
slug: string;
|
|
34
270
|
size: string;
|
|
@@ -54,6 +290,10 @@ interface HomeContent<X = unknown> extends DesignPresets {
|
|
|
54
290
|
title: string;
|
|
55
291
|
content: string;
|
|
56
292
|
hasVideoHero: boolean;
|
|
293
|
+
databaseId?: number;
|
|
294
|
+
designBlocks?: DesignBlock[];
|
|
295
|
+
/** Its Gravity Forms forms' descriptors, on a Site with `forms`. */
|
|
296
|
+
forms?: FormDescriptor[];
|
|
57
297
|
} & Extended<X>;
|
|
58
298
|
/** WordPress failed on the blocks, so this is the page without them. */
|
|
59
299
|
blocksOmitted: boolean;
|
|
@@ -176,12 +416,16 @@ declare function parseDesignBlocks(value: unknown): DesignBlock[] | undefined;
|
|
|
176
416
|
declare function escapeHtml(value: string): string;
|
|
177
417
|
/** What a block renderer is given besides its block. */
|
|
178
418
|
interface DesignRenderContext {
|
|
419
|
+
colorScheme?: "light" | "dark";
|
|
420
|
+
siteTitle?: string;
|
|
421
|
+
/** Current preloaded post when rendering a Query item or a post body. */
|
|
422
|
+
post?: DesignPostContext;
|
|
179
423
|
/** The block's children, rendered in order by the same renderers (when read). */
|
|
180
424
|
children: string;
|
|
181
425
|
/** The blocks it is inside, outermost first. */
|
|
182
426
|
ancestors: DesignBlock[];
|
|
183
427
|
/** Renders other blocks (a subset of the children, say) by the same renderers. */
|
|
184
|
-
render(this: void, blocks: DesignBlock[]): string;
|
|
428
|
+
render(this: void, blocks: DesignBlock[], post?: DesignPostContext): string;
|
|
185
429
|
/**
|
|
186
430
|
* A link from CMS data as the Frontend serves it: one into this Site (the
|
|
187
431
|
* CMS or the Site origin) becomes its path, another http(s) link stays
|
|
@@ -196,7 +440,17 @@ interface DesignRenderContext {
|
|
|
196
440
|
* CMS supplied (`escapeHtml`) and pass links through `context.href`.
|
|
197
441
|
*/
|
|
198
442
|
type DesignBlockRenderer = (block: DesignBlock, context: DesignRenderContext) => string;
|
|
199
|
-
interface DesignRenderOptions {
|
|
443
|
+
interface DesignRenderOptions extends DesignQueryResolverOptions {
|
|
444
|
+
/** Explicit surface scheme for the canonical Branding logo selection. */
|
|
445
|
+
colorScheme?: "light" | "dark";
|
|
446
|
+
/** Preloaded native Site text sources; no lookup occurs during rendering. */
|
|
447
|
+
textContext?: DesignTextContext;
|
|
448
|
+
/** Explicit Site-added capability model, shared with its stylesheet. */
|
|
449
|
+
presentationModel?: PresentationModel;
|
|
450
|
+
/** Gate generated media before composing already-delivered child HTML. */
|
|
451
|
+
mediaHtml?: (html: string) => string;
|
|
452
|
+
/** Preloaded context for native Post Title/Post Content outside a Query. */
|
|
453
|
+
post?: DesignPostContext;
|
|
200
454
|
/**
|
|
201
455
|
* The Site's renderers, by block name: its own blocks (such as
|
|
202
456
|
* `getquick/header-navigation`), and any core block it renders itself.
|
|
@@ -414,6 +668,36 @@ type CollectionTermListing = {
|
|
|
414
668
|
kind: "found";
|
|
415
669
|
terms: CollectionTermCount[];
|
|
416
670
|
} | NotServed;
|
|
671
|
+
/** Search public content already delivered to this Site's publication store. */
|
|
672
|
+
interface SearchQuery {
|
|
673
|
+
/** Text to find in titles, excerpts or bodies, ignoring case and accents. Blank finds nothing. */
|
|
674
|
+
search: string;
|
|
675
|
+
/** Page from 1; defaults to 1. URL strings are accepted. */
|
|
676
|
+
page?: number | string;
|
|
677
|
+
/** Results per page, 1–100; defaults to 12. URL strings are accepted. */
|
|
678
|
+
perPage?: number | string;
|
|
679
|
+
/** Configured language slug; defaults to the Site's default language. */
|
|
680
|
+
language?: string;
|
|
681
|
+
}
|
|
682
|
+
interface SearchItem {
|
|
683
|
+
/** Canonical path on this Site. */
|
|
684
|
+
uri: string;
|
|
685
|
+
/** Plain text, suitable for escaped text rendering. */
|
|
686
|
+
title: string;
|
|
687
|
+
/** Plain text excerpt, or a bounded body-text fallback. */
|
|
688
|
+
excerpt: string;
|
|
689
|
+
/** Configured language slug, including on monolingual Sites. */
|
|
690
|
+
language: string;
|
|
691
|
+
}
|
|
692
|
+
interface SearchPage {
|
|
693
|
+
items: SearchItem[];
|
|
694
|
+
total: number;
|
|
695
|
+
page: number;
|
|
696
|
+
perPage: number;
|
|
697
|
+
/** Zero when nothing matches. */
|
|
698
|
+
totalPages: number;
|
|
699
|
+
}
|
|
700
|
+
type SearchDelivery = Found<SearchPage> | NotServed;
|
|
417
701
|
//#endregion
|
|
418
702
|
//#region frontend/src/server.d.ts
|
|
419
703
|
interface ContentConfig<X = never> {
|
|
@@ -438,6 +722,14 @@ interface ContentConfig<X = never> {
|
|
|
438
722
|
* delivery; absent, bodies are delivered as published.
|
|
439
723
|
*/
|
|
440
724
|
consent?: ContentConsentConfig;
|
|
725
|
+
/**
|
|
726
|
+
* Headless Gravity Forms (ADR 0009). True, each front page, page, post and
|
|
727
|
+
* item is read with the public descriptors of the forms it references
|
|
728
|
+
* (gq-content's CMS forms module, active with Gravity Forms), stored with it
|
|
729
|
+
* as `forms`, and `publishedForm` finds them for the form endpoint. Absent,
|
|
730
|
+
* reads and stored bodies are unchanged.
|
|
731
|
+
*/
|
|
732
|
+
forms?: boolean;
|
|
441
733
|
/**
|
|
442
734
|
* The Site's own content on its pages and posts: GraphQL fields the runtime
|
|
443
735
|
* reads with each of them, and the value the Site makes of them, stored with
|
|
@@ -537,6 +829,15 @@ declare function createContentRuntime<X = never>(input: ContentConfig<X>): {
|
|
|
537
829
|
}) => Promise<Response>;
|
|
538
830
|
publishedHome: (siteOrigin?: string, language?: SiteLanguage) => Promise<HomeDelivery<X>>;
|
|
539
831
|
publishedEntry: (path: string, siteOrigin?: string) => Promise<EntryDelivery<X>>;
|
|
832
|
+
/**
|
|
833
|
+
* A Gravity Forms form's descriptor as published with the page at a path
|
|
834
|
+
* (the publication store's, as the page is served), for the form endpoint
|
|
835
|
+
* (`createFormsServer`'s `descriptor`). Null when the page isn't served,
|
|
836
|
+
* doesn't reference the form, or the Site doesn't opt in to `forms`.
|
|
837
|
+
*/
|
|
838
|
+
publishedForm: (path: string, formId: number, siteOrigin?: string) => Promise<FormDescriptor | null>;
|
|
839
|
+
/** Site-wide text search over delivered public content; never reads WordPress. */
|
|
840
|
+
search: (query: SearchQuery) => Promise<SearchDelivery>;
|
|
540
841
|
/**
|
|
541
842
|
* A page of a collection's items, from the publication store alone (never
|
|
542
843
|
* WordPress), newest first: those with the given terms and text, in the
|
|
@@ -562,6 +863,8 @@ declare function createContentRuntime<X = never>(input: ContentConfig<X>): {
|
|
|
562
863
|
* `renderDesignPattern`), with links into the CMS or `siteOrigin` served
|
|
563
864
|
* as this Site's paths.
|
|
564
865
|
*/
|
|
866
|
+
/** Preload selected standard Post/Page records through the existing store reader. */
|
|
867
|
+
preloadDesignQueryPosts: (pattern: DesignPattern | DesignBlock[] | null | undefined, siteOrigin?: string) => Promise<DesignPreloadedPosts>;
|
|
565
868
|
renderDesignPattern: (pattern: DesignPattern | DesignBlock[] | null | undefined, options?: DesignRenderOptions & {
|
|
566
869
|
siteOrigin?: string;
|
|
567
870
|
}) => string;
|
|
@@ -603,4 +906,4 @@ interface WordPressClient<X = unknown> {
|
|
|
603
906
|
}): Promise<Found<SiteChrome> | Unavailable>;
|
|
604
907
|
}
|
|
605
908
|
//#endregion
|
|
606
|
-
export {
|
|
909
|
+
export { Delivery as $, SqlDatabase as A, DesignPostContext as At, DesignBlockRenderer as B, renderDesignQuery as Bt, Moved as C, presentationVariables as Ct, SearchPage as D, designThemeVariables as Dt, SearchItem as E, designThemeStyleSheet as Et, isLanguageHome as F, DesignQueryResolverOptions as Ft, escapeHtml as G, DesignRenderContext as H, renderDesignText as Ht, languageSubject as I, designPostContext as It, Archives as J, parseDesignBlocks as K, routeLanguage as L, designQueryItems as Lt, SiteLanguage as M, DesignPreloadedPosts as Mt, WordPressLanguages as N, DesignQueryItem as Nt, SearchQuery as O, resolveDesignTheme as Ot, htmlLang as P, DesignQueryRenderContext as Pt, CollectionTerm as Q, siteLanguages as R, preloadDesignQueryPosts as Rt, HomePublication as S, presentationStyleSheet as St, SearchDelivery as T, DesignThemeOverrides as Tt, DesignRenderOptions as U, safeDesignRichText as Ut, DesignPattern as V, DesignTextContext as Vt, designMenuItems as W, CmsFailureReason as X, CmsFailure as Y, CollectionMembership as Z, EntryDelivery as _, PresentationTargets as _t, ContentExtension as a, Missing as at, HomeDelivery as b, createPresentationModel as bt, createContentRuntime as c, Translation as ct, CollectionListing as d, WordPressMenuItem as dt, DesignPresets as et, CollectionPage as f, WordPressPost as ft, DeliveryFailureReason as g, PresentationModel as gt, CollectionTermListing as h, PresentationBreakpoint as ht, ContentConsentConfig as i, HomeContent as it, SqlStatement as j, DesignPostRecord as jt, ContentBindings as k, resolvePresentationToken as kt, Alternate as l, Unavailable as lt, CollectionTermCount as m, Presentation as mt, CollectionConfig as n, Extended as nt, ContentRuntime as o, PublishedEntry as ot, CollectionQuery as p, WordPressSettings as pt, renderDesignPattern as q, ContentConfig as r, Found as rt, ExtensionNode as s, SiteChrome as st, WordPressClient as t, EntryContent as tt, CollectionItem as u, WordPressImage as ut, EntryPage as v, PresentationTheme as vt, NotServed as w, DesignTheme as wt, HomePage as x, presentationModel as xt, EntryPublication as y, Property as yt, DesignBlock as z, renderDesignPostBlock as zt };
|