@bettercms-ai/next 0.23.0 → 0.24.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/dist/index.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import { PageMetaJson, ContentBlock, DeliveredLayout, FieldStyles, SiteSeoDefaults, BlockStyle, FieldStyle, DeliveryComponent } from '@bettercms-ai/types';
2
- export { DeliveredLayout, PageMetaJson, RESPONSIVE_CSS, SiteSeoDefaults } from '@bettercms-ai/types';
2
+ export { DeliveredLayout, LinkValue, PageMetaJson, RESPONSIVE_CSS, SiteSeoDefaults, linkHref } from '@bettercms-ai/types';
3
3
  import { Metadata } from 'next';
4
4
  import { SeoInput, SeoLocation, DeliveryForm } from '@bettercms-ai/sdk';
5
5
  export { ResolvedSeo, SeoInput, resolveSeo } from '@bettercms-ai/sdk';
6
- import { CSSProperties, ReactElement, ElementType, ReactNode } from 'react';
6
+ import { CSSProperties, ReactElement, ElementType, ReactNode, ImgHTMLAttributes } from 'react';
7
+ import { ImageSource, ImageFormat, ImageFit } from '@bettercms-ai/image-url';
7
8
  export { ImageCrop, ImageFit, ImageFocal, ImageFormat, ImageSource, ImageUrlBuilder, ImageValueUrlOptions, imageUrl, default as imageUrlBuilder, imageValueObjectPosition, imageValueUrl } from '@bettercms-ai/image-url';
8
9
  import * as react_jsx_runtime from 'react/jsx-runtime';
9
10
 
@@ -591,7 +592,7 @@ interface BcmsFieldProps {
591
592
  path: string;
592
593
  /** Kind hint the editor's reflection branches on. Omit for plain text/number. */
593
594
  kind?: "richtext" | "image";
594
- /** Wrapper element. Defaults to a `display:contents` span. */
595
+ /** Wrapper element. Without it: no wrapper around a single DOM element, a `display:contents` span around anything else. */
595
596
  as?: ElementType;
596
597
  children: ReactNode;
597
598
  }
@@ -606,6 +607,32 @@ interface BcmsButtonProps {
606
607
  }
607
608
  declare function BcmsButton({ path, value, className }: BcmsButtonProps): react_jsx_runtime.JSX.Element | null;
608
609
 
610
+ /** What delivery adds to an image value beside its url: the facts this component reads. */
611
+ type ImageFacts = {
612
+ altText?: string | null;
613
+ alt?: string | null;
614
+ width?: number | null;
615
+ height?: number | null;
616
+ focalX?: number | null;
617
+ focalY?: number | null;
618
+ };
619
+ interface BcmsImageProps extends Omit<ImgHTMLAttributes<HTMLImageElement>, "src" | "srcSet" | "width" | "height"> {
620
+ src: ImageSource | (Exclude<ImageSource, string> & ImageFacts);
621
+ /** The field this image renders, in the editor grammar (`cover`, `hero.image`). */
622
+ path?: string;
623
+ width?: number;
624
+ height?: number;
625
+ format?: ImageFormat;
626
+ quality?: number;
627
+ fit?: ImageFit;
628
+ /** Focal point override, 0–1. Normally omitted: the value and the asset carry their own. */
629
+ focalX?: number | null;
630
+ focalY?: number | null;
631
+ /** Media host for a `src` that is only an asset id. Defaults to the platform's. */
632
+ baseUrl?: string;
633
+ }
634
+ declare function BcmsImage({ src, path, alt, width, height, format, quality, fit, sizes, loading, focalX, focalY, baseUrl, style, ...rest }: BcmsImageProps): react_jsx_runtime.JSX.Element;
635
+
609
636
  /** A `change` frame off the live stream. */
