@seamlet/astro 0.7.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -211,4 +211,4 @@ type FieldValue = string | number | boolean | null | readonly string[] | ImageVa
211
211
  declare function defaultValue(field: Field): FieldValue;
212
212
  declare function defaultContent(fields: Fields): Content;
213
213
 
214
- export { time as $, defaultContent as A, defaultValue as B, type ContentOf as C, type DateField as D, defineSchema as E, type Fields as F, type GroupField as G, group as H, type ImageField as I, image as J, link as K, type LinkValue as L, normalizedLine as M, type NumberField as N, type OptionValue as O, number as P, plainTextOf as Q, type RecordFields as R, readRichText as S, type TextField as T, type UrlField as U, type ValueOf as V, reference as W, references as X, richText as Y, richTextOf as Z, text as _, type Content as a, toggle as a0, url as a1, type ImageValue as b, type Field as c, type CollectionField as d, type LinkField as e, type ChoicesField as f, type TimeField as g, type ChoiceField as h, type ChoiceOption as i, type FieldKind as j, type FieldValue as k, type ImageFocus as l, type RecordOf as m, type ReferenceField as n, type ReferencesField as o, type RichBlock as p, type RichLine as q, type RichSpan as r, type RichText as s, type RichTextField as t, type ToggleField as u, asOneParagraph as v, choice as w, choices as x, collection as y, date as z };
214
+ export { time as $, defaultContent as A, defaultValue as B, type ContentOf as C, type DateField as D, defineSchema as E, type Fields as F, type GroupField as G, group as H, type ImageField as I, image as J, link as K, type LinkValue as L, normalizedLine as M, type NumberField as N, type OptionValue as O, number as P, plainTextOf as Q, type RichText as R, readRichText as S, type TextField as T, type UrlField as U, type ValueOf as V, reference as W, references as X, richText as Y, richTextOf as Z, text as _, type Content as a, toggle as a0, url as a1, type ImageValue as b, type Field as c, type CollectionField as d, type RecordFields as e, type LinkField as f, type ChoicesField as g, type TimeField as h, type ChoiceField as i, type ChoiceOption as j, type FieldKind as k, type FieldValue as l, type ImageFocus as m, type RecordOf as n, type ReferenceField as o, type ReferencesField as p, type RichBlock as q, type RichLine as r, type RichSpan as s, type RichTextField as t, type ToggleField as u, asOneParagraph as v, choice as w, choices as x, collection as y, date as z };
@@ -1,5 +1,5 @@
1
- import { F as Fields, a as Content } from './content-DeBXwSmg.js';
2
- import { F as FieldPath } from './parse-content-DqToE6I6.js';
1
+ import { R as RichText, F as Fields, a as Content } from './content-6k-E7NWf.js';
2
+ import { F as FieldPath } from './parse-content-C9ldnmvj.js';
3
3
 
