@bettercms-ai/kit 2.0.0-next.1 → 2.0.0-next.2
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/adapters/lossy.d.ts +4 -0
- package/dist/adapters/lossy.js +8 -2
- package/dist/adapters/lossy.js.map +1 -1
- package/dist/adapters/schema.js +28 -0
- package/dist/adapters/schema.js.map +1 -1
- package/dist/controls/rich-text/blocks.d.ts +6 -0
- package/dist/controls/rich-text/blocks.js +187 -0
- package/dist/controls/rich-text/blocks.js.map +1 -1
- package/dist/controls/rich-text/catalog.d.ts +2 -5
- package/dist/controls/rich-text/catalog.js +104 -6
- package/dist/controls/rich-text/catalog.js.map +1 -1
- package/dist/controls/rich-text/codec.d.ts +10 -1
- package/dist/controls/rich-text/codec.js +7 -0
- package/dist/controls/rich-text/codec.js.map +1 -1
- package/dist/controls/rich-text/control.js +1 -0
- package/dist/controls/rich-text/control.js.map +1 -1
- package/dist/controls/rich-text/dom.d.ts +79 -0
- package/dist/controls/rich-text/dom.js +159 -7
- package/dist/controls/rich-text/dom.js.map +1 -1
- package/dist/controls/rich-text/editor.d.ts +4 -2
- package/dist/controls/rich-text/editor.js +93 -3
- package/dist/controls/rich-text/editor.js.map +1 -1
- package/dist/controls/rich-text/ops.js +6 -0
- package/dist/controls/rich-text/ops.js.map +1 -1
- package/dist/controls/rich-text/toc.d.ts +3 -2
- package/dist/controls/rich-text/toc.js +1 -2
- package/dist/controls/rich-text/toc.js.map +1 -1
- package/dist/core/core.d.ts +1 -0
- package/dist/core/core.js +2 -0
- package/dist/core/core.js.map +1 -1
- package/dist/core/facets.d.ts +8 -0
- package/dist/core/facets.js +8 -0
- package/dist/core/facets.js.map +1 -1
- package/dist/library/kit-catalog.json +4 -2
- package/dist/schema/types.d.ts +8 -0
- package/dist/schema/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import * as React from "react";
|
|
19
19
|
import { type IslandEl, type IslandKind, type IslandModels } from "./dom";
|
|
20
|
+
import { type OutlineStore } from "./toc";
|
|
21
|
+
import type { RichTextRead } from "./codec";
|
|
20
22
|
import type { RichTextFeature } from "./codec";
|
|
21
23
|
export interface IslandCtx {
|
|
22
24
|
readOnly?: boolean;
|
|
@@ -44,6 +46,10 @@ export interface IslandCtx {
|
|
|
44
46
|
drag?: (el: IslandEl, e: React.PointerEvent) => void;
|
|
45
47
|
/** what the field's stored shape keeps (the host codec's features): a setting it cannot store is not drawn */
|
|
46
48
|
allows?: (f: RichTextFeature) => boolean;
|
|
49
|
+
/** the body's live outline (its top-level H2/H3), which a table of contents lists */
|
|
50
|
+
outline?: OutlineStore;
|
|
51
|
+
/** where an author bio and related posts point (the field's config, from the host codec) */
|
|
52
|
+
references?: RichTextRead["references"];
|
|
47
53
|
}
|
|
48
54
|
/** `label` names the step in the editor's one undo history ("Edit alt text"). */
|
|
49
55
|
export type Setter<K extends IslandKind> = (patch: Partial<IslandModels[K]> | ((m: IslandModels[K]) => IslandModels[K]), label?: string, record?: boolean) => void;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isCropRect } from "../../adapters/values.js";
|
|
1
2
|
import { cn } from "../../lib/cn.js";
|
|
2
3
|
import { useKitServices } from "../../context.js";
|
|
3
4
|
import { Button, IconButton } from "../../ui/button.js";
|
|
@@ -6,9 +7,14 @@ import { Input, Textarea } from "../../ui/input.js";
|
|
|
6
7
|
import { TableEditor } from "../table/table-editor.js";
|
|
7
8
|
import { VideoPreview } from "../media.js";
|
|
8
9
|
import { ArticleActions, ArticleCard, ArticleForm, ArticlePanel, articleCardKeyDown, useArticleOpen } from "./article-shell.js";
|
|
10
|
+
import { AuthorBlock } from "./author.js";
|
|
9
11
|
import { CALLOUT_TONES, placeCaret } from "./dom.js";
|
|
10
12
|
import { LinkForm } from "./link-form.js";
|
|
11
13
|
import { EmbedBlock } from "./embed.js";
|
|
14
|
+
import { GalleryBlock } from "./gallery.js";
|
|
15
|
+
import { TocBlock } from "./toc.js";
|
|
16
|
+
import { ColumnsBlock } from "./columns.js";
|
|
17
|
+
import { RelatedBlock } from "./related.js";
|
|
12
18
|
import { ComponentCard } from "./component-card.js";
|
|
13
19
|
import * as React from "react";
|
|
14
20
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -119,6 +125,36 @@ function Island({ el, ctx }) {
|
|
|
119
125
|
autoFocus,
|
|
120
126
|
m: model,
|
|
121
127
|
set
|
|
128
|
+
}) : kind === "gallery" ? /* @__PURE__ */ jsx(GalleryIsland, {
|
|
129
|
+
el,
|
|
130
|
+
ctx,
|
|
131
|
+
autoFocus,
|
|
132
|
+
m: model,
|
|
133
|
+
set
|
|
134
|
+
}) : kind === "toc" ? /* @__PURE__ */ jsx(TocIsland, {
|
|
135
|
+
el,
|
|
136
|
+
ctx,
|
|
137
|
+
autoFocus,
|
|
138
|
+
m: model,
|
|
139
|
+
set
|
|
140
|
+
}) : kind === "columns" ? /* @__PURE__ */ jsx(ColumnsIsland, {
|
|
141
|
+
el,
|
|
142
|
+
ctx,
|
|
143
|
+
autoFocus,
|
|
144
|
+
m: model,
|
|
145
|
+
set
|
|
146
|
+
}) : kind === "author" ? /* @__PURE__ */ jsx(AuthorIsland, {
|
|
147
|
+
el,
|
|
148
|
+
ctx,
|
|
149
|
+
autoFocus,
|
|
150
|
+
m: model,
|
|
151
|
+
set
|
|
152
|
+
}) : kind === "related" ? /* @__PURE__ */ jsx(RelatedIsland, {
|
|
153
|
+
el,
|
|
154
|
+
ctx,
|
|
155
|
+
autoFocus,
|
|
156
|
+
m: model,
|
|
157
|
+
set
|
|
122
158
|
}) : kind === "file" ? /* @__PURE__ */ jsx(FileBlock, {
|
|
123
159
|
el,
|
|
124
160
|
ctx,
|
|
@@ -160,6 +196,157 @@ function EmbedIsland({ m, set, el, ctx, autoFocus }) {
|
|
|
160
196
|
shape: ctx.allows?.("embedAspect") ?? false
|
|
161
197
|
});
|
|
162
198
|
}
|
|
199
|
+
/** The island's stored gallery (src, alt, caption per image) through gallery.tsx's block (V2's model, an image value each). */
|
|
200
|
+
/** RT9: a gallery image's framing, image-url's 0–1 focal point ⇄ the kit image value's percent */
|
|
201
|
+
var toGallery = (m) => ({
|
|
202
|
+
layout: m.layout ?? "grid",
|
|
203
|
+
images: m.images.map((x) => ({
|
|
204
|
+
_key: x._key,
|
|
205
|
+
image: x.src ? {
|
|
206
|
+
url: x.src,
|
|
207
|
+
...x.alt !== void 0 ? { alt: x.alt } : {},
|
|
208
|
+
...x.crop ? { crop: x.crop } : {},
|
|
209
|
+
...x.focal ? { focal: {
|
|
210
|
+
x: x.focal.x * 100,
|
|
211
|
+
y: x.focal.y * 100
|
|
212
|
+
} } : {}
|
|
213
|
+
} : null,
|
|
214
|
+
caption: x.caption ?? ""
|
|
215
|
+
}))
|
|
216
|
+
});
|
|
217
|
+
var cropOf = (c) => isCropRect(c) ? {
|
|
218
|
+
top: c.top,
|
|
219
|
+
right: c.right,
|
|
220
|
+
bottom: c.bottom,
|
|
221
|
+
left: c.left
|
|
222
|
+
} : void 0;
|
|
223
|
+
var focalOf = (f) => {
|
|
224
|
+
const p = f;
|
|
225
|
+
return typeof p?.x === "number" && typeof p?.y === "number" ? {
|
|
226
|
+
x: Math.round(p.x) / 100,
|
|
227
|
+
y: Math.round(p.y) / 100
|
|
228
|
+
} : void 0;
|
|
229
|
+
};
|
|
230
|
+
function GalleryIsland({ m, set, el, ctx, autoFocus }) {
|
|
231
|
+
return /* @__PURE__ */ jsx(GalleryBlock, {
|
|
232
|
+
m: toGallery(m),
|
|
233
|
+
set: (fn, label) => set((prev) => {
|
|
234
|
+
const next = fn(toGallery(prev));
|
|
235
|
+
const out = {
|
|
236
|
+
...prev,
|
|
237
|
+
images: next.images.map((x) => {
|
|
238
|
+
const crop = cropOf(x.image?.crop);
|
|
239
|
+
const focal = focalOf(x.image?.focal);
|
|
240
|
+
return {
|
|
241
|
+
_key: x._key,
|
|
242
|
+
src: x.image?.url ?? "",
|
|
243
|
+
...x.image?.alt !== void 0 ? { alt: x.image.alt } : {},
|
|
244
|
+
...x.caption ? { caption: x.caption } : {},
|
|
245
|
+
...crop ? { crop } : {},
|
|
246
|
+
...focal ? { focal } : {}
|
|
247
|
+
};
|
|
248
|
+
})
|
|
249
|
+
};
|
|
250
|
+
if (next.layout !== (prev.layout ?? "grid")) out.layout = next.layout;
|
|
251
|
+
return out;
|
|
252
|
+
}, label),
|
|
253
|
+
el,
|
|
254
|
+
ctx,
|
|
255
|
+
autoFocus
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
/** The island's stored table of contents (title, depth) through toc.tsx's block, which lists the editor's live outline. */
|
|
259
|
+
function TocIsland({ m, set, el, ctx, autoFocus }) {
|
|
260
|
+
return /* @__PURE__ */ jsx(TocBlock, {
|
|
261
|
+
m: {
|
|
262
|
+
title: m.title ?? "",
|
|
263
|
+
depth: m.depth ?? "3"
|
|
264
|
+
},
|
|
265
|
+
set: (fn, label) => set((prev) => {
|
|
266
|
+
const next = fn({
|
|
267
|
+
title: prev.title ?? "",
|
|
268
|
+
depth: prev.depth ?? "3"
|
|
269
|
+
});
|
|
270
|
+
const out = { ...prev };
|
|
271
|
+
if (next.title !== (prev.title ?? "")) out.title = next.title;
|
|
272
|
+
if (next.depth !== (prev.depth ?? "3")) out.depth = next.depth;
|
|
273
|
+
return out;
|
|
274
|
+
}, label),
|
|
275
|
+
el,
|
|
276
|
+
ctx,
|
|
277
|
+
autoFocus
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/** The island's stored columns (gap, each column's HTML) through columns.tsx's block. */
|
|
281
|
+
function ColumnsIsland({ m, set, el, ctx, autoFocus }) {
|
|
282
|
+
return /* @__PURE__ */ jsx(ColumnsBlock, {
|
|
283
|
+
m: {
|
|
284
|
+
gap: m.gap ?? "m",
|
|
285
|
+
cols: m.cols
|
|
286
|
+
},
|
|
287
|
+
set: (fn, label) => set((prev) => {
|
|
288
|
+
const next = fn({
|
|
289
|
+
gap: prev.gap ?? "m",
|
|
290
|
+
cols: prev.cols
|
|
291
|
+
});
|
|
292
|
+
const out = {
|
|
293
|
+
...prev,
|
|
294
|
+
cols: next.cols
|
|
295
|
+
};
|
|
296
|
+
if (next.gap !== (prev.gap ?? "m")) out.gap = next.gap;
|
|
297
|
+
return out;
|
|
298
|
+
}, label),
|
|
299
|
+
el,
|
|
300
|
+
ctx,
|
|
301
|
+
autoFocus
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
/** The island's stored author reference through author.tsx's block, picking from the field's authors collection. */
|
|
305
|
+
function AuthorIsland({ m, set, el, ctx, autoFocus }) {
|
|
306
|
+
return /* @__PURE__ */ jsx(AuthorBlock, {
|
|
307
|
+
m: { author: m.author ?? "" },
|
|
308
|
+
set: (fn, label) => set((prev) => {
|
|
309
|
+
const next = fn({ author: prev.author ?? "" });
|
|
310
|
+
return next.author === (prev.author ?? "") ? prev : {
|
|
311
|
+
...prev,
|
|
312
|
+
author: next.author
|
|
313
|
+
};
|
|
314
|
+
}, label),
|
|
315
|
+
el,
|
|
316
|
+
ctx,
|
|
317
|
+
autoFocus,
|
|
318
|
+
collection: ctx.references?.authors ?? ""
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
/** The island's stored related posts through related.tsx's block, over the field's posts collection. */
|
|
322
|
+
var toRelated = (m) => ({
|
|
323
|
+
title: m.title ?? "",
|
|
324
|
+
mode: m.mode ?? "topic",
|
|
325
|
+
count: m.count ?? 3,
|
|
326
|
+
posts: m.posts
|
|
327
|
+
});
|
|
328
|
+
function RelatedIsland({ m, set, el, ctx, autoFocus }) {
|
|
329
|
+
return /* @__PURE__ */ jsx(RelatedBlock, {
|
|
330
|
+
m: toRelated(m),
|
|
331
|
+
set: (fn, label) => set((prev) => {
|
|
332
|
+
const was = toRelated(prev);
|
|
333
|
+
const next = fn(was);
|
|
334
|
+
const out = {
|
|
335
|
+
...prev,
|
|
336
|
+
posts: next.posts
|
|
337
|
+
};
|
|
338
|
+
if (next.title !== was.title) out.title = next.title;
|
|
339
|
+
if (next.mode !== was.mode) out.mode = next.mode;
|
|
340
|
+
if (next.count !== was.count) out.count = next.count;
|
|
341
|
+
return out;
|
|
342
|
+
}, label),
|
|
343
|
+
el,
|
|
344
|
+
ctx,
|
|
345
|
+
autoFocus,
|
|
346
|
+
collection: ctx.references?.posts ?? "",
|
|
347
|
+
excludeId: ctx.references?.entryId
|
|
348
|
+
});
|
|
349
|
+
}
|
|
163
350
|
var Sep = () => /* @__PURE__ */ jsx("span", {
|
|
164
351
|
"aria-hidden": true,
|
|
165
352
|
className: "mx-0.5 h-4 w-px shrink-0 bg-kit-line"
|