@seamlet/astro 1.2.1 → 1.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/CHANGELOG.md +14 -0
- package/README.md +76 -0
- package/components/RequestForm.astro +192 -0
- package/dist/bridge.d.ts +2 -2
- package/dist/bridge.js +3 -2
- package/dist/chunk-2IK7D2AA.js +6 -0
- package/dist/{chunk-Y4R4YV5O.js → chunk-BCJUH3ZD.js} +1 -1
- package/dist/{chunk-OCA2WYK3.js → chunk-JQ4YD7MM.js} +8 -3
- package/dist/{chunk-UL2C2IB2.js → chunk-TMN7KG5M.js} +294 -4
- package/dist/{chunk-HFPZVDST.js → chunk-ULOKDC6D.js} +1 -1
- package/dist/cli.js +1 -1
- package/dist/client.js +8 -0
- package/dist/index.js +5 -5
- package/dist/{messages-C2OjqFmy.d.ts → messages-Dwjthhrk.d.ts} +1 -1
- package/dist/{parse-content-Bnn6Wa-l.d.ts → parse-content-CT2cUVL-.d.ts} +23 -4
- package/dist/preview-requests.d.ts +5 -3
- package/dist/preview-requests.js +5 -3
- package/dist/protocol.d.ts +3 -3
- package/dist/protocol.js +2 -2
- package/dist/request-sending-ZBTK5L7U.js +251 -0
- package/dist/routes/media.js +5 -5
- package/dist/schema.d.ts +103 -4
- package/dist/schema.js +63 -1
- package/dist/{site-description-BnHrODQX.d.ts → site-description-cKiFtNHW.d.ts} +100 -2
- package/dist/site.d.ts +7 -2
- package/dist/site.js +19 -3
- package/package.json +3 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as FieldPath, c as Field, d as CollectionField, F as Fields, G as GroupField, C as Content, e as RecordFields, f as RecordOf, g as ContentIssue } from './parse-content-
|
|
1
|
+
import { a as FieldPath, c as Field, d as CollectionField, F as Fields, G as GroupField, C as Content, e as RecordFields, f as RecordOf, g as ContentIssue } from './parse-content-CT2cUVL-.js';
|
|
2
2
|
|
|
3
3
|
/** What a path written on a page points at: a field, or a whole record of a collection. */
|
|
4
4
|
type FieldTarget = {
|
|
@@ -56,6 +56,87 @@ declare function readFields(input: unknown): Fields | undefined;
|
|
|
56
56
|
/** The schema the input describes, or the first problem that keeps it from being one. */
|
|
57
57
|
declare function checkFields(input: unknown): FieldsReading;
|
|
58
58
|
|
|
59
|
+
/** A line of words: a name, a city, the model of a car. */
|
|
60
|
+
interface RequestTextField {
|
|
61
|
+
readonly kind: "text";
|
|
62
|
+
readonly label: string;
|
|
63
|
+
readonly required?: boolean;
|
|
64
|
+
/** In characters as people see them; `DEFAULT_TEXT_LENGTH` when left out. */
|
|
65
|
+
readonly maxLength?: number;
|
|
66
|
+
}
|
|
67
|
+
/** Words of several lines: a comment, a question, what is to be built. */
|
|
68
|
+
interface RequestLongTextField {
|
|
69
|
+
readonly kind: "longText";
|
|
70
|
+
readonly label: string;
|
|
71
|
+
readonly required?: boolean;
|
|
72
|
+
/** In characters as people see them; `DEFAULT_LONG_TEXT_LENGTH` when left out. */
|
|
73
|
+
readonly maxLength?: number;
|
|
74
|
+
}
|
|
75
|
+
/** A phone number to call back. */
|
|
76
|
+
interface RequestPhoneField {
|
|
77
|
+
readonly kind: "phone";
|
|
78
|
+
readonly label: string;
|
|
79
|
+
readonly required?: boolean;
|
|
80
|
+
}
|
|
81
|
+
/** An email address to write back to. */
|
|
82
|
+
interface RequestEmailField {
|
|
83
|
+
readonly kind: "email";
|
|
84
|
+
readonly label: string;
|
|
85
|
+
readonly required?: boolean;
|
|
86
|
+
}
|
|
87
|
+
/** One of the options the form lists: a service, a size, a time to call. */
|
|
88
|
+
interface RequestChoiceField {
|
|
89
|
+
readonly kind: "choice";
|
|
90
|
+
readonly label: string;
|
|
91
|
+
readonly required?: boolean;
|
|
92
|
+
/** The options as the visitor reads them; the request keeps the one picked, as it reads. */
|
|
93
|
+
readonly options: readonly string[];
|
|
94
|
+
}
|
|
95
|
+
type RequestField = RequestTextField | RequestLongTextField | RequestPhoneField | RequestEmailField | RequestChoiceField;
|
|
96
|
+
type RequestFieldKind = RequestField["kind"];
|
|
97
|
+
/** The fields of a form by their names, in the order the form shows them. */
|
|
98
|
+
type RequestFields = Readonly<Record<string, RequestField>>;
|
|
99
|
+
interface RequestForm<F extends RequestFields = RequestFields> {
|
|
100
|
+
/** How the site and the CMS tell the form from the site's other forms: `callback`. */
|
|
101
|
+
readonly id: string;
|
|
102
|
+
/** How the CMS names the form's requests to the business: «Обратный звонок». */
|
|
103
|
+
readonly title: string;
|
|
104
|
+
readonly fields: F;
|
|
105
|
+
}
|
|
106
|
+
/** A line of words a visitor types without a limit of the site's own. */
|
|
107
|
+
declare const DEFAULT_TEXT_LENGTH = 200;
|
|
108
|
+
/** A comment a visitor types without a limit of the site's own. */
|
|
109
|
+
declare const DEFAULT_LONG_TEXT_LENGTH = 2000;
|
|
110
|
+
/** No field of a request holds more: a request is a message, not a document. */
|
|
111
|
+
declare const MAX_REQUEST_FIELD_LENGTH = 5000;
|
|
112
|
+
/** Declares a form of the site's requests: `requestForm({ id, title, fields })`. */
|
|
113
|
+
declare function requestForm<const F extends RequestFields>(form: RequestForm<F>): RequestForm<F>;
|
|
114
|
+
declare function requestText(options: Omit<RequestTextField, "kind">): RequestTextField;
|
|
115
|
+
declare function requestLongText(options: Omit<RequestLongTextField, "kind">): RequestLongTextField;
|
|
116
|
+
declare function requestPhone(options: Omit<RequestPhoneField, "kind">): RequestPhoneField;
|
|
117
|
+
declare function requestEmail(options: Omit<RequestEmailField, "kind">): RequestEmailField;
|
|
118
|
+
declare function requestChoice(options: Omit<RequestChoiceField, "kind">): RequestChoiceField;
|
|
119
|
+
/** Why a form of a site's description cannot be read. */
|
|
120
|
+
type RequestFormProblemReason = "not-a-form"
|
|
121
|
+
/** Not lower-case Latin letters, digits and hyphens, starting with a letter. */
|
|
122
|
+
| "invalid-id" | "invalid-title" | "no-fields"
|
|
123
|
+
/** A field's name is not a name of a JavaScript property such as `preferredTime`. */
|
|
124
|
+
| "invalid-field-name"
|
|
125
|
+
/** A field is not one of the kinds above, or its label, limit or options are not sound. */
|
|
126
|
+
| "invalid-field";
|
|
127
|
+
type RequestFormReading = {
|
|
128
|
+
readonly status: "read";
|
|
129
|
+
readonly form: RequestForm;
|
|
130
|
+
} | {
|
|
131
|
+
readonly status: "invalid";
|
|
132
|
+
readonly reason: RequestFormProblemReason;
|
|
133
|
+
};
|
|
134
|
+
/** The form the input describes, read back from JSON, or why it is not one. */
|
|
135
|
+
declare function readRequestForm(input: unknown): RequestFormReading;
|
|
136
|
+
declare function isFormId(value: unknown): value is string;
|
|
137
|
+
/** The longest words the field takes, in characters as people see them. */
|
|
138
|
+
declare function maxLengthOf(field: RequestTextField | RequestLongTextField): number;
|
|
139
|
+
|
|
59
140
|
/** What stands for the record in the address of its page: `/menu/[record]`. */
|
|
60
141
|
declare const RECORD_PLACEHOLDER = "[record]";
|
|
61
142
|
/** The pages of the records of a collection, as a site describes them to the CMS. */
|
|
@@ -162,6 +243,8 @@ interface SiteDescription {
|
|
|
162
243
|
readonly pages: readonly [SitePageDescription, ...SitePageDescription[]];
|
|
163
244
|
/** The pages of the records of collections; left out when the site has none. */
|
|
164
245
|
readonly recordPages?: readonly SiteRecordPageDescription[];
|
|
246
|
+
/** The forms of the site's requests; left out when the site has none. */
|
|
247
|
+
readonly forms?: readonly RequestForm[];
|
|
165
248
|
}
|
|
166
249
|
/** Why a site's description cannot be read: what to fix in the site. */
|
|
167
250
|
type SiteDescriptionProblem = {
|
|
@@ -223,6 +306,21 @@ type SiteDescriptionProblem = {
|
|
|
223
306
|
readonly code: "repeated-record-address";
|
|
224
307
|
readonly collection: string;
|
|
225
308
|
readonly address: string;
|
|
309
|
+
}
|
|
310
|
+
/** The forms are not a list. */
|
|
311
|
+
| {
|
|
312
|
+
readonly code: "invalid-forms";
|
|
313
|
+
}
|
|
314
|
+
/** The form at this place of the list is not one. */
|
|
315
|
+
| {
|
|
316
|
+
readonly code: "invalid-form";
|
|
317
|
+
readonly index: number;
|
|
318
|
+
readonly reason: RequestFormProblemReason;
|
|
319
|
+
}
|
|
320
|
+
/** Two forms with one id: a request names its form by it. */
|
|
321
|
+
| {
|
|
322
|
+
readonly code: "repeated-form-id";
|
|
323
|
+
readonly id: string;
|
|
226
324
|
};
|
|
227
325
|
type PageProblemReason = "not-a-page"
|
|
228
326
|
/** Not `/`, or not lower-case segments without a trailing slash, such as `/menu`. */
|
|
@@ -255,4 +353,4 @@ declare function checkSiteDescription(input: unknown): SiteDescriptionReading;
|
|
|
255
353
|
/** Whether the path names a group of a `title` and a `description` text. */
|
|
256
354
|
declare function isSearchTextsGroup(schema: Fields, path: string): boolean;
|
|
257
355
|
|
|
258
|
-
export {
|
|
356
|
+
export { requestLongText as $, type SitePageDescription as A, type SiteRecordPageDescription as B, type CollectionPath as C, DEFAULT_LONG_TEXT_LENGTH as D, checkFields as E, FIELD_PATH_SEPARATOR as F, checkSiteDescription as G, HOME_PAGE_PATH as H, isFormId as I, isRecordPagePath as J, isSearchTextsGroup as K, maxLengthOf as L, MAX_REQUEST_FIELD_LENGTH as M, readFields as N, readRequestForm as O, PAGE_PATH_SEPARATOR as P, readSiteDescription as Q, type RequestForm as R, type SiteDescription as S, recordAddressOf as T, recordAt as U, recordPageAt as V, recordPagePath as W, recordPages as X, requestChoice as Y, requestEmail as Z, requestForm as _, type SiteRecordPages as a, requestPhone as a0, requestText as a1, resolveFieldPath as a2, DEFAULT_TEXT_LENGTH as b, type FieldTarget as c, type FieldsReading as d, type PageProblemReason as e, type PlacedRecord as f, RECORD_PLACEHOLDER as g, type RecordFieldsAt as h, type RecordPagePath as i, type RecordPageProblemReason as j, type RecordPages as k, type RequestChoiceField as l, type RequestEmailField as m, type RequestField as n, type RequestFieldKind as o, type RequestFields as p, type RequestFormProblemReason as q, type RequestFormReading as r, type RequestLongTextField as s, type RequestPhoneField as t, type RequestTextField as u, SITE_DESCRIPTION_PATH as v, type SchemaProblem as w, type SchemaProblemReason as x, type SiteDescriptionProblem as y, type SiteDescriptionReading as z };
|
package/dist/site.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ImageMetadata } from 'astro';
|
|
2
2
|
import { AstroComponentFactory } from 'astro/runtime/server/index.js';
|
|
3
|
-
import { C as Content, F as Fields, b as ContentOf } from './parse-content-
|
|
4
|
-
import { a as SiteRecordPages, S as SiteDescription } from './site-description-
|
|
3
|
+
import { C as Content, F as Fields, b as ContentOf } from './parse-content-CT2cUVL-.js';
|
|
4
|
+
import { a as SiteRecordPages, S as SiteDescription, R as RequestForm } from './site-description-cKiFtNHW.js';
|
|
5
5
|
|
|
6
6
|
/** A page of the site: how the editor names it, and the component that renders it. */
|
|
7
7
|
interface SeamletPage {
|
|
@@ -58,6 +58,11 @@ interface SeamletSiteDefinition<F extends Fields> {
|
|
|
58
58
|
* editor can show it in the photo's field. A site without own photos leaves it out.
|
|
59
59
|
*/
|
|
60
60
|
readonly photos?: (src: string) => ImageMetadata | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* The forms visitors send the business requests with (`requestForm(...)`), rendered with
|
|
63
|
+
* `RequestForm.astro`: the CMS keeps the requests and passes them on.
|
|
64
|
+
*/
|
|
65
|
+
readonly forms?: readonly RequestForm[];
|
|
61
66
|
}
|
|
62
67
|
interface SeamletSite<F extends Fields = Fields> {
|
|
63
68
|
readonly id: string;
|
package/dist/site.js
CHANGED
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
previewedPageAt,
|
|
7
7
|
renderedPageAt,
|
|
8
8
|
staticPagesOf
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ULOKDC6D.js";
|
|
10
10
|
import {
|
|
11
11
|
checkSiteDescription,
|
|
12
12
|
formatFieldPath,
|
|
13
13
|
parseContent
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-TMN7KG5M.js";
|
|
15
15
|
|
|
16
16
|
// src/site.ts
|
|
17
17
|
import { cmsOrigin, siteId, siteTitle } from "virtual:seamlet/config";
|
|
@@ -70,13 +70,15 @@ function describeSite(identity, definition) {
|
|
|
70
70
|
...searchTexts === void 0 ? {} : { searchTexts }
|
|
71
71
|
})
|
|
72
72
|
);
|
|
73
|
+
const forms = definition.forms ?? [];
|
|
73
74
|
const description = {
|
|
74
75
|
id: identity.id,
|
|
75
76
|
title: identity.title,
|
|
76
77
|
schema: definition.schema,
|
|
77
78
|
initialContent: definition.initialContent,
|
|
78
79
|
pages,
|
|
79
|
-
...recordPages.length === 0 ? {} : { recordPages }
|
|
80
|
+
...recordPages.length === 0 ? {} : { recordPages },
|
|
81
|
+
...forms.length === 0 ? {} : { forms }
|
|
80
82
|
};
|
|
81
83
|
const asSent = JSON.parse(JSON.stringify(description));
|
|
82
84
|
const reading = checkSiteDescription(asSent);
|
|
@@ -127,8 +129,22 @@ function problemText(problem) {
|
|
|
127
129
|
return `record ${String(problem.index + 1)} of "${problem.collection}" in the initial content has neither a slug nor an id for its page`;
|
|
128
130
|
case "repeated-record-address":
|
|
129
131
|
return `two records of "${problem.collection}" in the initial content have their pages at "${problem.address}": give them other ids or slugs`;
|
|
132
|
+
case "invalid-forms":
|
|
133
|
+
return "forms is not a list";
|
|
134
|
+
case "invalid-form":
|
|
135
|
+
return `form ${String(problem.index + 1)} of forms: ${FORM_PROBLEM_TEXTS[problem.reason]}`;
|
|
136
|
+
case "repeated-form-id":
|
|
137
|
+
return `two forms have the id "${problem.id}": a request names its form by it`;
|
|
130
138
|
}
|
|
131
139
|
}
|
|
140
|
+
var FORM_PROBLEM_TEXTS = {
|
|
141
|
+
"not-a-form": "not a form",
|
|
142
|
+
"invalid-id": 'its id is not lower-case Latin letters, digits and hyphens, such as "callback"',
|
|
143
|
+
"invalid-title": "its title is empty",
|
|
144
|
+
"no-fields": "it has no fields",
|
|
145
|
+
"invalid-field-name": `a field's name is not a name such as "phone" or "preferredTime"`,
|
|
146
|
+
"invalid-field": "a field is not a request field, or its label, maxLength or options are not sound"
|
|
147
|
+
};
|
|
132
148
|
var SCHEMA_PROBLEM_TEXTS = {
|
|
133
149
|
"not-fields": "not fields of the schema language",
|
|
134
150
|
"invalid-name": "a field's name must not be empty, hold a dot or be a number",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seamlet/astro",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Connects an Astro site to the Seamlet CMS: the schema of its content, the preview the editor frames, and its published content.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -54,7 +54,8 @@
|
|
|
54
54
|
"types": "./dist/routes/site-description.d.ts",
|
|
55
55
|
"default": "./dist/routes/site-description.js"
|
|
56
56
|
},
|
|
57
|
-
"./components/RichText.astro": "./components/RichText.astro"
|
|
57
|
+
"./components/RichText.astro": "./components/RichText.astro",
|
|
58
|
+
"./components/RequestForm.astro": "./components/RequestForm.astro"
|
|
58
59
|
},
|
|
59
60
|
"files": [
|
|
60
61
|
"dist",
|