4
4
  interface Box {
5
5
  readonly top: number;
@@ -17,12 +17,53 @@ declare function shortcutOf(event: KeyboardEvent): Shortcut | undefined;
17
17
 
18
18
  type InlineEditingOutcome = "kept" | "reverted";
19
19
 
20
+ interface TextPoint {
21
+ /** The paragraph or the list item, counted from the start of the text. */
22
+ readonly line: number;
23
+ /** Characters from the start of the line; a line break is one character. */
24
+ readonly offset: number;
25
+ }
26
+ interface TextSelection {
27
+ readonly start: TextPoint;
28
+ readonly end: TextPoint;
29
+ }
30
+ type Mark = "bold" | "italic";
31
+ /** What the selected words have, or the words at the cursor when nothing is selected. */
32
+ interface TextFormats {
33
+ readonly isBold: boolean;
34
+ readonly isItalic: boolean;
35
+ readonly isList: boolean;
36
+ /** The address of the link the selection is in, when all of it is in one link. */
37
+ readonly href: string | undefined;
38
+ }
39
+ /** Whether the selection holds no characters: it is a cursor. */
40
+ declare function isCollapsed(selection: TextSelection): boolean;
41
+ /** The marks every selected word has, and the link they are in. */
42
+ declare function formatsAt(text: RichText, selection: TextSelection): TextFormats;
43
+ /** The words of the link the cursor is in, or undefined outside a link. */
44
+ declare function linkSelectionAt(text: RichText, point: TextPoint): TextSelection | undefined;
45
+ /** The mark on every selected word, or off them all when every one has it already. */
46
+ declare function toggleMark(text: RichText, selection: TextSelection, mark: Mark): RichText;
47
+ /** The selected words lead to the address, or lead nowhere when it is undefined. */
48
+ declare function setLink(text: RichText, selection: TextSelection, href: string | undefined): RichText;
49
+ /** The selected lines become a list, or paragraphs again when they all are a list already. */
50
+ declare function toggleList(text: RichText, selection: TextSelection): RichText;
51
+
52
+ /** A change of formatting the editor's toolbar asks for. */
53
+ type TextFormat = "bold" | "italic" | "list";
54
+ /** The selection in the typed text: where it is on the page and what its words have. */
55
+ interface TypedSelection {
56
+ readonly box: Box;
57
+ readonly isCollapsed: boolean;
58
+ readonly formats: TextFormats;
59
+ }
60
+
20
61
  /**
21
62
  * The version of what the two say to each other. A site updates @seamlet/astro when it likes, so the
22
63
  * editor may meet a bridge of another version: it tells by this number, said with `ready`, instead
23
64
  * of misreading the page. Raised whenever a message changes in a way the other side cannot read.
24
65
  */
25
- declare const PROTOCOL_VERSION = 1;
66
+ declare const PROTOCOL_VERSION = 2;
26
67
  interface Point {
27
68
  readonly x: number;
28
69
  readonly y: number;
@@ -99,6 +140,18 @@ type PageMessage =
99
140
  readonly type: "typed";
100
141
  readonly path: string;
101
142
  readonly text: string;
143
+ }
144
+ /** The formatted text typed in place, after every character and every change of its marks. */
145
+ | {
146
+ readonly type: "rich-typed";
147
+ readonly path: string;
148
+ readonly text: RichText;
149
+ }
150
+ /** Where the selection in the typed formatted text is now, for the editor's toolbar. */
151
+ | {
152
+ readonly type: "typed-selection";
153
+ readonly path: string;
154
+ readonly selection: TypedSelection | undefined;
102
155
  } | {
103
156
  readonly type: "typing-ended";
104
157
  readonly path: string;
@@ -127,6 +180,25 @@ type EditorMessage =
127
180
  readonly text: string;
128
181
  readonly isSingleLine: boolean;
129
182
  readonly point: Point;
183
+ }
184
+ /** Type the formatted text of the field in its element, if the element shows it as it is. */
185
+ | {
186
+ readonly type: "start-rich-typing";
187
+ readonly path: string;
188
+ readonly text: RichText;
189
+ /** The words alone, in an element of one line. */
190
+ readonly isInline: boolean;
191
+ readonly point: Point;
192
+ }
193
+ /** Mark the selected words of the formatted text typed in place, or make its lines a list. */
194
+ | {
195
+ readonly type: "format-typed";
196
+ readonly format: TextFormat;
197
+ }
198
+ /** The selected words of the typed text, or the link at the cursor, lead here, or nowhere. */
199
+ | {
200
+ readonly type: "link-typed";
201
+ readonly href: string | undefined;
130
202
  } | {
131
203
  readonly type: "stop-typing";
132
204
  }
@@ -140,4 +212,4 @@ declare function readPageMessage(data: unknown): PageMessage | undefined;
140
212
  /** The message the editor sent, or undefined for anything that is not one. */
141
213
  declare function readEditorMessage(data: unknown): EditorMessage | undefined;
142
214
 
143
- export { type Box as B, type EditorMessage as E, type InlineEditingOutcome as I, type LinkBox as L, type MarkerBox as M, type PageMessage as P, type Shortcut as S, type Viewport as V, type EditorKey as a, PROTOCOL_VERSION as b, type PageLayout as c, type Point as d, readPageMessage as e, readEditorMessage as r, shortcutOf as s };
215
+ export { type Box as B, type EditorMessage as E, type InlineEditingOutcome as I, type LinkBox as L, type Mark as M, type PageMessage as P, type Shortcut as S, type TextSelection as T, type Viewport as V, type EditorKey as a, type MarkerBox as b, PROTOCOL_VERSION as c, type PageLayout as d, type Point as e, type TextFormat as f, type TextFormats as g, type TextPoint as h, type TypedSelection as i, formatsAt as j, isCollapsed as k, linkSelectionAt as l, readPageMessage as m, shortcutOf as n, toggleMark as o, readEditorMessage as r, setLink as s, toggleList as t };
@@ -1,4 +1,4 @@
1
- import { F as Fields, C as ContentOf } from './content-DeBXwSmg.js';
1
+ import { F as Fields, C as ContentOf } from './content-6k-E7NWf.js';
2
2
 
3
3
  /** Where a value lives in the content: field names and, inside a collection, record indexes. */
4
4
  type FieldPath = readonly (string | number)[];
@@ -1,6 +1,7 @@
1
- export { B as Box, a as EditorKey, E as EditorMessage, I as InlineEditingOutcome, L as LinkBox, M as MarkerBox, b as PROTOCOL_VERSION, c as PageLayout, P as PageMessage, d as Point, S as Shortcut, V as Viewport, r as readEditorMessage, e as readPageMessage, s as shortcutOf } from './messages-ClePO8N_.js';
2
- import { F as Fields, I as ImageField } from './content-DeBXwSmg.js';
3
- import { F as FieldPath } from './parse-content-DqToE6I6.js';
1
+ import { T as TextSelection } from './messages-Dx0jNy3N.js';
2
+ export { B as Box, a as EditorKey, E as EditorMessage, I as InlineEditingOutcome, L as LinkBox, M as Mark, b as MarkerBox, c as PROTOCOL_VERSION, d as PageLayout, P as PageMessage, e as Point, S as Shortcut, f as TextFormat, g as TextFormats, h as TextPoint, i as TypedSelection, V as Viewport, j as formatsAt, k as isCollapsed, l as linkSelectionAt, r as readEditorMessage, m as readPageMessage, s as setLink, n as shortcutOf, t as toggleList, o as toggleMark } from './messages-Dx0jNy3N.js';
3
+ import { F as Fields, I as ImageField, R as RichText } from './content-6k-E7NWf.js';
4
+ import { F as FieldPath } from './parse-content-C9ldnmvj.js';
4
5
 
5
6
  declare function carriesFiles(event: DragEvent): boolean;
6
7
 
@@ -16,6 +17,17 @@ declare function imageFieldAt(schema: Fields, path: string | undefined): {
16
17
  */
17
18
  declare function closestMarkedPath(path: FieldPath, isMarked: (path: string) => boolean): string | undefined;
18
19
 
20
+ /** The elements of a text, put into the editable element in place of what it held. */
21
+ declare function renderRichText(element: HTMLElement, text: RichText): void;
22
+ /** What the editable element holds now, as formatted text. */
23
+ declare function readRichTextFrom(element: HTMLElement): RichText;
24
+ /** Where the selection is in the text of the element, or undefined when it is elsewhere. */
25
+ declare function readSelectionFrom(element: HTMLElement): TextSelection | undefined;
26
+ /** Puts the selection on the text of an element this module rendered. */
27
+ declare function selectIn(element: HTMLElement, selection: TextSelection): void;
28
+ /** Puts plain words in place of the selection, their line breaks as `<br>`, the cursor after them. */
29
+ declare function insertPlainText(element: HTMLElement, words: string): void;
30
+
19
31
  /** Where a site hands out its own photos: `/seamlet-photos/menu/cafe/01.jpg`. */
20
32
  declare const OWN_PHOTOS_PATH = "/seamlet-photos";
21
33
  /** An address of the site itself that is not an upload, and that cannot climb out of the site. */
@@ -23,4 +35,4 @@ declare function isOwnPhotoSrc(src: string): boolean;
23
35
  /** Where the site hands out its own photo; undefined for an upload or another site's address. */
24
36
  declare function ownPhotoPath(src: string): string | undefined;
25
37
 
26
- export { OWN_PHOTOS_PATH, carriesFiles, closestMarkedPath, imageFieldAt, isOwnPhotoSrc, ownPhotoPath };
38
+ export { OWN_PHOTOS_PATH, TextSelection, carriesFiles, closestMarkedPath, imageFieldAt, insertPlainText, isOwnPhotoSrc, ownPhotoPath, readRichTextFrom, readSelectionFrom, renderRichText, selectIn };
package/dist/protocol.js CHANGED
@@ -7,21 +7,43 @@ import {
7
7
  PROTOCOL_VERSION,
8
8
  carriesFiles,
9
9
  closestMarkedPath,
10
+ formatsAt,
10
11
  imageFieldAt,
12
+ insertPlainText,
13
+ isCollapsed,
14
+ linkSelectionAt,
11
15
  readEditorMessage,
12
16
  readPageMessage,
13
- shortcutOf
14
- } from "./chunk-4YLS3VPT.js";
17
+ readRichTextFrom,
18
+ readSelectionFrom,
19
+ renderRichText,
20
+ selectIn,
21
+ setLink,
22
+ shortcutOf,
23
+ toggleList,
24
+ toggleMark
25
+ } from "./chunk-27XIZEVS.js";
15
26
  import "./chunk-ZUJEM3P7.js";
16
27
  export {
17
28
  OWN_PHOTOS_PATH,
18
29
  PROTOCOL_VERSION,
19
30
  carriesFiles,
20
31
  closestMarkedPath,
32
+ formatsAt,
21
33
  imageFieldAt,
34
+ insertPlainText,
35
+ isCollapsed,
22
36
  isOwnPhotoSrc,
37
+ linkSelectionAt,
23
38
  ownPhotoPath,
24
39
  readEditorMessage,
25
40
  readPageMessage,
26
- shortcutOf
41
+ readRichTextFrom,
42
+ readSelectionFrom,
43
+ renderRichText,
44
+ selectIn,
45
+ setLink,
46
+ shortcutOf,
47
+ toggleList,
48
+ toggleMark
27
49
  };
package/dist/schema.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { b as ImageValue, L as LinkValue, c as Field, d as CollectionField, F as Fields, a as Content, R as RecordFields, C as ContentOf, G as GroupField, e as LinkField, T as TextField, U as UrlField, f as ChoicesField, g as TimeField, I as ImageField } from './content-DeBXwSmg.js';
2
- export { h as ChoiceField, i as ChoiceOption, D as DateField, j as FieldKind, k as FieldValue, l as ImageFocus, N as NumberField, O as OptionValue, m as RecordOf, n as ReferenceField, o as ReferencesField, p as RichBlock, q as RichLine, r as RichSpan, s as RichText, t as RichTextField, u as ToggleField, V as ValueOf, v as asOneParagraph, w as choice, x as choices, y as collection, z as date, A as defaultContent, B as defaultValue, E as defineSchema, H as group, J as image, K as link, M as normalizedLine, P as number, Q as plainTextOf, S as readRichText, W as reference, X as references, Y as richText, Z as richTextOf, _ as text, $ as time, a0 as toggle, a1 as url } from './content-DeBXwSmg.js';
3
- import { F as FieldPath } from './parse-content-DqToE6I6.js';
4
- export { C as ContentIssue, P as ParsedContent, c as countCharacters, f as formatFieldPath, p as parseContent } from './parse-content-DqToE6I6.js';
1
+ import { b as ImageValue, L as LinkValue, c as Field, d as CollectionField, F as Fields, a as Content, e as RecordFields, C as ContentOf, G as GroupField, f as LinkField, T as TextField, U as UrlField, g as ChoicesField, h as TimeField, I as ImageField } from './content-6k-E7NWf.js';
2
+ export { i as ChoiceField, j as ChoiceOption, D as DateField, k as FieldKind, l as FieldValue, m as ImageFocus, N as NumberField, O as OptionValue, n as RecordOf, o as ReferenceField, p as ReferencesField, q as RichBlock, r as RichLine, s as RichSpan, R as RichText, t as RichTextField, u as ToggleField, V as ValueOf, v as asOneParagraph, w as choice, x as choices, y as collection, z as date, A as defaultContent, B as defaultValue, E as defineSchema, H as group, J as image, K as link, M as normalizedLine, P as number, Q as plainTextOf, S as readRichText, W as reference, X as references, Y as richText, Z as richTextOf, _ as text, $ as time, a0 as toggle, a1 as url } from './content-6k-E7NWf.js';
3
+ import { F as FieldPath } from './parse-content-C9ldnmvj.js';
4
+ export { C as ContentIssue, P as ParsedContent, c as countCharacters, f as formatFieldPath, p as parseContent } from './parse-content-C9ldnmvj.js';
5
5
 
6
6
  declare const FIELD_PATH_ATTRIBUTE = "data-cms-path";
7
7
  interface FieldMarker {
package/dist/site.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { ImageMetadata } from 'astro';
2
2
  import { AstroComponentFactory } from 'astro/runtime/server/index.js';
3
- import { F as Fields, C as ContentOf } from './content-DeBXwSmg.js';
3
+ import { F as Fields, C as ContentOf } from './content-6k-E7NWf.js';
4
4
 
5
5
  interface SeamletSiteDefinition<F extends Fields> {
6
6
  /** The site's address in the CMS: `/sites/<id>`. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamlet/astro",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
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",
@@ -1,160 +0,0 @@
1
- import {
2
- formatFieldPath,
3
- resolveFieldPath
4
- } from "./chunk-ZUJEM3P7.js";
5
-
6
- // src/bridge/editor-shortcuts.ts
7
- function shortcutOf(event) {
8
- const hasCommandKey = event.metaKey || event.ctrlKey;
9
- if (!hasCommandKey || event.altKey) {
10
- return void 0;
11
- }
12
- switch (event.code) {
13
- case "KeyS":
14
- return "save";
15
- case "KeyZ":
16
- return event.shiftKey ? "redo" : "undo";
17
- case "KeyY":
18
- return "redo";
19
- default:
20
- return void 0;
21
- }
22
- }
23
-
24
- // src/bridge/image-fields.ts
25
- function imageFieldAt(schema, path) {
26
- const target = path === void 0 ? void 0 : resolveFieldPath(schema, path);
27
- const isImage = target?.kind === "field" && target.field.kind === "image";
28
- return isImage ? { path: target.path, field: target.field } : void 0;
29
- }
30
-
31
- // src/bridge/messages.ts
32
- var PROTOCOL_VERSION = 1;
33
- var EDITOR_KEYS = /* @__PURE__ */ new Set([
34
- "save",
35
- "undo",
36
- "redo",
37
- "escape"
38
- ]);
39
- var TYPING_OUTCOMES = /* @__PURE__ */ new Set([
40
- "kept",
41
- "reverted"
42
- ]);
43
- function readPageMessage(data) {
44
- if (!isRecord(data)) return void 0;
45
- return isPageMessage(data) ? data : void 0;
46
- }
47
- function readEditorMessage(data) {
48
- if (!isRecord(data)) return void 0;
49
- return isEditorMessage(data) ? data : void 0;
50
- }
51
- function isPageMessage(message) {
52
- switch (message["type"]) {
53
- case "ready":
54
- return isNumber(message["protocol"]);
55
- case "file-drag-end":
56
- case "rendered":
57
- case "render-failed":
58
- return true;
59
- case "layout":
60
- return isLayout(message["layout"]);
61
- case "hover":
62
- case "file-drag":
63
- return isOptional(message["path"], isString);
64
- case "click":
65
- return isOptional(message["target"], isClickTarget);
66
- case "link-click":
67
- return isString(message["href"]);
68
- case "key":
69
- return isString(message["key"]) && EDITOR_KEYS.has(message["key"]);
70
- case "file-drop":
71
- return isString(message["path"]) && message["file"] instanceof File;
72
- case "typing-started":
73
- case "typing-refused":
74
- return isString(message["path"]);
75
- case "typed":
76
- return isString(message["path"]) && isString(message["text"]);
77
- case "typing-ended":
78
- return isString(message["path"]) && isString(message["outcome"]) && TYPING_OUTCOMES.has(message["outcome"]);
79
- default:
80
- return false;
81
- }
82
- }
83
- function isEditorMessage(message) {
84
- switch (message["type"]) {
85
- case "connect":
86
- return isRecord(message["schema"]);
87
- case "render":
88
- return isRecord(message["content"]);
89
- case "start-typing":
90
- return isString(message["path"]) && isString(message["text"]) && typeof message["isSingleLine"] === "boolean" && isPoint(message["point"]);
91
- case "stop-typing":
92
- return true;
93
- case "scroll-to":
94
- return isFieldPath(message["path"]);
95
- default:
96
- return false;
97
- }
98
- }
99
- function isLayout(value) {
100
- if (!isRecord(value)) return false;
101
- const markers = value["markers"];
102
- return Array.isArray(markers) && markers.every(isMarkerBox) && isViewport(value["viewport"]) && isOptional(value["link"], isLinkBox);
103
- }
104
- function isMarkerBox(value) {
105
- return isRecord(value) && isString(value["path"]) && isBox(value["box"]);
106
- }
107
- function isLinkBox(value) {
108
- return isRecord(value) && isString(value["href"]) && isBox(value["box"]);
109
- }
110
- function isClickTarget(value) {
111
- return isRecord(value) && isString(value["path"]) && isPoint(value["point"]);
112
- }
113
- function isBox(value) {
114
- return isRecord(value) && isNumber(value["top"]) && isNumber(value["left"]) && isNumber(value["width"]) && isNumber(value["height"]);
115
- }
116
- function isViewport(value) {
117
- return isRecord(value) && isNumber(value["width"]) && isNumber(value["height"]);
118
- }
119
- function isPoint(value) {
120
- return isRecord(value) && isNumber(value["x"]) && isNumber(value["y"]);
121
- }
122
- function isFieldPath(value) {
123
- return Array.isArray(value) && value.every((segment) => isString(segment) || isNumber(segment));
124
- }
125
- function isOptional(value, isPresent) {
126
- return value === void 0 || isPresent(value);
127
- }
128
- function isRecord(value) {
129
- return typeof value === "object" && value !== null && !Array.isArray(value);
130
- }
131
- function isString(value) {
132
- return typeof value === "string";
133
- }
134
- function isNumber(value) {
135
- return typeof value === "number" && Number.isFinite(value);
136
- }
137
-
138
- // src/bridge/file-drags.ts
139
- function carriesFiles(event) {
140
- return event.dataTransfer?.types.includes("Files") === true;
141
- }
142
-
143
- // src/bridge/marked-paths.ts
144
- function closestMarkedPath(path, isMarked) {
145
- for (let length = path.length; length > 0; length -= 1) {
146
- const candidate = formatFieldPath(path.slice(0, length));
147
- if (isMarked(candidate)) return candidate;
148
- }
149
- return void 0;
150
- }
151
-
152
- export {
153
- shortcutOf,
154
- imageFieldAt,
155
- PROTOCOL_VERSION,
156
- readPageMessage,
157
- readEditorMessage,
158
- carriesFiles,
159
- closestMarkedPath
160
- };