@fragmentsx/runtime-react 0.1.0 → 0.2.0-dev-20260831061037

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 CHANGED
@@ -8,12 +8,11 @@ React.
8
8
  ## Что это решает
9
9
 
10
10
  Скомпилированный сервером фрагмент — это ESM-артефакт, который нужно
11
- загрузить, смонтировать в дерево React, подключить его стили и дать доступу
11
+ загрузить, смонтировать в дерево React, подключить его стили и дать доступ
12
12
  к метрикам и переменным области. `runtime-react` закрывает весь этот путь:
13
13
 
14
- - `FragmentsProvider` + `FragmentsClientProvider` — контекст клиента на
15
- дерево приложения;
16
- - `Area` / `FragmentRenderer` — резолвинг и рендер области/фрагмента;
14
+ - `FragmentsProvider` — контекст клиента на дерево приложения;
15
+ - `Area` / `FragmentRenderer` — резолвинг области и рендер фрагмента;
17
16
  - `useFragmentComponent`, `useFragmentStylesheet`, `FragmentStylesheet` —
18
17
  подгрузка компонента и его CSS;
19
18
  - `useFragmentMetrics`, `useArea`, `useProjectProperty` — доступ к метрикам,
@@ -25,27 +24,79 @@ React.
25
24
  pnpm add @fragmentsx/runtime-react @fragmentsx/fragments-client react react-dom
26
25
  ```
27
26
 
27
+ Пакет объявляет `react` в `peerDependencies` (`^17 || ^18 || ^19`).
28
+
29
+ Если приложение собирается через Vite — поставьте ещё плагин, который
30
+ резолвит bare imports внутри загружаемых артефактов:
31
+
32
+ ```bash
33
+ pnpm add -D @fragmentsx/vite-plugin
34
+ ```
35
+
28
36
  ## Использование
29
37
 
30
38
  ```tsx
31
- import { createBrowserClient, FragmentsProvider, Area } from '@fragmentsx/runtime-react';
39
+ import {
40
+ createBrowserClient,
41
+ FragmentsProvider,
42
+ Area,
43
+ } from '@fragmentsx/runtime-react';
32
44
 
33
45
  const client = createBrowserClient({
34
- apiUrl: 'https://api.fragments.example.com',
35
- projectId: 'my-project',
46
+ apiToken: import.meta.env.VITE_FRAGMENTS_API_TOKEN,
47
+ backendEndpoint: 'https://api.example.com',
36
48
  });
37
49
 
38
50
  function App() {
39
51
  return (
40
52
  <FragmentsProvider client={client}>
41
- <Area code="home" />
53
+ <Area areaCode="home" />
42
54
  </FragmentsProvider>
43
55
  );
44
56
  }
