@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.
Files changed (37) hide show
  1. package/dist/adapters/lossy.d.ts +4 -0
  2. package/dist/adapters/lossy.js +8 -2
  3. package/dist/adapters/lossy.js.map +1 -1
  4. package/dist/adapters/schema.js +28 -0
  5. package/dist/adapters/schema.js.map +1 -1
  6. package/dist/controls/rich-text/blocks.d.ts +6 -0
  7. package/dist/controls/rich-text/blocks.js +187 -0
  8. package/dist/controls/rich-text/blocks.js.map +1 -1
  9. package/dist/controls/rich-text/catalog.d.ts +2 -5
  10. package/dist/controls/rich-text/catalog.js +104 -6
  11. package/dist/controls/rich-text/catalog.js.map +1 -1
  12. package/dist/controls/rich-text/codec.d.ts +10 -1
  13. package/dist/controls/rich-text/codec.js +7 -0
  14. package/dist/controls/rich-text/codec.js.map +1 -1
  15. package/dist/controls/rich-text/control.js +1 -0
  16. package/dist/controls/rich-text/control.js.map +1 -1
  17. package/dist/controls/rich-text/dom.d.ts +79 -0
  18. package/dist/controls/rich-text/dom.js +159 -7
  19. package/dist/controls/rich-text/dom.js.map +1 -1
  20. package/dist/controls/rich-text/editor.d.ts +4 -2
  21. package/dist/controls/rich-text/editor.js +93 -3
  22. package/dist/controls/rich-text/editor.js.map +1 -1
  23. package/dist/controls/rich-text/ops.js +6 -0
  24. package/dist/controls/rich-text/ops.js.map +1 -1
  25. package/dist/controls/rich-text/toc.d.ts +3 -2
  26. package/dist/controls/rich-text/toc.js +1 -2
  27. package/dist/controls/rich-text/toc.js.map +1 -1
  28. package/dist/core/core.d.ts +1 -0
  29. package/dist/core/core.js +2 -0
  30. package/dist/core/core.js.map +1 -1
  31. package/dist/core/facets.d.ts +8 -0
  32. package/dist/core/facets.js +8 -0
  33. package/dist/core/facets.js.map +1 -1
  34. package/dist/library/kit-catalog.json +4 -2
  35. package/dist/schema/types.d.ts +8 -0
  36. package/dist/schema/types.js.map +1 -1
  37. 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"