610
637
  interface BcmsChangeEvent<T = unknown> {
611
638
  type: "entry" | "page";
@@ -687,4 +714,4 @@ interface VisualEditingProps {
687
714
  studioUrl?: string;
688
715
  }
689
716
 
690
- export { type BcmsBlocksProps, BcmsButton, type BcmsButtonProps, BcmsDraftMarker, BcmsField, type BcmsFieldProps, type BcmsFormProps, type BcmsLiveProps, type BetterCMSConfig, type BetterCMSEntry, BetterCMSError, type BetterCMSLiveConfig, type BetterCMSNext, type BetterCMSPage, type ContentSnapshot, type ContentSource, DEFAULT_SNAPSHOT_FILE, type DraftModeRouteConfig, type EntryList, type FieldAttrs, type GetEntryOptions, type ListEntriesOptions, type LlmsModel, type LlmsModelField, type LlmsTxtOptions, type LlmsTxtRouteConfig, PREVIEW_TOKEN_COOKIE, type ReadOptions, type RevalidateRouteConfig, SNAPSHOT_VERSION, type SectionColumnAttrs, type SectionRootAttrs, type SectionRootBlock, type SnapshotForms, type SnapshotPage, type VisualEditingProps, buildMetadata, buildSnapshot, createBetterCMS, createDisableDraftRoute, createDraftModeRoute, createRevalidateRoute, defineBetterCMSLive, fetchModels, fieldAttrs, fieldStyleOf, generateLlmsTxt, getComponent, getContent, getForm, getPage, getPreviewToken, isDraftEnabled, llmsTxtRoute, parseSnapshot, readComponents, readForms, readPages, readSnapshot, sectionColumnAttrs, sectionRootAttrs, serializeSnapshot, writeSnapshot };
717
+ export { type BcmsBlocksProps, BcmsButton, type BcmsButtonProps, BcmsDraftMarker, BcmsField, type BcmsFieldProps, type BcmsFormProps, BcmsImage, type BcmsImageProps, type BcmsLiveProps, type BetterCMSConfig, type BetterCMSEntry, BetterCMSError, type BetterCMSLiveConfig, type BetterCMSNext, type BetterCMSPage, type ContentSnapshot, type ContentSource, DEFAULT_SNAPSHOT_FILE, type DraftModeRouteConfig, type EntryList, type FieldAttrs, type GetEntryOptions, type ListEntriesOptions, type LlmsModel, type LlmsModelField, type LlmsTxtOptions, type LlmsTxtRouteConfig, PREVIEW_TOKEN_COOKIE, type ReadOptions, type RevalidateRouteConfig, SNAPSHOT_VERSION, type SectionColumnAttrs, type SectionRootAttrs, type SectionRootBlock, type SnapshotForms, type SnapshotPage, type VisualEditingProps, buildMetadata, buildSnapshot, createBetterCMS, createDisableDraftRoute, createDraftModeRoute, createRevalidateRoute, defineBetterCMSLive, fetchModels, fieldAttrs, fieldStyleOf, generateLlmsTxt, getComponent, getContent, getForm, getPage, getPreviewToken, isDraftEnabled, llmsTxtRoute, parseSnapshot, readComponents, readForms, readPages, readSnapshot, sectionColumnAttrs, sectionRootAttrs, serializeSnapshot, writeSnapshot };
package/dist/index.js CHANGED
@@ -222,6 +222,7 @@ function buildMetadata(page, siteDefaults = {}, location = {}) {
222
222
 
223
223
  // src/index.ts
224
224
  import { RESPONSIVE_CSS } from "@bettercms-ai/types";
225
+ import { linkHref } from "@bettercms-ai/types";
225
226
 
226
227
  // src/section-root.ts
227
228
  import { blockStyleToColumnCss, blockStyleToCss, hideOnAttr } from "@bettercms-ai/types";
@@ -621,9 +622,15 @@ function getComponent(idOrSlug, path) {
621
622
  }
622
623
 
623
624
  // src/field.tsx
625
+ import { Children, cloneElement, isValidElement } from "react";
624
626
  import { jsx } from "react/jsx-runtime";
625
627
  function BcmsField({ path, kind, as, children }) {
626
628
  const Tag = as ?? "span";
629
+ const only = as ? [] : Children.toArray(children);
630
+ const sole = only.length === 1 && isValidElement(only[0]) && typeof only[0].type === "string" ? only[0] : null;
631
+ if (sole && sole.props["data-bcms-field"] === void 0 && sole.props["data-bcms-layout-field"] === void 0) {
632
+ return cloneElement(sole, { "data-bcms-field": path, "data-bcms-kind": kind });
633
+ }
627
634
  return /* @__PURE__ */ jsx(
628
635
  Tag,
629
636
  {
@@ -661,6 +668,78 @@ function BcmsButton({ path, value, className }) {
661
668
  );
662
669
  }
663
670
 
671
+ // src/image.tsx
672
+ import imageUrlBuilder, {
673
+ focalInCrop,
674
+ normalizeImageCrop,
675
+ normalizeImageFocal,
676
+ objectPosition
677
+ } from "@bettercms-ai/image-url";
678
+ import { jsx as jsx3 } from "react/jsx-runtime";
679
+ var LADDER = [480, 768, 1080, 1440, 1920];
680
+ var num = (v) => typeof v === "number" && Number.isFinite(v) ? v : void 0;
681
+ function BcmsImage({
682
+ src,
683
+ path,
684
+ alt,
685
+ width,
686
+ height,
687
+ format = "webp",
688
+ quality,
689
+ fit,
690
+ sizes,
691
+ loading = "lazy",
692
+ focalX,
693
+ focalY,
694
+ baseUrl,
695
+ style,
696
+ ...rest
697
+ }) {
698
+ const asset = typeof src === "object" && src !== null ? src : {};
699
+ const explicit = focalX != null || focalY != null;
700
+ const stored = normalizeImageFocal(asset.focal) ?? (num(asset.focalX) != null || num(asset.focalY) != null ? { x: num(asset.focalX) ?? 0.5, y: num(asset.focalY) ?? 0.5 } : null);
701
+ const inWindow = stored ? focalInCrop(stored, normalizeImageCrop(asset.crop)) : null;
702
+ const fx = explicit ? focalX : inWindow?.x;
703
+ const fy = explicit ? focalY : inWindow?.y;
704
+ const hasFocal = fx != null || fy != null;
705
+ const builder = imageUrlBuilder({ baseUrl });
706
+ const make = () => {
707
+ let b = builder(src);
708
+ if (width) b = b.width(width);
709
+ if (height) b = b.height(height);
710
+ if (format) b = b.format(format);
711
+ if (quality) b = b.quality(quality);
712
+ if (fit) b = b.fit(fit);
713
+ if (hasFocal) b = b.focal(fx ?? 0.5, fy ?? 0.5);
714
+ return b;
715
+ };
716
+ const src1x = make().url();
717
+ const own = num(asset.width);
718
+ const ladder = own ? [.../* @__PURE__ */ new Set([...LADDER.filter((w) => w < own), Math.min(own, LADDER[LADDER.length - 1])])] : LADDER;
719
+ const srcSet = sizes && !width ? ladder.map((w) => `${make().width(w).url()} ${w}w`).join(", ") : `${src1x} 1x, ${make().dpr(2).url()} 2x`;
720
+ const merged = {
721
+ ...width ? { width: `${width}px`, maxWidth: "100%", height: "auto" } : {},
722
+ ...hasFocal ? { objectPosition: objectPosition({ x: fx, y: fy }) } : {},
723
+ ...style
724
+ };
725
+ return /* @__PURE__ */ jsx3(
726
+ "img",
727
+ {
728
+ src: src1x,
729
+ srcSet,
730
+ alt: alt ?? (typeof asset.altText === "string" ? asset.altText : typeof asset.alt === "string" ? asset.alt : ""),
731
+ "data-bcms-field": path,
732
+ "data-bcms-kind": path ? "image" : void 0,
733
+ width,
734
+ height,
735
+ sizes,
736
+ loading,
737
+ style: Object.keys(merged).length > 0 ? merged : void 0,
738
+ ...rest
739
+ }
740
+ );
741
+ }
742
+
664
743
  // src/live-config.ts
665
744
  function defineBetterCMSLive(config) {
666
745
  const base = config.apiUrl.replace(/\/+$/, "");
@@ -705,6 +784,7 @@ export {
705
784
  BcmsButton,
706
785
  BcmsDraftMarker,
707
786
  BcmsField,
787
+ BcmsImage,
708
788
  BetterCMSError,
709
789
  DEFAULT_SNAPSHOT_FILE,
710
790
  PREVIEW_TOKEN_COOKIE,
@@ -731,6 +811,7 @@ export {
731
811
  imageValueObjectPosition,
732
812
  imageValueUrl,
733
813
  isDraftEnabled,
814
+ linkHref,
734
815
  llmsTxtRoute,
735
816
  parseSnapshot,
736
817
  readComponents,