45
57
  ```
46
58
 
59
+ `apiToken` обязателен. `backendEndpoint` — источник манифеста области; если
60
+ не передан, клиент бьётся в `window.location.origin`, что удобно при
61
+ same-origin проксировании `/api` на публичный API площадки.
62
+
63
+ `Area` сама разрешает область и внутри себя обёрнута в `Suspense` — пока
64
+ манифест грузится, поддерево пустое. Под капотом:
65
+
66
+ ```
67
+ <Area areaCode> → GET <backendEndpoint>/api/area/<code>/compiled
68
+ → manifest.fragments[*].moduleUrl → import(артефакт)
69
+ → <FragmentStylesheet href={cssUrl}/> + рендер фрагмента
70
+ ```
71
+
72
+ ### Рендер конкретного фрагмента
73
+
74
+ Когда область разрешать не нужно, используйте `FragmentRenderer` напрямую:
75
+
76
+ ```tsx
77
+ import { FragmentRenderer } from '@fragmentsx/runtime-react';
78
+
79
+ <FragmentRenderer fragmentId={42} props={{ title: 'Привет' }} />
80
+ ```
81
+
82
+ `AreaProps` — `{ areaCode: string; options?: { timeout?, pause?, ssr? } }`.
83
+ `FragmentRendererProps` — `{ fragmentId: number; props?; globalCssUrl?;
84
+ projectProperties?; onError? }`.
85
+
86
+ ## Обработка ошибок
87
+
88
+ Пакет реэкспортирует типизированные ошибки транспорта, чтобы их можно было
89
+ различать в границах ошибок приложения:
90
+
91
+ ```ts
92
+ import {
93
+ FragmentsAreaError,
94
+ FragmentsApiVersionError,
95
+ FragmentsLoadError,
96
+ } from '@fragmentsx/runtime-react';
97
+ ```
98
+
47
99
  ## Пара с fragments-client
48
100
 
49
- `runtime-react` зависит от `@fragmentsx/fragments-client` как от транспортного
50
- ядра (`workspace:*` внутри монорепозитория, `^0.1.0` из npm) — устанавливать
51
- и обновлять пакеты стоит вместе.
101
+ `runtime-react` зависит от `@fragmentsx/fragments-client` как от
102
+ транспортного ядра — устанавливать и обновлять пакеты стоит вместе.
package/dist/index.d.ts CHANGED
@@ -20,13 +20,33 @@ import { ReactNode } from 'react';
20
20
  export declare const Area: FC<AreaProps>;
21
21
 
22
22
  /**
23
- * Props для Area компонента (D-09, сокращён Phase 73 B-13):
23
+ * Сентинел нерезолвленной области — возвращается вместо чтения `$area.read`,
24
+ * когда на сервере `options.ssr === false`, либо когда `options.pause === true`
25
+ * (suspense-режим).
26
+ *
27
+ * Совместим с `UseAreaResult` по форме (тип возврата хука не расширяется),
28
+ * поэтому правка остаётся minor: потребитель, передающий `rootFragmentId`
29
+ * в проп типа `number`, продолжает компилироваться. Заморожен — сравнение
30
+ * по ссылке в `Area.tsx` не должно ломаться мутацией снаружи.
31
+ */
32
+ export declare const AREA_UNRESOLVED: UseAreaResult;
33
+
34
+ /**
35
+ * Props для Area компонента (D-09, сокращён Phase 73 B-13; расширен quick 260830-rvp):
24
36
  * - areaCode — строковый код области (Area.code в backend schema)
25
37
  * - options.pause — пропустить рендер (conditional skip per legacy contract)
26
38
  * - options.timeout — network timeout для $area.resolve fetch
27
39
  * - options.ssr — отключить auto-resolve в SSR environment (default `true`);
28
40
  * в browser auto-resolve запускается всегда. Параллель к render-react
29
41
  * Area options.ssr.
42
+ * - options.props (INT-03) — объект мержится поверх серверных props (ключи
43
+ * потребителя выигрывают), функция вызывается с серверными props и её
44
+ * результат уходит в артефакт целиком. Обе формы поддержаны намеренно —
45
+ * паритет с legacy render-react, с которого мигрирует потребитель.
46
+ * - options.fallback (INT-04) — узел, видимый до разрешения области; default
47
+ * `null` (прежнее поведение).
48
+ * - options.onError (INT-04) — вызывается при броске внутри поддерева;
49
+ * default — только dev-лог границы (прежнее поведение).
30
50
  */
31
51
  export declare interface AreaProps {
32
52
  areaCode: string;
@@ -34,6 +54,9 @@ export declare interface AreaProps {
34
54
  timeout?: number;
35
55
  pause?: boolean;
36
56
  ssr?: boolean;
57
+ props?: Record<string, unknown> | ((serverProps: Record<string, unknown>) => Record<string, unknown>);
58
+ fallback?: ReactNode;
59
+ onError?: (error: Error) => void;
37
60
  };
38
61
  }
39
62
 
@@ -203,7 +226,15 @@ export declare interface ReachGoalInfo {
203
226
  campaignId?: number;
204
227
  }
205
228
 
206
- export declare function useArea(areaCode: string, options?: UseAreaOptions): UseAreaResult;
229
+ /** Suspense-режим (по умолчанию либо явный `suspense: true`) — прежний throw-протокол. */
230
+ export declare function useArea(areaCode: string, options?: UseAreaOptions & {
231
+ suspense?: true;
232
+ }): UseAreaResult;
233
+
234
+ /** Не-suspense режим (INT-05) — явный `suspense: false` возвращает состояние вместо throw. */
235
+ export declare function useArea(areaCode: string, options: UseAreaOptions & {
236
+ suspense: false;
237
+ }): UseAreaState;
207
238
 
208
239
  /**
209
240
  * Опции хука. По дизайну API параллелен render-react useArea:
@@ -211,16 +242,22 @@ export declare function useArea(areaCode: string, options?: UseAreaOptions): Use
211
242
  * - `ssr` — стартовать ли auto-resolve на сервере (default `true`, чтобы
212
243
  * Next.js getServerSideProps мог hydration'ить с прогретым кэшем).
213
244
  * В browser environment auto-resolve всегда включён.
245
+ * - `pause` (INT-06) — пропустить резолв и чтение кэша вовсе; паритет
246
+ * с `AreaProps.options.pause`.
247
+ * - `suspense` (INT-05) — `false` переключает хук на `UseAreaState` вместо
248
+ * throw-протокола; по умолчанию `true` (прежнее поведение).
214
249
  */
215
- declare interface UseAreaOptions {
250
+ export declare interface UseAreaOptions {
216
251
  timeout?: number;
217
252
  ssr?: boolean;
253
+ pause?: boolean;
254
+ suspense?: boolean;
218
255
  }
219
256
 
220
257
  /**
221
258
  * Result shape возвращаемый useArea — зеркалирует AreaResolveResult из client-core.
222
259
  */
223
- declare interface UseAreaResult {
260
+ export declare interface UseAreaResult {
224
261
  rootFragmentId: number;
225
262
  /**
226
263
  * Phase 73, B-02/B-06: значения props корневого артефакта, разрешённые сервером
@@ -244,6 +281,26 @@ declare interface UseAreaResult {
244
281
  globalCssUrl: string | null;
245
282
  }
246
283
 
284
+ /**
285
+ * Состояние, возвращаемое `useArea(code, {suspense:false})` вместо throw.
286
+ */
287
+ export declare interface UseAreaState {
288
+ status: UseAreaStatus;
289
+ data: UseAreaResult | null;
290
+ error: Error | null;
291
+ }
292
+
293
+ /**
294
+ * Union статуса не-suspense режима (quick 260830-rvp, INT-05):
295
+ * - `idle` — пауза (`options.pause`) либо серверный пропуск (`ssr:false` на сервере).
296
+ * - `loading` — кэш пуст, резолв запущен (идемпотентно), данных ещё нет.
297
+ * - `ready` — терминальный кэш-хит, данные доступны.
298
+ * - `not-found` — терминальная ошибка резолва (сохранённая в rejected-кэше);
299
+ * отдельного статуса под сетевой сбой нет намеренно — оба исхода для площадки
300
+ * означают «показать свой шаблон», различие доступно через поле `error`.
301
+ */
302
+ export declare type UseAreaStatus = "idle" | "loading" | "ready" | "not-found";
303
+
247
304
  /**
248
305
  * useCssChunk — no-op stub для compiled fragments.
249
306
  *
package/dist/index.es.js CHANGED
@@ -1,32 +1,32 @@
1
- import { jsx as o, jsxs as M, Fragment as j } from "react/jsx-runtime";
2
- import { createContext as f, useContext as a, useMemo as g, useLayoutEffect as N, useEffect as S, version as I, Component as R, Suspense as C } from "react";
3
- import { createFragmentsClient as k } from "@fragmentsx/fragments-client";
4
- import { FragmentsApiVersionError as ne, FragmentsAreaError as oe, FragmentsLoadError as se } from "@fragmentsx/fragments-client";
5
- const c = f(
1
+ import { jsx as u, jsxs as N, Fragment as k } from "react/jsx-runtime";
2
+ import { createContext as m, useContext as f, useMemo as C, useState as I, useEffect as P, useLayoutEffect as R, version as b, Component as p, Suspense as y } from "react";
3
+ import { createFragmentsClient as _ } from "@fragmentsx/fragments-client";
4
+ import { FragmentsApiVersionError as le, FragmentsAreaError as se, FragmentsLoadError as ae } from "@fragmentsx/fragments-client";
5
+ const o = m(
6
6
  null
7
7
  );
8
- c.displayName = "FragmentsClientContext";
9
- function _(r) {
10
- return /* @__PURE__ */ o(c.Provider, { value: r.value, children: r.children });
8
+ o.displayName = "FragmentsClientContext";
9
+ function U(r) {
10
+ return /* @__PURE__ */ u(o.Provider, { value: r.value, children: r.children });
11
11
  }
12
- function b() {
13
- return a(c);
12
+ function L() {
13
+ return f(o);
14
14
  }
15
- const v = f(null);
16
- v.displayName = "InstanceIdContext";
17
- const h = f(
15
+ const F = m(null);
16
+ F.displayName = "InstanceIdContext";
17
+ const v = m(
18
18
  null
19
19
  );
20
- h.displayName = "ModulesMapContext";
21
- function B({
20
+ v.displayName = "ModulesMapContext";
21
+ function O({
22
22
  value: r,
23
23
  children: e
24
24
  }) {
25
- return /* @__PURE__ */ o(h.Provider, { value: r, children: e });
25
+ return /* @__PURE__ */ u(v.Provider, { value: r, children: e });
26
26
  }
27
- function H() {
28
- const r = a(c);
29
- return g(
27
+ function W() {
28
+ const r = f(o);
29
+ return C(
30
30
  () => ({
31
31
  reachGoal: (e) => {
32
32
  var n, t;
@@ -36,48 +36,72 @@ function H() {
36
36
  [r]
37
37
  );
38
38
  }
39
- function L(r) {
40
- const e = a(h);
39
+ function B(r) {
40
+ const e = f(v);
41
41
  if (!e)
42
42
  throw new Error("[useFragmentComponent] No ModulesMapProvider in tree");
43
43
  return e.read(r);
44
44
  }
45
- const U = typeof window < "u";
46
- function $(r, e) {
47
- const n = a(c);
45
+ const D = typeof window < "u", x = Object.freeze({
46
+ rootFragmentId: 0,
47
+ props: {},
48
+ projectProperties: {},
49
+ globalCssUrl: null
50
+ });
51
+ function V(r, e) {
52
+ const n = f(o);
48
53
  if (!n)
49
54
  throw new Error("[useArea] No FragmentsClientProvider in tree");
50
55
  const t = n.$area;
51
56
  if (!(t != null && t.read))
52
57
  throw new Error("[useArea] $area plugin not mounted");
53
- if ((U || ((e == null ? void 0 : e.ssr) ?? !0)) && !t.has(r)) {
54
- const i = (e == null ? void 0 : e.timeout) != null ? { timeout: e.timeout } : void 0;
55
- t.resolve(r, i);
56
- }
57
- return t.read(r);
58
+ const l = (e == null ? void 0 : e.suspense) ?? !0, d = (e == null ? void 0 : e.pause) === !0 || !D && (e == null ? void 0 : e.ssr) === !1, s = (e == null ? void 0 : e.timeout) != null ? { timeout: e.timeout } : void 0, [, a] = I(0);
59
+ if (P(() => {
60
+ if (l || d) return;
61
+ let c = !0;
62
+ return t.resolve(r, s).finally(() => {
63
+ c && a((h) => h + 1);
64
+ }), () => {
65
+ c = !1;
66
+ };
67
+ }, [r, l, e == null ? void 0 : e.pause, e == null ? void 0 : e.timeout, e == null ? void 0 : e.ssr]), l)
68
+ return d ? x : (t.has(r) || t.resolve(r, s), t.read(r));
69
+ if (d)
70
+ return { status: "idle", data: null, error: null };
71
+ if (t.has(r))
72
+ try {
73
+ return { status: "ready", data: t.read(r), error: null };
74
+ } catch (c) {
75
+ return {
76
+ status: "not-found",
77
+ data: null,
78
+ error: c instanceof Error ? c : new Error(String(c))
79
+ };
80
+ }
81
+ return t.resolve(r, s), { status: "loading", data: null, error: null };
58
82
  }
59
- const E = typeof window < "u", D = () => {
60
- }, d = /* @__PURE__ */ new Map(), F = (r, e) => {
61
- if (!E)
62
- return D;
63
- const n = d.get(e);
83
+ const w = typeof window < "u", $ = () => {
84
+ }, i = /* @__PURE__ */ new Map(), A = (r, e) => {
85
+ if (!w)
86
+ return $;
87
+ const n = i.get(e);
64
88
  if (n)
65
89
  return n.refCount += 1, () => {
66
- n.refCount -= 1, n.refCount === 0 && (n.linkEl.remove(), d.delete(e));
90
+ n.refCount -= 1, n.refCount === 0 && (n.linkEl.remove(), i.delete(e));
67
91
  };
68
92
  const t = document.createElement("link");
69
93
  t.rel = "stylesheet", t.href = r, t.setAttribute("data-fragment-key", e), document.head.appendChild(t);
70
- const s = { refCount: 1, linkEl: t };
71
- return d.set(e, s), () => {
72
- s.refCount -= 1, s.refCount === 0 && (s.linkEl.remove(), d.delete(e));
94
+ const l = { refCount: 1, linkEl: t };
95
+ return i.set(e, l), () => {
96
+ l.refCount -= 1, l.refCount === 0 && (l.linkEl.remove(), i.delete(e));
73
97
  };
74
- }, O = E ? N : S;
75
- function V(r, e) {
76
- O(() => F(r, e), [r, e]);
98
+ }, T = w ? R : P;
99
+ function G(r, e) {
100
+ T(() => A(r, e), [r, e]);
77
101
  }
78
- const G = parseInt(I.split(".")[0], 10), K = G >= 19;
79
- function m({ href: r, fragmentKey: e }) {
80
- return K ? /* @__PURE__ */ o(
102
+ const K = parseInt(b.split(".")[0], 10), z = K >= 19;
103
+ function g({ href: r, fragmentKey: e }) {
104
+ return z ? /* @__PURE__ */ u(
81
105
  "link",
82
106
  {
83
107
  rel: "stylesheet",
@@ -85,13 +109,13 @@ function m({ href: r, fragmentKey: e }) {
85
109
  precedence: "default",
86
110
  "data-fragment-key": e
87
111
  }
88
- ) : (V(r, e), null);
112
+ ) : (G(r, e), null);
89
113
  }
90
- function Q(r) {
114
+ function X(r) {
91
115
  }
92
- const P = {}, p = f(null);
93
- p.displayName = "ProjectPropertiesContext";
94
- class y extends R {
116
+ const M = {}, E = m(null);
117
+ E.displayName = "ProjectPropertiesContext";
118
+ class S extends p {
95
119
  constructor() {
96
120
  super(...arguments), this.state = { hasError: !1 };
97
121
  }
@@ -99,104 +123,108 @@ class y extends R {
99
123
  return { hasError: !0 };
100
124
  }
101
125
  componentDidCatch(e, n) {
102
- var t, s;
103
- process.env.NODE_ENV !== "production" && console.error("[fragments] Area error:", e, n.componentStack), (s = (t = this.props).onError) == null || s.call(t, e);
126
+ var t, l;
127
+ process.env.NODE_ENV !== "production" && console.error("[fragments] Area error:", e, n.componentStack), (l = (t = this.props).onError) == null || l.call(t, e);
104
128
  }
105
129
  render() {
106
130
  return this.state.hasError ? null : this.props.children;
107
131
  }
108
132
  }
109
- const x = ({
133
+ const j = ({
110
134
  fragmentId: r,
111
135
  props: e,
112
136
  globalCssUrl: n = null,
113
- projectProperties: t = P
137
+ projectProperties: t = M
114
138
  }) => {
115
- const s = L(r), l = b().$fragments, u = l == null ? void 0 : l.getRef(r), w = l == null ? void 0 : l.getScopeClass(r), A = e ?? {};
116
- return /* @__PURE__ */ M(j, { children: [
117
- n != null && /* @__PURE__ */ o(
118
- m,
139
+ const l = B(r), s = L().$fragments, a = s == null ? void 0 : s.getRef(r), c = s == null ? void 0 : s.getScopeClass(r), h = e ?? {};
140
+ return /* @__PURE__ */ N(k, { children: [
141
+ n != null && /* @__PURE__ */ u(
142
+ g,
119
143
  {
120
144
  href: n,
121
145
  fragmentKey: "global"
122
146
  }
123
147
  ),
124
- u && /* @__PURE__ */ o(
125
- m,
148
+ a && /* @__PURE__ */ u(
149
+ g,
126
150
  {
127
- href: u.cssUrl,
151
+ href: a.cssUrl,
128
152
  fragmentKey: `fragment:${r}:css`
129
153
  }
130
154
  ),
131
- (u == null ? void 0 : u.fontsUrl) != null && /* @__PURE__ */ o(
132
- m,
155
+ (a == null ? void 0 : a.fontsUrl) != null && /* @__PURE__ */ u(
156
+ g,
133
157
  {
134
- href: u.fontsUrl,
158
+ href: a.fontsUrl,
135
159
  fragmentKey: `fragment:${r}:fonts`
136
160
  }
137
161
  ),
138
- /* @__PURE__ */ o(p.Provider, { value: t, children: /* @__PURE__ */ o(v.Provider, { value: null, children: /* @__PURE__ */ o(
162
+ /* @__PURE__ */ u(E.Provider, { value: t, children: /* @__PURE__ */ u(F.Provider, { value: null, children: /* @__PURE__ */ u(
139
163
  "div",
140
164
  {
141
- className: w,
165
+ className: c,
142
166
  style: { display: "contents" },
143
- children: /* @__PURE__ */ o(s, { ...A })
167
+ children: /* @__PURE__ */ u(l, { ...h })
144
168
  }
145
169
  ) }) })
146
170
  ] });
147
- }, W = ({ onError: r, ...e }) => /* @__PURE__ */ o(C, { fallback: null, children: /* @__PURE__ */ o(y, { onError: r, children: /* @__PURE__ */ o(x, { ...e }) }) }), T = ({ areaCode: r, options: e }) => {
171
+ }, Y = ({ onError: r, ...e }) => /* @__PURE__ */ u(y, { fallback: null, children: /* @__PURE__ */ u(S, { onError: r, children: /* @__PURE__ */ u(j, { ...e }) }) }), J = ({ areaCode: r, options: e }) => {
148
172
  if ((e == null ? void 0 : e.pause) === !0)
149
173
  return null;
150
- const { rootFragmentId: n, props: t, projectProperties: s, globalCssUrl: i } = $(r, {
174
+ const n = V(r, {
151
175
  timeout: e == null ? void 0 : e.timeout,
152
176
  ssr: e == null ? void 0 : e.ssr
153
177
  });
154
- return /* @__PURE__ */ o(
155
- x,
178
+ if (n === x)
179
+ return null;
180
+ const { rootFragmentId: t, props: l, projectProperties: d, globalCssUrl: s } = n, a = typeof (e == null ? void 0 : e.props) == "function" ? e.props(l) : e != null && e.props ? { ...l, ...e.props } : l;
181
+ return /* @__PURE__ */ u(
182
+ j,
156
183
  {
157
- fragmentId: n,
158
- props: t,
159
- globalCssUrl: i,
160
- projectProperties: s
184
+ fragmentId: t,
185
+ props: a,
186
+ globalCssUrl: s,
187
+ projectProperties: d
161
188
  }
162
189
  );
163
- }, X = ({ areaCode: r, options: e }) => /* @__PURE__ */ o(C, { fallback: null, children: /* @__PURE__ */ o(y, { children: /* @__PURE__ */ o(T, { areaCode: r, options: e }) }) });
164
- function Y({ client: r, children: e }) {
165
- const n = g(
190
+ }, Z = ({ areaCode: r, options: e }) => /* @__PURE__ */ u(y, { fallback: (e == null ? void 0 : e.fallback) ?? null, children: /* @__PURE__ */ u(S, { onError: e == null ? void 0 : e.onError, children: /* @__PURE__ */ u(J, { areaCode: r, options: e }) }) });
191
+ function ee({ client: r, children: e }) {
192
+ const n = C(
166
193
  () => ({
167
194
  read: (t) => r.$fragments.read(t)
168
195
  }),
169
196
  [r]
170
197
  );
171
- return /* @__PURE__ */ o(_, { value: r, children: /* @__PURE__ */ o(B, { value: n, children: e }) });
198
+ return /* @__PURE__ */ u(U, { value: r, children: /* @__PURE__ */ u(O, { value: n, children: e }) });
172
199
  }
173
- function Z(r) {
174
- return (a(p) ?? P)[r];
200
+ function re(r) {
201
+ return (f(E) ?? M)[r];
175
202
  }
176
- function ee(r) {
177
- return k({ ...r, inject: F });
203
+ function te(r) {
204
+ return _({ ...r, inject: A });
178
205
  }
179
206
  export {
180
- X as Area,
181
- W as FragmentRenderer,
182
- m as FragmentStylesheet,
183
- ne as FragmentsApiVersionError,
184
- oe as FragmentsAreaError,
185
- c as FragmentsClientContext,
186
- _ as FragmentsClientProvider,
187
- se as FragmentsLoadError,
188
- Y as FragmentsProvider,
189
- v as InstanceIdContext,
190
- h as ModulesMapContext,
191
- B as ModulesMapProvider,
192
- p as ProjectPropertiesContext,
193
- ee as createBrowserClient,
194
- P as defaultProjectProperties,
195
- F as injectStylesheet,
196
- $ as useArea,
197
- Q as useCssChunk,
198
- L as useFragmentComponent,
199
- H as useFragmentMetrics,
200
- V as useFragmentStylesheet,
201
- Z as useProjectProperty
207
+ x as AREA_UNRESOLVED,
208
+ Z as Area,
209
+ Y as FragmentRenderer,
210
+ g as FragmentStylesheet,
211
+ le as FragmentsApiVersionError,
212
+ se as FragmentsAreaError,
213
+ o as FragmentsClientContext,
214
+ U as FragmentsClientProvider,
215
+ ae as FragmentsLoadError,
216
+ ee as FragmentsProvider,
217
+ F as InstanceIdContext,
218
+ v as ModulesMapContext,
219
+ O as ModulesMapProvider,
220
+ E as ProjectPropertiesContext,
221
+ te as createBrowserClient,
222
+ M as defaultProjectProperties,
223
+ A as injectStylesheet,
224
+ V as useArea,
225
+ X as useCssChunk,
226
+ B as useFragmentComponent,
227
+ W as useFragmentMetrics,
228
+ G as useFragmentStylesheet,
229
+ re as useProjectProperty
202
230
  };
package/dist/index.umd.js CHANGED
@@ -1 +1 @@
1
- (function(t,n){typeof exports=="object"&&typeof module<"u"?n(exports,require("react/jsx-runtime"),require("react"),require("@fragmentsx/fragments-client")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","@fragmentsx/fragments-client"],n):(t=typeof globalThis<"u"?globalThis:t||self,n(t.FragmentsRuntimeReact={},t.jsxRuntime,t.React,t.fragmentsClient))})(this,function(t,n,u,d){"use strict";const a=u.createContext(null);a.displayName="FragmentsClientContext";function y(r){return n.jsx(a.Provider,{value:r.value,children:r.children})}function b(){return u.useContext(a)}const F=u.createContext(null);F.displayName="InstanceIdContext";const f=u.createContext(null);f.displayName="ModulesMapContext";function E({value:r,children:e}){return n.jsx(f.Provider,{value:r,children:e})}function x(){const r=u.useContext(a);return u.useMemo(()=>({reachGoal:e=>{var o,s;(s=(o=r==null?void 0:r.$metrics)==null?void 0:o.reachGoal)==null||s.call(o,e)}}),[r])}function p(r){const e=u.useContext(f);if(!e)throw new Error("[useFragmentComponent] No ModulesMapProvider in tree");return e.read(r)}const I=typeof window<"u";function M(r,e){const o=u.useContext(a);if(!o)throw new Error("[useArea] No FragmentsClientProvider in tree");const s=o.$area;if(!(s!=null&&s.read))throw new Error("[useArea] $area plugin not mounted");if((I||((e==null?void 0:e.ssr)??!0))&&!s.has(r)){const h=(e==null?void 0:e.timeout)!=null?{timeout:e.timeout}:void 0;s.resolve(r,h)}return s.read(r)}const j=typeof window<"u",N=()=>{},m=new Map,P=(r,e)=>{if(!j)return N;const o=m.get(e);if(o)return o.refCount+=1,()=>{o.refCount-=1,o.refCount===0&&(o.linkEl.remove(),m.delete(e))};const s=document.createElement("link");s.rel="stylesheet",s.href=r,s.setAttribute("data-fragment-key",e),document.head.appendChild(s);const l={refCount:1,linkEl:s};return m.set(e,l),()=>{l.refCount-=1,l.refCount===0&&(l.linkEl.remove(),m.delete(e))}},k=j?u.useLayoutEffect:u.useEffect;function A(r,e){k(()=>P(r,e),[r,e])}const O=parseInt(u.version.split(".")[0],10)>=19;function g({href:r,fragmentKey:e}){return O?n.jsx("link",{rel:"stylesheet",href:r,precedence:"default","data-fragment-key":e}):(A(r,e),null)}function _(r){}const v={},C=u.createContext(null);C.displayName="ProjectPropertiesContext";class w extends u.Component{constructor(){super(...arguments),this.state={hasError:!1}}static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(e,o){var s,l;process.env.NODE_ENV!=="production"&&console.error("[fragments] Area error:",e,o.componentStack),(l=(s=this.props).onError)==null||l.call(s,e)}render(){return this.state.hasError?null:this.props.children}}const S=({fragmentId:r,props:e,globalCssUrl:o=null,projectProperties:s=v})=>{const l=p(r),c=b().$fragments,i=c==null?void 0:c.getRef(r),q=c==null?void 0:c.getScopeClass(r),D=e??{};return n.jsxs(n.Fragment,{children:[o!=null&&n.jsx(g,{href:o,fragmentKey:"global"}),i&&n.jsx(g,{href:i.cssUrl,fragmentKey:`fragment:${r}:css`}),(i==null?void 0:i.fontsUrl)!=null&&n.jsx(g,{href:i.fontsUrl,fragmentKey:`fragment:${r}:fonts`}),n.jsx(C.Provider,{value:s,children:n.jsx(F.Provider,{value:null,children:n.jsx("div",{className:q,style:{display:"contents"},children:n.jsx(l,{...D})})})})]})},T=({onError:r,...e})=>n.jsx(u.Suspense,{fallback:null,children:n.jsx(w,{onError:r,children:n.jsx(S,{...e})})}),B=({areaCode:r,options:e})=>{if((e==null?void 0:e.pause)===!0)return null;const{rootFragmentId:o,props:s,projectProperties:l,globalCssUrl:h}=M(r,{timeout:e==null?void 0:e.timeout,ssr:e==null?void 0:e.ssr});return n.jsx(S,{fragmentId:o,props:s,globalCssUrl:h,projectProperties:l})},L=({areaCode:r,options:e})=>n.jsx(u.Suspense,{fallback:null,children:n.jsx(w,{children:n.jsx(B,{areaCode:r,options:e})})});function U({client:r,children:e}){const o=u.useMemo(()=>({read:s=>r.$fragments.read(s)}),[r]);return n.jsx(y,{value:r,children:n.jsx(E,{value:o,children:e})})}function V(r){return(u.useContext(C)??v)[r]}function $(r){return d.createFragmentsClient({...r,inject:P})}Object.defineProperty(t,"FragmentsApiVersionError",{enumerable:!0,get:()=>d.FragmentsApiVersionError}),Object.defineProperty(t,"FragmentsAreaError",{enumerable:!0,get:()=>d.FragmentsAreaError}),Object.defineProperty(t,"FragmentsLoadError",{enumerable:!0,get:()=>d.FragmentsLoadError}),t.Area=L,t.FragmentRenderer=T,t.FragmentStylesheet=g,t.FragmentsClientContext=a,t.FragmentsClientProvider=y,t.FragmentsProvider=U,t.InstanceIdContext=F,t.ModulesMapContext=f,t.ModulesMapProvider=E,t.ProjectPropertiesContext=C,t.createBrowserClient=$,t.defaultProjectProperties=v,t.injectStylesheet=P,t.useArea=M,t.useCssChunk=_,t.useFragmentComponent=p,t.useFragmentMetrics=x,t.useFragmentStylesheet=A,t.useProjectProperty=V,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
1
+ (function(t,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("react/jsx-runtime"),require("react"),require("@fragmentsx/fragments-client")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react","@fragmentsx/fragments-client"],u):(t=typeof globalThis<"u"?globalThis:t||self,u(t.FragmentsRuntimeReact={},t.jsxRuntime,t.React,t.fragmentsClient))})(this,function(t,u,s,m){"use strict";const o=s.createContext(null);o.displayName="FragmentsClientContext";function j(r){return u.jsx(o.Provider,{value:r.value,children:r.children})}function k(){return s.useContext(o)}const P=s.createContext(null);P.displayName="InstanceIdContext";const g=s.createContext(null);g.displayName="ModulesMapContext";function M({value:r,children:e}){return u.jsx(g.Provider,{value:r,children:e})}function x(){const r=s.useContext(o);return s.useMemo(()=>({reachGoal:e=>{var l,n;(n=(l=r==null?void 0:r.$metrics)==null?void 0:l.reachGoal)==null||n.call(l,e)}}),[r])}function S(r){const e=s.useContext(g);if(!e)throw new Error("[useFragmentComponent] No ModulesMapProvider in tree");return e.read(r)}const _=typeof window<"u",v=Object.freeze({rootFragmentId:0,props:{},projectProperties:{},globalCssUrl:null});function w(r,e){const l=s.useContext(o);if(!l)throw new Error("[useArea] No FragmentsClientProvider in tree");const n=l.$area;if(!(n!=null&&n.read))throw new Error("[useArea] $area plugin not mounted");const a=(e==null?void 0:e.suspense)??!0,i=(e==null?void 0:e.pause)===!0||!_&&(e==null?void 0:e.ssr)===!1,c=(e==null?void 0:e.timeout)!=null?{timeout:e.timeout}:void 0,[,d]=s.useState(0);if(s.useEffect(()=>{if(a||i)return;let f=!0;return n.resolve(r,c).finally(()=>{f&&d(A=>A+1)}),()=>{f=!1}},[r,a,e==null?void 0:e.pause,e==null?void 0:e.timeout,e==null?void 0:e.ssr]),a)return i?v:(n.has(r)||n.resolve(r,c),n.read(r));if(i)return{status:"idle",data:null,error:null};if(n.has(r))try{return{status:"ready",data:n.read(r),error:null}}catch(f){return{status:"not-found",data:null,error:f instanceof Error?f:new Error(String(f))}}return n.resolve(r,c),{status:"loading",data:null,error:null}}const b=typeof window<"u",L=()=>{},h=new Map,F=(r,e)=>{if(!b)return L;const l=h.get(e);if(l)return l.refCount+=1,()=>{l.refCount-=1,l.refCount===0&&(l.linkEl.remove(),h.delete(e))};const n=document.createElement("link");n.rel="stylesheet",n.href=r,n.setAttribute("data-fragment-key",e),document.head.appendChild(n);const a={refCount:1,linkEl:n};return h.set(e,a),()=>{a.refCount-=1,a.refCount===0&&(a.linkEl.remove(),h.delete(e))}},T=b?s.useLayoutEffect:s.useEffect;function I(r,e){T(()=>F(r,e),[r,e])}const U=parseInt(s.version.split(".")[0],10)>=19;function C({href:r,fragmentKey:e}){return U?u.jsx("link",{rel:"stylesheet",href:r,precedence:"default","data-fragment-key":e}):(I(r,e),null)}function V(r){}const y={},E=s.createContext(null);E.displayName="ProjectPropertiesContext";class N extends s.Component{constructor(){super(...arguments),this.state={hasError:!1}}static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(e,l){var n,a;process.env.NODE_ENV!=="production"&&console.error("[fragments] Area error:",e,l.componentStack),(a=(n=this.props).onError)==null||a.call(n,e)}render(){return this.state.hasError?null:this.props.children}}const O=({fragmentId:r,props:e,globalCssUrl:l=null,projectProperties:n=y})=>{const a=S(r),c=k().$fragments,d=c==null?void 0:c.getRef(r),f=c==null?void 0:c.getScopeClass(r),A=e??{};return u.jsxs(u.Fragment,{children:[l!=null&&u.jsx(C,{href:l,fragmentKey:"global"}),d&&u.jsx(C,{href:d.cssUrl,fragmentKey:`fragment:${r}:css`}),(d==null?void 0:d.fontsUrl)!=null&&u.jsx(C,{href:d.fontsUrl,fragmentKey:`fragment:${r}:fonts`}),u.jsx(E.Provider,{value:n,children:u.jsx(P.Provider,{value:null,children:u.jsx("div",{className:f,style:{display:"contents"},children:u.jsx(a,{...A})})})})]})},B=({onError:r,...e})=>u.jsx(s.Suspense,{fallback:null,children:u.jsx(N,{onError:r,children:u.jsx(O,{...e})})}),D=({areaCode:r,options:e})=>{if((e==null?void 0:e.pause)===!0)return null;const l=w(r,{timeout:e==null?void 0:e.timeout,ssr:e==null?void 0:e.ssr});if(l===v)return null;const{rootFragmentId:n,props:a,projectProperties:i,globalCssUrl:c}=l,d=typeof(e==null?void 0:e.props)=="function"?e.props(a):e!=null&&e.props?{...a,...e.props}:a;return u.jsx(O,{fragmentId:n,props:d,globalCssUrl:c,projectProperties:i})},$=({areaCode:r,options:e})=>u.jsx(s.Suspense,{fallback:(e==null?void 0:e.fallback)??null,children:u.jsx(N,{onError:e==null?void 0:e.onError,children:u.jsx(D,{areaCode:r,options:e})})});function q({client:r,children:e}){const l=s.useMemo(()=>({read:n=>r.$fragments.read(n)}),[r]);return u.jsx(j,{value:r,children:u.jsx(M,{value:l,children:e})})}function G(r){return(s.useContext(E)??y)[r]}function J(r){return m.createFragmentsClient({...r,inject:F})}Object.defineProperty(t,"FragmentsApiVersionError",{enumerable:!0,get:()=>m.FragmentsApiVersionError}),Object.defineProperty(t,"FragmentsAreaError",{enumerable:!0,get:()=>m.FragmentsAreaError}),Object.defineProperty(t,"FragmentsLoadError",{enumerable:!0,get:()=>m.FragmentsLoadError}),t.AREA_UNRESOLVED=v,t.Area=$,t.FragmentRenderer=B,t.FragmentStylesheet=C,t.FragmentsClientContext=o,t.FragmentsClientProvider=j,t.FragmentsProvider=q,t.InstanceIdContext=P,t.ModulesMapContext=g,t.ModulesMapProvider=M,t.ProjectPropertiesContext=E,t.createBrowserClient=J,t.defaultProjectProperties=y,t.injectStylesheet=F,t.useArea=w,t.useCssChunk=V,t.useFragmentComponent=S,t.useFragmentMetrics=x,t.useFragmentStylesheet=I,t.useProjectProperty=G,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@fragmentsx/runtime-react",
3
3
  "private": false,
4
- "version": "0.1.0",
4
+ "version": "0.2.0-dev-20260831061037",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@graph-state/core": "^0.13.3",
35
- "@fragmentsx/fragments-client": "0.1.0"
35
+ "@fragmentsx/fragments-client": "0.2.0-dev-20260831061037"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@testing-library/jest-dom": "^6.6.3",