@pactor-app/app 1.41.0 → 1.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +171 -51
- package/dist/index.d.cts +65 -4
- package/dist/index.d.ts +65 -4
- package/dist/index.js +183 -56
- package/package.json +9 -9
package/dist/index.cjs
CHANGED
|
@@ -27,6 +27,7 @@ __export(index_exports, {
|
|
|
27
27
|
ReactRouterBinding: () => ReactRouterBinding,
|
|
28
28
|
SitemapApp: () => SitemapApp,
|
|
29
29
|
createHttpHooks: () => createHttpHooks,
|
|
30
|
+
createLocalStorageLocaleStorage: () => createLocalStorageLocaleStorage,
|
|
30
31
|
createPactorApplication: () => createPactorApplication,
|
|
31
32
|
createPactorPage: () => createPactorPage,
|
|
32
33
|
createRuntimeHttpAdapter: () => createRuntimeHttpAdapter,
|
|
@@ -281,8 +282,13 @@ function Application({ app }) {
|
|
|
281
282
|
}
|
|
282
283
|
function AppShell({
|
|
283
284
|
app,
|
|
284
|
-
session
|
|
285
|
+
session: initialSession
|
|
285
286
|
}) {
|
|
287
|
+
const liveSession = (0, import_react4.useSyncExternalStore)(
|
|
288
|
+
app.subscribeSession,
|
|
289
|
+
app.getSession
|
|
290
|
+
);
|
|
291
|
+
const session = liveSession ?? initialSession;
|
|
286
292
|
const Router = app.routerOptions.type === "hash" ? import_react_router_dom.HashRouter : import_react_router_dom.BrowserRouter;
|
|
287
293
|
const InteractionKit = app.interactionKit.Provider;
|
|
288
294
|
const Providers = app.providers;
|
|
@@ -339,7 +345,7 @@ function ShellLayout({
|
|
|
339
345
|
pageId,
|
|
340
346
|
route: pageRoute
|
|
341
347
|
},
|
|
342
|
-
pageLoaderKey(pageId, pageRoute)
|
|
348
|
+
pageLoaderKey(pageId, pageRoute, session.i18nVersion)
|
|
343
349
|
)
|
|
344
350
|
}
|
|
345
351
|
)
|
|
@@ -376,8 +382,8 @@ function ShellLayout({
|
|
|
376
382
|
}
|
|
377
383
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LayoutComponent, { brand: session.brand, children: outlet });
|
|
378
384
|
}
|
|
379
|
-
function pageLoaderKey(pageId, route) {
|
|
380
|
-
return `${pageId}|${JSON.stringify(route.params)}|${JSON.stringify(route.query)}`;
|
|
385
|
+
function pageLoaderKey(pageId, route, i18nVersion) {
|
|
386
|
+
return `${pageId}|${i18nVersion}|${JSON.stringify(route.params)}|${JSON.stringify(route.query)}`;
|
|
381
387
|
}
|
|
382
388
|
function NotFoundPage() {
|
|
383
389
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -488,6 +494,32 @@ function createPactorAssembly(options) {
|
|
|
488
494
|
};
|
|
489
495
|
}
|
|
490
496
|
|
|
497
|
+
// src/locale-storage.ts
|
|
498
|
+
function createLocalStorageLocaleStorage(key = "pactor.locale") {
|
|
499
|
+
return {
|
|
500
|
+
get() {
|
|
501
|
+
if (typeof localStorage === "undefined") {
|
|
502
|
+
return void 0;
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
const value = localStorage.getItem(key);
|
|
506
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
507
|
+
} catch {
|
|
508
|
+
return void 0;
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
set(locale) {
|
|
512
|
+
if (typeof localStorage === "undefined") {
|
|
513
|
+
return;
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
localStorage.setItem(key, locale);
|
|
517
|
+
} catch {
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
491
523
|
// src/application.ts
|
|
492
524
|
var ReactRouterBinding = class {
|
|
493
525
|
constructor() {
|
|
@@ -628,6 +660,15 @@ function createPactorApplication(options) {
|
|
|
628
660
|
const permissionAdapter = (0, import_permission.createPermissionAdapter)(permissionStore);
|
|
629
661
|
const routerAdapter = (0, import_router2.createRouterAdapter)(navigation);
|
|
630
662
|
let session = null;
|
|
663
|
+
const sessionListeners = /* @__PURE__ */ new Set();
|
|
664
|
+
let pendingLocale = null;
|
|
665
|
+
function updateSession(next) {
|
|
666
|
+
session = next;
|
|
667
|
+
for (const listener of [...sessionListeners]) {
|
|
668
|
+
listener();
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
const localeStorage = options.localeStorage === false ? void 0 : options.localeStorage ?? createLocalStorageLocaleStorage();
|
|
631
672
|
const handle = {
|
|
632
673
|
appId,
|
|
633
674
|
overlayManager,
|
|
@@ -658,10 +699,10 @@ function createPactorApplication(options) {
|
|
|
658
699
|
logo: void 0
|
|
659
700
|
};
|
|
660
701
|
const browserLocale = typeof navigator !== "undefined" && typeof navigator.language === "string" ? navigator.language : "zh-CN";
|
|
661
|
-
const locale = options.locale ?? (typeof bootstrap.locale === "string" ? bootstrap.locale : void 0) ?? browserLocale;
|
|
702
|
+
const locale = options.locale ?? localeStorage?.get() ?? (typeof bootstrap.locale === "string" ? bootstrap.locale : void 0) ?? browserLocale;
|
|
662
703
|
const defaultLocale = options.defaultLocale ?? (typeof bootstrap.defaultLocale === "string" ? bootstrap.defaultLocale : void 0) ?? "zh-CN";
|
|
663
704
|
const messages = options.messages ?? (isRecord(bootstrap.messages) ? bootstrap.messages : void 0) ?? {};
|
|
664
|
-
|
|
705
|
+
let next = {
|
|
665
706
|
bootstrap,
|
|
666
707
|
menuRegistry,
|
|
667
708
|
layoutType,
|
|
@@ -671,11 +712,30 @@ function createPactorApplication(options) {
|
|
|
671
712
|
app: appRecord,
|
|
672
713
|
locale,
|
|
673
714
|
defaultLocale,
|
|
674
|
-
messages
|
|
715
|
+
messages,
|
|
716
|
+
i18nVersion: 0
|
|
675
717
|
};
|
|
676
|
-
|
|
718
|
+
if (pendingLocale !== null) {
|
|
719
|
+
next = {
|
|
720
|
+
...next,
|
|
721
|
+
locale: pendingLocale.locale,
|
|
722
|
+
messages: pendingLocale.messages ?? next.messages
|
|
723
|
+
};
|
|
724
|
+
pendingLocale = null;
|
|
725
|
+
localeStorage?.set(next.locale);
|
|
726
|
+
}
|
|
727
|
+
updateSession(next);
|
|
677
728
|
return next;
|
|
678
729
|
},
|
|
730
|
+
subscribeSession(listener) {
|
|
731
|
+
sessionListeners.add(listener);
|
|
732
|
+
return () => {
|
|
733
|
+
sessionListeners.delete(listener);
|
|
734
|
+
};
|
|
735
|
+
},
|
|
736
|
+
getSession() {
|
|
737
|
+
return session;
|
|
738
|
+
},
|
|
679
739
|
createPageRuntime(pageDsl, route) {
|
|
680
740
|
return (0, import_runtime4.createPageRuntime)(pageDsl, {
|
|
681
741
|
components,
|
|
@@ -733,11 +793,20 @@ function createPactorApplication(options) {
|
|
|
733
793
|
},
|
|
734
794
|
setLocale(locale, messages) {
|
|
735
795
|
if (session === null) {
|
|
736
|
-
|
|
796
|
+
pendingLocale = { locale, messages };
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
const nextMessages = messages ?? session.messages;
|
|
800
|
+
if (locale === session.locale && nextMessages === session.messages) {
|
|
737
801
|
return;
|
|
738
802
|
}
|
|
739
|
-
|
|
740
|
-
|
|
803
|
+
updateSession({
|
|
804
|
+
...session,
|
|
805
|
+
locale,
|
|
806
|
+
messages: nextMessages,
|
|
807
|
+
i18nVersion: session.i18nVersion + 1
|
|
808
|
+
});
|
|
809
|
+
localeStorage?.set(locale);
|
|
741
810
|
}
|
|
742
811
|
};
|
|
743
812
|
}
|
|
@@ -790,7 +859,16 @@ function createPactorPage(options = {}) {
|
|
|
790
859
|
});
|
|
791
860
|
}
|
|
792
861
|
return function ConfiguredPactorPage(props) {
|
|
793
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
862
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_runtime5.I18nContextProvider, { value: i18n, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
863
|
+
EmbeddedPage,
|
|
864
|
+
{
|
|
865
|
+
assembly,
|
|
866
|
+
options,
|
|
867
|
+
createRuntime,
|
|
868
|
+
resolvePage: options.loader ? resolvePage : void 0,
|
|
869
|
+
...props
|
|
870
|
+
}
|
|
871
|
+
) });
|
|
794
872
|
};
|
|
795
873
|
async function resolvePage(pageId) {
|
|
796
874
|
if (!options.loader) {
|
|
@@ -812,13 +890,13 @@ function PactorPage(props) {
|
|
|
812
890
|
function EmbeddedPage({
|
|
813
891
|
assembly,
|
|
814
892
|
options,
|
|
815
|
-
i18n,
|
|
816
893
|
createRuntime,
|
|
817
894
|
resolvePage,
|
|
818
895
|
pageId,
|
|
819
896
|
pageDsl,
|
|
820
897
|
route
|
|
821
898
|
}) {
|
|
899
|
+
const { t } = (0, import_runtime5.useI18n)();
|
|
822
900
|
const [state, setState] = (0, import_react6.useState)({ status: "loading" });
|
|
823
901
|
const [retryTick, setRetryTick] = (0, import_react6.useState)(0);
|
|
824
902
|
const onError = options.onError;
|
|
@@ -879,15 +957,15 @@ function EmbeddedPage({
|
|
|
879
957
|
ResultView,
|
|
880
958
|
{
|
|
881
959
|
className: "pactor-app-page-load-error",
|
|
882
|
-
title: "
|
|
960
|
+
title: t("pactor.page.loadFailed"),
|
|
883
961
|
subTitle: state.error.message,
|
|
884
|
-
extra: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PrimaryButton, { onClick: () => setRetryTick((n) => n + 1), children: "
|
|
962
|
+
extra: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PrimaryButton, { onClick: () => setRetryTick((n) => n + 1), children: t("pactor.page.retry") })
|
|
885
963
|
}
|
|
886
964
|
);
|
|
887
965
|
} else {
|
|
888
966
|
content = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PageErrorBoundary, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_runtime5.PageRuntimeView, { runtime: state.runtime, children: resolvePage !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(OverlayHost2, { manager: assembly.overlayManager, resolvePage }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(OverlayHost2, { manager: assembly.overlayManager }) }) });
|
|
889
967
|
}
|
|
890
|
-
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
968
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(InteractionProvider2, { bridge: assembly.uiBridge, children: content });
|
|
891
969
|
}
|
|
892
970
|
|
|
893
971
|
// src/sitemap/actions.ts
|
|
@@ -930,7 +1008,9 @@ var defaultSitemapActions = {
|
|
|
930
1008
|
};
|
|
931
1009
|
|
|
932
1010
|
// src/sitemap/SitemapApp.tsx
|
|
1011
|
+
var import_core4 = require("@pactor-app/core");
|
|
933
1012
|
var import_router3 = require("@pactor-app/router");
|
|
1013
|
+
var import_runtime6 = require("@pactor-app/runtime");
|
|
934
1014
|
var import_components2 = require("@pactor-app/ui/components");
|
|
935
1015
|
var import_react8 = require("react");
|
|
936
1016
|
|
|
@@ -1259,6 +1339,18 @@ function SitemapMenu({
|
|
|
1259
1339
|
);
|
|
1260
1340
|
}
|
|
1261
1341
|
function SitemapApp(props) {
|
|
1342
|
+
const i18n = (0, import_react8.useMemo)(
|
|
1343
|
+
() => (0, import_core4.createI18nContext)({
|
|
1344
|
+
locale: props.locale,
|
|
1345
|
+
defaultLocale: props.defaultLocale,
|
|
1346
|
+
messages: props.messages
|
|
1347
|
+
}),
|
|
1348
|
+
[props.locale, props.defaultLocale, props.messages]
|
|
1349
|
+
);
|
|
1350
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_runtime6.I18nContextProvider, { value: i18n, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SitemapAppInner, { ...props }) });
|
|
1351
|
+
}
|
|
1352
|
+
function SitemapAppInner(props) {
|
|
1353
|
+
const { t } = (0, import_runtime6.useI18n)();
|
|
1262
1354
|
const { sources, fetcher, baseUrl } = props;
|
|
1263
1355
|
const browserRoute = useBrowserRoute();
|
|
1264
1356
|
const pathname = props.pathname ?? browserRoute.pathname;
|
|
@@ -1308,26 +1400,19 @@ function SitemapApp(props) {
|
|
|
1308
1400
|
}
|
|
1309
1401
|
}, [decision, navigate]);
|
|
1310
1402
|
if (state.status === "loading") {
|
|
1311
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Centered, { children: props.loading ?? "
|
|
1403
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Centered, { children: props.loading ?? t("pactor.table.loading") });
|
|
1312
1404
|
}
|
|
1313
1405
|
if (state.status === "error") {
|
|
1314
|
-
return props.renderError !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: props.renderError(state.error) }) : /* @__PURE__ */ (0, import_jsx_runtime6.
|
|
1315
|
-
"sitemap \u52A0\u8F7D\u5931\u8D25\uFF1A",
|
|
1316
|
-
state.error.message
|
|
1317
|
-
] });
|
|
1406
|
+
return props.renderError !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: props.renderError(state.error) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Centered, { children: t("pactor.sitemap.loadError", { message: state.error.message }) });
|
|
1318
1407
|
}
|
|
1319
1408
|
if (sitemap === null || registry === null || resolution === null) {
|
|
1320
1409
|
return null;
|
|
1321
1410
|
}
|
|
1322
1411
|
if (!decision.allow) {
|
|
1323
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Centered, { children: "
|
|
1412
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Centered, { children: t("pactor.sitemap.redirecting") });
|
|
1324
1413
|
}
|
|
1325
1414
|
if (resolution.route === null) {
|
|
1326
|
-
return props.renderNotFound !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: props.renderNotFound(pathname) }) : /* @__PURE__ */ (0, import_jsx_runtime6.
|
|
1327
|
-
"\u9875\u9762\u4E0D\u5B58\u5728\uFF08",
|
|
1328
|
-
pathname,
|
|
1329
|
-
"\uFF09"
|
|
1330
|
-
] });
|
|
1415
|
+
return props.renderNotFound !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: props.renderNotFound(pathname) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Centered, { children: t("pactor.sitemap.notFound", { path: pathname }) });
|
|
1331
1416
|
}
|
|
1332
1417
|
const { pageId, layoutName, highlightKey, params } = resolution.route;
|
|
1333
1418
|
return (
|
|
@@ -1361,6 +1446,7 @@ function SitemapLayout({
|
|
|
1361
1446
|
routeParams,
|
|
1362
1447
|
props
|
|
1363
1448
|
}) {
|
|
1449
|
+
const { t } = (0, import_runtime6.useI18n)();
|
|
1364
1450
|
const sessionService = props.sessionService ?? "session.context";
|
|
1365
1451
|
const session = (0, import_react8.useMemo)(
|
|
1366
1452
|
() => ({
|
|
@@ -1423,11 +1509,61 @@ function SitemapLayout({
|
|
|
1423
1509
|
};
|
|
1424
1510
|
}, [layoutDsl, layoutName, sessionService]);
|
|
1425
1511
|
if (layoutDsl === void 0 || layoutPage === null) {
|
|
1426
|
-
return /* @__PURE__ */ (0, import_jsx_runtime6.
|
|
1427
|
-
"\u5E03\u5C40\u672A\u5B9A\u4E49\uFF1A",
|
|
1428
|
-
layoutName
|
|
1429
|
-
] });
|
|
1512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Centered, { children: t("pactor.sitemap.layoutMissing", { name: layoutName }) });
|
|
1430
1513
|
}
|
|
1514
|
+
const messagesSignature = JSON.stringify(props.messages ?? {});
|
|
1515
|
+
const pageFactory = (0, import_react8.useMemo)(
|
|
1516
|
+
() => createPactorPage({
|
|
1517
|
+
loader,
|
|
1518
|
+
services,
|
|
1519
|
+
actions,
|
|
1520
|
+
navigate,
|
|
1521
|
+
httpAdapter: props.httpAdapter,
|
|
1522
|
+
permissions: sitemap.permissions ?? [],
|
|
1523
|
+
components: props.components,
|
|
1524
|
+
locale: props.locale,
|
|
1525
|
+
defaultLocale: props.defaultLocale,
|
|
1526
|
+
messages: props.messages
|
|
1527
|
+
}),
|
|
1528
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1529
|
+
[
|
|
1530
|
+
loader,
|
|
1531
|
+
services,
|
|
1532
|
+
actions,
|
|
1533
|
+
navigate,
|
|
1534
|
+
props.httpAdapter,
|
|
1535
|
+
props.components,
|
|
1536
|
+
sitemap,
|
|
1537
|
+
props.locale,
|
|
1538
|
+
props.defaultLocale,
|
|
1539
|
+
messagesSignature
|
|
1540
|
+
]
|
|
1541
|
+
);
|
|
1542
|
+
const layoutFactory = (0, import_react8.useMemo)(
|
|
1543
|
+
() => createPactorPage({
|
|
1544
|
+
services,
|
|
1545
|
+
actions,
|
|
1546
|
+
navigate,
|
|
1547
|
+
httpAdapter: props.httpAdapter,
|
|
1548
|
+
components: { PageOutlet, SitemapMenu, ...props.components },
|
|
1549
|
+
locale: props.locale,
|
|
1550
|
+
defaultLocale: props.defaultLocale,
|
|
1551
|
+
messages: props.messages
|
|
1552
|
+
}),
|
|
1553
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1554
|
+
[
|
|
1555
|
+
services,
|
|
1556
|
+
actions,
|
|
1557
|
+
navigate,
|
|
1558
|
+
props.httpAdapter,
|
|
1559
|
+
props.components,
|
|
1560
|
+
props.locale,
|
|
1561
|
+
props.defaultLocale,
|
|
1562
|
+
messagesSignature
|
|
1563
|
+
]
|
|
1564
|
+
);
|
|
1565
|
+
const Page = pageFactory;
|
|
1566
|
+
const LayoutPage = layoutFactory;
|
|
1431
1567
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1432
1568
|
OutletContext.Provider,
|
|
1433
1569
|
{
|
|
@@ -1435,32 +1571,15 @@ function SitemapLayout({
|
|
|
1435
1571
|
// 页面实例:key 随 pageId + pathname 变化(route 参数变化需重建,
|
|
1436
1572
|
// PactorPage 的 route prop 不参与运行时重建)——布局保持挂载
|
|
1437
1573
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1438
|
-
|
|
1574
|
+
Page,
|
|
1439
1575
|
{
|
|
1440
1576
|
pageId,
|
|
1441
|
-
route: { params: routeParams, query }
|
|
1442
|
-
loader,
|
|
1443
|
-
services,
|
|
1444
|
-
actions,
|
|
1445
|
-
permissions: sitemap.permissions ?? [],
|
|
1446
|
-
navigate,
|
|
1447
|
-
httpAdapter: props.httpAdapter,
|
|
1448
|
-
components: props.components
|
|
1577
|
+
route: { params: routeParams, query }
|
|
1449
1578
|
},
|
|
1450
1579
|
`${pageId}@${pathname}`
|
|
1451
1580
|
)
|
|
1452
1581
|
),
|
|
1453
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1454
|
-
PactorPage,
|
|
1455
|
-
{
|
|
1456
|
-
pageDsl: layoutPage,
|
|
1457
|
-
services,
|
|
1458
|
-
actions,
|
|
1459
|
-
navigate,
|
|
1460
|
-
httpAdapter: props.httpAdapter,
|
|
1461
|
-
components: { PageOutlet, SitemapMenu, ...props.components }
|
|
1462
|
-
}
|
|
1463
|
-
)
|
|
1582
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LayoutPage, { pageDsl: layoutPage })
|
|
1464
1583
|
}
|
|
1465
1584
|
);
|
|
1466
1585
|
}
|
|
@@ -1490,6 +1609,7 @@ function Centered({ children }) {
|
|
|
1490
1609
|
ReactRouterBinding,
|
|
1491
1610
|
SitemapApp,
|
|
1492
1611
|
createHttpHooks,
|
|
1612
|
+
createLocalStorageLocaleStorage,
|
|
1493
1613
|
createPactorApplication,
|
|
1494
1614
|
createPactorPage,
|
|
1495
1615
|
createRuntimeHttpAdapter,
|
package/dist/index.d.cts
CHANGED
|
@@ -55,6 +55,26 @@ interface PactorAssemblyOptions {
|
|
|
55
55
|
navigate: (to: string) => void;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* 语言偏好持久化适配器(设计 D4):
|
|
60
|
+
* 框架缺省写入 localStorage,接入方可经 options.localeStorage
|
|
61
|
+
* 关闭(false)或替换为自定义实现(cookie / 服务端同步等)。
|
|
62
|
+
*/
|
|
63
|
+
/** 语言偏好存储适配器:读写当前语言代码 */
|
|
64
|
+
interface LocaleStorage {
|
|
65
|
+
/** 读取持久化的语言代码(无记录返回 undefined) */
|
|
66
|
+
get(): string | undefined;
|
|
67
|
+
/** 写入语言代码(持久化不可用时静默降级,不抛异常) */
|
|
68
|
+
set(locale: string): void;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* localStorage 实现的 LocaleStorage 工厂(key 缺省 'pactor.locale',
|
|
72
|
+
* 可经参数更换)。读写前置 `typeof localStorage !== 'undefined'`
|
|
73
|
+
* 判断并 try/catch 包裹:SSR / 隐私模式 / 用户禁用存储时静默降级
|
|
74
|
+
* 为无持久化(行为等同未接入持久化)。
|
|
75
|
+
*/
|
|
76
|
+
declare function createLocalStorageLocaleStorage(key?: string): LocaleStorage;
|
|
77
|
+
|
|
58
78
|
/** 认证令牌提供者:同步或异步返回 Bearer token(无令牌返回 undefined) */
|
|
59
79
|
type AuthTokenProvider = () => string | undefined | Promise<string | undefined>;
|
|
60
80
|
/** 路由配置(V1 支持 browser + basename;hash 预留) */
|
|
@@ -131,12 +151,18 @@ interface PactorApplicationOptions {
|
|
|
131
151
|
authTokenProvider?: AuthTokenProvider;
|
|
132
152
|
/** HTTP 钩子:加工页面运行时所有 HTTP 出口(request 改配置 / response 改数据) */
|
|
133
153
|
httpAdapter?: PactorHttpHooks;
|
|
134
|
-
/**
|
|
154
|
+
/** 当前语言代码(优先级高于持久化值、bootstrap.locale 与浏览器语言) */
|
|
135
155
|
locale?: string;
|
|
136
156
|
/** 回退语言代码(缺省 'zh-CN') */
|
|
137
157
|
defaultLocale?: string;
|
|
138
158
|
/** 翻译消息表(优先级高于 bootstrap.messages) */
|
|
139
159
|
messages?: I18nMessages;
|
|
160
|
+
/**
|
|
161
|
+
* 语言偏好持久化适配器(设计 D4):缺省
|
|
162
|
+
* `createLocalStorageLocaleStorage('pactor.locale')`;传 `false` 关闭
|
|
163
|
+
* 框架持久化(由调用方自管);自定义实现可替换为 cookie / 服务端同步。
|
|
164
|
+
*/
|
|
165
|
+
localeStorage?: LocaleStorage | false;
|
|
140
166
|
}
|
|
141
167
|
/**
|
|
142
168
|
* bootstrap 会话(设计决策 D1/D2):启动编排的产物,
|
|
@@ -166,6 +192,11 @@ interface PactorAppSession {
|
|
|
166
192
|
defaultLocale: string;
|
|
167
193
|
/** 翻译消息表 */
|
|
168
194
|
messages: I18nMessages;
|
|
195
|
+
/**
|
|
196
|
+
* i18n 版本(设计 D3):locale 或 messages 任一变化时 +1,
|
|
197
|
+
* 页面加载器 key 携带该版本以触发页面运行时重建。
|
|
198
|
+
*/
|
|
199
|
+
i18nVersion: number;
|
|
169
200
|
}
|
|
170
201
|
/** 应用实例(设计决策 D4):mount/unmount 与扩展注册 API */
|
|
171
202
|
interface PactorApplication {
|
|
@@ -182,7 +213,17 @@ interface PactorApplication {
|
|
|
182
213
|
registerService(name: string, handler: ServiceHandler): void;
|
|
183
214
|
/** 注册业务能力(同名覆盖) */
|
|
184
215
|
registerCapability(name: string, capability: unknown): void;
|
|
185
|
-
/**
|
|
216
|
+
/**
|
|
217
|
+
* 运行时切换语言(低频操作):无整页刷新地更新应用级 i18n 配置——
|
|
218
|
+
* 布局与菜单保留,内置组件默认文案与页面表达式按新语言渲染,
|
|
219
|
+
* 语言偏好经 localeStorage 持久化(options.localeStorage 可关闭/替换)。
|
|
220
|
+
*
|
|
221
|
+
* - `messages` 未传时保留现有业务词条:内置文案立即切换,
|
|
222
|
+
* 业务文案经回退链(defaultLocale)继续展示,异步补齐后再调用一次即可;
|
|
223
|
+
* - 页面运行时按 i18n 版本重建:页面内 DataStore 快照与未提交表单
|
|
224
|
+
* 在此次切换中丢失(布局、菜单、路由、会话均保留);
|
|
225
|
+
* - bootstrap 完成前调用会被暂存,会话就绪后自动应用。
|
|
226
|
+
*/
|
|
186
227
|
setLocale(locale: string, messages?: I18nMessages): void;
|
|
187
228
|
}
|
|
188
229
|
/**
|
|
@@ -211,6 +252,13 @@ interface PactorApplicationHandle {
|
|
|
211
252
|
readonly navigation: ReactRouterBinding;
|
|
212
253
|
/** 启动编排:加载 bootstrap 并组装会话(失败 reject,由组合层渲染重试页) */
|
|
213
254
|
loadSession(): Promise<PactorAppSession>;
|
|
255
|
+
/**
|
|
256
|
+
* 订阅会话变化(设计 D1):setLocale 更新会话时通知所有监听器
|
|
257
|
+
* (AppShell 经 useSyncExternalStore 消费)。返回取消订阅函数。
|
|
258
|
+
*/
|
|
259
|
+
subscribeSession(listener: () => void): () => void;
|
|
260
|
+
/** 当前会话快照(bootstrap 完成前为 null) */
|
|
261
|
+
getSession(): PactorAppSession | null;
|
|
214
262
|
/** 页面运行时工厂(设计决策 D2):注入共享 registries / adapters / route / user / app */
|
|
215
263
|
createPageRuntime(pageDsl: PageDsl, route: RouteContext): PageRuntime;
|
|
216
264
|
/** OverlayHost 的 page overlay 页面加载(loader.loadPage → PageDsl) */
|
|
@@ -556,6 +604,15 @@ interface SitemapAppProps {
|
|
|
556
604
|
guard?: SitemapGuard;
|
|
557
605
|
/** 会话服务名(缺省 session.context) */
|
|
558
606
|
sessionService?: string;
|
|
607
|
+
/** 当前语言代码(透传页面与布局运行时;缺省 'zh-CN')。切换即重建页面 */
|
|
608
|
+
locale?: string;
|
|
609
|
+
/** 回退语言代码(缺省 'zh-CN') */
|
|
610
|
+
defaultLocale?: string;
|
|
611
|
+
/**
|
|
612
|
+
* 翻译消息表(透传页面与布局运行时)。按值参与重建判定:
|
|
613
|
+
* 宿主每次渲染新建等值对象不会触发重建,但内容变化会。
|
|
614
|
+
*/
|
|
615
|
+
messages?: I18nMessages;
|
|
559
616
|
/** 加载中视图 */
|
|
560
617
|
loading?: ReactNode;
|
|
561
618
|
/** sitemap 加载失败视图 */
|
|
@@ -563,7 +620,11 @@ interface SitemapAppProps {
|
|
|
563
620
|
/** 路由未命中视图 */
|
|
564
621
|
renderNotFound?: (path: string) => ReactNode;
|
|
565
622
|
}
|
|
566
|
-
|
|
623
|
+
/**
|
|
624
|
+
* SitemapApp 外壳(设计 D7):按 props 组装 i18n 上下文并经 Provider
|
|
625
|
+
* 包裹——自身状态文案与页面/布局运行时消费同一语言配置。
|
|
626
|
+
*/
|
|
627
|
+
declare function SitemapApp(props: SitemapAppProps): react.JSX.Element;
|
|
567
628
|
|
|
568
629
|
/** createHttpHooks 配置 */
|
|
569
630
|
interface CreateHttpHooksOptions {
|
|
@@ -625,4 +686,4 @@ interface SitemapSessionContext {
|
|
|
625
686
|
/** 注册会话桥服务(缺省名 session.context,与 loader 注入的 dataSource 对应) */
|
|
626
687
|
declare function createSitemapSessionServices(session: SitemapSessionContext, serviceName?: string): Record<string, ServiceHandler>;
|
|
627
688
|
|
|
628
|
-
export { Application, type ApplicationProps, type AuthTokenProvider, type CreateHttpHooksOptions, DslPageLoader, type DslPageLoaderProps, type FetchSitemapOptions, type LayoutDsl, type PactorAppSession, type PactorApplication, type PactorApplicationHandle, type PactorApplicationOptions, type PactorHttpHooks, PactorPage, type PactorPageOptions, type PactorPageProps, type PactorRouterOptions, PageErrorBoundary, ReactRouterBinding, SitemapApp, type SitemapAppProps, type SitemapGuard, type SitemapGuardContext, type SitemapGuardDecision, type SitemapLoaderOptions, type SitemapMenuItem, type SitemapNavItem, type SitemapPageEntry, type SitemapResource, type SitemapRouteMatch, type SitemapRouteResolution, type SitemapSessionContext, createHttpHooks, createPactorApplication, createPactorPage, createRuntimeHttpAdapter, createSitemapLoader, createSitemapSessionServices, defaultSitemapActions, defaultSitemapGuard, fetchSitemap, mergeSitemapMenus, resolveSitemapRoute, toSitemapNavItems, withHttpHooks, wrapHttpAdapter };
|
|
689
|
+
export { Application, type ApplicationProps, type AuthTokenProvider, type CreateHttpHooksOptions, DslPageLoader, type DslPageLoaderProps, type FetchSitemapOptions, type LayoutDsl, type LocaleStorage, type PactorAppSession, type PactorApplication, type PactorApplicationHandle, type PactorApplicationOptions, type PactorHttpHooks, PactorPage, type PactorPageOptions, type PactorPageProps, type PactorRouterOptions, PageErrorBoundary, ReactRouterBinding, SitemapApp, type SitemapAppProps, type SitemapGuard, type SitemapGuardContext, type SitemapGuardDecision, type SitemapLoaderOptions, type SitemapMenuItem, type SitemapNavItem, type SitemapPageEntry, type SitemapResource, type SitemapRouteMatch, type SitemapRouteResolution, type SitemapSessionContext, createHttpHooks, createLocalStorageLocaleStorage, createPactorApplication, createPactorPage, createRuntimeHttpAdapter, createSitemapLoader, createSitemapSessionServices, defaultSitemapActions, defaultSitemapGuard, fetchSitemap, mergeSitemapMenus, resolveSitemapRoute, toSitemapNavItems, withHttpHooks, wrapHttpAdapter };
|
package/dist/index.d.ts
CHANGED
|
@@ -55,6 +55,26 @@ interface PactorAssemblyOptions {
|
|
|
55
55
|
navigate: (to: string) => void;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/**
|
|
59
|
+
* 语言偏好持久化适配器(设计 D4):
|
|
60
|
+
* 框架缺省写入 localStorage,接入方可经 options.localeStorage
|
|
61
|
+
* 关闭(false)或替换为自定义实现(cookie / 服务端同步等)。
|
|
62
|
+
*/
|
|
63
|
+
/** 语言偏好存储适配器:读写当前语言代码 */
|
|
64
|
+
interface LocaleStorage {
|
|
65
|
+
/** 读取持久化的语言代码(无记录返回 undefined) */
|
|
66
|
+
get(): string | undefined;
|
|
67
|
+
/** 写入语言代码(持久化不可用时静默降级,不抛异常) */
|
|
68
|
+
set(locale: string): void;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* localStorage 实现的 LocaleStorage 工厂(key 缺省 'pactor.locale',
|
|
72
|
+
* 可经参数更换)。读写前置 `typeof localStorage !== 'undefined'`
|
|
73
|
+
* 判断并 try/catch 包裹:SSR / 隐私模式 / 用户禁用存储时静默降级
|
|
74
|
+
* 为无持久化(行为等同未接入持久化)。
|
|
75
|
+
*/
|
|
76
|
+
declare function createLocalStorageLocaleStorage(key?: string): LocaleStorage;
|
|
77
|
+
|
|
58
78
|
/** 认证令牌提供者:同步或异步返回 Bearer token(无令牌返回 undefined) */
|
|
59
79
|
type AuthTokenProvider = () => string | undefined | Promise<string | undefined>;
|
|
60
80
|
/** 路由配置(V1 支持 browser + basename;hash 预留) */
|
|
@@ -131,12 +151,18 @@ interface PactorApplicationOptions {
|
|
|
131
151
|
authTokenProvider?: AuthTokenProvider;
|
|
132
152
|
/** HTTP 钩子:加工页面运行时所有 HTTP 出口(request 改配置 / response 改数据) */
|
|
133
153
|
httpAdapter?: PactorHttpHooks;
|
|
134
|
-
/**
|
|
154
|
+
/** 当前语言代码(优先级高于持久化值、bootstrap.locale 与浏览器语言) */
|
|
135
155
|
locale?: string;
|
|
136
156
|
/** 回退语言代码(缺省 'zh-CN') */
|
|
137
157
|
defaultLocale?: string;
|
|
138
158
|
/** 翻译消息表(优先级高于 bootstrap.messages) */
|
|
139
159
|
messages?: I18nMessages;
|
|
160
|
+
/**
|
|
161
|
+
* 语言偏好持久化适配器(设计 D4):缺省
|
|
162
|
+
* `createLocalStorageLocaleStorage('pactor.locale')`;传 `false` 关闭
|
|
163
|
+
* 框架持久化(由调用方自管);自定义实现可替换为 cookie / 服务端同步。
|
|
164
|
+
*/
|
|
165
|
+
localeStorage?: LocaleStorage | false;
|
|
140
166
|
}
|
|
141
167
|
/**
|
|
142
168
|
* bootstrap 会话(设计决策 D1/D2):启动编排的产物,
|
|
@@ -166,6 +192,11 @@ interface PactorAppSession {
|
|
|
166
192
|
defaultLocale: string;
|
|
167
193
|
/** 翻译消息表 */
|
|
168
194
|
messages: I18nMessages;
|
|
195
|
+
/**
|
|
196
|
+
* i18n 版本(设计 D3):locale 或 messages 任一变化时 +1,
|
|
197
|
+
* 页面加载器 key 携带该版本以触发页面运行时重建。
|
|
198
|
+
*/
|
|
199
|
+
i18nVersion: number;
|
|
169
200
|
}
|
|
170
201
|
/** 应用实例(设计决策 D4):mount/unmount 与扩展注册 API */
|
|
171
202
|
interface PactorApplication {
|
|
@@ -182,7 +213,17 @@ interface PactorApplication {
|
|
|
182
213
|
registerService(name: string, handler: ServiceHandler): void;
|
|
183
214
|
/** 注册业务能力(同名覆盖) */
|
|
184
215
|
registerCapability(name: string, capability: unknown): void;
|
|
185
|
-
/**
|
|
216
|
+
/**
|
|
217
|
+
* 运行时切换语言(低频操作):无整页刷新地更新应用级 i18n 配置——
|
|
218
|
+
* 布局与菜单保留,内置组件默认文案与页面表达式按新语言渲染,
|
|
219
|
+
* 语言偏好经 localeStorage 持久化(options.localeStorage 可关闭/替换)。
|
|
220
|
+
*
|
|
221
|
+
* - `messages` 未传时保留现有业务词条:内置文案立即切换,
|
|
222
|
+
* 业务文案经回退链(defaultLocale)继续展示,异步补齐后再调用一次即可;
|
|
223
|
+
* - 页面运行时按 i18n 版本重建:页面内 DataStore 快照与未提交表单
|
|
224
|
+
* 在此次切换中丢失(布局、菜单、路由、会话均保留);
|
|
225
|
+
* - bootstrap 完成前调用会被暂存,会话就绪后自动应用。
|
|
226
|
+
*/
|
|
186
227
|
setLocale(locale: string, messages?: I18nMessages): void;
|
|
187
228
|
}
|
|
188
229
|
/**
|
|
@@ -211,6 +252,13 @@ interface PactorApplicationHandle {
|
|
|
211
252
|
readonly navigation: ReactRouterBinding;
|
|
212
253
|
/** 启动编排:加载 bootstrap 并组装会话(失败 reject,由组合层渲染重试页) */
|
|
213
254
|
loadSession(): Promise<PactorAppSession>;
|
|
255
|
+
/**
|
|
256
|
+
* 订阅会话变化(设计 D1):setLocale 更新会话时通知所有监听器
|
|
257
|
+
* (AppShell 经 useSyncExternalStore 消费)。返回取消订阅函数。
|
|
258
|
+
*/
|
|
259
|
+
subscribeSession(listener: () => void): () => void;
|
|
260
|
+
/** 当前会话快照(bootstrap 完成前为 null) */
|
|
261
|
+
getSession(): PactorAppSession | null;
|
|
214
262
|
/** 页面运行时工厂(设计决策 D2):注入共享 registries / adapters / route / user / app */
|
|
215
263
|
createPageRuntime(pageDsl: PageDsl, route: RouteContext): PageRuntime;
|
|
216
264
|
/** OverlayHost 的 page overlay 页面加载(loader.loadPage → PageDsl) */
|
|
@@ -556,6 +604,15 @@ interface SitemapAppProps {
|
|
|
556
604
|
guard?: SitemapGuard;
|
|
557
605
|
/** 会话服务名(缺省 session.context) */
|
|
558
606
|
sessionService?: string;
|
|
607
|
+
/** 当前语言代码(透传页面与布局运行时;缺省 'zh-CN')。切换即重建页面 */
|
|
608
|
+
locale?: string;
|
|
609
|
+
/** 回退语言代码(缺省 'zh-CN') */
|
|
610
|
+
defaultLocale?: string;
|
|
611
|
+
/**
|
|
612
|
+
* 翻译消息表(透传页面与布局运行时)。按值参与重建判定:
|
|
613
|
+
* 宿主每次渲染新建等值对象不会触发重建,但内容变化会。
|
|
614
|
+
*/
|
|
615
|
+
messages?: I18nMessages;
|
|
559
616
|
/** 加载中视图 */
|
|
560
617
|
loading?: ReactNode;
|
|
561
618
|
/** sitemap 加载失败视图 */
|
|
@@ -563,7 +620,11 @@ interface SitemapAppProps {
|
|
|
563
620
|
/** 路由未命中视图 */
|
|
564
621
|
renderNotFound?: (path: string) => ReactNode;
|
|
565
622
|
}
|
|
566
|
-
|
|
623
|
+
/**
|
|
624
|
+
* SitemapApp 外壳(设计 D7):按 props 组装 i18n 上下文并经 Provider
|
|
625
|
+
* 包裹——自身状态文案与页面/布局运行时消费同一语言配置。
|
|
626
|
+
*/
|
|
627
|
+
declare function SitemapApp(props: SitemapAppProps): react.JSX.Element;
|
|
567
628
|
|
|
568
629
|
/** createHttpHooks 配置 */
|
|
569
630
|
interface CreateHttpHooksOptions {
|
|
@@ -625,4 +686,4 @@ interface SitemapSessionContext {
|
|
|
625
686
|
/** 注册会话桥服务(缺省名 session.context,与 loader 注入的 dataSource 对应) */
|
|
626
687
|
declare function createSitemapSessionServices(session: SitemapSessionContext, serviceName?: string): Record<string, ServiceHandler>;
|
|
627
688
|
|
|
628
|
-
export { Application, type ApplicationProps, type AuthTokenProvider, type CreateHttpHooksOptions, DslPageLoader, type DslPageLoaderProps, type FetchSitemapOptions, type LayoutDsl, type PactorAppSession, type PactorApplication, type PactorApplicationHandle, type PactorApplicationOptions, type PactorHttpHooks, PactorPage, type PactorPageOptions, type PactorPageProps, type PactorRouterOptions, PageErrorBoundary, ReactRouterBinding, SitemapApp, type SitemapAppProps, type SitemapGuard, type SitemapGuardContext, type SitemapGuardDecision, type SitemapLoaderOptions, type SitemapMenuItem, type SitemapNavItem, type SitemapPageEntry, type SitemapResource, type SitemapRouteMatch, type SitemapRouteResolution, type SitemapSessionContext, createHttpHooks, createPactorApplication, createPactorPage, createRuntimeHttpAdapter, createSitemapLoader, createSitemapSessionServices, defaultSitemapActions, defaultSitemapGuard, fetchSitemap, mergeSitemapMenus, resolveSitemapRoute, toSitemapNavItems, withHttpHooks, wrapHttpAdapter };
|
|
689
|
+
export { Application, type ApplicationProps, type AuthTokenProvider, type CreateHttpHooksOptions, DslPageLoader, type DslPageLoaderProps, type FetchSitemapOptions, type LayoutDsl, type LocaleStorage, type PactorAppSession, type PactorApplication, type PactorApplicationHandle, type PactorApplicationOptions, type PactorHttpHooks, PactorPage, type PactorPageOptions, type PactorPageProps, type PactorRouterOptions, PageErrorBoundary, ReactRouterBinding, SitemapApp, type SitemapAppProps, type SitemapGuard, type SitemapGuardContext, type SitemapGuardDecision, type SitemapLoaderOptions, type SitemapMenuItem, type SitemapNavItem, type SitemapPageEntry, type SitemapResource, type SitemapRouteMatch, type SitemapRouteResolution, type SitemapSessionContext, createHttpHooks, createLocalStorageLocaleStorage, createPactorApplication, createPactorPage, createRuntimeHttpAdapter, createSitemapLoader, createSitemapSessionServices, defaultSitemapActions, defaultSitemapGuard, fetchSitemap, mergeSitemapMenus, resolveSitemapRoute, toSitemapNavItems, withHttpHooks, wrapHttpAdapter };
|
package/dist/index.js
CHANGED
|
@@ -23,7 +23,11 @@ import { resolveLayout } from "@pactor-app/ui/layout";
|
|
|
23
23
|
import { resolveRoute } from "@pactor-app/router";
|
|
24
24
|
import { DynamicDslRoute, useReactRouterBridge } from "@pactor-app/router/react";
|
|
25
25
|
import { I18nContextProvider } from "@pactor-app/runtime";
|
|
26
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
useEffect as useEffect2,
|
|
28
|
+
useState as useState2,
|
|
29
|
+
useSyncExternalStore
|
|
30
|
+
} from "react";
|
|
27
31
|
import {
|
|
28
32
|
BrowserRouter,
|
|
29
33
|
HashRouter,
|
|
@@ -252,8 +256,13 @@ function Application({ app }) {
|
|
|
252
256
|
}
|
|
253
257
|
function AppShell({
|
|
254
258
|
app,
|
|
255
|
-
session
|
|
259
|
+
session: initialSession
|
|
256
260
|
}) {
|
|
261
|
+
const liveSession = useSyncExternalStore(
|
|
262
|
+
app.subscribeSession,
|
|
263
|
+
app.getSession
|
|
264
|
+
);
|
|
265
|
+
const session = liveSession ?? initialSession;
|
|
257
266
|
const Router = app.routerOptions.type === "hash" ? HashRouter : BrowserRouter;
|
|
258
267
|
const InteractionKit = app.interactionKit.Provider;
|
|
259
268
|
const Providers = app.providers;
|
|
@@ -310,7 +319,7 @@ function ShellLayout({
|
|
|
310
319
|
pageId,
|
|
311
320
|
route: pageRoute
|
|
312
321
|
},
|
|
313
|
-
pageLoaderKey(pageId, pageRoute)
|
|
322
|
+
pageLoaderKey(pageId, pageRoute, session.i18nVersion)
|
|
314
323
|
)
|
|
315
324
|
}
|
|
316
325
|
)
|
|
@@ -347,8 +356,8 @@ function ShellLayout({
|
|
|
347
356
|
}
|
|
348
357
|
return /* @__PURE__ */ jsx4(LayoutComponent, { brand: session.brand, children: outlet });
|
|
349
358
|
}
|
|
350
|
-
function pageLoaderKey(pageId, route) {
|
|
351
|
-
return `${pageId}|${JSON.stringify(route.params)}|${JSON.stringify(route.query)}`;
|
|
359
|
+
function pageLoaderKey(pageId, route, i18nVersion) {
|
|
360
|
+
return `${pageId}|${i18nVersion}|${JSON.stringify(route.params)}|${JSON.stringify(route.query)}`;
|
|
352
361
|
}
|
|
353
362
|
function NotFoundPage() {
|
|
354
363
|
return /* @__PURE__ */ jsx4(
|
|
@@ -467,6 +476,32 @@ function createPactorAssembly(options) {
|
|
|
467
476
|
};
|
|
468
477
|
}
|
|
469
478
|
|
|
479
|
+
// src/locale-storage.ts
|
|
480
|
+
function createLocalStorageLocaleStorage(key = "pactor.locale") {
|
|
481
|
+
return {
|
|
482
|
+
get() {
|
|
483
|
+
if (typeof localStorage === "undefined") {
|
|
484
|
+
return void 0;
|
|
485
|
+
}
|
|
486
|
+
try {
|
|
487
|
+
const value = localStorage.getItem(key);
|
|
488
|
+
return typeof value === "string" && value !== "" ? value : void 0;
|
|
489
|
+
} catch {
|
|
490
|
+
return void 0;
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
set(locale) {
|
|
494
|
+
if (typeof localStorage === "undefined") {
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
try {
|
|
498
|
+
localStorage.setItem(key, locale);
|
|
499
|
+
} catch {
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
|
|
470
505
|
// src/application.ts
|
|
471
506
|
var ReactRouterBinding = class {
|
|
472
507
|
constructor() {
|
|
@@ -607,6 +642,15 @@ function createPactorApplication(options) {
|
|
|
607
642
|
const permissionAdapter = createPermissionAdapter(permissionStore);
|
|
608
643
|
const routerAdapter = createRouterAdapter(navigation);
|
|
609
644
|
let session = null;
|
|
645
|
+
const sessionListeners = /* @__PURE__ */ new Set();
|
|
646
|
+
let pendingLocale = null;
|
|
647
|
+
function updateSession(next) {
|
|
648
|
+
session = next;
|
|
649
|
+
for (const listener of [...sessionListeners]) {
|
|
650
|
+
listener();
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
const localeStorage = options.localeStorage === false ? void 0 : options.localeStorage ?? createLocalStorageLocaleStorage();
|
|
610
654
|
const handle = {
|
|
611
655
|
appId,
|
|
612
656
|
overlayManager,
|
|
@@ -637,10 +681,10 @@ function createPactorApplication(options) {
|
|
|
637
681
|
logo: void 0
|
|
638
682
|
};
|
|
639
683
|
const browserLocale = typeof navigator !== "undefined" && typeof navigator.language === "string" ? navigator.language : "zh-CN";
|
|
640
|
-
const locale = options.locale ?? (typeof bootstrap.locale === "string" ? bootstrap.locale : void 0) ?? browserLocale;
|
|
684
|
+
const locale = options.locale ?? localeStorage?.get() ?? (typeof bootstrap.locale === "string" ? bootstrap.locale : void 0) ?? browserLocale;
|
|
641
685
|
const defaultLocale = options.defaultLocale ?? (typeof bootstrap.defaultLocale === "string" ? bootstrap.defaultLocale : void 0) ?? "zh-CN";
|
|
642
686
|
const messages = options.messages ?? (isRecord(bootstrap.messages) ? bootstrap.messages : void 0) ?? {};
|
|
643
|
-
|
|
687
|
+
let next = {
|
|
644
688
|
bootstrap,
|
|
645
689
|
menuRegistry,
|
|
646
690
|
layoutType,
|
|
@@ -650,11 +694,30 @@ function createPactorApplication(options) {
|
|
|
650
694
|
app: appRecord,
|
|
651
695
|
locale,
|
|
652
696
|
defaultLocale,
|
|
653
|
-
messages
|
|
697
|
+
messages,
|
|
698
|
+
i18nVersion: 0
|
|
654
699
|
};
|
|
655
|
-
|
|
700
|
+
if (pendingLocale !== null) {
|
|
701
|
+
next = {
|
|
702
|
+
...next,
|
|
703
|
+
locale: pendingLocale.locale,
|
|
704
|
+
messages: pendingLocale.messages ?? next.messages
|
|
705
|
+
};
|
|
706
|
+
pendingLocale = null;
|
|
707
|
+
localeStorage?.set(next.locale);
|
|
708
|
+
}
|
|
709
|
+
updateSession(next);
|
|
656
710
|
return next;
|
|
657
711
|
},
|
|
712
|
+
subscribeSession(listener) {
|
|
713
|
+
sessionListeners.add(listener);
|
|
714
|
+
return () => {
|
|
715
|
+
sessionListeners.delete(listener);
|
|
716
|
+
};
|
|
717
|
+
},
|
|
718
|
+
getSession() {
|
|
719
|
+
return session;
|
|
720
|
+
},
|
|
658
721
|
createPageRuntime(pageDsl, route) {
|
|
659
722
|
return createPageRuntime(pageDsl, {
|
|
660
723
|
components,
|
|
@@ -712,11 +775,20 @@ function createPactorApplication(options) {
|
|
|
712
775
|
},
|
|
713
776
|
setLocale(locale, messages) {
|
|
714
777
|
if (session === null) {
|
|
715
|
-
|
|
778
|
+
pendingLocale = { locale, messages };
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
const nextMessages = messages ?? session.messages;
|
|
782
|
+
if (locale === session.locale && nextMessages === session.messages) {
|
|
716
783
|
return;
|
|
717
784
|
}
|
|
718
|
-
|
|
719
|
-
|
|
785
|
+
updateSession({
|
|
786
|
+
...session,
|
|
787
|
+
locale,
|
|
788
|
+
messages: nextMessages,
|
|
789
|
+
i18nVersion: session.i18nVersion + 1
|
|
790
|
+
});
|
|
791
|
+
localeStorage?.set(locale);
|
|
720
792
|
}
|
|
721
793
|
};
|
|
722
794
|
}
|
|
@@ -729,7 +801,8 @@ import {
|
|
|
729
801
|
createPageRuntime as createPageRuntime2,
|
|
730
802
|
DslSourceResolver,
|
|
731
803
|
I18nContextProvider as I18nContextProvider2,
|
|
732
|
-
PageRuntimeView as PageRuntimeView2
|
|
804
|
+
PageRuntimeView as PageRuntimeView2,
|
|
805
|
+
useI18n
|
|
733
806
|
} from "@pactor-app/runtime";
|
|
734
807
|
import {
|
|
735
808
|
useEffect as useEffect3,
|
|
@@ -779,7 +852,16 @@ function createPactorPage(options = {}) {
|
|
|
779
852
|
});
|
|
780
853
|
}
|
|
781
854
|
return function ConfiguredPactorPage(props) {
|
|
782
|
-
return /* @__PURE__ */ jsx5(
|
|
855
|
+
return /* @__PURE__ */ jsx5(I18nContextProvider2, { value: i18n, children: /* @__PURE__ */ jsx5(
|
|
856
|
+
EmbeddedPage,
|
|
857
|
+
{
|
|
858
|
+
assembly,
|
|
859
|
+
options,
|
|
860
|
+
createRuntime,
|
|
861
|
+
resolvePage: options.loader ? resolvePage : void 0,
|
|
862
|
+
...props
|
|
863
|
+
}
|
|
864
|
+
) });
|
|
783
865
|
};
|
|
784
866
|
async function resolvePage(pageId) {
|
|
785
867
|
if (!options.loader) {
|
|
@@ -801,13 +883,13 @@ function PactorPage(props) {
|
|
|
801
883
|
function EmbeddedPage({
|
|
802
884
|
assembly,
|
|
803
885
|
options,
|
|
804
|
-
i18n,
|
|
805
886
|
createRuntime,
|
|
806
887
|
resolvePage,
|
|
807
888
|
pageId,
|
|
808
889
|
pageDsl,
|
|
809
890
|
route
|
|
810
891
|
}) {
|
|
892
|
+
const { t } = useI18n();
|
|
811
893
|
const [state, setState] = useState3({ status: "loading" });
|
|
812
894
|
const [retryTick, setRetryTick] = useState3(0);
|
|
813
895
|
const onError = options.onError;
|
|
@@ -868,15 +950,15 @@ function EmbeddedPage({
|
|
|
868
950
|
ResultView,
|
|
869
951
|
{
|
|
870
952
|
className: "pactor-app-page-load-error",
|
|
871
|
-
title: "
|
|
953
|
+
title: t("pactor.page.loadFailed"),
|
|
872
954
|
subTitle: state.error.message,
|
|
873
|
-
extra: /* @__PURE__ */ jsx5(PrimaryButton, { onClick: () => setRetryTick((n) => n + 1), children: "
|
|
955
|
+
extra: /* @__PURE__ */ jsx5(PrimaryButton, { onClick: () => setRetryTick((n) => n + 1), children: t("pactor.page.retry") })
|
|
874
956
|
}
|
|
875
957
|
);
|
|
876
958
|
} else {
|
|
877
959
|
content = /* @__PURE__ */ jsx5(PageErrorBoundary, { children: /* @__PURE__ */ jsx5(PageRuntimeView2, { runtime: state.runtime, children: resolvePage !== void 0 ? /* @__PURE__ */ jsx5(OverlayHost2, { manager: assembly.overlayManager, resolvePage }) : /* @__PURE__ */ jsx5(OverlayHost2, { manager: assembly.overlayManager }) }) });
|
|
878
960
|
}
|
|
879
|
-
return /* @__PURE__ */ jsx5(
|
|
961
|
+
return /* @__PURE__ */ jsx5(InteractionProvider2, { bridge: assembly.uiBridge, children: content });
|
|
880
962
|
}
|
|
881
963
|
|
|
882
964
|
// src/sitemap/actions.ts
|
|
@@ -919,7 +1001,12 @@ var defaultSitemapActions = {
|
|
|
919
1001
|
};
|
|
920
1002
|
|
|
921
1003
|
// src/sitemap/SitemapApp.tsx
|
|
1004
|
+
import { createI18nContext as createI18nContext3 } from "@pactor-app/core";
|
|
922
1005
|
import { MenuRegistry as MenuRegistry2 } from "@pactor-app/router";
|
|
1006
|
+
import {
|
|
1007
|
+
I18nContextProvider as I18nContextProvider3,
|
|
1008
|
+
useI18n as useI18n2
|
|
1009
|
+
} from "@pactor-app/runtime";
|
|
923
1010
|
import { Menu } from "@pactor-app/ui/components";
|
|
924
1011
|
import {
|
|
925
1012
|
createContext,
|
|
@@ -930,7 +1017,7 @@ import {
|
|
|
930
1017
|
} from "react";
|
|
931
1018
|
|
|
932
1019
|
// src/sitemap/browser-route.ts
|
|
933
|
-
import { useCallback, useMemo, useSyncExternalStore } from "react";
|
|
1020
|
+
import { useCallback, useMemo, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
934
1021
|
var NAV_EVENT = "pactor:sitemap-navigate";
|
|
935
1022
|
function readLocation() {
|
|
936
1023
|
return `${window.location.pathname}${window.location.search}`;
|
|
@@ -944,7 +1031,7 @@ function subscribe(callback) {
|
|
|
944
1031
|
};
|
|
945
1032
|
}
|
|
946
1033
|
function useBrowserRoute() {
|
|
947
|
-
const location =
|
|
1034
|
+
const location = useSyncExternalStore2(
|
|
948
1035
|
subscribe,
|
|
949
1036
|
readLocation,
|
|
950
1037
|
// SSR 快照:服务端无 window,宿主应注入 pathname / navigate
|
|
@@ -1231,7 +1318,7 @@ function createSitemapSessionServices(session, serviceName = "session.context")
|
|
|
1231
1318
|
}
|
|
1232
1319
|
|
|
1233
1320
|
// src/sitemap/SitemapApp.tsx
|
|
1234
|
-
import { Fragment, jsx as jsx6
|
|
1321
|
+
import { Fragment, jsx as jsx6 } from "react/jsx-runtime";
|
|
1235
1322
|
var OutletContext = createContext(null);
|
|
1236
1323
|
function PageOutlet() {
|
|
1237
1324
|
return use(OutletContext);
|
|
@@ -1254,6 +1341,18 @@ function SitemapMenu({
|
|
|
1254
1341
|
);
|
|
1255
1342
|
}
|
|
1256
1343
|
function SitemapApp(props) {
|
|
1344
|
+
const i18n = useMemo2(
|
|
1345
|
+
() => createI18nContext3({
|
|
1346
|
+
locale: props.locale,
|
|
1347
|
+
defaultLocale: props.defaultLocale,
|
|
1348
|
+
messages: props.messages
|
|
1349
|
+
}),
|
|
1350
|
+
[props.locale, props.defaultLocale, props.messages]
|
|
1351
|
+
);
|
|
1352
|
+
return /* @__PURE__ */ jsx6(I18nContextProvider3, { value: i18n, children: /* @__PURE__ */ jsx6(SitemapAppInner, { ...props }) });
|
|
1353
|
+
}
|
|
1354
|
+
function SitemapAppInner(props) {
|
|
1355
|
+
const { t } = useI18n2();
|
|
1257
1356
|
const { sources, fetcher, baseUrl } = props;
|
|
1258
1357
|
const browserRoute = useBrowserRoute();
|
|
1259
1358
|
const pathname = props.pathname ?? browserRoute.pathname;
|
|
@@ -1303,26 +1402,19 @@ function SitemapApp(props) {
|
|
|
1303
1402
|
}
|
|
1304
1403
|
}, [decision, navigate]);
|
|
1305
1404
|
if (state.status === "loading") {
|
|
1306
|
-
return /* @__PURE__ */ jsx6(Centered, { children: props.loading ?? "
|
|
1405
|
+
return /* @__PURE__ */ jsx6(Centered, { children: props.loading ?? t("pactor.table.loading") });
|
|
1307
1406
|
}
|
|
1308
1407
|
if (state.status === "error") {
|
|
1309
|
-
return props.renderError !== void 0 ? /* @__PURE__ */ jsx6(Fragment, { children: props.renderError(state.error) }) : /* @__PURE__ */
|
|
1310
|
-
"sitemap \u52A0\u8F7D\u5931\u8D25\uFF1A",
|
|
1311
|
-
state.error.message
|
|
1312
|
-
] });
|
|
1408
|
+
return props.renderError !== void 0 ? /* @__PURE__ */ jsx6(Fragment, { children: props.renderError(state.error) }) : /* @__PURE__ */ jsx6(Centered, { children: t("pactor.sitemap.loadError", { message: state.error.message }) });
|
|
1313
1409
|
}
|
|
1314
1410
|
if (sitemap === null || registry === null || resolution === null) {
|
|
1315
1411
|
return null;
|
|
1316
1412
|
}
|
|
1317
1413
|
if (!decision.allow) {
|
|
1318
|
-
return /* @__PURE__ */ jsx6(Centered, { children: "
|
|
1414
|
+
return /* @__PURE__ */ jsx6(Centered, { children: t("pactor.sitemap.redirecting") });
|
|
1319
1415
|
}
|
|
1320
1416
|
if (resolution.route === null) {
|
|
1321
|
-
return props.renderNotFound !== void 0 ? /* @__PURE__ */ jsx6(Fragment, { children: props.renderNotFound(pathname) }) : /* @__PURE__ */
|
|
1322
|
-
"\u9875\u9762\u4E0D\u5B58\u5728\uFF08",
|
|
1323
|
-
pathname,
|
|
1324
|
-
"\uFF09"
|
|
1325
|
-
] });
|
|
1417
|
+
return props.renderNotFound !== void 0 ? /* @__PURE__ */ jsx6(Fragment, { children: props.renderNotFound(pathname) }) : /* @__PURE__ */ jsx6(Centered, { children: t("pactor.sitemap.notFound", { path: pathname }) });
|
|
1326
1418
|
}
|
|
1327
1419
|
const { pageId, layoutName, highlightKey, params } = resolution.route;
|
|
1328
1420
|
return (
|
|
@@ -1356,6 +1448,7 @@ function SitemapLayout({
|
|
|
1356
1448
|
routeParams,
|
|
1357
1449
|
props
|
|
1358
1450
|
}) {
|
|
1451
|
+
const { t } = useI18n2();
|
|
1359
1452
|
const sessionService = props.sessionService ?? "session.context";
|
|
1360
1453
|
const session = useMemo2(
|
|
1361
1454
|
() => ({
|
|
@@ -1418,11 +1511,61 @@ function SitemapLayout({
|
|
|
1418
1511
|
};
|
|
1419
1512
|
}, [layoutDsl, layoutName, sessionService]);
|
|
1420
1513
|
if (layoutDsl === void 0 || layoutPage === null) {
|
|
1421
|
-
return /* @__PURE__ */
|
|
1422
|
-
"\u5E03\u5C40\u672A\u5B9A\u4E49\uFF1A",
|
|
1423
|
-
layoutName
|
|
1424
|
-
] });
|
|
1514
|
+
return /* @__PURE__ */ jsx6(Centered, { children: t("pactor.sitemap.layoutMissing", { name: layoutName }) });
|
|
1425
1515
|
}
|
|
1516
|
+
const messagesSignature = JSON.stringify(props.messages ?? {});
|
|
1517
|
+
const pageFactory = useMemo2(
|
|
1518
|
+
() => createPactorPage({
|
|
1519
|
+
loader,
|
|
1520
|
+
services,
|
|
1521
|
+
actions,
|
|
1522
|
+
navigate,
|
|
1523
|
+
httpAdapter: props.httpAdapter,
|
|
1524
|
+
permissions: sitemap.permissions ?? [],
|
|
1525
|
+
components: props.components,
|
|
1526
|
+
locale: props.locale,
|
|
1527
|
+
defaultLocale: props.defaultLocale,
|
|
1528
|
+
messages: props.messages
|
|
1529
|
+
}),
|
|
1530
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1531
|
+
[
|
|
1532
|
+
loader,
|
|
1533
|
+
services,
|
|
1534
|
+
actions,
|
|
1535
|
+
navigate,
|
|
1536
|
+
props.httpAdapter,
|
|
1537
|
+
props.components,
|
|
1538
|
+
sitemap,
|
|
1539
|
+
props.locale,
|
|
1540
|
+
props.defaultLocale,
|
|
1541
|
+
messagesSignature
|
|
1542
|
+
]
|
|
1543
|
+
);
|
|
1544
|
+
const layoutFactory = useMemo2(
|
|
1545
|
+
() => createPactorPage({
|
|
1546
|
+
services,
|
|
1547
|
+
actions,
|
|
1548
|
+
navigate,
|
|
1549
|
+
httpAdapter: props.httpAdapter,
|
|
1550
|
+
components: { PageOutlet, SitemapMenu, ...props.components },
|
|
1551
|
+
locale: props.locale,
|
|
1552
|
+
defaultLocale: props.defaultLocale,
|
|
1553
|
+
messages: props.messages
|
|
1554
|
+
}),
|
|
1555
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1556
|
+
[
|
|
1557
|
+
services,
|
|
1558
|
+
actions,
|
|
1559
|
+
navigate,
|
|
1560
|
+
props.httpAdapter,
|
|
1561
|
+
props.components,
|
|
1562
|
+
props.locale,
|
|
1563
|
+
props.defaultLocale,
|
|
1564
|
+
messagesSignature
|
|
1565
|
+
]
|
|
1566
|
+
);
|
|
1567
|
+
const Page = pageFactory;
|
|
1568
|
+
const LayoutPage = layoutFactory;
|
|
1426
1569
|
return /* @__PURE__ */ jsx6(
|
|
1427
1570
|
OutletContext.Provider,
|
|
1428
1571
|
{
|
|
@@ -1430,32 +1573,15 @@ function SitemapLayout({
|
|
|
1430
1573
|
// 页面实例:key 随 pageId + pathname 变化(route 参数变化需重建,
|
|
1431
1574
|
// PactorPage 的 route prop 不参与运行时重建)——布局保持挂载
|
|
1432
1575
|
/* @__PURE__ */ jsx6(
|
|
1433
|
-
|
|
1576
|
+
Page,
|
|
1434
1577
|
{
|
|
1435
1578
|
pageId,
|
|
1436
|
-
route: { params: routeParams, query }
|
|
1437
|
-
loader,
|
|
1438
|
-
services,
|
|
1439
|
-
actions,
|
|
1440
|
-
permissions: sitemap.permissions ?? [],
|
|
1441
|
-
navigate,
|
|
1442
|
-
httpAdapter: props.httpAdapter,
|
|
1443
|
-
components: props.components
|
|
1579
|
+
route: { params: routeParams, query }
|
|
1444
1580
|
},
|
|
1445
1581
|
`${pageId}@${pathname}`
|
|
1446
1582
|
)
|
|
1447
1583
|
),
|
|
1448
|
-
children: /* @__PURE__ */ jsx6(
|
|
1449
|
-
PactorPage,
|
|
1450
|
-
{
|
|
1451
|
-
pageDsl: layoutPage,
|
|
1452
|
-
services,
|
|
1453
|
-
actions,
|
|
1454
|
-
navigate,
|
|
1455
|
-
httpAdapter: props.httpAdapter,
|
|
1456
|
-
components: { PageOutlet, SitemapMenu, ...props.components }
|
|
1457
|
-
}
|
|
1458
|
-
)
|
|
1584
|
+
children: /* @__PURE__ */ jsx6(LayoutPage, { pageDsl: layoutPage })
|
|
1459
1585
|
}
|
|
1460
1586
|
);
|
|
1461
1587
|
}
|
|
@@ -1484,6 +1610,7 @@ export {
|
|
|
1484
1610
|
ReactRouterBinding,
|
|
1485
1611
|
SitemapApp,
|
|
1486
1612
|
createHttpHooks,
|
|
1613
|
+
createLocalStorageLocaleStorage,
|
|
1487
1614
|
createPactorApplication,
|
|
1488
1615
|
createPactorPage,
|
|
1489
1616
|
createRuntimeHttpAdapter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pactor-app/app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.43.0",
|
|
4
4
|
"description": "Pactor application: one-stop composition layer (createPactorApplication) wiring loader, bootstrap, registries, router, layout, interaction and page runtimes",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pactor",
|
|
@@ -46,14 +46,14 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@pactor-app/core": "1.
|
|
50
|
-
"@pactor-app/
|
|
51
|
-
"@pactor-app/resource": "1.
|
|
52
|
-
"@pactor-app/
|
|
53
|
-
"@pactor-app/
|
|
54
|
-
"@pactor-app/
|
|
55
|
-
"@pactor-app/
|
|
56
|
-
"@pactor-app/
|
|
49
|
+
"@pactor-app/core": "1.43.0",
|
|
50
|
+
"@pactor-app/permission": "1.43.0",
|
|
51
|
+
"@pactor-app/resource": "1.43.0",
|
|
52
|
+
"@pactor-app/runtime": "1.43.0",
|
|
53
|
+
"@pactor-app/schema": "1.43.0",
|
|
54
|
+
"@pactor-app/expression": "1.43.0",
|
|
55
|
+
"@pactor-app/ui": "1.43.0",
|
|
56
|
+
"@pactor-app/router": "1.43.0"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
59
|
"react": ">=18",
|