@ablogcms/react-router 3.2.28-beta.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/README.md ADDED
@@ -0,0 +1,14 @@
1
+ # @ablogcms/react-router
2
+
3
+ CMS 管理画面の list-view 系画面(エントリー一覧・モジュール一覧など)専用の `react-router`
4
+ ルーター生成ヘルパーを提供するパッケージ。
5
+
6
+ ## 使い方
7
+
8
+ ```ts
9
+ import createLoader from '@ablogcms/react-router/list-view/create-loader';
10
+ import createRouter from '@ablogcms/react-router/list-view/create-router';
11
+ ```
12
+
13
+ 一覧画面用のルーターとローダーを組み立てる。CMS 管理画面の list-view ページ専用のため、
14
+ 他の用途での利用は想定していない。
@@ -0,0 +1,36 @@
1
+ // src/list-view/createRouter.tsx
2
+ import { ScrollRestoration, createBrowserRouter, useParams, useRouteError } from "react-router";
3
+ import { useMemo } from "react";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ function ErrorElement({ element }) {
6
+ const error = useRouteError();
7
+ console.error(error);
8
+ return /* @__PURE__ */ jsx(Fragment, { children: element });
9
+ }
10
+ function RouteElement({
11
+ element,
12
+ contextProvider: ContextProvider
13
+ }) {
14
+ const params = useParams();
15
+ const context = useMemo(() => ACMS.Library.parseAcmsPath(decodeURI(params["*"])), [params]);
16
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
17
+ ContextProvider ? /* @__PURE__ */ jsx(ContextProvider, { context, children: element }) : element,
18
+ /* @__PURE__ */ jsx(ScrollRestoration, {})
19
+ ] });
20
+ }
21
+ function createRouter({ element, errorElement, contextProvider, ...rest }) {
22
+ const router = createBrowserRouter([
23
+ {
24
+ path: "*",
25
+ element: /* @__PURE__ */ jsx(RouteElement, { element, contextProvider }),
26
+ errorElement: /* @__PURE__ */ jsx(ErrorElement, { element: errorElement }),
27
+ ...rest
28
+ }
29
+ ]);
30
+ return router;
31
+ }
32
+
33
+ export {
34
+ createRouter
35
+ };
36
+ //# sourceMappingURL=chunk-LL3PVY7W.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/list-view/createRouter.tsx"],"sourcesContent":["import { type RouteObject, ScrollRestoration, createBrowserRouter, useParams, useRouteError } from 'react-router';\nimport { type ComponentType, type ReactNode, useMemo } from 'react';\nimport type { AcmsContext } from '@ablogcms/url/types';\n\n/**\n * URL から解決した ACMS コンテキストをルート要素へ供給するコンポーネント。\n *\n * CMS コア側の `AcmsContextProvider` を注入するための口。パッケージから\n * コア(`ablogcms/js/src/stores/acms`)を直接参照すると alias 依存になり npm 公開できないため、\n * 依存の向きを呼び出し側からの注入に反転させている。\n */\nexport type AcmsRouteContextProvider = ComponentType<{ context: AcmsContext; children: ReactNode }>;\n\ntype CreateRouterOptions = RouteObject & {\n contextProvider?: AcmsRouteContextProvider;\n};\n\n/**\n * エラーコンポーネントを作成する\n */\nfunction ErrorElement({ element }: { element: ReactNode }): ReactNode {\n const error = useRouteError();\n console.error(error);\n return <>{element}</>;\n}\n\n/**\n * ルートコンポーネントを作成する\n */\nfunction RouteElement({\n element,\n contextProvider: ContextProvider,\n}: {\n element: ReactNode;\n contextProvider?: AcmsRouteContextProvider;\n}): RouteObject['element'] {\n const params = useParams();\n // 直接 parseAcmsPath を import せずグローバル経由で呼ぶ。ACMS.Library 側は実行時の\n // 設定を織り込んだ状態で公開されており、素の関数呼び出しと挙動が一致する保証がないため\n const context = useMemo(() => ACMS.Library.parseAcmsPath(decodeURI(params['*'] as string)), [params]);\n\n return (\n <>\n {ContextProvider ? <ContextProvider context={context}>{element}</ContextProvider> : element}\n <ScrollRestoration />\n </>\n );\n}\n\n/**\n * 管理画面のルートコンポーネントを作成する\n *\n * @warning\n * このメソッドはReactコンポーネントの中で利用すると、コンポーネントが表示されない不具合があります。\n * コンポーネントの外で呼び出すようにしてください。\n */\nexport default function createRouter({ element, errorElement, contextProvider, ...rest }: CreateRouterOptions) {\n // ルーターの作成\n const router = createBrowserRouter([\n {\n path: '*',\n element: <RouteElement element={element} contextProvider={contextProvider} />,\n errorElement: <ErrorElement element={errorElement} />,\n ...rest,\n },\n ]);\n\n return router;\n}\n"],"mappings":";AAAA,SAA2B,mBAAmB,qBAAqB,WAAW,qBAAqB;AACnG,SAA6C,eAAe;AAsBnD,wBAmBL,YAnBK;AAHT,SAAS,aAAa,EAAE,QAAQ,GAAsC;AACpE,QAAM,QAAQ,cAAc;AAC5B,UAAQ,MAAM,KAAK;AACnB,SAAO,gCAAG,mBAAQ;AACpB;AAKA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA,iBAAiB;AACnB,GAG2B;AACzB,QAAM,SAAS,UAAU;AAGzB,QAAM,UAAU,QAAQ,MAAM,KAAK,QAAQ,cAAc,UAAU,OAAO,GAAG,CAAW,CAAC,GAAG,CAAC,MAAM,CAAC;AAEpG,SACE,iCACG;AAAA,sBAAkB,oBAAC,mBAAgB,SAAmB,mBAAQ,IAAqB;AAAA,IACpF,oBAAC,qBAAkB;AAAA,KACrB;AAEJ;AASe,SAAR,aAA8B,EAAE,SAAS,cAAc,iBAAiB,GAAG,KAAK,GAAwB;AAE7G,QAAM,SAAS,oBAAoB;AAAA,IACjC;AAAA,MACE,MAAM;AAAA,MACN,SAAS,oBAAC,gBAAa,SAAkB,iBAAkC;AAAA,MAC3E,cAAc,oBAAC,gBAAa,SAAS,cAAc;AAAA,MACnD,GAAG;AAAA,IACL;AAAA,EACF,CAAC;AAED,SAAO;AACT;","names":[]}
@@ -0,0 +1,50 @@
1
+ // src/list-view/createLoader.ts
2
+ import { redirect, matchPath } from "react-router";
3
+ import { parseUrlSearchParams } from "@ablogcms/utils";
4
+ function createStorageKey(id) {
5
+ return `acms-${id}-root-${ACMS.Config.root}-suid-${ACMS.Config.suid}-bid-${ACMS.Config.bid}`;
6
+ }
7
+ function createLoader({
8
+ id,
9
+ admin,
10
+ onLoad,
11
+ ignoredParams = []
12
+ }) {
13
+ const storageKey = createStorageKey(id);
14
+ let isFirstMount = true;
15
+ const loader = ({ params, request }) => {
16
+ const path = params["*"];
17
+ const url = new URL(request.url);
18
+ const context = ACMS.Library.parseAcmsPath(decodeURI(path));
19
+ const match = matchPath(`${ACMS.Config.root}bid/:bid/admin/${admin}`, url.pathname);
20
+ if (isFirstMount && match && url.searchParams.size === 0) {
21
+ const data = localStorage.getItem(storageKey);
22
+ if (data) {
23
+ const savedContext = JSON.parse(data);
24
+ return redirect(ACMS.Library.acmsLink({ ...savedContext, bid: match.params.bid, admin }));
25
+ }
26
+ }
27
+ if (match && url.searchParams.size === 0) {
28
+ localStorage.removeItem(storageKey);
29
+ } else {
30
+ ignoredParams.forEach((param) => {
31
+ url.searchParams.delete(param);
32
+ });
33
+ const data = {
34
+ ...context,
35
+ field: context.field?.toString(),
36
+ searchParams: parseUrlSearchParams(url.searchParams)
37
+ };
38
+ localStorage.setItem(storageKey, JSON.stringify(data));
39
+ }
40
+ onLoad({ context, url });
41
+ isFirstMount = false;
42
+ return null;
43
+ };
44
+ return loader;
45
+ }
46
+
47
+ export {
48
+ createLoader
49
+ };
50
+ //# sourceMappingURL=chunk-T4KEVRNL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/list-view/createLoader.ts"],"sourcesContent":["import { redirect, matchPath, type RouteObject } from 'react-router';\nimport { parseUrlSearchParams } from '@ablogcms/utils';\nimport type { AcmsContext } from '@ablogcms/url/types';\n\nexport interface CreateLoaderOptions {\n id: string;\n admin: string;\n onLoad: ({ context, url }: { context: AcmsContext; url: URL }) => void | Promise<void>;\n ignoredParams?: string[];\n}\n\n/**\n * ストレージキー生成関数\n */\nfunction createStorageKey(id: string): string {\n return `acms-${id}-root-${ACMS.Config.root}-suid-${ACMS.Config.suid}-bid-${ACMS.Config.bid}`;\n}\n\n/**\n * ローダー関数を作成する\n */\nexport default function createLoader({\n id,\n admin,\n onLoad,\n ignoredParams = [],\n}: CreateLoaderOptions): RouteObject['loader'] {\n const storageKey = createStorageKey(id);\n let isFirstMount = true;\n\n const loader: RouteObject['loader'] = ({ params, request }) => {\n const path = params['*'] as string;\n const url = new URL(request.url);\n const context = ACMS.Library.parseAcmsPath(decodeURI(path));\n const match = matchPath(`${ACMS.Config.root}bid/:bid/admin/${admin}`, url.pathname);\n\n if (isFirstMount && match && url.searchParams.size === 0) {\n // 初回アクセスかつ、検索条件がない場合はローカルストレージから取得\n const data = localStorage.getItem(storageKey);\n if (data) {\n // ローカルストレージにデータがある場合はリダイレクト\n const savedContext: AcmsContext & { searchParams: Record<string, string | string[]> } = JSON.parse(data);\n return redirect(ACMS.Library.acmsLink({ ...savedContext, bid: match.params.bid, admin }));\n }\n }\n\n if (match && url.searchParams.size === 0) {\n // 検索条件がない場合\n localStorage.removeItem(storageKey);\n } else {\n // 検索条件がある場合\n ignoredParams.forEach((param) => {\n url.searchParams.delete(param);\n });\n const data = {\n ...context,\n field: context.field?.toString(),\n searchParams: parseUrlSearchParams(url.searchParams),\n };\n localStorage.setItem(storageKey, JSON.stringify(data));\n }\n\n // プリロード処理の実行\n onLoad({ context, url });\n isFirstMount = false;\n\n return null;\n };\n\n return loader;\n}\n"],"mappings":";AAAA,SAAS,UAAU,iBAAmC;AACtD,SAAS,4BAA4B;AAarC,SAAS,iBAAiB,IAAoB;AAC5C,SAAO,QAAQ,EAAE,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,OAAO,IAAI,QAAQ,KAAK,OAAO,GAAG;AAC5F;AAKe,SAAR,aAA8B;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAgB,CAAC;AACnB,GAA+C;AAC7C,QAAM,aAAa,iBAAiB,EAAE;AACtC,MAAI,eAAe;AAEnB,QAAM,SAAgC,CAAC,EAAE,QAAQ,QAAQ,MAAM;AAC7D,UAAM,OAAO,OAAO,GAAG;AACvB,UAAM,MAAM,IAAI,IAAI,QAAQ,GAAG;AAC/B,UAAM,UAAU,KAAK,QAAQ,cAAc,UAAU,IAAI,CAAC;AAC1D,UAAM,QAAQ,UAAU,GAAG,KAAK,OAAO,IAAI,kBAAkB,KAAK,IAAI,IAAI,QAAQ;AAElF,QAAI,gBAAgB,SAAS,IAAI,aAAa,SAAS,GAAG;AAExD,YAAM,OAAO,aAAa,QAAQ,UAAU;AAC5C,UAAI,MAAM;AAER,cAAM,eAAkF,KAAK,MAAM,IAAI;AACvG,eAAO,SAAS,KAAK,QAAQ,SAAS,EAAE,GAAG,cAAc,KAAK,MAAM,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,MAC1F;AAAA,IACF;AAEA,QAAI,SAAS,IAAI,aAAa,SAAS,GAAG;AAExC,mBAAa,WAAW,UAAU;AAAA,IACpC,OAAO;AAEL,oBAAc,QAAQ,CAAC,UAAU;AAC/B,YAAI,aAAa,OAAO,KAAK;AAAA,MAC/B,CAAC;AACD,YAAM,OAAO;AAAA,QACX,GAAG;AAAA,QACH,OAAO,QAAQ,OAAO,SAAS;AAAA,QAC/B,cAAc,qBAAqB,IAAI,YAAY;AAAA,MACrD;AACA,mBAAa,QAAQ,YAAY,KAAK,UAAU,IAAI,CAAC;AAAA,IACvD;AAGA,WAAO,EAAE,SAAS,IAAI,CAAC;AACvB,mBAAe;AAEf,WAAO;AAAA,EACT;AAEA,SAAO;AACT;","names":[]}
@@ -0,0 +1,4 @@
1
+ export { default as createLoader } from './list-view/createLoader.js';
2
+ export type { CreateLoaderOptions } from './list-view/createLoader.js';
3
+ export { default as createRouter } from './list-view/createRouter.js';
4
+ export type { AcmsRouteContextProvider } from './list-view/createRouter.js';
package/dist/index.mjs ADDED
@@ -0,0 +1,11 @@
1
+ import {
2
+ createLoader
3
+ } from "./chunk-T4KEVRNL.mjs";
4
+ import {
5
+ createRouter
6
+ } from "./chunk-LL3PVY7W.mjs";
7
+ export {
8
+ createLoader,
9
+ createRouter
10
+ };
11
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,15 @@
1
+ import { type RouteObject } from 'react-router';
2
+ import type { AcmsContext } from '@ablogcms/url/types';
3
+ export interface CreateLoaderOptions {
4
+ id: string;
5
+ admin: string;
6
+ onLoad: ({ context, url }: {
7
+ context: AcmsContext;
8
+ url: URL;
9
+ }) => void | Promise<void>;
10
+ ignoredParams?: string[];
11
+ }
12
+ /**
13
+ * ローダー関数を作成する
14
+ */
15
+ export default function createLoader({ id, admin, onLoad, ignoredParams, }: CreateLoaderOptions): RouteObject['loader'];
@@ -0,0 +1,7 @@
1
+ import {
2
+ createLoader
3
+ } from "../chunk-T4KEVRNL.mjs";
4
+ export {
5
+ createLoader as default
6
+ };
7
+ //# sourceMappingURL=createLoader.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,26 @@
1
+ import { type RouteObject } from 'react-router';
2
+ import { type ComponentType, type ReactNode } from 'react';
3
+ import type { AcmsContext } from '@ablogcms/url/types';
4
+ /**
5
+ * URL から解決した ACMS コンテキストをルート要素へ供給するコンポーネント。
6
+ *
7
+ * CMS コア側の `AcmsContextProvider` を注入するための口。パッケージから
8
+ * コア(`ablogcms/js/src/stores/acms`)を直接参照すると alias 依存になり npm 公開できないため、
9
+ * 依存の向きを呼び出し側からの注入に反転させている。
10
+ */
11
+ export type AcmsRouteContextProvider = ComponentType<{
12
+ context: AcmsContext;
13
+ children: ReactNode;
14
+ }>;
15
+ type CreateRouterOptions = RouteObject & {
16
+ contextProvider?: AcmsRouteContextProvider;
17
+ };
18
+ /**
19
+ * 管理画面のルートコンポーネントを作成する
20
+ *
21
+ * @warning
22
+ * このメソッドはReactコンポーネントの中で利用すると、コンポーネントが表示されない不具合があります。
23
+ * コンポーネントの外で呼び出すようにしてください。
24
+ */
25
+ export default function createRouter({ element, errorElement, contextProvider, ...rest }: CreateRouterOptions): import("react-router").DataRouter;
26
+ export {};
@@ -0,0 +1,7 @@
1
+ import {
2
+ createRouter
3
+ } from "../chunk-LL3PVY7W.mjs";
4
+ export {
5
+ createRouter as default
6
+ };
7
+ //# sourceMappingURL=createRouter.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@ablogcms/react-router",
3
+ "version": "3.2.28-beta.0",
4
+ "type": "module",
5
+ "description": "CMS 管理画面 list-view 画面用の react-router ヘルパー",
6
+ "license": "MIT",
7
+ "homepage": "https://www.a-blogcms.jp",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+ssh://git@bitbucket.org:appleple/ablogcms.git",
11
+ "directory": "packages/frontend/react-router"
12
+ },
13
+ "sideEffects": false,
14
+ "dependencies": {
15
+ "react-router": "^8.3.0",
16
+ "@ablogcms/url": "3.2.28-beta.0",
17
+ "@ablogcms/utils": "3.2.28-beta.0"
18
+ },
19
+ "peerDependencies": {
20
+ "react": "^19",
21
+ "@types/react": "^19.2.17"
22
+ },
23
+ "peerDependenciesMeta": {
24
+ "@types/react": {
25
+ "optional": true
26
+ }
27
+ },
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.mjs",
32
+ "default": "./dist/index.mjs"
33
+ },
34
+ "./list-view/create-loader": {
35
+ "types": "./dist/list-view/createLoader.d.ts",
36
+ "import": "./dist/list-view/createLoader.mjs",
37
+ "default": "./dist/list-view/createLoader.mjs"
38
+ },
39
+ "./list-view/create-router": {
40
+ "types": "./dist/list-view/createRouter.d.ts",
41
+ "import": "./dist/list-view/createRouter.mjs",
42
+ "default": "./dist/list-view/createRouter.mjs"
43
+ }
44
+ },
45
+ "publishConfig": {
46
+ "access": "public"
47
+ },
48
+ "files": [
49
+ "dist"
50
+ ],
51
+ "scripts": {
52
+ "build": "node ../../../tools/build-package.mjs"
53
+ }
54
+ }