@viglet/shio-react-sdk 2026.2.1 → 2026.3.3

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/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # @viglet/shio-react-sdk
2
+
3
+ [![npm](https://img.shields.io/npm/v/@viglet/shio-react-sdk?logo=npm)](https://www.npmjs.com/package/@viglet/shio-react-sdk)
4
+ [![License](https://img.shields.io/npm/l/@viglet/shio-react-sdk)](https://github.com/openviglet/shio/blob/HEAD/LICENSE)
5
+ [![Website](https://img.shields.io/badge/website-0ea5e9?logo=googlechrome&logoColor=white)](https://openviglet.github.io/shio/)
6
+
7
+ The **React SDK** for **[Viglet Shio](https://openviglet.github.io/shio/)**, the open
8
+ source, **agent-ready CMS**. Hooks and render components for
9
+ consuming Shio content through the **Content Delivery API (CDA)**, built on
10
+ [`@viglet/shio-client`](https://www.npmjs.com/package/@viglet/shio-client).
11
+
12
+ - **React 18 / 19** — `react` is a peer dependency.
13
+ - Targets the stable, read-only CDA contract (`/api/v2/cda/**`).
14
+ - Everything the core client exports is **re-exported** here, so this is the only
15
+ package a React app needs.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install @viglet/shio-react-sdk react
21
+ ```
22
+
23
+ ## Quick start
24
+
25
+ Wrap your tree once:
26
+
27
+ ```tsx
28
+ import { ShioProvider } from "@viglet/shio-react-sdk";
29
+
30
+ export function App({ children }: { children: React.ReactNode }) {
31
+ return (
32
+ <ShioProvider
33
+ baseUrl="https://cms.example.com"
34
+ apiToken={import.meta.env.VITE_SHIO_CDA_TOKEN}
35
+ >
36
+ {children}
37
+ </ShioProvider>
38
+ );
39
+ }
40
+ ```
41
+
42
+ Then read content anywhere below it:
43
+
44
+ ```tsx
45
+ import { useShioPostByUrl, ShioRichText } from "@viglet/shio-react-sdk";
46
+
47
+ function Article({ siteId, url }: { siteId: string; url: string }) {
48
+ const { data: post, loading, error } = useShioPostByUrl(siteId, url);
49
+
50
+ if (loading) return <p>Loading…</p>;
51
+ if (error) return <p>{error.message}</p>;
52
+ if (!post) return <p>Not found</p>;
53
+
54
+ return (
55
+ <article>
56
+ <h1>{String(post.attrs.title ?? "")}</h1>
57
+ <ShioRichText html={String(post.attrs.content ?? "")} />
58
+ </article>
59
+ );
60
+ }
61
+ ```
62
+
63
+ `<ShioProvider>` also accepts an already-built client:
64
+ `<ShioProvider client={myClient}>`.
65
+
66
+ ## Hooks
67
+
68
+ Every hook returns a `ShioAsyncState<T>` — `{ data, loading, error }`.
69
+
70
+ | Hook | Returns |
71
+ |---|---|
72
+ | `useShioSites()` | Every site the token can see |
73
+ | `useShioSite(siteId)` | One site |
74
+ | `useShioChildren(folderId, params?)` | A folder's children, paged |
75
+ | `useShioBreadcrumb(objectId)` | The path from the site root to an object |
76
+ | `useShioPost(postId)` | One post by id |
77
+ | `useShioPostByUrl(siteId, url)` | One post by its friendly URL — built for `[...slug]` routing |
78
+ | `useShioQuery(params?, enabled?)` | A query across a site / folder / post-type, paged |
79
+ | `useShioClient()` | The `ShioClient` from context, for anything the hooks don't cover |
80
+
81
+ ## Components
82
+
83
+ | Component | For |
84
+ |---|---|
85
+ | `<ShioRichText html={…} />` | Renders an HTML-editor field safely into a `div` (accepts any `div` props) |
86
+ | `<ShioImage src={…} baseUrl={…} alt={…} />` | Resolves a stored file reference to a URL and renders an `img` |
87
+ | `<ShioRelator items={…}>` | Maps over a Relator (nested repeatable) field |
88
+ | `<ShioField value={…} as={…} />` | Renders one attribute by kind — `text`, `html`, `image`, `list`, `json` |
89
+
90
+ ## Next.js
91
+
92
+ For **server components**, use
93
+ [`@viglet/shio-client`](https://www.npmjs.com/package/@viglet/shio-client)
94
+ directly — it is zero-dependency and needs no provider. Reach for this package
95
+ in **client components**, where the hooks give you loading and error state.
96
+
97
+ The fastest way to a working project is the generator, which wires both up for
98
+ you:
99
+
100
+ ```bash
101
+ npm create @viglet/shio-app@latest my-site
102
+ ```
103
+
104
+ ## Related packages
105
+
106
+ | Package | For |
107
+ |---|---|
108
+ | [`@viglet/shio-client`](https://www.npmjs.com/package/@viglet/shio-client) | The framework-agnostic core this is built on |
109
+ | [`@viglet/shio`](https://www.npmjs.com/package/@viglet/shio) | The Shio CLI — content as files, `shio types`, and the MCP bridge for [Claude Code](https://claude.com/claude-code) |
110
+ | [`@viglet/shio-sections`](https://www.npmjs.com/package/@viglet/shio-sections) | The page-section vocabulary and its React components |
111
+ | [`@viglet/shio-model`](https://www.npmjs.com/package/@viglet/shio-model) | Author the content model as typed code |
112
+ | [`@viglet/shio-editor-cors`](https://www.npmjs.com/package/@viglet/shio-editor-cors) | Inline visual editing with the Universal Editor |
113
+ | [`@viglet/create-shio-app`](https://www.npmjs.com/package/@viglet/create-shio-app) | Next.js starter generator |
114
+
115
+ ## Develop
116
+
117
+ ```bash
118
+ npm run build # vite lib build + .d.ts
119
+ npm run typecheck
120
+ ```
121
+
122
+ ## License
123
+
124
+ Apache-2.0 — [Viglet Shio](https://openviglet.github.io/shio/) ·
125
+ [github.com/openviglet/shio](https://github.com/openviglet/shio) ·
126
+ [docs.viglet.org/shio](https://docs.viglet.org/shio/) ·
127
+ part of the [Viglet](https://www.viglet.org) open source family.
@@ -0,0 +1,40 @@
1
+ import type { ReactNode } from "react";
2
+ import type { ShioBlock } from "@viglet/shio-client";
3
+ /** A component rendering one block of its kind. */
4
+ export type ShioBlockComponent<T extends ShioBlock = ShioBlock> = (props: {
5
+ block: T;
6
+ }) => ReactNode;
7
+ /** Block type to component. Every key is optional: a kind with no entry falls back. */
8
+ export type ShioBlockComponents = {
9
+ [K in ShioBlock["type"]]?: ShioBlockComponent<Extract<ShioBlock, {
10
+ type: K;
11
+ }>>;
12
+ };
13
+ export interface ShioBlocksProps {
14
+ /** The field's blocks — `shioBlocks(post, "BODY")` from the core client. */
15
+ blocks: ShioBlock[] | null | undefined;
16
+ /** A component per block type. Anything not named here uses the fallback. */
17
+ components?: ShioBlockComponents;
18
+ /**
19
+ * The rendered HTML the CDA delivers beside the blocks (`post.rendered?.BODY`), used for a
20
+ * block type this build has no component for.
21
+ */
22
+ fallbackHtml?: Record<string, string> | string | null;
23
+ }
24
+ /**
25
+ * SH1016 — a blocks body rendered with your own components.
26
+ *
27
+ * <p>The CDA delivers a body twice: as an array of typed blocks and as HTML. This maps the first
28
+ * onto components you own, which is the whole reason the body stopped being a string.</p>
29
+ *
30
+ * <h2>The fallback is per block, not per document</h2>
31
+ *
32
+ * <p>A page with one block type you have no component for should render the seven it knows. Falling
33
+ * back for the whole document would make adding a block type to the model blank a page that was
34
+ * working — which is the failure a fallback exists to prevent, arriving by the fallback.</p>
35
+ *
36
+ * <p>An unhandled block renders a readable default rather than nothing: a heading is a heading, a
37
+ * list is a list. Rendering nothing is how content goes missing silently, and "I did not write a
38
+ * component for `embed`" should not mean "the embed is gone".</p>
39
+ */
40
+ export declare function ShioBlocks({ blocks, components, fallbackHtml }: ShioBlocksProps): import("react").JSX.Element | null;
@@ -1,8 +1,18 @@
1
- import type { ShioPost } from "@viglet/shio-client";
2
- /** Get a published post by id (attributes expanded). `null` when not found. */
3
- export declare function useShioPost(postId: string | undefined): import("./use-async").ShioAsyncState<ShioPost | null>;
1
+ import type { ShioContentState, ShioPost } from "@viglet/shio-client";
2
+ /**
3
+ * Get a published post by id (attributes expanded). `null` when not found.
4
+ *
5
+ * SH1081 — `state` asks for another version (`"draft"`, `"rev:<n>"`), which needs a preview token.
6
+ */
7
+ export declare function useShioPost(postId: string | undefined, state?: ShioContentState): import("./use-async").ShioAsyncState<ShioPost | null>;
4
8
  /**
5
9
  * Resolve a published post by site + friendly URL — the client-side analog of
6
10
  * the catch-all route. `null` when unresolved.
11
+ *
12
+ * SH1081 — `options.locale` pins a translation and `options.state` asks for another version, as
13
+ * the client's `getPostByUrl` takes them.
7
14
  */
8
- export declare function useShioPostByUrl(siteId: string | undefined, url: string | undefined): import("./use-async").ShioAsyncState<ShioPost | null>;
15
+ export declare function useShioPostByUrl(siteId: string | undefined, url: string | undefined, options?: {
16
+ locale?: string;
17
+ state?: ShioContentState;
18
+ }): import("./use-async").ShioAsyncState<ShioPost | null>;
@@ -1,3 +1,10 @@
1
1
  import type { ShioListing, ShioQueryParams } from "@viglet/shio-client";
2
- /** Query published posts by site / folder / post type (always returns a listing). */
3
- export declare function useShioQuery(params?: ShioQueryParams): import("./use-async").ShioAsyncState<ShioListing>;
2
+ /**
3
+ * Query published posts by site / folder / post type (always returns a listing).
4
+ *
5
+ * Pass `enabled: false` to defer the request until its inputs are ready — e.g.
6
+ * while a `siteId` is still being resolved from {@link useShioSites}. While
7
+ * disabled the hook stays idle (`loading: false`, `data: undefined`) and never
8
+ * fires a request with half-resolved params.
9
+ */
10
+ export declare function useShioQuery(params?: ShioQueryParams, enabled?: boolean): import("./use-async").ShioAsyncState<ShioListing>;
package/dist/index.d.ts CHANGED
@@ -9,6 +9,8 @@ export { useShioBreadcrumb } from "./hooks/use-shio-breadcrumb";
9
9
  export { useShioPost, useShioPostByUrl } from "./hooks/use-shio-post";
10
10
  export { useShioQuery } from "./hooks/use-shio-query";
11
11
  export { ShioRichText } from "./components/shio-rich-text";
12
+ export { ShioBlocks } from "./components/shio-blocks";
13
+ export type { ShioBlocksProps, ShioBlockComponent, ShioBlockComponents } from "./components/shio-blocks";
12
14
  export type { ShioRichTextProps } from "./components/shio-rich-text";
13
15
  export { ShioImage } from "./components/shio-image";
14
16
  export type { ShioImageProps } from "./components/shio-image";
@@ -16,4 +18,4 @@ export { ShioRelator } from "./components/shio-relator";
16
18
  export type { ShioRelatorProps } from "./components/shio-relator";
17
19
  export { ShioField } from "./components/shio-field";
18
20
  export type { ShioFieldProps, ShioFieldKind } from "./components/shio-field";
19
- export type { ShioClientConfig, ShioRequestOptions, ShioSite, ShioFolder, ShioPostSummary, ShioPost, ShioListing, ShioPath, ShioQueryParams, ShioPageParams, } from "@viglet/shio-client";
21
+ export type { ShioClientConfig, ShioRequestOptions, ShioSite, ShioSiteLocales, ShioFolder, ShioPostSummary, ShioPost, ShioListing, ShioPath, ShioQueryParams, ShioPageParams, } from "@viglet/shio-client";
@@ -1,154 +1,209 @@
1
- import { jsx as u, Fragment as s } from "react/jsx-runtime";
2
- import { createContext as S, useMemo as d, useContext as g, useState as y, useEffect as C, Fragment as A } from "react";
3
- import { ShioClient as b } from "@viglet/shio-client";
4
- import { ShioClient as q, ShioHttpError as G, createShioClient as Q } from "@viglet/shio-client";
5
- const f = S(null);
6
- function R(t) {
7
- const { children: n } = t, i = "client" in t ? t.client : void 0, e = i ? void 0 : t, o = d(
8
- () => i ?? new b(e),
9
- // Rebuild only when a meaningful connection field changes.
10
- [i, e == null ? void 0 : e.baseUrl, e == null ? void 0 : e.apiToken, e == null ? void 0 : e.fetch, e == null ? void 0 : e.credentials]
11
- );
12
- return /* @__PURE__ */ u(f.Provider, { value: o, children: n });
13
- }
14
- function c() {
15
- const t = g(f);
16
- if (!t)
17
- throw new Error("useShioClient must be used within a <ShioProvider>");
18
- return t;
19
- }
20
- function h(t, n, i = !0) {
21
- const [e, o] = y({
22
- data: void 0,
23
- loading: i,
24
- error: null
25
- });
26
- return C(() => {
27
- if (!i) {
28
- o({ data: void 0, loading: !1, error: null });
29
- return;
30
- }
31
- const r = new AbortController();
32
- return o((l) => ({ ...l, loading: !0, error: null })), t(r.signal).then((l) => {
33
- r.signal.aborted || o({ data: l, loading: !1, error: null });
34
- }).catch((l) => {
35
- r.signal.aborted || o({
36
- data: void 0,
37
- loading: !1,
38
- error: l instanceof Error ? l : new Error(String(l))
39
- });
40
- }), () => r.abort();
41
- }, n), e;
42
- }
43
- function _() {
44
- const t = c();
45
- return h((n) => t.getSites({ signal: n }), [t]);
46
- }
47
- function z(t) {
48
- const n = c();
49
- return h(
50
- (i) => n.getSite(t, { signal: i }),
51
- [n, t],
52
- !!t
53
- );
54
- }
55
- function B(t, n) {
56
- const i = c();
57
- return h(
58
- (e) => i.listChildren(t, n, { signal: e }),
59
- [i, t, n == null ? void 0 : n.page, n == null ? void 0 : n.size],
60
- !!t
61
- );
62
- }
63
- function F(t) {
64
- const n = c();
65
- return h(
66
- (i) => n.getPath(t, { signal: i }),
67
- [n, t],
68
- !!t
69
- );
70
- }
71
- function H(t) {
72
- const n = c();
73
- return h(
74
- (i) => n.getPost(t, { signal: i }),
75
- [n, t],
76
- !!t
77
- );
78
- }
79
- function k(t, n) {
80
- const i = c();
81
- return h(
82
- (e) => i.getPostByUrl(t, n, { signal: e }),
83
- [i, t, n],
84
- !!t && !!n
85
- );
86
- }
87
- function v(t) {
88
- const n = c();
89
- return h(
90
- (i) => n.query(t, { signal: i }),
91
- [
92
- n,
93
- t == null ? void 0 : t.siteId,
94
- t == null ? void 0 : t.folderId,
95
- t == null ? void 0 : t.postType,
96
- t == null ? void 0 : t.page,
97
- t == null ? void 0 : t.size
98
- ]
99
- );
100
- }
101
- function w({ html: t, ...n }) {
102
- return t ? /* @__PURE__ */ u("div", { ...n, dangerouslySetInnerHTML: { __html: t } }) : null;
103
- }
104
- function x({ src: t, baseUrl: n, alt: i = "", ...e }) {
105
- if (!t) return null;
106
- const r = /^(https?:)?\/\//.test(t) || t.startsWith("data:") || !n ? t : `${n.replace(/\/+$/, "")}/${t.replace(/^\/+/, "")}`;
107
- return /* @__PURE__ */ u("img", { src: r, alt: i, ...e });
108
- }
109
- function J({
110
- items: t,
111
- children: n,
112
- keyFor: i
113
- }) {
114
- const e = Array.isArray(t) ? t : [];
115
- return /* @__PURE__ */ u(s, { children: e.map((o, r) => /* @__PURE__ */ u(A, { children: n(o, r) }, i ? i(o, r) : r)) });
116
- }
117
- const E = /<[a-z][\s\S]*>/i, P = /\.(png|jpe?g|gif|webp|svg|avif)$/i;
118
- function T(t) {
119
- return typeof t == "string" ? E.test(t) ? "html" : P.test(t.trim()) ? "image" : "text" : Array.isArray(t) ? "list" : t !== null && typeof t == "object" ? "json" : "text";
120
- }
121
- function L({ value: t, as: n, baseUrl: i, className: e }) {
122
- if (t == null || t === "") return null;
123
- switch (n ?? T(t)) {
124
- case "html":
125
- return /* @__PURE__ */ u(w, { className: e, html: String(t) });
126
- case "image":
127
- return /* @__PURE__ */ u(x, { className: e, src: String(t), baseUrl: i });
128
- case "list":
129
- return /* @__PURE__ */ u("ul", { className: e, children: t.map((r, l) => /* @__PURE__ */ u("li", { children: typeof r == "object" ? JSON.stringify(r) : String(r) }, l)) });
130
- case "json":
131
- return /* @__PURE__ */ u("pre", { className: e, children: JSON.stringify(t, null, 2) });
132
- case "text":
133
- default:
134
- return /* @__PURE__ */ u("span", { className: e, children: String(t) });
135
- }
136
- }
137
- export {
138
- q as ShioClient,
139
- L as ShioField,
140
- G as ShioHttpError,
141
- x as ShioImage,
142
- R as ShioProvider,
143
- J as ShioRelator,
144
- w as ShioRichText,
145
- Q as createShioClient,
146
- F as useShioBreadcrumb,
147
- B as useShioChildren,
148
- c as useShioClient,
149
- H as useShioPost,
150
- k as useShioPostByUrl,
151
- v as useShioQuery,
152
- z as useShioSite,
153
- _ as useShioSites
154
- };
1
+ import { Fragment as e, createContext as t, useContext as n, useEffect as r, useMemo as i, useState as a } from "react";
2
+ import { ShioClient as o, ShioClient as s, ShioHttpError as c, createShioClient as l } from "@viglet/shio-client";
3
+ import { Fragment as u, jsx as d } from "react/jsx-runtime";
4
+ // src/provider.tsx
5
+ var f = t(null);
6
+ function p(e) {
7
+ let { children: t } = e, n = "client" in e ? e.client : void 0, r = n ? void 0 : e, a = i(() => n ?? new s(r), [
8
+ n,
9
+ r?.baseUrl,
10
+ r?.apiToken,
11
+ r?.fetch,
12
+ r?.credentials
13
+ ]);
14
+ return /* @__PURE__ */ d(f.Provider, {
15
+ value: a,
16
+ children: t
17
+ });
18
+ }
19
+ function m() {
20
+ let e = n(f);
21
+ if (!e) throw Error("useShioClient must be used within a <ShioProvider>");
22
+ return e;
23
+ }
24
+ // src/hooks/use-async.ts
25
+ function h(e, t, n = !0) {
26
+ let [i, o] = a({
27
+ data: void 0,
28
+ loading: n,
29
+ error: null
30
+ });
31
+ return r(() => {
32
+ if (!n) {
33
+ o({
34
+ data: void 0,
35
+ loading: !1,
36
+ error: null
37
+ });
38
+ return;
39
+ }
40
+ let t = new AbortController();
41
+ return o((e) => ({
42
+ ...e,
43
+ loading: !0,
44
+ error: null
45
+ })), e(t.signal).then((e) => {
46
+ t.signal.aborted || o({
47
+ data: e,
48
+ loading: !1,
49
+ error: null
50
+ });
51
+ }).catch((e) => {
52
+ t.signal.aborted || o({
53
+ data: void 0,
54
+ loading: !1,
55
+ error: e instanceof Error ? e : Error(String(e))
56
+ });
57
+ }), () => t.abort();
58
+ }, t), i;
59
+ }
60
+ // src/hooks/use-shio-sites.ts
61
+ function g() {
62
+ let e = m();
63
+ return h((t) => e.getSites({ signal: t }), [e]);
64
+ }
65
+ function _(e) {
66
+ let t = m();
67
+ return h((n) => t.getSite(e, { signal: n }), [t, e], !!e);
68
+ }
69
+ // src/hooks/use-shio-children.ts
70
+ function v(e, t) {
71
+ let n = m();
72
+ return h((r) => n.listChildren(e, t, { signal: r }), [
73
+ n,
74
+ e,
75
+ t?.page,
76
+ t?.size,
77
+ t?.locale,
78
+ t?.state
79
+ ], !!e);
80
+ }
81
+ // src/hooks/use-shio-breadcrumb.ts
82
+ function y(e) {
83
+ let t = m();
84
+ return h((n) => t.getPath(e, { signal: n }), [t, e], !!e);
85
+ }
86
+ // src/hooks/use-shio-post.ts
87
+ function b(e, t) {
88
+ let n = m();
89
+ return h((r) => n.getPost(e, {
90
+ signal: r,
91
+ state: t
92
+ }), [
93
+ n,
94
+ e,
95
+ t
96
+ ], !!e);
97
+ }
98
+ function x(e, t, n) {
99
+ let r = m(), i = n?.locale, a = n?.state;
100
+ return h((n) => i ? r.getPostByUrl(e, t, i, {
101
+ signal: n,
102
+ state: a
103
+ }) : r.getPostByUrl(e, t, {
104
+ signal: n,
105
+ state: a
106
+ }), [
107
+ r,
108
+ e,
109
+ t,
110
+ i,
111
+ a
112
+ ], !!e && !!t);
113
+ }
114
+ // src/hooks/use-shio-query.ts
115
+ function S(e, t = !0) {
116
+ let n = m();
117
+ return h((t) => n.query(e, { signal: t }), [
118
+ n,
119
+ e?.siteId,
120
+ e?.folderId,
121
+ e?.postType,
122
+ e?.page,
123
+ e?.size,
124
+ e?.locale,
125
+ e?.state
126
+ ], t);
127
+ }
128
+ // src/components/shio-rich-text.tsx
129
+ function C({ html: e, ...t }) {
130
+ return e ? /* @__PURE__ */ d("div", {
131
+ ...t,
132
+ dangerouslySetInnerHTML: { __html: e }
133
+ }) : null;
134
+ }
135
+ // src/components/shio-blocks.tsx
136
+ function w({ blocks: e, components: t, fallbackHtml: n }) {
137
+ return e?.length ? /* @__PURE__ */ d(u, { children: e.map((e) => {
138
+ let r = t?.[e.type];
139
+ return /* @__PURE__ */ d("div", { children: r ? /* @__PURE__ */ d(r, { block: e }) : T(e, n) }, e.key);
140
+ }) }) : null;
141
+ }
142
+ function T(e, t) {
143
+ switch (e.type) {
144
+ case "heading": {
145
+ let t = `h${Math.min(6, Math.max(1, e.level ?? 2))}`;
146
+ return /* @__PURE__ */ d(t, { children: e.text });
147
+ }
148
+ case "paragraph": return /* @__PURE__ */ d("p", { children: e.text });
149
+ case "quote": return /* @__PURE__ */ d("blockquote", { children: e.text });
150
+ case "code": return /* @__PURE__ */ d("pre", { children: /* @__PURE__ */ d("code", { children: e.text }) });
151
+ case "list": return e.ordered ? /* @__PURE__ */ d("ol", { children: (e.items ?? []).map(E) }) : /* @__PURE__ */ d("ul", { children: (e.items ?? []).map(E) });
152
+ case "image": return /* @__PURE__ */ d("img", {
153
+ src: e.src,
154
+ alt: e.alt ?? ""
155
+ });
156
+ case "embed":
157
+ case "reference": return null;
158
+ default: return typeof t == "string" && t ? /* @__PURE__ */ d("div", { dangerouslySetInnerHTML: { __html: t } }) : null;
159
+ }
160
+ }
161
+ function E(e, t) {
162
+ return /* @__PURE__ */ d("li", { children: e }, `${t}-${e}`);
163
+ }
164
+ // src/components/shio-image.tsx
165
+ function D({ src: e, baseUrl: t, alt: n = "", ...r }) {
166
+ if (!e) return null;
167
+ let i = /^(https?:)?\/\//.test(e) || e.startsWith("data:") || !t ? e : `${t.replace(/\/+$/, "")}/${e.replace(/^\/+/, "")}`;
168
+ return /* @__PURE__ */ d("img", {
169
+ src: i,
170
+ alt: n,
171
+ ...r
172
+ });
173
+ }
174
+ // src/components/shio-relator.tsx
175
+ function O({ items: t, children: n, keyFor: r }) {
176
+ return /* @__PURE__ */ d(u, { children: (Array.isArray(t) ? t : []).map((t, i) => /* @__PURE__ */ d(e, { children: n(t, i) }, r ? r(t, i) : i)) });
177
+ }
178
+ // src/components/shio-field.tsx
179
+ var k = /<[a-z][\s\S]*>/i, A = /\.(png|jpe?g|gif|webp|svg|avif)$/i;
180
+ function j(e) {
181
+ return typeof e == "string" ? k.test(e) ? "html" : A.test(e.trim()) ? "image" : "text" : Array.isArray(e) ? "list" : typeof e == "object" && e ? "json" : "text";
182
+ }
183
+ function M({ value: e, as: t, baseUrl: n, className: r }) {
184
+ if (e == null || e === "") return null;
185
+ switch (t ?? j(e)) {
186
+ case "html": return /* @__PURE__ */ d(C, {
187
+ className: r,
188
+ html: String(e)
189
+ });
190
+ case "image": return /* @__PURE__ */ d(D, {
191
+ className: r,
192
+ src: String(e),
193
+ baseUrl: n
194
+ });
195
+ case "list": return /* @__PURE__ */ d("ul", {
196
+ className: r,
197
+ children: e.map((e, t) => /* @__PURE__ */ d("li", { children: typeof e == "object" ? JSON.stringify(e) : String(e) }, t))
198
+ });
199
+ case "json": return /* @__PURE__ */ d("pre", {
200
+ className: r,
201
+ children: JSON.stringify(e, null, 2)
202
+ });
203
+ default: return /* @__PURE__ */ d("span", {
204
+ className: r,
205
+ children: String(e)
206
+ });
207
+ }
208
+ }
209
+ export { w as ShioBlocks, o as ShioClient, M as ShioField, c as ShioHttpError, D as ShioImage, p as ShioProvider, O as ShioRelator, C as ShioRichText, l as createShioClient, y as useShioBreadcrumb, v as useShioChildren, m as useShioClient, b as useShioPost, x as useShioPostByUrl, S as useShioQuery, _ as useShioSite, g as useShioSites };
@@ -1 +1 @@
1
- (function(r,o){typeof exports=="object"&&typeof module<"u"?o(exports,require("react/jsx-runtime"),require("react"),require("@viglet/shio-client")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","@viglet/shio-client"],o):(r=typeof globalThis<"u"?globalThis:r||self,o(r.ShioReactSdk={},r.jsxRuntime,r.React,r.ShioClient))})(this,(function(r,o,f,d){"use strict";const s=f.createContext(null);function b(e){const{children:t}=e,i="client"in e?e.client:void 0,n=i?void 0:e,c=f.useMemo(()=>i??new d.ShioClient(n),[i,n==null?void 0:n.baseUrl,n==null?void 0:n.apiToken,n==null?void 0:n.fetch,n==null?void 0:n.credentials]);return o.jsx(s.Provider,{value:c,children:t})}function h(){const e=f.useContext(s);if(!e)throw new Error("useShioClient must be used within a <ShioProvider>");return e}function S(e,t,i=!0){const[n,c]=f.useState({data:void 0,loading:i,error:null});return f.useEffect(()=>{if(!i){c({data:void 0,loading:!1,error:null});return}const u=new AbortController;return c(l=>({...l,loading:!0,error:null})),e(u.signal).then(l=>{u.signal.aborted||c({data:l,loading:!1,error:null})}).catch(l=>{u.signal.aborted||c({data:void 0,loading:!1,error:l instanceof Error?l:new Error(String(l))})}),()=>u.abort()},t),n}function P(){const e=h();return S(t=>e.getSites({signal:t}),[e])}function C(e){const t=h();return S(i=>t.getSite(e,{signal:i}),[t,e],!!e)}function j(e,t){const i=h();return S(n=>i.listChildren(e,t,{signal:n}),[i,e,t==null?void 0:t.page,t==null?void 0:t.size],!!e)}function A(e){const t=h();return S(i=>t.getPath(e,{signal:i}),[t,e],!!e)}function E(e){const t=h();return S(i=>t.getPost(e,{signal:i}),[t,e],!!e)}function T(e,t){const i=h();return S(n=>i.getPostByUrl(e,t,{signal:n}),[i,e,t],!!e&&!!t)}function w(e){const t=h();return S(i=>t.query(e,{signal:i}),[t,e==null?void 0:e.siteId,e==null?void 0:e.folderId,e==null?void 0:e.postType,e==null?void 0:e.page,e==null?void 0:e.size])}function g({html:e,...t}){return e?o.jsx("div",{...t,dangerouslySetInnerHTML:{__html:e}}):null}function y({src:e,baseUrl:t,alt:i="",...n}){if(!e)return null;const u=/^(https?:)?\/\//.test(e)||e.startsWith("data:")||!t?e:`${t.replace(/\/+$/,"")}/${e.replace(/^\/+/,"")}`;return o.jsx("img",{src:u,alt:i,...n})}function v({items:e,children:t,keyFor:i}){const n=Array.isArray(e)?e:[];return o.jsx(o.Fragment,{children:n.map((c,u)=>o.jsx(f.Fragment,{children:t(c,u)},i?i(c,u):u))})}const O=/<[a-z][\s\S]*>/i,B=/\.(png|jpe?g|gif|webp|svg|avif)$/i;function M(e){return typeof e=="string"?O.test(e)?"html":B.test(e.trim())?"image":"text":Array.isArray(e)?"list":e!==null&&typeof e=="object"?"json":"text"}function q({value:e,as:t,baseUrl:i,className:n}){if(e==null||e==="")return null;switch(t??M(e)){case"html":return o.jsx(g,{className:n,html:String(e)});case"image":return o.jsx(y,{className:n,src:String(e),baseUrl:i});case"list":return o.jsx("ul",{className:n,children:e.map((u,l)=>o.jsx("li",{children:typeof u=="object"?JSON.stringify(u):String(u)},l))});case"json":return o.jsx("pre",{className:n,children:JSON.stringify(e,null,2)});case"text":default:return o.jsx("span",{className:n,children:String(e)})}}Object.defineProperty(r,"ShioClient",{enumerable:!0,get:()=>d.ShioClient}),Object.defineProperty(r,"ShioHttpError",{enumerable:!0,get:()=>d.ShioHttpError}),Object.defineProperty(r,"createShioClient",{enumerable:!0,get:()=>d.createShioClient}),r.ShioField=q,r.ShioImage=y,r.ShioProvider=b,r.ShioRelator=v,r.ShioRichText=g,r.useShioBreadcrumb=A,r.useShioChildren=j,r.useShioClient=h,r.useShioPost=E,r.useShioPostByUrl=T,r.useShioQuery=w,r.useShioSite=C,r.useShioSites=P,Object.defineProperty(r,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports,require("react"),require("@viglet/shio-client"),require("react/jsx-runtime")):typeof define==`function`&&define.amd?define([`exports`,`react`,`@viglet/shio-client`,`react/jsx-runtime`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ShioReactSdk={},e.React,e.ShioClient,e.jsxRuntime))})(this,function(e,t,n,r){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var i=(0,t.createContext)(null);function a(e){let{children:a}=e,o=`client`in e?e.client:void 0,s=o?void 0:e,c=(0,t.useMemo)(()=>o??new n.ShioClient(s),[o,s?.baseUrl,s?.apiToken,s?.fetch,s?.credentials]);return(0,r.jsx)(i.Provider,{value:c,children:a})}function o(){let e=(0,t.useContext)(i);if(!e)throw Error(`useShioClient must be used within a <ShioProvider>`);return e}function s(e,n,r=!0){let[i,a]=(0,t.useState)({data:void 0,loading:r,error:null});return(0,t.useEffect)(()=>{if(!r){a({data:void 0,loading:!1,error:null});return}let t=new AbortController;return a(e=>({...e,loading:!0,error:null})),e(t.signal).then(e=>{t.signal.aborted||a({data:e,loading:!1,error:null})}).catch(e=>{t.signal.aborted||a({data:void 0,loading:!1,error:e instanceof Error?e:Error(String(e))})}),()=>t.abort()},n),i}function c(){let e=o();return s(t=>e.getSites({signal:t}),[e])}function l(e){let t=o();return s(n=>t.getSite(e,{signal:n}),[t,e],!!e)}function u(e,t){let n=o();return s(r=>n.listChildren(e,t,{signal:r}),[n,e,t?.page,t?.size,t?.locale,t?.state],!!e)}function d(e){let t=o();return s(n=>t.getPath(e,{signal:n}),[t,e],!!e)}function f(e,t){let n=o();return s(r=>n.getPost(e,{signal:r,state:t}),[n,e,t],!!e)}function p(e,t,n){let r=o(),i=n?.locale,a=n?.state;return s(n=>i?r.getPostByUrl(e,t,i,{signal:n,state:a}):r.getPostByUrl(e,t,{signal:n,state:a}),[r,e,t,i,a],!!e&&!!t)}function m(e,t=!0){let n=o();return s(t=>n.query(e,{signal:t}),[n,e?.siteId,e?.folderId,e?.postType,e?.page,e?.size,e?.locale,e?.state],t)}function h({html:e,...t}){return e?(0,r.jsx)(`div`,{...t,dangerouslySetInnerHTML:{__html:e}}):null}function g({blocks:e,components:t,fallbackHtml:n}){return e?.length?(0,r.jsx)(r.Fragment,{children:e.map(e=>{let i=t?.[e.type];return(0,r.jsx)(`div`,{children:i?(0,r.jsx)(i,{block:e}):_(e,n)},e.key)})}):null}function _(e,t){switch(e.type){case`heading`:{let t=`h${Math.min(6,Math.max(1,e.level??2))}`;return(0,r.jsx)(t,{children:e.text})}case`paragraph`:return(0,r.jsx)(`p`,{children:e.text});case`quote`:return(0,r.jsx)(`blockquote`,{children:e.text});case`code`:return(0,r.jsx)(`pre`,{children:(0,r.jsx)(`code`,{children:e.text})});case`list`:return e.ordered?(0,r.jsx)(`ol`,{children:(e.items??[]).map(v)}):(0,r.jsx)(`ul`,{children:(e.items??[]).map(v)});case`image`:return(0,r.jsx)(`img`,{src:e.src,alt:e.alt??``});case`embed`:case`reference`:return null;default:return typeof t==`string`&&t?(0,r.jsx)(`div`,{dangerouslySetInnerHTML:{__html:t}}):null}}function v(e,t){return(0,r.jsx)(`li`,{children:e},`${t}-${e}`)}function y({src:e,baseUrl:t,alt:n=``,...i}){if(!e)return null;let a=/^(https?:)?\/\//.test(e)||e.startsWith(`data:`)||!t?e:`${t.replace(/\/+$/,``)}/${e.replace(/^\/+/,``)}`;return(0,r.jsx)(`img`,{src:a,alt:n,...i})}function b({items:e,children:n,keyFor:i}){return(0,r.jsx)(r.Fragment,{children:(Array.isArray(e)?e:[]).map((e,a)=>(0,r.jsx)(t.Fragment,{children:n(e,a)},i?i(e,a):a))})}var x=/<[a-z][\s\S]*>/i,S=/\.(png|jpe?g|gif|webp|svg|avif)$/i;function C(e){return typeof e==`string`?x.test(e)?`html`:S.test(e.trim())?`image`:`text`:Array.isArray(e)?`list`:typeof e==`object`&&e?`json`:`text`}function w({value:e,as:t,baseUrl:n,className:i}){if(e==null||e===``)return null;switch(t??C(e)){case`html`:return(0,r.jsx)(h,{className:i,html:String(e)});case`image`:return(0,r.jsx)(y,{className:i,src:String(e),baseUrl:n});case`list`:return(0,r.jsx)(`ul`,{className:i,children:e.map((e,t)=>(0,r.jsx)(`li`,{children:typeof e==`object`?JSON.stringify(e):String(e)},t))});case`json`:return(0,r.jsx)(`pre`,{className:i,children:JSON.stringify(e,null,2)});default:return(0,r.jsx)(`span`,{className:i,children:String(e)})}}e.ShioBlocks=g,Object.defineProperty(e,"ShioClient",{enumerable:!0,get:function(){return n.ShioClient}}),e.ShioField=w,Object.defineProperty(e,"ShioHttpError",{enumerable:!0,get:function(){return n.ShioHttpError}}),e.ShioImage=y,e.ShioProvider=a,e.ShioRelator=b,e.ShioRichText=h,Object.defineProperty(e,"createShioClient",{enumerable:!0,get:function(){return n.createShioClient}}),e.useShioBreadcrumb=d,e.useShioChildren=u,e.useShioClient=o,e.useShioPost=f,e.useShioPostByUrl=p,e.useShioQuery=m,e.useShioSite=l,e.useShioSites=c});
package/dist/types.d.ts CHANGED
@@ -3,4 +3,4 @@
3
3
  * re-exported here for convenience, so React consumers can import them from a
4
4
  * single package.
5
5
  */
6
- export type { ShioClientConfig, ShioRequestOptions, ShioSite, ShioFolder, ShioPostSummary, ShioPost, ShioListing, ShioPath, ShioQueryParams, ShioPageParams, } from "@viglet/shio-client";
6
+ export type { ShioClientConfig, ShioRequestOptions, ShioSite, ShioSiteLocales, ShioFolder, ShioPostSummary, ShioPost, ShioListing, ShioPath, ShioQueryParams, ShioPageParams, } from "@viglet/shio-client";
package/package.json CHANGED
@@ -1,7 +1,16 @@
1
1
  {
2
2
  "name": "@viglet/shio-react-sdk",
3
- "version": "2026.2.1",
4
- "description": "React SDK for consuming Shio CMS content via the Content Delivery API (CDA). Hooks + render components built on @viglet/shio-client.",
3
+ "version": "2026.3.3",
4
+ "description": "React SDK for consuming Viglet Shio content via the Content Delivery API (CDA). Hooks + render components built on @viglet/shio-client.",
5
+ "homepage": "https://openviglet.github.io/shio/",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/openviglet/shio.git",
9
+ "directory": "shio-react-sdk"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/openviglet/shio/issues"
13
+ },
5
14
  "type": "module",
6
15
  "main": "dist/shio-react-sdk.umd.cjs",
7
16
  "module": "dist/shio-react-sdk.js",
@@ -17,27 +26,41 @@
17
26
  "dist"
18
27
  ],
19
28
  "dependencies": {
20
- "@viglet/shio-client": "2026.2.1"
29
+ "@viglet/shio-client": "2026.3.3"
21
30
  },
22
31
  "peerDependencies": {
23
32
  "react": ">=18.0.0"
24
33
  },
25
34
  "devDependencies": {
26
- "@types/react": "^19.1.2",
27
- "react": "^19.1.0",
35
+ "@types/react": "^19.3.0",
36
+ "react": "^19.3.1",
28
37
  "typescript": "^5.8.3",
29
- "vite": "^6.3.1"
38
+ "vite": "^8.3.5"
30
39
  },
31
40
  "keywords": [
32
41
  "shio",
42
+ "viglet",
33
43
  "cms",
34
- "headless",
44
+ "headless-cms",
45
+ "content-management-system",
46
+ "agent",
47
+ "ai",
48
+ "mcp",
49
+ "model-context-protocol",
50
+ "claude-code",
35
51
  "react",
36
52
  "sdk",
37
- "cda"
53
+ "cda",
54
+ "hooks",
55
+ "nextjs",
56
+ "typescript",
57
+ "headless"
38
58
  ],
39
- "author": "Viglet Team",
40
- "license": "GPL-3.0",
59
+ "author": {
60
+ "name": "Viglet Team",
61
+ "url": "https://www.viglet.org"
62
+ },
63
+ "license": "Apache-2.0",
41
64
  "scripts": {
42
65
  "dev": "vite build --watch",
43
66
  "build": "vite build && tsc --emitDeclarationOnly",