@sevenfold/setto-client 0.35.0 → 0.36.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.
Files changed (39) hide show
  1. package/dist/SettoAnimation.d.ts +1 -1
  2. package/dist/block-tree/SettoBlockTree.d.ts +2 -2
  3. package/dist/block-tree/extract-keys.d.ts +1 -1
  4. package/dist/block-tree/registry.d.ts +1 -1
  5. package/dist/block-tree/schema.d.ts +3 -3
  6. package/dist/block-tree/validate.d.ts +1 -1
  7. package/dist/blog/SettoBlog.d.ts +20 -0
  8. package/dist/blog/data.d.ts +36 -0
  9. package/dist/blog/index.d.ts +4 -4
  10. package/dist/blog/render.d.ts +16 -0
  11. package/dist/blog/strings.d.ts +25 -0
  12. package/dist/blog/validate.d.ts +1 -1
  13. package/dist/edit-mode/mount.d.ts +1 -1
  14. package/dist/index.d.ts +62 -59
  15. package/dist/lib/api.d.ts +2 -2
  16. package/dist/lib/map-location.d.ts +2 -2
  17. package/dist/lib/page-store.d.ts +1 -1
  18. package/dist/lib/use-site-access.d.ts +1 -1
  19. package/dist/modules/chat/index.d.ts +2 -2
  20. package/dist/modules/domain/index.d.ts +1 -1
  21. package/dist/modules/forms/SettoForm.d.ts +1 -1
  22. package/dist/modules/forms/api.d.ts +1 -1
  23. package/dist/modules/forms/field-tools.d.ts +1 -1
  24. package/dist/modules/forms/index.d.ts +6 -6
  25. package/dist/modules/index.d.ts +2 -2
  26. package/dist/pages/SettoPage.d.ts +1 -1
  27. package/dist/pages/bundled.d.ts +1 -1
  28. package/dist/pages/manifest.d.ts +18 -1
  29. package/dist/provider.d.ts +6 -6
  30. package/dist/setto-client.js +735 -198
  31. package/dist/setto-client.js.map +1 -1
  32. package/dist/types.d.ts +9 -1
  33. package/dist/vite/index.d.ts +6 -0
  34. package/dist/vite/plugin.d.ts +32 -0
  35. package/dist/vite/static.d.ts +78 -0
  36. package/dist/vite.js +550 -0
  37. package/dist/vite.js.map +1 -0
  38. package/package.json +11 -3
  39. package/virtual.d.ts +11 -0
