@krantho/ui-react 0.0.0-stage → 1.0.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.
- package/LICENSE +21 -0
- package/dist/components/client/CMSImage.d.ts +4 -0
- package/dist/components/client/CMSImage.d.ts.map +1 -0
- package/dist/components/client/CMSImage.js +23 -0
- package/dist/components/client/CMSImage.js.map +1 -0
- package/dist/components/client/CMSMarkdown.d.ts +4 -0
- package/dist/components/client/CMSMarkdown.d.ts.map +1 -0
- package/dist/components/client/CMSMarkdown.js +15 -0
- package/dist/components/client/CMSMarkdown.js.map +1 -0
- package/dist/components/client/CMSText.d.ts +4 -0
- package/dist/components/client/CMSText.d.ts.map +1 -0
- package/dist/components/client/CMSText.js +15 -0
- package/dist/components/client/CMSText.js.map +1 -0
- package/dist/components/server/CMSImageServer.d.ts +4 -0
- package/dist/components/server/CMSImageServer.d.ts.map +1 -0
- package/dist/components/server/CMSImageServer.js +27 -0
- package/dist/components/server/CMSImageServer.js.map +1 -0
- package/dist/components/server/CMSMarkdownServer.d.ts +4 -0
- package/dist/components/server/CMSMarkdownServer.d.ts.map +1 -0
- package/dist/components/server/CMSMarkdownServer.js +24 -0
- package/dist/components/server/CMSMarkdownServer.js.map +1 -0
- package/dist/components/server/CMSTextServer.d.ts +4 -0
- package/dist/components/server/CMSTextServer.d.ts.map +1 -0
- package/dist/components/server/CMSTextServer.js +22 -0
- package/dist/components/server/CMSTextServer.js.map +1 -0
- package/dist/components/utils.d.ts +4 -0
- package/dist/components/utils.d.ts.map +1 -0
- package/dist/components/utils.js +18 -0
- package/dist/components/utils.js.map +1 -0
- package/dist/context.d.ts +4 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +12 -0
- package/dist/context.js.map +1 -0
- package/dist/hooks/content-context.d.ts +10 -0
- package/dist/hooks/content-context.d.ts.map +1 -0
- package/dist/hooks/content-context.js +12 -0
- package/dist/hooks/content-context.js.map +1 -0
- package/dist/hooks/use-cms-config.d.ts +3 -0
- package/dist/hooks/use-cms-config.d.ts.map +1 -0
- package/dist/hooks/use-cms-config.js +12 -0
- package/dist/hooks/use-cms-config.js.map +1 -0
- package/dist/hooks/use-content.d.ts +3 -0
- package/dist/hooks/use-content.d.ts.map +1 -0
- package/dist/hooks/use-content.js +79 -0
- package/dist/hooks/use-content.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +9 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +25 -0
- package/dist/provider.js.map +1 -0
- package/dist/server/cms-context.d.ts +19 -0
- package/dist/server/cms-context.d.ts.map +1 -0
- package/dist/server/cms-context.js +45 -0
- package/dist/server/cms-context.js.map +1 -0
- package/dist/server/content-loader.d.ts +26 -0
- package/dist/server/content-loader.d.ts.map +1 -0
- package/dist/server/content-loader.js +110 -0
- package/dist/server/content-loader.js.map +1 -0
- package/dist/server/seo-jsonld.d.ts +27 -0
- package/dist/server/seo-jsonld.d.ts.map +1 -0
- package/dist/server/seo-jsonld.js +45 -0
- package/dist/server/seo-jsonld.js.map +1 -0
- package/dist/server/seo-resolver.d.ts +32 -0
- package/dist/server/seo-resolver.d.ts.map +1 -0
- package/dist/server/seo-resolver.js +84 -0
- package/dist/server/seo-resolver.js.map +1 -0
- package/dist/server.d.ts +11 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +12 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +87 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -3
- package/README.md +0 -3
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { cache } from 'react';
|
|
2
|
+
import { getServerLoader, loadCollection, loadContent, loadSummaries } from './content-loader.js';
|
|
3
|
+
/**
|
|
4
|
+
* Load the published version of a document. The returned `fields` is
|
|
5
|
+
* `Record<string, unknown>` — callers can narrow to `Record<string, string>`
|
|
6
|
+
* when they know the content shape. Throws a 404 `NetworkError` when the
|
|
7
|
+
* document has no published version.
|
|
8
|
+
*/
|
|
9
|
+
export const getCMSContent = cache(async (collection, slug, options) => {
|
|
10
|
+
return loadContent({ collection, slug, locale: options?.locale }, options);
|
|
11
|
+
});
|
|
12
|
+
/** The slugs of the published documents in a collection */
|
|
13
|
+
export const getCMSSlugs = cache(async (collection, locale) => {
|
|
14
|
+
const docs = await getServerLoader().listPublishedSummaries(collection, locale);
|
|
15
|
+
return docs.map((doc) => doc.slug);
|
|
16
|
+
});
|
|
17
|
+
/** Every published document in a collection */
|
|
18
|
+
export const getAllCMSContent = cache(async (collection, options) => {
|
|
19
|
+
try {
|
|
20
|
+
return await loadCollection(collection, options?.locale, options);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
if (process.env.NODE_ENV === 'development') {
|
|
24
|
+
console.warn(`Failed to load the ${collection} collection:`, error);
|
|
25
|
+
}
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* The published documents of a collection without their bodies: the fields a
|
|
31
|
+
* list, a card or a navigation shows. Nothing is rendered; a page that shows a
|
|
32
|
+
* document's body reads `getAllCMSContent` or `getCMSContent`.
|
|
33
|
+
*/
|
|
34
|
+
export const getAllCMSSummaries = cache(async (collection, options) => {
|
|
35
|
+
try {
|
|
36
|
+
return await loadSummaries(collection, options?.locale);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (process.env.NODE_ENV === 'development') {
|
|
40
|
+
console.warn(`Failed to load the ${collection} collection:`, error);
|
|
41
|
+
}
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
//# sourceMappingURL=cms-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cms-context.js","sourceRoot":"","sources":["../../src/server/cms-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAE7B,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAEjG;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAChC,KAAK,EAAE,UAAkB,EAAE,IAAY,EAAE,OAA2B,EAAuB,EAAE;IAC3F,OAAO,WAAW,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAA;AAC5E,CAAC,CACF,CAAA;AAED,2DAA2D;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,CAC9B,KAAK,EAAE,UAAkB,EAAE,MAA2B,EAAqB,EAAE;IAC3E,MAAM,IAAI,GAAG,MAAM,eAAe,EAAE,CAAC,sBAAsB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAC/E,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;AACpC,CAAC,CACF,CAAA;AAED,+CAA+C;AAC/C,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CACnC,KAAK,EAAE,UAAkB,EAAE,OAA2B,EAAyB,EAAE;IAC/E,IAAI,CAAC;QACH,OAAO,MAAM,cAAc,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;IACnE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,sBAAsB,UAAU,cAAc,EAAE,KAAK,CAAC,CAAA;QACrE,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC,CACF,CAAA;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,CACrC,KAAK,EAAE,UAAkB,EAAE,OAA2B,EAAyB,EAAE;IAC/E,IAAI,CAAC;QACH,OAAO,MAAM,aAAa,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,CAAC,CAAA;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,EAAE,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,sBAAsB,UAAU,cAAc,EAAE,KAAK,CAAC,CAAA;QACrE,CAAC;QACD,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC,CACF,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ContentRef, IPublishedContentLoader, IPublishedSeoLoader } from '@krantho/core';
|
|
2
|
+
import type { CMSContent, CMSSummary, ContentLoaderOptions } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* What server components read through: published content, and the pages' SEO
|
|
5
|
+
* when the loader serves it (`createContentLoader()` does). Without SEO, the
|
|
6
|
+
* resolvers fall back to content fields and render no JSON-LD.
|
|
7
|
+
*/
|
|
8
|
+
export type ServerContentLoader = IPublishedContentLoader & Partial<IPublishedSeoLoader>;
|
|
9
|
+
/** The loader server components read through */
|
|
10
|
+
export declare function getServerLoader(): ServerContentLoader;
|
|
11
|
+
/**
|
|
12
|
+
* Set the loader server components read through — `createContentLoader()` from
|
|
13
|
+
* `@krantho/server` (re-exported by the framework adapters). Pages read only
|
|
14
|
+
* the live (published) version of each document.
|
|
15
|
+
*/
|
|
16
|
+
export declare function initServerLoader(loader: ServerContentLoader): void;
|
|
17
|
+
/**
|
|
18
|
+
* Load the live version of a document. A document with no published version
|
|
19
|
+
* — never published, unpublished or deleted — is a 404.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadContent(ref: ContentRef, options?: ContentLoaderOptions): Promise<CMSContent>;
|
|
22
|
+
/** Load the live version of every published document in a collection */
|
|
23
|
+
export declare function loadCollection(collection: string, locale?: string | undefined, options?: ContentLoaderOptions): Promise<CMSContent[]>;
|
|
24
|
+
/** Load the live version of every published document in a collection, without bodies: nothing is rendered */
|
|
25
|
+
export declare function loadSummaries(collection: string, locale?: string | undefined): Promise<CMSSummary[]>;
|
|
26
|
+
//# sourceMappingURL=content-loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-loader.d.ts","sourceRoot":"","sources":["../../src/server/content-loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,uBAAuB,EACvB,mBAAmB,EAEpB,MAAM,eAAe,CAAA;AAEtB,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAA;AAE5E;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,uBAAuB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;AAIxF,gDAAgD;AAChD,wBAAgB,eAAe,IAAI,mBAAmB,CAOrD;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAElE;AAiED;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,UAAU,EACf,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,UAAU,CAAC,CAWrB;AAED,wEAAwE;AACxE,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,EAC3B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,UAAU,EAAE,CAAC,CAWvB;AAED,6GAA6G;AAC7G,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,GAC1B,OAAO,CAAC,UAAU,EAAE,CAAC,CAiBvB"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { NetworkError, renderContent } from '@krantho/core';
|
|
2
|
+
let serverLoader = null;
|
|
3
|
+
/** The loader server components read through */
|
|
4
|
+
export function getServerLoader() {
|
|
5
|
+
if (!serverLoader) {
|
|
6
|
+
throw new Error('Server content loader not initialized. Call initServerLoader() with a content loader.');
|
|
7
|
+
}
|
|
8
|
+
return serverLoader;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Set the loader server components read through — `createContentLoader()` from
|
|
12
|
+
* `@krantho/server` (re-exported by the framework adapters). Pages read only
|
|
13
|
+
* the live (published) version of each document.
|
|
14
|
+
*/
|
|
15
|
+
export function initServerLoader(loader) {
|
|
16
|
+
serverLoader = loader;
|
|
17
|
+
}
|
|
18
|
+
function generateExcerpt(sections, rawContent, length = 160) {
|
|
19
|
+
const sectionKeys = Object.keys(sections);
|
|
20
|
+
const firstKey = sectionKeys[0];
|
|
21
|
+
const firstSection = firstKey ? sections[firstKey] : undefined;
|
|
22
|
+
const source = firstSection ?? rawContent;
|
|
23
|
+
const plainText = source
|
|
24
|
+
.replace(/<[^>]+>/g, '')
|
|
25
|
+
.replace(/#{1,6}\s+/g, '')
|
|
26
|
+
.replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
|
|
27
|
+
.replace(/[*_`~]/g, '')
|
|
28
|
+
.replace(/\n+/g, ' ')
|
|
29
|
+
.trim();
|
|
30
|
+
if (plainText.length <= length)
|
|
31
|
+
return plainText;
|
|
32
|
+
const truncated = plainText.substring(0, length);
|
|
33
|
+
const lastSpace = truncated.lastIndexOf(' ');
|
|
34
|
+
return truncated.substring(0, lastSpace) + '...';
|
|
35
|
+
}
|
|
36
|
+
async function toCMSContent(doc, options, preview) {
|
|
37
|
+
const { processMarkdown = true, extractSections = true, generateExcerpt: shouldGenerateExcerpt = true, excerptLength = 160, } = options;
|
|
38
|
+
const rendered = await renderContent(doc.fields, doc.body);
|
|
39
|
+
const sections = extractSections ? rendered.sections : {};
|
|
40
|
+
return {
|
|
41
|
+
collection: doc.collection,
|
|
42
|
+
slug: doc.slug,
|
|
43
|
+
locale: doc.locale,
|
|
44
|
+
fields: doc.fields,
|
|
45
|
+
html: processMarkdown ? rendered.html : rendered.content,
|
|
46
|
+
rawContent: rendered.content,
|
|
47
|
+
sections,
|
|
48
|
+
excerpt: shouldGenerateExcerpt
|
|
49
|
+
? generateExcerpt(sections, rendered.content, excerptLength)
|
|
50
|
+
: undefined,
|
|
51
|
+
preview,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function loadFailure(error) {
|
|
55
|
+
if (error instanceof NetworkError)
|
|
56
|
+
return error;
|
|
57
|
+
return new NetworkError(error instanceof Error ? error.message : 'Unknown error during content loading', 500);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Load the live version of a document. A document with no published version
|
|
61
|
+
* — never published, unpublished or deleted — is a 404.
|
|
62
|
+
*/
|
|
63
|
+
export async function loadContent(ref, options = {}) {
|
|
64
|
+
const loader = getServerLoader();
|
|
65
|
+
try {
|
|
66
|
+
const doc = await loader.getPublished(ref);
|
|
67
|
+
if (!doc) {
|
|
68
|
+
throw new NetworkError(`No published content: ${ref.collection}/${ref.slug}`, 404);
|
|
69
|
+
}
|
|
70
|
+
return await toCMSContent(doc, options, await loader.isPreview());
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
throw loadFailure(error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Load the live version of every published document in a collection */
|
|
77
|
+
export async function loadCollection(collection, locale, options = {}) {
|
|
78
|
+
const loader = getServerLoader();
|
|
79
|
+
try {
|
|
80
|
+
const [docs, preview] = await Promise.all([
|
|
81
|
+
loader.listPublished(collection, locale),
|
|
82
|
+
loader.isPreview(),
|
|
83
|
+
]);
|
|
84
|
+
return await Promise.all(docs.map((doc) => toCMSContent(doc, options, preview)));
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
throw loadFailure(error);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Load the live version of every published document in a collection, without bodies: nothing is rendered */
|
|
91
|
+
export async function loadSummaries(collection, locale) {
|
|
92
|
+
const loader = getServerLoader();
|
|
93
|
+
try {
|
|
94
|
+
const [docs, preview] = await Promise.all([
|
|
95
|
+
loader.listPublishedSummaries(collection, locale),
|
|
96
|
+
loader.isPreview(),
|
|
97
|
+
]);
|
|
98
|
+
return docs.map((doc) => ({
|
|
99
|
+
collection: doc.collection,
|
|
100
|
+
slug: doc.slug,
|
|
101
|
+
locale: doc.locale,
|
|
102
|
+
fields: doc.fields,
|
|
103
|
+
preview,
|
|
104
|
+
}));
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
throw loadFailure(error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=content-loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-loader.js","sourceRoot":"","sources":["../../src/server/content-loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { PageStructure } from '@krantho/core';
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the complete JSON-LD graph for a page, composed from its published
|
|
4
|
+
* version: site-level (ProfessionalService, WebSite, Person) + collection-level
|
|
5
|
+
* (Article, Service) + document-level overrides — all in a single @graph, with
|
|
6
|
+
* the page node and what the page's structure states (its trail, its place in
|
|
7
|
+
* a sequence, its kind). Null when the document has no published version, or
|
|
8
|
+
* the loader serves no SEO.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveJsonLd(collection: string, slug: string, locale?: string | undefined, structure?: PageStructure | undefined): Promise<Record<string, unknown> | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Render the complete JSON-LD structured data for a page.
|
|
13
|
+
*
|
|
14
|
+
* One component, one @graph — contains all entities from the full
|
|
15
|
+
* SEO hierarchy (site → collection → document). Place in each page, and pass
|
|
16
|
+
* the structure the page renders — the trail of its breadcrumb, its place in a
|
|
17
|
+
* sequence, its kind — so the structured data states what the page shows.
|
|
18
|
+
*
|
|
19
|
+
* The layout does NOT render JSON-LD. Each page owns its complete graph.
|
|
20
|
+
*/
|
|
21
|
+
export declare function SeoJsonLd({ collection, slug, locale, structure, }: {
|
|
22
|
+
collection: string;
|
|
23
|
+
slug: string;
|
|
24
|
+
locale?: string | undefined;
|
|
25
|
+
structure?: PageStructure | undefined;
|
|
26
|
+
}): Promise<React.ReactElement | null>;
|
|
27
|
+
//# sourceMappingURL=seo-jsonld.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-jsonld.d.ts","sourceRoot":"","sources":["../../src/server/seo-jsonld.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAuBlD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,EAC3B,SAAS,CAAC,EAAE,aAAa,GAAG,SAAS,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAEzC;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,EAC9B,UAAU,EACV,IAAI,EACJ,MAAM,EACN,SAAS,GACV,EAAE;IACD,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,SAAS,CAAC,EAAE,aAAa,GAAG,SAAS,CAAA;CACtC,GAAG,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAWrC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { serializeJsonLd } from '@krantho/seo-shared';
|
|
3
|
+
import { cache } from 'react';
|
|
4
|
+
import { getServerLoader } from './content-loader.js';
|
|
5
|
+
/** One composition per page render; React's cache matches arguments by identity, so the structure travels as JSON */
|
|
6
|
+
const composeJsonLd = cache(async (collection, slug, locale, structure) => {
|
|
7
|
+
const shape = structure ? JSON.parse(structure) : undefined;
|
|
8
|
+
try {
|
|
9
|
+
return (await getServerLoader().jsonLd?.({ collection, slug, locale }, shape)) ?? null;
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
console.error(`[krantho] JSON-LD for ${collection}/${slug} could not be composed:`, error);
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the complete JSON-LD graph for a page, composed from its published
|
|
18
|
+
* version: site-level (ProfessionalService, WebSite, Person) + collection-level
|
|
19
|
+
* (Article, Service) + document-level overrides — all in a single @graph, with
|
|
20
|
+
* the page node and what the page's structure states (its trail, its place in
|
|
21
|
+
* a sequence, its kind). Null when the document has no published version, or
|
|
22
|
+
* the loader serves no SEO.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveJsonLd(collection, slug, locale, structure) {
|
|
25
|
+
return composeJsonLd(collection, slug, locale, structure ? JSON.stringify(structure) : undefined);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Render the complete JSON-LD structured data for a page.
|
|
29
|
+
*
|
|
30
|
+
* One component, one @graph — contains all entities from the full
|
|
31
|
+
* SEO hierarchy (site → collection → document). Place in each page, and pass
|
|
32
|
+
* the structure the page renders — the trail of its breadcrumb, its place in a
|
|
33
|
+
* sequence, its kind — so the structured data states what the page shows.
|
|
34
|
+
*
|
|
35
|
+
* The layout does NOT render JSON-LD. Each page owns its complete graph.
|
|
36
|
+
*/
|
|
37
|
+
export async function SeoJsonLd({ collection, slug, locale, structure, }) {
|
|
38
|
+
const graph = await resolveJsonLd(collection, slug, locale, structure);
|
|
39
|
+
if (!graph)
|
|
40
|
+
return null;
|
|
41
|
+
return (_jsx("script", { type: "application/ld+json",
|
|
42
|
+
// biome-ignore lint/security/noDangerouslySetInnerHtml: serializeJsonLd escapes `<`, so the JSON cannot end the script tag
|
|
43
|
+
dangerouslySetInnerHTML: { __html: serializeJsonLd(graph) } }));
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=seo-jsonld.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-jsonld.js","sourceRoot":"","sources":["../../src/server/seo-jsonld.tsx"],"names":[],"mappings":";AACA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAA;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAErD,qHAAqH;AACrH,MAAM,aAAa,GAAG,KAAK,CACzB,KAAK,EACH,UAAkB,EAClB,IAAY,EACZ,MAA0B,EAC1B,SAA6B,EACY,EAAE;IAC3C,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,SAAS,CAAmB,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9E,IAAI,CAAC;QACH,OAAO,CAAC,MAAM,eAAe,EAAE,CAAC,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,CAAC,CAAC,IAAI,IAAI,CAAA;IACxF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,UAAU,IAAI,IAAI,yBAAyB,EAAE,KAAK,CAAC,CAAA;QAC1F,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC,CACF,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,UAAkB,EAClB,IAAY,EACZ,MAA2B,EAC3B,SAAqC;IAErC,OAAO,aAAa,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;AACnG,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAC9B,UAAU,EACV,IAAI,EACJ,MAAM,EACN,SAAS,GAMV;IACC,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,CAAA;IACtE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAA;IAEvB,OAAO,CACL,iBACE,IAAI,EAAC,qBAAqB;QAC1B,2HAA2H;QAC3H,uBAAuB,EAAE,EAAE,MAAM,EAAE,eAAe,CAAC,KAAK,CAAC,EAAE,GAC3D,CACH,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Resolved SEO metadata for a page */
|
|
2
|
+
export interface SeoMeta {
|
|
3
|
+
title: string;
|
|
4
|
+
description: string;
|
|
5
|
+
image?: string | undefined;
|
|
6
|
+
canonical?: string | undefined;
|
|
7
|
+
author?: string | undefined;
|
|
8
|
+
datePublished?: string | undefined;
|
|
9
|
+
dateModified?: string | undefined;
|
|
10
|
+
og?: {
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
image?: string | undefined;
|
|
14
|
+
type: string;
|
|
15
|
+
siteName?: string | undefined;
|
|
16
|
+
url?: string | undefined;
|
|
17
|
+
};
|
|
18
|
+
twitter?: {
|
|
19
|
+
card: string;
|
|
20
|
+
site?: string | undefined;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Resolve SEO metadata for a page.
|
|
25
|
+
*
|
|
26
|
+
* Reads the SEO configuration first (user-edited + AI-generated properties),
|
|
27
|
+
* falls back to CMS content fields, then to site-level OG defaults.
|
|
28
|
+
*
|
|
29
|
+
* Priority: seo_config.properties → CMS fields → site defaults
|
|
30
|
+
*/
|
|
31
|
+
export declare const resolveSeoContent: (collection: string, slug: string, locale?: string | undefined) => Promise<SeoMeta>;
|
|
32
|
+
//# sourceMappingURL=seo-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-resolver.d.ts","sourceRoot":"","sources":["../../src/server/seo-resolver.ts"],"names":[],"mappings":"AAiBA,uCAAuC;AACvC,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC3B,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACjC,EAAE,CAAC,EAAE;QACH,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,EAAE,MAAM,CAAA;QACnB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC1B,IAAI,EAAE,MAAM,CAAA;QACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC7B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KACzB,CAAA;IACD,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAA;QACZ,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAC1B,CAAA;CACF;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,eACT,MAAM,QAAQ,MAAM,WAAW,MAAM,GAAG,SAAS,KAAG,OAAO,CAAC,OAAO,CAwEvF,CAAA"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { buildSeoFieldMap, resolveSeoField } from '@krantho/seo-shared';
|
|
2
|
+
import { cache } from 'react';
|
|
3
|
+
import { getServerLoader, loadContent } from './content-loader.js';
|
|
4
|
+
/** The primary entity's properties of an SEO configuration; empty when none or unreadable */
|
|
5
|
+
async function seoConfigProperties(configId, locale) {
|
|
6
|
+
try {
|
|
7
|
+
return (await getServerLoader().seoProperties?.(configId, locale)) ?? {};
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
console.error(`[krantho] SEO properties for ${configId} could not be read:`, error);
|
|
11
|
+
return {};
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolve SEO metadata for a page.
|
|
16
|
+
*
|
|
17
|
+
* Reads the SEO configuration first (user-edited + AI-generated properties),
|
|
18
|
+
* falls back to CMS content fields, then to site-level OG defaults.
|
|
19
|
+
*
|
|
20
|
+
* Priority: seo_config.properties → CMS fields → site defaults
|
|
21
|
+
*/
|
|
22
|
+
export const resolveSeoContent = cache(async (collection, slug, locale) => {
|
|
23
|
+
// Load CMS content for fallback values
|
|
24
|
+
let cmsFields = {};
|
|
25
|
+
try {
|
|
26
|
+
const content = await loadContent({ collection, slug, locale });
|
|
27
|
+
cmsFields = content.fields;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// Content may not exist yet
|
|
31
|
+
}
|
|
32
|
+
// Load document-level and site-level SEO configs in parallel
|
|
33
|
+
const [seoProps, siteProps] = await Promise.all([
|
|
34
|
+
seoConfigProperties(`doc:${collection}/${slug}`, locale),
|
|
35
|
+
seoConfigProperties('site'),
|
|
36
|
+
]);
|
|
37
|
+
// Build dynamic field map from CMS fields
|
|
38
|
+
const fieldMap = buildSeoFieldMap(Object.keys(cmsFields));
|
|
39
|
+
// Resolve with priority: seo properties → CMS fields (via field map) → site defaults
|
|
40
|
+
const title = str(seoProps['headline']) ||
|
|
41
|
+
str(seoProps['name']) ||
|
|
42
|
+
resolveSeoField(fieldMap, 'title', cmsFields) ||
|
|
43
|
+
slug;
|
|
44
|
+
const description = str(seoProps['description']) || resolveSeoField(fieldMap, 'description', cmsFields) || '';
|
|
45
|
+
const image = str(seoProps['image']) ||
|
|
46
|
+
resolveSeoField(fieldMap, 'image', cmsFields) ||
|
|
47
|
+
str(siteProps['og-default-image']) ||
|
|
48
|
+
undefined;
|
|
49
|
+
// OG fields: per-document overrides → content fields → resolved values → site defaults
|
|
50
|
+
const ogTitle = resolveSeoField(fieldMap, 'ogTitle', cmsFields) || title;
|
|
51
|
+
const ogDescription = resolveSeoField(fieldMap, 'ogDescription', cmsFields) || description;
|
|
52
|
+
const ogImage = resolveSeoField(fieldMap, 'ogImage', cmsFields) || image;
|
|
53
|
+
const ogType = resolveSeoField(fieldMap, 'ogType', cmsFields) || 'website';
|
|
54
|
+
const siteName = str(siteProps['name']) || undefined;
|
|
55
|
+
const twitterHandle = str(siteProps['twitter-handle']) || undefined;
|
|
56
|
+
const canonicalUrl = str(seoProps['url']) || resolveSeoField(fieldMap, 'canonicalUrl', cmsFields) || undefined;
|
|
57
|
+
return {
|
|
58
|
+
title,
|
|
59
|
+
description,
|
|
60
|
+
image,
|
|
61
|
+
canonical: canonicalUrl,
|
|
62
|
+
author: str(seoProps['author']) || resolveSeoField(fieldMap, 'author', cmsFields) || undefined,
|
|
63
|
+
datePublished: str(seoProps['datePublished']) ||
|
|
64
|
+
resolveSeoField(fieldMap, 'datePublished', cmsFields) ||
|
|
65
|
+
undefined,
|
|
66
|
+
dateModified: str(seoProps['dateModified']) || undefined,
|
|
67
|
+
og: {
|
|
68
|
+
title: ogTitle,
|
|
69
|
+
description: ogDescription,
|
|
70
|
+
image: ogImage,
|
|
71
|
+
type: ogType,
|
|
72
|
+
siteName,
|
|
73
|
+
url: canonicalUrl,
|
|
74
|
+
},
|
|
75
|
+
twitter: {
|
|
76
|
+
card: ogImage ? 'summary_large_image' : 'summary',
|
|
77
|
+
site: twitterHandle,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
});
|
|
81
|
+
function str(v) {
|
|
82
|
+
return typeof v === 'string' && v.length > 0 ? v : '';
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=seo-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-resolver.js","sourceRoot":"","sources":["../../src/server/seo-resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { NetworkError } from '@krantho/core';
|
|
2
|
+
export { CMSImageServer } from './components/server/CMSImageServer.js';
|
|
3
|
+
export { CMSMarkdownServer } from './components/server/CMSMarkdownServer.js';
|
|
4
|
+
export { CMSTextServer } from './components/server/CMSTextServer.js';
|
|
5
|
+
export { getAllCMSContent, getAllCMSSummaries, getCMSContent, getCMSSlugs, } from './server/cms-context.js';
|
|
6
|
+
export { initServerLoader, loadContent } from './server/content-loader.js';
|
|
7
|
+
export { resolveJsonLd, SeoJsonLd } from './server/seo-jsonld.js';
|
|
8
|
+
export type { SeoMeta } from './server/seo-resolver.js';
|
|
9
|
+
export { resolveSeoContent } from './server/seo-resolver.js';
|
|
10
|
+
export type { CMSContent, CMSContentOptions, CMSImageServerProps, CMSMarkdownServerProps, CMSSummary, CMSSummaryOptions, CMSTextServerProps, ContentLoaderOptions, ContentLocation, } from './types.js';
|
|
11
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAA;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AAEpE,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,WAAW,GACZ,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAC1E,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AACjE,YAAY,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA;AAE5D,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,GAChB,MAAM,YAAY,CAAA"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// Server components
|
|
2
|
+
// The error the read path throws — `status` 404 when nothing is published
|
|
3
|
+
export { NetworkError } from '@krantho/core';
|
|
4
|
+
export { CMSImageServer } from './components/server/CMSImageServer.js';
|
|
5
|
+
export { CMSMarkdownServer } from './components/server/CMSMarkdownServer.js';
|
|
6
|
+
export { CMSTextServer } from './components/server/CMSTextServer.js';
|
|
7
|
+
// Server utilities
|
|
8
|
+
export { getAllCMSContent, getAllCMSSummaries, getCMSContent, getCMSSlugs, } from './server/cms-context.js';
|
|
9
|
+
export { initServerLoader, loadContent } from './server/content-loader.js';
|
|
10
|
+
export { resolveJsonLd, SeoJsonLd } from './server/seo-jsonld.js';
|
|
11
|
+
export { resolveSeoContent } from './server/seo-resolver.js';
|
|
12
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,oBAAoB;AAEpB,0EAA0E;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAA;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0CAA0C,CAAA;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AACpE,mBAAmB;AACnB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,WAAW,GACZ,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAA;AAC1E,OAAO,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAA;AAEjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { SemanticStyle } from '@krantho/core';
|
|
2
|
+
export declare class ConfigurationError extends Error {
|
|
3
|
+
context?: string | undefined;
|
|
4
|
+
constructor(message: string, context?: string | undefined);
|
|
5
|
+
}
|
|
6
|
+
export interface CMSConfig {
|
|
7
|
+
contentPath?: string;
|
|
8
|
+
assetsPath?: string;
|
|
9
|
+
imagesPath?: string;
|
|
10
|
+
autoReload?: boolean;
|
|
11
|
+
errorBoundary?: boolean;
|
|
12
|
+
cacheContent?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface CMSContent {
|
|
15
|
+
collection: string;
|
|
16
|
+
slug: string;
|
|
17
|
+
locale: string;
|
|
18
|
+
fields: Record<string, unknown>;
|
|
19
|
+
html: string;
|
|
20
|
+
rawContent: string;
|
|
21
|
+
sections: Record<string, string>;
|
|
22
|
+
excerpt?: string | undefined;
|
|
23
|
+
/** Whether it was read for an editor's preview: the Live marks apply (`kranthoField`) */
|
|
24
|
+
preview: boolean;
|
|
25
|
+
}
|
|
26
|
+
/** A published document without its body: its fields, for a page that only lists documents */
|
|
27
|
+
export interface CMSSummary {
|
|
28
|
+
collection: string;
|
|
29
|
+
slug: string;
|
|
30
|
+
locale: string;
|
|
31
|
+
fields: Record<string, unknown>;
|
|
32
|
+
/** Whether it was read for an editor's preview: the Live marks apply (`kranthoField`) */
|
|
33
|
+
preview: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface ContentLoaderOptions {
|
|
36
|
+
processMarkdown?: boolean;
|
|
37
|
+
extractSections?: boolean;
|
|
38
|
+
generateExcerpt?: boolean;
|
|
39
|
+
excerptLength?: number;
|
|
40
|
+
}
|
|
41
|
+
/** Options for listing published summaries in server components */
|
|
42
|
+
export interface CMSSummaryOptions {
|
|
43
|
+
/** Omitted: the site's default locale */
|
|
44
|
+
locale?: string | undefined;
|
|
45
|
+
}
|
|
46
|
+
/** Options for reading published content in server components */
|
|
47
|
+
export interface CMSContentOptions extends ContentLoaderOptions, CMSSummaryOptions {
|
|
48
|
+
}
|
|
49
|
+
/** Which document a server component renders: a slug in a collection, in a locale */
|
|
50
|
+
export interface ContentLocation {
|
|
51
|
+
collection: string;
|
|
52
|
+
/** Omitted: the site's default locale */
|
|
53
|
+
locale?: string | undefined;
|
|
54
|
+
}
|
|
55
|
+
export interface CMSTextProps {
|
|
56
|
+
slug: string;
|
|
57
|
+
field: string;
|
|
58
|
+
variant?: SemanticStyle['variant'];
|
|
59
|
+
color?: SemanticStyle['color'];
|
|
60
|
+
align?: SemanticStyle['align'];
|
|
61
|
+
weight?: SemanticStyle['weight'];
|
|
62
|
+
size?: SemanticStyle['size'];
|
|
63
|
+
fallback?: string;
|
|
64
|
+
className?: string;
|
|
65
|
+
component?: string;
|
|
66
|
+
}
|
|
67
|
+
export interface CMSMarkdownProps {
|
|
68
|
+
slug: string;
|
|
69
|
+
section?: string;
|
|
70
|
+
variant?: SemanticStyle['variant'];
|
|
71
|
+
color?: SemanticStyle['color'];
|
|
72
|
+
align?: SemanticStyle['align'];
|
|
73
|
+
className?: string;
|
|
74
|
+
}
|
|
75
|
+
export type CMSTextServerProps = CMSTextProps & ContentLocation;
|
|
76
|
+
export type CMSMarkdownServerProps = CMSMarkdownProps & ContentLocation;
|
|
77
|
+
export type CMSImageServerProps = CMSImageProps & ContentLocation;
|
|
78
|
+
export interface CMSImageProps {
|
|
79
|
+
slug: string;
|
|
80
|
+
field: string;
|
|
81
|
+
alt?: string;
|
|
82
|
+
width?: number;
|
|
83
|
+
height?: number;
|
|
84
|
+
lazy?: boolean;
|
|
85
|
+
className?: string;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAGlC;IAFT,YACE,OAAe,EACR,OAAgB;QAEvB,KAAK,CAAC,OAAO,CAAC,CAAA;QAFP,YAAO,GAAP,OAAO,CAAS;QAGvB,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAA;IAClC,CAAC;CACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@krantho/ui-react",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "React server components, server utilities and hooks that render published krantho content.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://krantho.com",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/descoped/krantho.git",
|
|
10
|
+
"directory": "packages/ui-react"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/descoped/krantho/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./server": {
|
|
22
|
+
"types": "./dist/server.d.ts",
|
|
23
|
+
"import": "./dist/server.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist"
|
|
28
|
+
],
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@krantho/core": "1.0.1",
|
|
31
|
+
"@krantho/seo-shared": "1.0.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^25.9.9",
|
|
35
|
+
"@types/react": "^19.3.0",
|
|
36
|
+
"@types/react-dom": "^19.3.0",
|
|
37
|
+
"react": "^19.3.1",
|
|
38
|
+
"react-dom": "^19.3.1",
|
|
39
|
+
"typescript": "^6.0.3"
|
|
40
|
+
},
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"react": ">=19.0.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"clean": "rm -rf dist"
|
|
48
|
+
}
|
|
6
49
|
}
|
package/README.md
DELETED