@@ -1,5 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
- import type { AnimationPreset } from './block-tree/schema';
2
+ import type { AnimationPreset } from './block-tree/schema.js';
3
3
  export interface SettoAnimationProps {
4
4
  preset: AnimationPreset;
5
5
  /** Delay before play, in milliseconds. */
@@ -1,6 +1,6 @@
1
1
  import { type ComponentType } from 'react';
2
- import { type SettoIconRenderProps } from '../SettoIcon';
3
- import type { BlockTree } from './schema';
2
+ import { type SettoIconRenderProps } from '../SettoIcon.js';
3
+ import type { BlockTree } from './schema.js';
4
4
  export interface SettoBlockTreeProps {
5
5
  /** Validated block tree, typically parsed from `home.layout.json`. */
6
6
  tree: BlockTree;
@@ -3,7 +3,7 @@
3
3
  * sample-locale entries it expects. The agent uses this output to validate
4
4
  * that the generated `no.json` covers everything the tree references.
5
5
  */
6
- import type { BlockTree } from './schema';
6
+ import type { BlockTree } from './schema.js';
7
7
  export interface ContentKeyRequirements {
8
8
  /** Plain i18n keys that must exist with a string value. */
9
9
  keys: Set<string>;
@@ -5,7 +5,7 @@
5
5
  * consult this registry for allowed children, required content keys, and
6
6
  * whether a type carries a theme id.
7
7
  */
8
- import type { BlockNode, BlockNodeType } from './schema';
8
+ import type { BlockNode, BlockNodeType } from './schema.js';
9
9
  export interface BlockTypeMeta {
10
10
  /**
11
11
  * Allowed child types. `null` means the node is a leaf; `'any'` means any
@@ -74,8 +74,8 @@ export interface RepeaterNode extends BaseNode {
74
74
  */
75
75
  itemTemplate: BlockNode[];
76
76
  }
77
- export type { FormFieldType } from '../modules/forms/fields';
78
- export type { FormFieldProp as FormField } from '../modules/forms/fields';
77
+ export type { FormFieldType } from '../modules/forms/fields.js';
78
+ export type { FormFieldProp as FormField } from '../modules/forms/fields.js';
79
79
  export interface FormNode extends BaseNode {
80
80
  type: 'form';
81
81
  /**
@@ -95,7 +95,7 @@ export interface FormNode extends BaseNode {
95
95
  * Seed fields, used only while the locale has no `form.{formId}.fields`
96
96
  * list. Once the editor touches the field set, the locale wins.
97
97
  */
98
- fields?: import('../modules/forms/fields').FormFieldProp[];
98
+ fields?: import('../modules/forms/fields.js').FormFieldProp[];
99
99
  }
100
100
  export interface VideoNode extends BaseNode {
101
101
  type: 'video';
@@ -5,7 +5,7 @@
5
5
  * and `setto-agent` (after generation, before sandbox build). No external
6
6
  * dependencies so we can ship to host sites without bundle bloat.
7
7
  */
8
- import type { BlockTree, FormField } from './schema';
8
+ import type { BlockTree, FormField } from './schema.js';
9
9
  export interface ValidationIssue {
10
10
  /** Dotted path to the offending node, e.g. `root[2].children[0]`. */
11
11
  path: string;
@@ -0,0 +1,20 @@
1
+ import { type BuiltinSectionProps } from '../pages/SettoPage.js';
2
+ export declare function SettoBlogSection({ sectionId, first }: BuiltinSectionProps): import("react/jsx-runtime").JSX.Element;
3
+ /**
4
+ * The blog for a site that routes by hand instead of through `pages.json`
5
+ * (setto.no): mount it on `<basePath>` and `<basePath>/*`, and pass the same
6
+ * path to `settoBlog({ blogPath })`.
7
+ *
8
+ * <Route path="/blogg/*" element={<SettoBlog basePath="/blogg" />} />
9
+ */
10
+ export declare function SettoBlog({ basePath, title }: {
11
+ basePath?: string;
12
+ title?: string;
13
+ }): import("react/jsx-runtime").JSX.Element;
14
+ export declare function SettoBlogLatest({ sectionId, first }: BuiltinSectionProps): import("react/jsx-runtime").JSX.Element | null;
15
+ /**
16
+ * Shape is scoped `.setto-blog :where(…)` (one class: beats Preflight's
17
+ * element resets); colour stays at zero specificity so the site's own wins.
18
+ * Same split, same reason, as the form's sheet.
19
+ */
20
+ export declare const BLOG_CSS = "\n.setto-blog{padding:clamp(48px,8vw,96px) 16px}\n.setto-blog :where(.setto-blog__inner){max-width:68ch;margin:0 auto}\n.setto-blog :where(.setto-blog__inner--wide){max-width:1120px}\n.setto-blog :where(.setto-blog__title){font-family:var(--setto-display-font,inherit);font-size:clamp(2rem,4vw,2.75rem);line-height:1.15;font-weight:600;margin:0 0 .75em}\n.setto-blog :where(.setto-blog__list){display:grid;gap:clamp(1.5rem,3vw,2.5rem);grid-template-columns:repeat(auto-fill,minmax(min(100%,300px),1fr))}\n.setto-blog :where(.setto-blog__card){display:grid;gap:.9rem;align-content:start}\n.setto-blog :where(.setto-blog__card-cover){display:block;overflow:hidden;border-radius:.9rem;aspect-ratio:16/10}\n.setto-blog :where(.setto-blog__card-cover img,.setto-blog__cover img,.setto-blog__figure img,.setto-blog__gallery-item img){display:block;width:100%;height:100%;object-fit:cover}\n.setto-blog :where(.setto-blog__card-body){display:grid;gap:.45rem}\n.setto-blog :where(.setto-blog__card-title){font-family:var(--setto-display-font,inherit);font-size:1.3rem;line-height:1.25;font-weight:600;margin:0}\n.setto-blog :where(.setto-blog__card-lead){margin:0;line-height:1.55}\n.setto-blog :where(.setto-blog__date){font-size:.875rem;letter-spacing:.01em}\n.setto-blog :where(.setto-blog__more,.setto-blog__back){display:inline-flex;gap:.35em;align-items:center;font-weight:500;width:fit-content}\n.setto-blog :where(.setto-blog__back){margin-bottom:2rem}\n.setto-blog :where(.setto-blog__latest-head){display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:.5rem 1.5rem;margin-bottom:1.75rem}\n.setto-blog :where(.setto-blog__latest-head .setto-blog__title){margin:0}\n.setto-blog :where(.setto-blog__post-header){display:grid;gap:.6rem;margin-bottom:2rem}\n.setto-blog :where(.setto-blog__post-title){font-family:var(--setto-display-font,inherit);font-size:clamp(2rem,5vw,3rem);line-height:1.1;font-weight:600;margin:0}\n.setto-blog :where(.setto-blog__lead){font-size:1.2rem;line-height:1.5;margin:0}\n.setto-blog :where(.setto-blog__cover){margin:0 0 2.5rem;overflow:hidden;border-radius:1rem;aspect-ratio:16/9}\n.setto-blog :where(.setto-blog__prose){font-size:1.075rem;line-height:1.7}\n.setto-blog :where(.setto-blog__prose > * + *){margin-top:1.15em}\n.setto-blog :where(.setto-blog__prose h2,.setto-blog__prose h3,.setto-blog__prose h4){font-family:var(--setto-display-font,inherit);line-height:1.25;font-weight:600;margin:1.8em 0 0}\n.setto-blog :where(.setto-blog__prose h2){font-size:1.6rem}\n.setto-blog :where(.setto-blog__prose h3){font-size:1.3rem}\n.setto-blog :where(.setto-blog__prose h4){font-size:1.1rem}\n.setto-blog :where(.setto-blog__prose ul,.setto-blog__prose ol){padding-left:1.4em}\n.setto-blog :where(.setto-blog__prose ul){list-style:disc}\n.setto-blog :where(.setto-blog__prose ol){list-style:decimal}\n.setto-blog :where(.setto-blog__prose li + li){margin-top:.35em}\n.setto-blog :where(.setto-blog__prose blockquote){margin-left:0;padding-left:1.1em;border-left-width:3px;border-left-style:solid;font-style:italic}\n.setto-blog :where(.setto-blog__prose pre){overflow-x:auto;padding:1em;border-radius:.6rem;font-size:.9em}\n.setto-blog :where(.setto-blog__prose code){font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.92em}\n.setto-blog :where(.setto-blog__prose hr){border:0;border-top-width:1px;border-top-style:solid;margin:2.5em 0}\n.setto-blog :where(.setto-blog__prose a){text-decoration:underline;text-underline-offset:.18em}\n.setto-blog :where(.setto-blog__table){overflow-x:auto}\n.setto-blog :where(.setto-blog__table table){border-collapse:collapse;width:100%;font-size:.95em}\n.setto-blog :where(.setto-blog__table th,.setto-blog__table td){padding:.55em .8em;border-bottom-width:1px;border-bottom-style:solid;text-align:left}\n.setto-blog :where(.setto-blog__figure,.setto-blog__gallery,.setto-blog__video){margin:2em 0}\n.setto-blog :where(.setto-blog__figure img){border-radius:.8rem;height:auto}\n.setto-blog :where(figcaption){font-size:.9rem;margin-top:.6em;opacity:.75}\n.setto-blog :where(.setto-blog__gallery-grid){display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(min(100%,150px),1fr))}\n.setto-blog :where(.setto-blog__gallery-item){margin:0}\n.setto-blog :where(.setto-blog__gallery-item img){border-radius:.6rem;aspect-ratio:4/3}\n.setto-blog :where(.setto-blog__video-frame){position:relative;aspect-ratio:16/9;border-radius:.8rem;overflow:hidden}\n.setto-blog :where(.setto-blog__video-frame iframe){position:absolute;inset:0;width:100%;height:100%;border:0}\n.setto-blog :where(.setto-blog__video-play){position:absolute;inset:0;width:100%;height:100%;padding:0;border:0;cursor:pointer;display:grid;place-items:center}\n.setto-blog :where(.setto-blog__video-play img){position:absolute;inset:0;width:100%;height:100%;object-fit:cover}\n.setto-blog :where(.setto-blog__video-icon){position:relative;display:block;line-height:0}\n.setto-blog :where(.setto-blog__callout){padding:1.1em 1.3em;border-radius:.8rem;border-left-width:4px;border-left-style:solid}\n.setto-blog :where(.setto-blog__callout > * + *){margin-top:.7em}\n.setto-blog :where(.setto-blog__callout ul,.setto-blog__callout ol){padding-left:1.3em;list-style:disc}\n.setto-blog :where(.setto-blog__share){display:flex;flex-wrap:wrap;gap:.5rem .9rem;align-items:center;margin-top:3rem;padding-top:1.5rem;border-top-width:1px;border-top-style:solid}\n.setto-blog :where(.setto-blog__share-label){font-weight:600}\n.setto-blog :where(.setto-blog__share a,.setto-blog__share button){font:inherit;padding:.35rem .85rem;border-radius:999px;border-width:1px;border-style:solid;cursor:pointer;text-decoration:none;line-height:1.4}\n.setto-blog :where(.setto-blog__empty,.setto-blog__loading){opacity:.75}\n:where(.setto-blog){color:inherit}\n:where(.setto-blog__date){opacity:.7}\n:where(.setto-blog a){color:inherit}\n:where(.setto-blog__prose blockquote,.setto-blog__prose hr,.setto-blog__table th,.setto-blog__table td,.setto-blog__share){border-color:color-mix(in srgb,currentColor 18%,transparent)}\n:where(.setto-blog__prose pre,.setto-blog__card-cover){background:color-mix(in srgb,currentColor 6%,transparent)}\n:where(.setto-blog__share a,.setto-blog__share button){border-color:color-mix(in srgb,currentColor 30%,transparent);background:transparent;color:inherit}\n:where(.setto-blog__callout){background:color-mix(in srgb,currentColor 5%,transparent);border-left-color:color-mix(in srgb,currentColor 40%,transparent)}\n:where(.setto-blog__callout[data-tone=\"tip\"]){border-left-color:#0f7b4f}\n:where(.setto-blog__callout[data-tone=\"warning\"]){border-left-color:#b54708}\n:where(.setto-blog__video-frame){background:#000}\n";
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The posts a site's build hands to the library, and how a page chooses among
3
+ * them. No parser and no React: the build (`@setto/client/vite`) has already
4
+ * validated every file against the contract and turned its body into a syntax
5
+ * tree, so the browser only walks data.
6
+ */
7
+ import type { Root } from 'mdast';
8
+ import type { BlogFrontmatter } from './contract.js';
9
+ /** A post as the list knows it: its frontmatter, and nothing to download. */
10
+ export type BlogPostSummary = BlogFrontmatter;
11
+ /** A post as its page knows it: frontmatter and the body's syntax tree. */
12
+ export interface BlogPostData {
13
+ frontmatter: BlogFrontmatter;
14
+ body: Root;
15
+ }
16
+ /**
17
+ * What `virtual:setto-blog` exports and `SettoConfig.blog` carries. Bodies are
18
+ * loaded one at a time, so a site with a hundred posts does not ship a
19
+ * hundred articles to read one.
20
+ */
21
+ export interface SettoBlogData {
22
+ posts: readonly BlogPostSummary[];
23
+ load(slug: string, locale: string): Promise<BlogPostData | null>;
24
+ }
25
+ /** Newest first; a tie breaks on slug so the order never flickers. */
26
+ export declare function byDateDesc(a: BlogPostSummary, b: BlogPostSummary): number;
27
+ /**
28
+ * One entry per post, in the reader's language where it exists and in the
29
+ * site's own otherwise. A post written only in Norwegian still shows to an
30
+ * English reader — untranslated is better than missing.
31
+ */
32
+ export declare function postsForLanguage(posts: readonly BlogPostSummary[], language: string, fallbackLanguage: string): BlogPostSummary[];
33
+ /** The version of one post to show this reader, or null if there is none. */
34
+ export declare function postForSlug(posts: readonly BlogPostSummary[], slug: string, language: string, fallbackLanguage: string): BlogPostSummary | null;
35
+ /** `2026-10-01` as «1. oktober 2026» or «1 October 2026». */
36
+ export declare function formatPostDate(date: string, language: string): string;
@@ -5,8 +5,8 @@
5
5
  * bundle: setto-server and setto-agent validate with it, and the site's build
6
6
  * step uses it to read posts.
7
7
  */
8
- export * from './contract';
8
+ export * from './contract.js';
9
9
  /** The host a post's images must come from: pass it as `imageHosts`. */
10
- export { SETTO_MEDIA_HOST, isSettoMediaUrl } from '../lib/media';
11
- export { validateBlogPost, parseBlogPost } from './validate';
12
- export type { BlogIssue, BlogPost, BlogValidationResult, BlogValidateOptions } from './validate';
10
+ export { SETTO_MEDIA_HOST, isSettoMediaUrl } from '../lib/media.js';
11
+ export { validateBlogPost, parseBlogPost } from './validate.js';
12
+ export type { BlogIssue, BlogPost, BlogValidationResult, BlogValidateOptions } from './validate.js';
@@ -0,0 +1,16 @@
1
+ import type { RootContent } from 'mdast';
2
+ export declare function BlogBody({ nodes, language }: {
3
+ nodes: readonly RootContent[];
4
+ language: string;
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ /**
7
+ * An image, resized by the site's optimizer when it has one and the image is
8
+ * one it may read (`isOptimizable`: this site's own, or a blog photograph in
9
+ * Setto's media store). If a variant fails, the original is shown instead.
10
+ */
11
+ export declare function BlogImg({ src, alt, sizes, className }: {
12
+ src: string;
13
+ alt: string;
14
+ sizes: string;
15
+ className?: string;
16
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The few words the blog says itself — around the posts, never in them. In
3
+ * Norwegian and English; any other language reads English, which is what a
4
+ * visitor who chose it can most likely read.
5
+ */
6
+ declare const NO: {
7
+ blog: string;
8
+ latest: string;
9
+ allPosts: string;
10
+ readMore: string;
11
+ back: string;
12
+ empty: string;
13
+ notFound: string;
14
+ loading: string;
15
+ share: string;
16
+ moreShare: string;
17
+ copyLink: string;
18
+ copied: string;
19
+ email: string;
20
+ video: string;
21
+ play: string;
22
+ };
23
+ export type BlogStrings = typeof NO;
24
+ export declare function blogStrings(language: string): BlogStrings;
25
+ export {};
@@ -7,7 +7,7 @@
7
7
  * first reader of a failure is usually a model that has to fix its own output.
8
8
  */
9
9
  import type { Root } from 'mdast';
10
- import { type BlogFrontmatter } from './contract';
10
+ import { type BlogFrontmatter } from './contract.js';
11
11
  export interface BlogIssue {
12
12
  /** `frontmatter`, `frontmatter.<key>`, `body` or `path`. */
13
13
  path: string;
@@ -1,5 +1,5 @@
1
1
  import { type ReactNode } from 'react';
2
- import type { ThemeStore } from '../lib/theme-store';
2
+ import type { ThemeStore } from '../lib/theme-store.js';
3
3
  interface EditModeShellProps {
4
4
  children: ReactNode;
5
5
  themeStore: ThemeStore | null;
package/dist/index.d.ts CHANGED
@@ -1,59 +1,62 @@
1
- export { SettoLanguages } from './LanguageSwitcher';
2
- export { DEFAULT_LANGUAGE, languageName, pickInitialLanguage, siteLanguages, } from './lib/languages';
3
- export { alternateLinks, languageFromPath, pathForLanguage, redirectForVisitor, type LanguageRoute, } from './lib/language-routing';
4
- export { SettoProvider, useSetto } from './provider';
5
- export { GuestEditProvider, useGuestEdit } from './guest-edit';
6
- export { SettoChrome, useSettoChromeSlot } from './chrome';
7
- export type { SettoChromeHandshake } from './chrome';
8
- export { T } from './T';
9
- export { SettoSection } from './SettoSection';
10
- export { SettoBlock } from './SettoBlock';
11
- export { SettoIcon } from './SettoIcon';
12
- export type { SettoIconProps, SettoIconRenderProps } from './SettoIcon';
13
- export { SettoImage } from './SettoImage';
14
- export type { SettoImageProps, ImageToolsProps } from './SettoImage';
15
- export { SETTO_IMAGE_QUALITY, SETTO_IMAGE_WIDTHS, isOptimizable, optimizedSrcSet, optimizedUrl, settoVercelImagesConfig, } from './lib/optimized-image';
16
- export { SETTO_MEDIA_HOST, isSettoMediaUrl } from './lib/media';
17
- export { SettoRepeater } from './SettoRepeater';
18
- export type { SettoRepeaterProps } from './SettoRepeater';
19
- export { SettoForm, FORM_FIELD_TYPES, FORM_FIELD_TYPE_LABELS, fieldTypeHasOptions, fieldTypeHasPlaceholder, formFieldsPrefix, isFormFieldType, readLocaleFields, settoSubmissionUrl, } from './modules/forms';
20
- export { SettoChat } from './modules/chat';
21
- export type { SettoFormProps, SettoFormClassNames, FormFieldProp, FormSettings, FormSubmissionRow, FormValue, FormValues, ResolvedFormField, SubmissionEnvelope, } from './modules/forms';
22
- export { SETTO_MODULES } from './modules';
23
- export type { SettoModule } from './modules';
24
- export { SettoVideo } from './SettoVideo';
25
- export type { SettoVideoProps } from './SettoVideo';
26
- export { SettoMap } from './SettoMap';
27
- export type { SettoMapProps } from './SettoMap';
28
- export type { MapLocation, MapToolsProps, MapToolsComponent } from './map-tools';
29
- export { SettoPage, SettoTextSection, usePageManifest, useSettoMenu, } from './pages/SettoPage';
30
- export type { SettoPageProps, BuiltinSectionProps } from './pages/SettoPage';
31
- export { PAGES_PATH, PAGES_MANIFEST_VERSION, BUILTIN_SECTION_TYPES, parseManifest, normalisePath, pageForPath, pageById, findSection, visibleMenu, applyOp, applyOps, builtinKeys, pageTitleKey, serialiseManifest, isSafeHref, ManifestError, } from './pages/manifest';
32
- export type { PagesManifest, PageEntry, PageSection, MenuItem, MenuList, ManifestOp, ManifestIssue, ManifestParse, BuiltinSectionType, } from './pages/manifest';
33
- export { PageStore, EMPTY_PAGE_STORE_SNAPSHOT, countChanges } from './lib/page-store';
34
- export type { PageStoreSnapshot } from './lib/page-store';
35
- export { SettoAnimation } from './SettoAnimation';
36
- export type { SettoAnimationProps } from './SettoAnimation';
37
- export { useSectionTheme } from './use-section-theme';
38
- export { SettoAdminApp } from './admin/App';
39
- export { SettoContext } from './provider';
40
- export type { SettoContextValue } from './provider';
41
- export { AuthGate } from './edit-mode/auth-gate';
42
- export type { SettoConfig, BrandColor, DeploymentRow, SiteRow, ContentFile, PublishFile, PublishResult, PublishTranslation, } from './types';
43
- export type { SectionSchema, SectionColorField } from './section-schema';
44
- export { SettoBlockTree } from './block-tree/SettoBlockTree';
45
- export type { SettoBlockTreeProps } from './block-tree/SettoBlockTree';
46
- export type { BlockTree, BlockTreeVersion, BlockNode, BlockNodeType, SectionNode, BlockBoxNode, ContainerNode, ContainerTag, TextNode, TextAs, ImageNode, IconNode, RepeaterNode, FormNode, FormField, FormFieldType, VideoNode, AnimationNode, AnimationPreset, } from './block-tree/schema';
47
- export { validateBlockTree, parseBlockTree, type ValidationIssue, type ValidationResult, } from './block-tree/validate';
48
- export { extractContentKeys, type ContentKeyRequirements, } from './block-tree/extract-keys';
49
- export { BLOCK_REGISTRY, BLOCK_TYPES, nodeChildren } from './block-tree/registry';
50
- export type { BlockTypeMeta } from './block-tree/registry';
51
- export { SETTO_BASE, siteHomeUrl, isAdminRoute, isAdminDeploymentView, adminViewUrl, currentAdminView, isAdminPanelView, adminRedirectUrl, CHECKOUT_INTENT, checkoutIntentUrl, wantsCheckout, withoutCheckoutIntent, } from './lib/urls';
52
- export { SettoMark } from './edit-mode/setto-mark';
53
- export { FloatingPopover } from './edit-mode/floating-popover';
54
- export type { FieldPatch, FormFieldToolsProps, FormFieldToolsComponent, } from './modules/forms/field-tools';
55
- export { isLinkContext } from './lib/link-context';
56
- export { useCoarsePointer } from './lib/use-coarse-pointer';
57
- export { FAB_SIZE, FAB_INSET } from './edit-mode/constants';
58
- export { EMPTY_I18N_STORE_SNAPSHOT } from './lib/i18n-store';
59
- export type { I18nStoreSnapshot } from './lib/i18n-store';
1
+ export { SettoLanguages } from './LanguageSwitcher.js';
2
+ export { DEFAULT_LANGUAGE, languageName, pickInitialLanguage, siteLanguages, } from './lib/languages.js';
3
+ export { alternateLinks, languageFromPath, pathForLanguage, redirectForVisitor, type LanguageRoute, } from './lib/language-routing.js';
4
+ export { SettoProvider, useSetto } from './provider.js';
5
+ export { GuestEditProvider, useGuestEdit } from './guest-edit.js';
6
+ export { SettoChrome, useSettoChromeSlot } from './chrome.js';
7
+ export type { SettoChromeHandshake } from './chrome.js';
8
+ export { T } from './T.js';
9
+ export { SettoSection } from './SettoSection.js';
10
+ export { SettoBlock } from './SettoBlock.js';
11
+ export { SettoIcon } from './SettoIcon.js';
12
+ export type { SettoIconProps, SettoIconRenderProps } from './SettoIcon.js';
13
+ export { SettoImage } from './SettoImage.js';
14
+ export type { SettoImageProps, ImageToolsProps } from './SettoImage.js';
15
+ export { SETTO_IMAGE_QUALITY, SETTO_IMAGE_WIDTHS, isOptimizable, optimizedSrcSet, optimizedUrl, settoVercelImagesConfig, } from './lib/optimized-image.js';
16
+ export { SETTO_MEDIA_HOST, isSettoMediaUrl } from './lib/media.js';
17
+ export { SettoBlog, SettoBlogSection, SettoBlogLatest, BLOG_CSS } from './blog/SettoBlog.js';
18
+ export { postsForLanguage, postForSlug, formatPostDate } from './blog/data.js';
19
+ export type { SettoBlogData, BlogPostData, BlogPostSummary } from './blog/data.js';
20
+ export { SettoRepeater } from './SettoRepeater.js';
21
+ export type { SettoRepeaterProps } from './SettoRepeater.js';
22
+ export { SettoForm, FORM_FIELD_TYPES, FORM_FIELD_TYPE_LABELS, fieldTypeHasOptions, fieldTypeHasPlaceholder, formFieldsPrefix, isFormFieldType, readLocaleFields, settoSubmissionUrl, } from './modules/forms/index.js';
23
+ export { SettoChat } from './modules/chat/index.js';
24
+ export type { SettoFormProps, SettoFormClassNames, FormFieldProp, FormSettings, FormSubmissionRow, FormValue, FormValues, ResolvedFormField, SubmissionEnvelope, } from './modules/forms/index.js';
25
+ export { SETTO_MODULES } from './modules/index.js';
26
+ export type { SettoModule } from './modules/index.js';
27
+ export { SettoVideo } from './SettoVideo.js';
28
+ export type { SettoVideoProps } from './SettoVideo.js';
29
+ export { SettoMap } from './SettoMap.js';
30
+ export type { SettoMapProps } from './SettoMap.js';
31
+ export type { MapLocation, MapToolsProps, MapToolsComponent } from './map-tools.js';
32
+ export { SettoPage, SettoTextSection, usePageManifest, useSettoMenu, } from './pages/SettoPage.js';
33
+ export type { SettoPageProps, BuiltinSectionProps } from './pages/SettoPage.js';
34
+ export { PAGES_PATH, PAGES_MANIFEST_VERSION, BUILTIN_SECTION_TYPES, parseManifest, normalisePath, pageForPath, blogPage, blogSlugForPath, pageById, findSection, visibleMenu, applyOp, applyOps, builtinKeys, pageTitleKey, serialiseManifest, isSafeHref, ManifestError, } from './pages/manifest.js';
35
+ export type { PagesManifest, PageEntry, PageSection, MenuItem, MenuList, ManifestOp, ManifestIssue, ManifestParse, BuiltinSectionType, } from './pages/manifest.js';
36
+ export { PageStore, EMPTY_PAGE_STORE_SNAPSHOT, countChanges } from './lib/page-store.js';
37
+ export type { PageStoreSnapshot } from './lib/page-store.js';
38
+ export { SettoAnimation } from './SettoAnimation.js';
39
+ export type { SettoAnimationProps } from './SettoAnimation.js';
40
+ export { useSectionTheme } from './use-section-theme.js';
41
+ export { SettoAdminApp } from './admin/App.js';
42
+ export { SettoContext } from './provider.js';
43
+ export type { SettoContextValue } from './provider.js';
44
+ export { AuthGate } from './edit-mode/auth-gate.js';
45
+ export type { SettoConfig, BrandColor, DeploymentRow, SiteRow, ContentFile, PublishFile, PublishResult, PublishTranslation, } from './types.js';
46
+ export type { SectionSchema, SectionColorField } from './section-schema.js';
47
+ export { SettoBlockTree } from './block-tree/SettoBlockTree.js';
48
+ export type { SettoBlockTreeProps } from './block-tree/SettoBlockTree.js';
49
+ export type { BlockTree, BlockTreeVersion, BlockNode, BlockNodeType, SectionNode, BlockBoxNode, ContainerNode, ContainerTag, TextNode, TextAs, ImageNode, IconNode, RepeaterNode, FormNode, FormField, FormFieldType, VideoNode, AnimationNode, AnimationPreset, } from './block-tree/schema.js';
50
+ export { validateBlockTree, parseBlockTree, type ValidationIssue, type ValidationResult, } from './block-tree/validate.js';
51
+ export { extractContentKeys, type ContentKeyRequirements, } from './block-tree/extract-keys.js';
52
+ export { BLOCK_REGISTRY, BLOCK_TYPES, nodeChildren } from './block-tree/registry.js';
53
+ export type { BlockTypeMeta } from './block-tree/registry.js';
54
+ export { SETTO_BASE, siteHomeUrl, isAdminRoute, isAdminDeploymentView, adminViewUrl, currentAdminView, isAdminPanelView, adminRedirectUrl, CHECKOUT_INTENT, checkoutIntentUrl, wantsCheckout, withoutCheckoutIntent, } from './lib/urls.js';
55
+ export { SettoMark } from './edit-mode/setto-mark.js';
56
+ export { FloatingPopover } from './edit-mode/floating-popover.js';
57
+ export type { FieldPatch, FormFieldToolsProps, FormFieldToolsComponent, } from './modules/forms/field-tools.js';
58
+ export { isLinkContext } from './lib/link-context.js';
59
+ export { useCoarsePointer } from './lib/use-coarse-pointer.js';
60
+ export { FAB_SIZE, FAB_INSET } from './edit-mode/constants.js';
61
+ export { EMPTY_I18N_STORE_SNAPSHOT } from './lib/i18n-store.js';
62
+ export type { I18nStoreSnapshot } from './lib/i18n-store.js';
package/dist/lib/api.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { SupabaseClient } from '@supabase/supabase-js';
2
- import type { ContentFile, PublishFile, PublishResult } from '../types';
3
- import type { AssetDraft } from './asset-store';
2
+ import type { ContentFile, PublishFile, PublishResult } from '../types.js';
3
+ import type { AssetDraft } from './asset-store.js';
4
4
  /**
5
5
  * One authenticated JSON call against setto-server. Modules build their api
6
6
  * segment on this (see `modules/forms/api.ts`) rather than on `fetch`, so
@@ -1,5 +1,5 @@
1
- import type { MapLocation } from '../map-tools';
2
- import type { I18nStore } from './i18n-store';
1
+ import type { MapLocation } from '../map-tools.js';
2
+ import type { I18nStore } from './i18n-store.js';
3
3
  /**
4
4
  * Where a `SettoMap` points, and how that becomes an OpenStreetMap embed.
5
5
  *
@@ -1,4 +1,4 @@
1
- import { type ManifestOp, type PagesManifest } from '../pages/manifest';
1
+ import { type ManifestOp, type PagesManifest } from '../pages/manifest.js';
2
2
  export interface PageStoreSnapshot {
3
3
  manifest: PagesManifest | null;
4
4
  /** How many pages, sections and links differ from what is published. */
@@ -1,5 +1,5 @@
1
1
  import type { Session, SupabaseClient } from '@supabase/supabase-js';
2
- import type { SiteRow } from '../types';
2
+ import type { SiteRow } from '../types.js';
3
3
  export interface SiteAccessState {
4
4
  /** All sites the current user can access. `null` until loaded. */
5
5
  sites: SiteRow[] | null;
@@ -1,3 +1,3 @@
1
- import type { SettoModule } from '../module';
1
+ import type { SettoModule } from '../module.js';
2
2
  export declare const chatModule: SettoModule;
3
- export { SettoChat } from './SettoChat';
3
+ export { SettoChat } from './SettoChat.js';
@@ -1,4 +1,4 @@
1
- import type { SettoModule } from '../module';
1
+ import type { SettoModule } from '../module.js';
2
2
  /**
3
3
  * The customer's own domain.
4
4
  *
@@ -1,4 +1,4 @@
1
- import { type FormFieldProp } from './fields';
1
+ import { type FormFieldProp } from './fields.js';
2
2
  /**
3
3
  * A form the site owner can change and a visitor can trust.
4
4
  *
@@ -1,4 +1,4 @@
1
- import type { ApiRequest } from '../../lib/api';
1
+ import type { ApiRequest } from '../../lib/api.js';
2
2
  /** The forms row of `site_module_settings` as the server reports it, with the defaults resolved. */
3
3
  export interface FormSettings {
4
4
  /** Addresses the owner chose; empty means "use the defaults". */
@@ -1,5 +1,5 @@
1
1
  import type { ComponentType } from 'react';
2
- import type { FormFieldType, ResolvedFormField } from './fields';
2
+ import type { FormFieldType, ResolvedFormField } from './fields.js';
3
3
  /**
4
4
  * The contract between a form on the customer's page and the editing tools
5
5
  * Setto serves for it.
@@ -1,12 +1,12 @@
1
- import type { SettoModule } from '../module';
1
+ import type { SettoModule } from '../module.js';
2
2
  /**
3
3
  * The forms module: a form primitive the site renders, and the api segment
4
4
  * behind it. Server side lives in setto-server `src/modules/forms`, and so
5
5
  * does the inbox the customer reads submissions in.
6
6
  */
7
7
  export declare const formsModule: SettoModule;
8
- export { SettoForm } from './SettoForm';
9
- export type { SettoFormProps, SettoFormClassNames } from './SettoForm';
10
- export type { FormSettings, FormSubmissionRow, FormsApi } from './api';
11
- export { FORM_FIELD_TYPES, FORM_FIELD_TYPE_LABELS, fieldTypeHasOptions, fieldTypeHasPlaceholder, formFieldsPrefix, isFormFieldType, readLocaleFields, settoSubmissionUrl, } from './fields';
12
- export type { FormFieldProp, FormFieldType, FormValue, FormValues, ResolvedFormField, SubmissionEnvelope, } from './fields';
8
+ export { SettoForm } from './SettoForm.js';
9
+ export type { SettoFormProps, SettoFormClassNames } from './SettoForm.js';
10
+ export type { FormSettings, FormSubmissionRow, FormsApi } from './api.js';
11
+ export { FORM_FIELD_TYPES, FORM_FIELD_TYPE_LABELS, fieldTypeHasOptions, fieldTypeHasPlaceholder, formFieldsPrefix, isFormFieldType, readLocaleFields, settoSubmissionUrl, } from './fields.js';
12
+ export type { FormFieldProp, FormFieldType, FormValue, FormValues, ResolvedFormField, SubmissionEnvelope, } from './fields.js';
@@ -1,5 +1,5 @@
1
- import type { SettoModule } from './module';
2
- export type { SettoModule } from './module';
1
+ import type { SettoModule } from './module.js';
2
+ export type { SettoModule } from './module.js';
3
3
  /** Every module the dashboard shows, in tab order. Setto draws the tabs. */
4
4
  export declare const SETTO_MODULES: readonly SettoModule[];
5
5
  export declare function findModule(id: string | null): SettoModule | undefined;
@@ -1,5 +1,5 @@
1
1
  import { type ComponentType, type ReactNode } from 'react';
2
- import { type BuiltinSectionType, type MenuItem, type MenuList, type PagesManifest } from './manifest';
2
+ import { type BuiltinSectionType, type MenuItem, type MenuList, type PagesManifest } from './manifest.js';
3
3
  /**
4
4
  * The manifest as it stands now, drafts included, re-rendering on change.
5
5
  * `null` on a site that has none.
@@ -1,4 +1,4 @@
1
- import { type PagesManifest } from './manifest';
1
+ import { type PagesManifest } from './manifest.js';
2
2
  /**
3
3
  * The manifest the site was built with, checked once.
4
4
  *
@@ -26,8 +26,14 @@ export declare const PAGES_PATH = "src/content/pages.json";
26
26
  * `text` is a heading, an optional intro and a list of paragraphs with
27
27
  * optional headings: enough for terms, privacy, an «about» page. It is what
28
28
  * lets Pixel add a «Vilkår» page in the chat instead of in a sandbox.
29
+ *
30
+ * `blog` is the blog (R24): the list of posts on its page, and a single post
31
+ * at `<page path>/<slug>` — the one page whose path has room below it. At
32
+ * most one per site, and never on the front page, which would swallow every
33
+ * address. `blog-latest` is a band of the newest posts, for the front page.
34
+ * Both read the posts the site's build bundles (`SettoConfig.blog`).
29
35
  */
30
- export declare const BUILTIN_SECTION_TYPES: readonly ["text"];
36
+ export declare const BUILTIN_SECTION_TYPES: readonly ["text", "blog", "blog-latest"];
31
37
  export type BuiltinSectionType = (typeof BUILTIN_SECTION_TYPES)[number];
32
38
  export interface PageSection {
33
39
  /** Unique across the whole site: it is also the theme id and the anchor. */
@@ -85,6 +91,17 @@ export declare function isSafeHref(href: string): boolean;
85
91
  /** `/vilkar/` and `/vilkar` are one page; the empty path is the front page. */
86
92
  export declare function normalisePath(path: string): string;
87
93
  export declare function pageForPath(manifest: PagesManifest, path: string): PageEntry | null;
94
+ /** The page holding the site's blog, and the section on it. */
95
+ export declare function blogPage(manifest: PagesManifest): {
96
+ page: PageEntry;
97
+ section: PageSection;
98
+ } | null;
99
+ /**
100
+ * The post a path names: `/blogg/ny-kaffemaskin` → `ny-kaffemaskin` when the
101
+ * blog lives at `/blogg`. One segment below the blog page and a valid slug;
102
+ * anything else is not a post.
103
+ */
104
+ export declare function blogSlugForPath(manifest: PagesManifest, path: string): string | null;
88
105
  export declare function pageById(manifest: PagesManifest, id: string): PageEntry | null;
89
106
  /** The page a section is on, and where. */
90
107
  export declare function findSection(manifest: PagesManifest, sectionId: string): {
@@ -1,11 +1,11 @@
1
1
  import { type ReactNode } from 'react';
2
2
  import type { SupabaseClient, Session } from '@supabase/supabase-js';
3
- import { type SettoApi } from './lib/api';
4
- import { I18nStore } from './lib/i18n-store';
5
- import { AssetStore } from './lib/asset-store';
6
- import { ThemeStore } from './lib/theme-store';
7
- import { PageStore } from './lib/page-store';
8
- import type { SettoConfig, SiteRow } from './types';
3
+ import { type SettoApi } from './lib/api.js';
4
+ import { I18nStore } from './lib/i18n-store.js';
5
+ import { AssetStore } from './lib/asset-store.js';
6
+ import { ThemeStore } from './lib/theme-store.js';
7
+ import { PageStore } from './lib/page-store.js';
8
+ import type { SettoConfig, SiteRow } from './types.js';
9
9
  export interface SettoContextValue {
10
10
  config: SettoConfig;
11
11
  supabase: SupabaseClient;