@hackersheet/next-document-content-components 0.1.0-alpha.2 → 0.1.0-alpha.21

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.
Files changed (64) hide show
  1. package/dist/cjs/components/code-block/code-block-copy-button.d.ts +13 -2
  2. package/dist/cjs/components/code-block/code-block-copy-button.js +2 -2
  3. package/dist/cjs/components/code-block/code-block-icon.d.ts +38 -4
  4. package/dist/cjs/components/code-block/code-block-icon.js +12 -0
  5. package/dist/cjs/components/code-block/code-block.d.ts +1 -1
  6. package/dist/cjs/components/code-block/code-block.js +3 -9
  7. package/dist/cjs/components/code-block/directory-tree-item.d.ts +15 -0
  8. package/dist/cjs/components/code-block/directory-tree-item.js +38 -0
  9. package/dist/cjs/components/code-block/directory-tree.d.ts +13 -0
  10. package/dist/cjs/components/code-block/{code-block-kifu.js → directory-tree.js} +12 -35
  11. package/dist/cjs/components/code-block/parse-tree-output.d.ts +26 -0
  12. package/dist/cjs/components/code-block/parse-tree-output.js +111 -0
  13. package/dist/cjs/components/code-block/shiki.js +25 -7
  14. package/dist/cjs/components/gist/gist.d.ts +6 -0
  15. package/dist/cjs/components/{index.js → gist/gist.js} +26 -27
  16. package/dist/cjs/components/heading/heading.d.ts +6 -0
  17. package/dist/cjs/components/{kifu-to/kifu-to.js → heading/heading.js} +7 -9
  18. package/dist/cjs/components/image/image.js +1 -2
  19. package/dist/cjs/components/link/link.js +1 -1
  20. package/dist/cjs/components/link-card/link-card.js +1 -2
  21. package/dist/cjs/components/mermaid/mermaid.d.ts +6 -0
  22. package/dist/cjs/components/{code-block/code-block-mermaid.js → mermaid/mermaid.js} +9 -8
  23. package/dist/cjs/components/youtube/youtube.js +1 -1
  24. package/dist/cjs/index.d.ts +4 -1
  25. package/dist/cjs/index.js +48 -5
  26. package/dist/esm/components/code-block/code-block-copy-button.d.mts +13 -2
  27. package/dist/esm/components/code-block/code-block-copy-button.mjs +2 -2
  28. package/dist/esm/components/code-block/code-block-icon.d.mts +38 -4
  29. package/dist/esm/components/code-block/code-block-icon.mjs +25 -1
  30. package/dist/esm/components/code-block/code-block.d.mts +1 -1
  31. package/dist/esm/components/code-block/code-block.mjs +3 -9
  32. package/dist/esm/components/code-block/directory-tree-item.d.mts +15 -0
  33. package/dist/esm/components/code-block/directory-tree-item.mjs +8 -0
  34. package/dist/esm/components/code-block/directory-tree.d.mts +13 -0
  35. package/dist/esm/components/code-block/directory-tree.mjs +13 -0
  36. package/dist/esm/components/code-block/parse-tree-output.d.mts +26 -0
  37. package/dist/esm/components/code-block/parse-tree-output.mjs +87 -0
  38. package/dist/esm/components/code-block/shiki.mjs +21 -8
  39. package/dist/esm/components/gist/gist.d.mts +6 -0
  40. package/dist/esm/components/gist/gist.mjs +25 -0
  41. package/dist/esm/components/heading/heading.d.mts +6 -0
  42. package/dist/esm/components/heading/heading.mjs +9 -0
  43. package/dist/esm/components/image/image.mjs +1 -2
  44. package/dist/esm/components/link/link.mjs +1 -1
  45. package/dist/esm/components/link-card/link-card.mjs +1 -2
  46. package/dist/esm/components/mermaid/mermaid.d.mts +6 -0
  47. package/dist/esm/components/{code-block/code-block-mermaid.mjs → mermaid/mermaid.mjs} +6 -5
  48. package/dist/esm/components/youtube/youtube.mjs +1 -1
  49. package/dist/esm/index.d.mts +4 -1
  50. package/dist/esm/index.mjs +22 -1
  51. package/package.json +23 -36
  52. package/dist/cjs/components/code-block/code-block-kifu.d.ts +0 -9
  53. package/dist/cjs/components/code-block/code-block-mermaid.d.ts +0 -8
  54. package/dist/cjs/components/index.d.ts +0 -9
  55. package/dist/cjs/components/kifu-to/kifu-to.d.ts +0 -6
  56. package/dist/esm/components/code-block/code-block-kifu.d.mts +0 -9
  57. package/dist/esm/components/code-block/code-block-kifu.mjs +0 -36
  58. package/dist/esm/components/code-block/code-block-mermaid.d.mts +0 -8
  59. package/dist/esm/components/index.d.mts +0 -9
  60. package/dist/esm/components/index.mjs +0 -16
  61. package/dist/esm/components/kifu-to/kifu-to.d.mts +0 -6
  62. package/dist/esm/components/kifu-to/kifu-to.mjs +0 -11
  63. package/dist/style.module.css +0 -280
  64. package/dist/style.module.scss.d.ts +0 -9
@@ -27,11 +27,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
27
  mod
28
28
  ));
29
29
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
- var code_block_mermaid_exports = {};
31
- __export(code_block_mermaid_exports, {
32
- default: () => CodeBlockMermaid
30
+ var mermaid_exports = {};
31
+ __export(mermaid_exports, {
32
+ default: () => Mermaid
33
33
  });
34
- module.exports = __toCommonJS(code_block_mermaid_exports);
34
+ module.exports = __toCommonJS(mermaid_exports);
35
35
  var import_crypto = require("crypto");
36
36
  var import_mermaid = __toESM(require("mermaid"));
37
37
  var import_next_themes = require("next-themes");
@@ -41,7 +41,7 @@ function createId(code) {
41
41
  hash.update(code);
42
42
  return "id-" + hash.digest("hex");
43
43
  }
44
- function CodeBlockMermaid({ code }) {
44
+ function Mermaid({ code }) {
45
45
  const ref = (0, import_react.useRef)(null);
46
46
  const [mounted, setMounted] = (0, import_react.useState)(false);
47
47
  const [svg, setSvg] = (0, import_react.useState)("");
@@ -65,7 +65,8 @@ function CodeBlockMermaid({ code }) {
65
65
  };
66
66
  renderMermaid();
67
67
  }, [mounted, code, id, theme, systemTheme, setSvg, setMounted]);
68
- if (!mounted)
69
- return /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", null, "Loading..."));
70
- return /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement("div", { dangerouslySetInnerHTML: { __html: svg }, ref }));
68
+ if (!mounted) {
69
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "mermaid-block mermaid-loading" }, /* @__PURE__ */ import_react.default.createElement("div", null, "Loading..."));
70
+ }
71
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "mermaid-block", dangerouslySetInnerHTML: { __html: svg }, ref });
71
72
  }
@@ -35,5 +35,5 @@ var import_google = require("@next/third-parties/google");
35
35
  var import_react = __toESM(require("react"));
36
36
  async function Youtube({ videoId, params, playLabel, ...props }) {
37
37
  const paramsString = params ? Object.entries(params).filter(([, value]) => value !== void 0).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&") : void 0;
38
- return /* @__PURE__ */ import_react.default.createElement(import_google.YouTubeEmbed, { ...props, videoid: videoId, params: paramsString, playlabel: playLabel });
38
+ return /* @__PURE__ */ import_react.default.createElement("div", { className: "youtube-block" }, /* @__PURE__ */ import_react.default.createElement(import_google.YouTubeEmbed, { ...props, videoid: videoId, params: paramsString, playlabel: playLabel }));
39
39
  }
@@ -1,8 +1,11 @@
1
1
  export { default as CodeBlock } from './components/code-block/code-block.js';
2
+ export { default as DirectoryTree } from './components/code-block/directory-tree.js';
3
+ export { default as Gist } from './components/gist/gist.js';
4
+ export { default as Heading } from './components/heading/heading.js';
2
5
  export { default as Image } from './components/image/image.js';
3
- export { default as KifuTo } from './components/kifu-to/kifu-to.js';
4
6
  export { default as Link } from './components/link/link.js';
5
7
  export { default as LinkCard } from './components/link-card/link-card.js';
8
+ export { default as Mermaid } from './components/mermaid/mermaid.js';
6
9
  export { default as XPost } from './components/x-post/x-post.js';
7
10
  export { default as Youtube } from './components/youtube/youtube.js';
8
11
  import 'react';
package/dist/cjs/index.js CHANGED
@@ -1,8 +1,14 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
6
12
  var __copyProps = (to, from, except, desc) => {
7
13
  if (from && typeof from === "object" || typeof from === "function") {
8
14
  for (let key of __getOwnPropNames(from))
@@ -11,12 +17,49 @@ var __copyProps = (to, from, except, desc) => {
11
17
  }
12
18
  return to;
13
19
  };
14
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
15
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
16
- var src_exports = {};
17
- module.exports = __toCommonJS(src_exports);
18
- __reExport(src_exports, require("./components"), module.exports);
29
+ var index_exports = {};
30
+ __export(index_exports, {
31
+ CodeBlock: () => import_code_block.default,
32
+ DirectoryTree: () => import_directory_tree.default,
33
+ Gist: () => import_gist.default,
34
+ Heading: () => import_heading.default,
35
+ Image: () => import_image.default,
36
+ Link: () => import_link.default,
37
+ LinkCard: () => import_link_card.default,
38
+ Mermaid: () => import_mermaid.default,
39
+ XPost: () => import_x_post.default,
40
+ Youtube: () => import_youtube.default
41
+ });
42
+ module.exports = __toCommonJS(index_exports);
43
+ var import_code_block = __toESM(require("./components/code-block/code-block"));
44
+ var import_directory_tree = __toESM(require("./components/code-block/directory-tree"));
45
+ var import_gist = __toESM(require("./components/gist/gist"));
46
+ var import_heading = __toESM(require("./components/heading/heading"));
47
+ var import_image = __toESM(require("./components/image/image"));
48
+ var import_link = __toESM(require("./components/link/link"));
49
+ var import_link_card = __toESM(require("./components/link-card/link-card"));
50
+ var import_mermaid = __toESM(require("./components/mermaid/mermaid"));
51
+ var import_x_post = __toESM(require("./components/x-post/x-post"));
52
+ var import_youtube = __toESM(require("./components/youtube/youtube"));
19
53
  // Annotate the CommonJS export names for ESM import in node:
20
54
  0 && (module.exports = {
21
- ...require("./components")
55
+ CodeBlock,
56
+ DirectoryTree,
57
+ Gist,
58
+ Heading,
59
+ Image,
60
+ Link,
61
+ LinkCard,
62
+ Mermaid,
63
+ XPost,
64
+ Youtube
22
65
  });
@@ -1,8 +1,19 @@
1
1
  import React from 'react';
2
2
 
3
- interface CodeBlockCopyButtonProps {
3
+ type CodeBlockCopyButtonProps = {
4
4
  code: string;
5
- }
5
+ };
6
+ /**
7
+ * コードブロック用のコピー ボタンコンポーネント。
8
+ *
9
+ * 与えられた code をクリップボードに書き込み、コピー完了時にアイコンをチェックに切り替えます。
10
+ *
11
+ * @param props.code コピー対象のコード文字列(Shiki 注釈が含まれている可能性あり)。
12
+ * @returns コピー用ボタンの React 要素。
13
+ *
14
+ * @remarks
15
+ * ブラウザの navigator.clipboard を使用します。ユーザーの環境によっては権限や HTTPS が必要です。
16
+ */
6
17
  declare function CodeBlockCopyButton({ code }: CodeBlockCopyButtonProps): React.JSX.Element;
7
18
 
8
19
  export { type CodeBlockCopyButtonProps, CodeBlockCopyButton as default };
@@ -1,16 +1,16 @@
1
1
  "use client";
2
2
  import React, { useState } from "react";
3
3
  import { HiOutlineClipboardDocumentList, HiCheck } from "react-icons/hi2";
4
+ const removeShikiCode = (code) => code.replace(/ *\/\/.*\[!code[^\]]+\]/gm, "").trim();
4
5
  function CodeBlockCopyButton({ code }) {
5
6
  const [copied, setCopied] = useState(false);
6
- const removeShikiCode = (code2) => code2.replace(/ *\/\/.*\[!code[^\]]+\]/gm, "").trim();
7
7
  const handleClick = () => {
8
8
  navigator.clipboard.writeText(removeShikiCode(code)).then(() => {
9
9
  setCopied(true);
10
10
  setTimeout(() => setCopied(false), 1e3);
11
11
  });
12
12
  };
13
- return /* @__PURE__ */ React.createElement("button", { onClick: handleClick }, copied ? /* @__PURE__ */ React.createElement(HiCheck, { size: 18 }) : /* @__PURE__ */ React.createElement(HiOutlineClipboardDocumentList, { size: 18 }));
13
+ return /* @__PURE__ */ React.createElement("button", { onClick: handleClick, "aria-label": "Copy code to clipboard" }, copied ? /* @__PURE__ */ React.createElement(HiCheck, { size: 18 }) : /* @__PURE__ */ React.createElement(HiOutlineClipboardDocumentList, { size: 18 }));
14
14
  }
15
15
  export {
16
16
  CodeBlockCopyButton as default
@@ -1,8 +1,42 @@
1
- import React from 'react';
1
+ import { JSX } from 'react';
2
2
 
3
- interface CodeBlockIconProps {
3
+ /**
4
+ * CodeBlockIcon コンポーネントの props 型定義。
5
+ *
6
+ * `language` プロパティに基づいて、コードブロックに表示する代表的なアイコンを返します。
7
+ * 小文字の言語識別子(例: `"typescript"`, `"bash"`, `"json"`, `"markdown"`)を想定しています。
8
+ * 未知の値やサポート外の値は汎用のコードアイコンにフォールバックします。
9
+ */
10
+ type CodeBlockIconProps = {
11
+ /**
12
+ * アイコン選択に用いる言語識別子(小文字推奨)。例: 'typescript', 'bash', 'json'
13
+ */
4
14
  language: string;
5
- }
6
- declare function CodeBlockIcon({ language }: CodeBlockIconProps): React.JSX.Element;
15
+ };
16
+ /**
17
+ * 指定された言語に対応するアイコンを返すコンポーネント。
18
+ *
19
+ * 共通の言語識別子を `react-icons` のアイコンにマッピングします。
20
+ * 認識できない言語は汎用の括弧(コード)アイコンに置き換わります。
21
+ *
22
+ * 使用例:
23
+ *
24
+ * ```tsx
25
+ * <CodeBlockIcon language="typescript" />
26
+ * ```
27
+ *
28
+ * サポート例(非網羅):
29
+ * - 'bash' | 'sh' -> ターミナルアイコン
30
+ * - 'typescript' -> TypeScript アイコン
31
+ * - 'tsx' -> React アイコン
32
+ * - 'json' -> JSON アイコン
33
+ * - 'markdown' -> Markdown アイコン
34
+ * - 'hcl' -> Terraform アイコン
35
+ * - 'php', 'ruby', 'yaml', 'text' など
36
+ *
37
+ * @param props.language アイコン選択に用いる小文字の言語名
38
+ * @returns 選択されたアイコンを含む JSX 要素
39
+ */
40
+ declare function CodeBlockIcon({ language }: CodeBlockIconProps): JSX.Element;
7
41
 
8
42
  export { type CodeBlockIconProps, CodeBlockIcon as default };
@@ -1,7 +1,19 @@
1
1
  import React from "react";
2
2
  import { FaTerminal, FaReact } from "react-icons/fa6";
3
3
  import { HiCodeBracket } from "react-icons/hi2";
4
- import { SiTypescript, SiTerraform, SiMarkdown, SiPhp, SiRuby, SiYaml } from "react-icons/si";
4
+ import {
5
+ SiTypescript,
6
+ SiTerraform,
7
+ SiMarkdown,
8
+ SiPhp,
9
+ SiRuby,
10
+ SiYaml,
11
+ SiJavascript,
12
+ SiPython,
13
+ SiKotlin,
14
+ SiGo,
15
+ SiRust
16
+ } from "react-icons/si";
5
17
  import { TbTxt } from "react-icons/tb";
6
18
  import { VscJson } from "react-icons/vsc";
7
19
  function CodeBlockIcon({ language }) {
@@ -9,6 +21,18 @@ function CodeBlockIcon({ language }) {
9
21
  case "sh":
10
22
  case "bash":
11
23
  return /* @__PURE__ */ React.createElement(FaTerminal, null);
24
+ case "js":
25
+ case "javascript":
26
+ return /* @__PURE__ */ React.createElement(SiJavascript, null);
27
+ case "py":
28
+ case "python":
29
+ return /* @__PURE__ */ React.createElement(SiPython, null);
30
+ case "kotlin":
31
+ return /* @__PURE__ */ React.createElement(SiKotlin, null);
32
+ case "go":
33
+ return /* @__PURE__ */ React.createElement(SiGo, null);
34
+ case "rust":
35
+ return /* @__PURE__ */ React.createElement(SiRust, null);
12
36
  case "hcl":
13
37
  return /* @__PURE__ */ React.createElement(SiTerraform, null);
14
38
  case "typescript":
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { CodeBlockComponentProps } from '@hackersheet/react-document-content';
3
3
 
4
- declare function CodeBlock({ code, language }: CodeBlockComponentProps): Promise<React.JSX.Element>;
4
+ declare function CodeBlock({ code, ...props }: CodeBlockComponentProps): Promise<React.JSX.Element>;
5
5
 
6
6
  export { CodeBlock as default };
@@ -1,16 +1,10 @@
1
1
  import React from "react";
2
2
  import CodeBlockCopyButton from "./code-block-copy-button";
3
3
  import CodeBlockIcon from "./code-block-icon";
4
- import CodeBlockKifu from "./code-block-kifu";
5
- import CodeBlockMermaid from "./code-block-mermaid";
6
4
  import { highlighteCode } from "./shiki";
7
- async function CodeBlock({ code, language }) {
8
- const [lang, filename] = language.split(":");
9
- const isMermaid = lang === "mermaid";
10
- const isKifu = lang === "kifu";
11
- if (isMermaid) return /* @__PURE__ */ React.createElement(CodeBlockMermaid, { code });
12
- if (isKifu) return /* @__PURE__ */ React.createElement(CodeBlockKifu, { kifu: code, filename });
13
- const html = await highlighteCode(code, lang);
5
+ async function CodeBlock({ code, ...props }) {
6
+ const [language, filename] = props.language.split(":");
7
+ const html = await highlighteCode(code, language);
14
8
  return /* @__PURE__ */ React.createElement("div", { className: "code-block" }, /* @__PURE__ */ React.createElement("div", { className: "code-block-header" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(CodeBlockIcon, { language })), /* @__PURE__ */ React.createElement("div", { className: "code-block-filename" }, filename), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(CodeBlockCopyButton, { code }))), html && /* @__PURE__ */ React.createElement("div", { dangerouslySetInnerHTML: { __html: html } }), !html && /* @__PURE__ */ React.createElement("pre", null, code));
15
9
  }
16
10
  export {
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { TreeNode } from './parse-tree-output.mjs';
3
+
4
+ type DirectoryTreeItemProps = {
5
+ node: TreeNode;
6
+ };
7
+ /**
8
+ * 単一のツリーノード(ディレクトリまたはファイル)をレンダリングするコンポーネント。
9
+ * 再帰的に自身を呼び出して子ノードを描画します。
10
+ *
11
+ * @param props.node - 表示対象の TreeNode
12
+ */
13
+ declare function DirectoryTreeItem({ node }: DirectoryTreeItemProps): React.JSX.Element;
14
+
15
+ export { DirectoryTreeItem as default };
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import { LuFolder, LuFile } from "react-icons/lu";
3
+ function DirectoryTreeItem({ node }) {
4
+ return /* @__PURE__ */ React.createElement("li", { key: node.id, className: `${node.type === "directory" ? "directory-tree-directory" : "directory-tree-file"}` }, /* @__PURE__ */ React.createElement("div", { className: "directory-tree-node-content" }, /* @__PURE__ */ React.createElement("div", { className: "directory-tree-icon" }, node.type === "directory" && /* @__PURE__ */ React.createElement(LuFolder, null), node.type === "file" && /* @__PURE__ */ React.createElement(LuFile, null)), /* @__PURE__ */ React.createElement("div", null, node.name)), node.children && /* @__PURE__ */ React.createElement("ul", null, node.children.map((child) => /* @__PURE__ */ React.createElement(DirectoryTreeItem, { key: child.id, node: child }))));
5
+ }
6
+ export {
7
+ DirectoryTreeItem as default
8
+ };
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { DirectoryTreeComponentProps } from '@hackersheet/react-document-content';
3
+
4
+ /**
5
+ * code ブロック内の `tree` コマンド出力をパースしてツリーをレンダリングするコンポーネント。
6
+ * ヘッダにはツリーアイコン、ファイル名(language のコロン以降)、コピー用ボタンを表示します。
7
+ *
8
+ * @param props.code - `tree` コマンドの出力テキスト
9
+ * @param props.language - 言語/ファイル名情報(形式: "xxx:filename")
10
+ */
11
+ declare function DirectoryTree({ code, ...props }: DirectoryTreeComponentProps): Promise<React.JSX.Element>;
12
+
13
+ export { DirectoryTree as default };
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ import { LuFolderTree } from "react-icons/lu";
3
+ import CodeBlockCopyButton from "./code-block-copy-button";
4
+ import DirectoryTreeItem from "./directory-tree-item";
5
+ import parseTreeOutput from "./parse-tree-output";
6
+ async function DirectoryTree({ code, ...props }) {
7
+ const [, filename] = props.language.split(":");
8
+ const treeNode = parseTreeOutput(code);
9
+ return /* @__PURE__ */ React.createElement("div", { className: "code-block" }, /* @__PURE__ */ React.createElement("div", { className: "code-block-header" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(LuFolderTree, null)), /* @__PURE__ */ React.createElement("div", { className: "code-block-filename" }, filename), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement(CodeBlockCopyButton, { code }))), /* @__PURE__ */ React.createElement("div", null, treeNode ? /* @__PURE__ */ React.createElement("ul", { className: "directory-tree" }, /* @__PURE__ */ React.createElement(DirectoryTreeItem, { node: treeNode })) : /* @__PURE__ */ React.createElement("pre", null, code)));
10
+ }
11
+ export {
12
+ DirectoryTree as default
13
+ };
@@ -0,0 +1,26 @@
1
+ type TreeNode = {
2
+ id: string;
3
+ name: string;
4
+ type: 'file' | 'directory';
5
+ extension?: string;
6
+ level: number;
7
+ children?: TreeNode[];
8
+ };
9
+ /**
10
+ * `tree` コマンドの出力(box-drawing を含むテキスト)をパースして TreeNode のツリー構造を返します。
11
+ *
12
+ * @remarks
13
+ * - 入力は Linux/macOS の `tree` コマンドの標準出力を想定しています。
14
+ * - 行先頭の箱線文字(`│`, `├`, `└`, `─`)や 4 スペースインデントを解析して階層を決定します。
15
+ * - 最後に出力されるサマリ行(例: `3 directories, 5 files`)は自動的に除外します。
16
+ * - 子要素が存在する行のみをディレクトリと見なすルールを採用しています(子要素が無ければファイル)。
17
+ * - 解析中に例外が発生した場合は `null` を返します(呼び出し元でフォールバック処理を行ってください)。
18
+ *
19
+ * @param treeOutput - `tree` コマンドで得られたテキスト全体
20
+ * @returns 解析に成功した場合はルート `TreeNode`、失敗または空入力の場合は `null`
21
+ *
22
+ * @complexity O(n) - 入力行数 n に対して一度の走査で処理します(追加で逆順集計を行うためメモリは O(n))。
23
+ */
24
+ declare function parseTreeOutput(treeOutput: string): TreeNode | null;
25
+
26
+ export { type TreeNode, parseTreeOutput as default, parseTreeOutput };
@@ -0,0 +1,87 @@
1
+ import { createHash } from "crypto";
2
+ function encryptSha256(str) {
3
+ const hash = createHash("sha256");
4
+ hash.update(str);
5
+ return hash.digest("hex");
6
+ }
7
+ function parseTreeOutput(treeOutput) {
8
+ const raw = treeOutput.replace(/\r/g, "").trim();
9
+ if (!raw) return null;
10
+ const lines = raw.split("\n");
11
+ const filteredLines = lines.filter(
12
+ (l) => !/^\s*(?:\d+\s+directories?,\s*\d+\s+files?|\d+\s+directories?|\d+\s+files?)\s*$/i.test(l)
13
+ );
14
+ const idPrefix = "tree-" + encryptSha256(raw) + "-";
15
+ const rootNode = {
16
+ id: idPrefix + "root",
17
+ name: "",
18
+ type: "directory",
19
+ level: 0,
20
+ children: []
21
+ };
22
+ const stack = [{ node: rootNode, level: 0 }];
23
+ const getExtension = (filename) => filename.match(/\.(\w+)$/)?.[1];
24
+ const cleanNodeName = (name) => name.replace(/^[\s│├└─]+/, "").trim();
25
+ try {
26
+ const treeLineRegex = /^(?<prefix>(?:│\s{3}|\s{4})*)(?<connector>├── |└── )?(?<name>.*)$/;
27
+ const lineInfos = filteredLines.map((ln) => {
28
+ const normalized = ln.replace(/\t/g, " ");
29
+ const m = normalized.match(treeLineRegex);
30
+ if (m && m.groups) {
31
+ const prefix = m.groups["prefix"] || "";
32
+ const connector = m.groups["connector"] || "";
33
+ const name = (m.groups["name"] || "").trim();
34
+ const groupMatches = prefix.match(/(?:│\s{3}|\s{4})/g);
35
+ const level = (groupMatches ? groupMatches.length : 0) + (connector ? 1 : 0);
36
+ return { rawLine: normalized, level, cleanedName: cleanNodeName(name) };
37
+ }
38
+ return { rawLine: normalized, level: 0, cleanedName: cleanNodeName(normalized.trim()) };
39
+ });
40
+ const reduceResult = lineInfos.reduceRight(
41
+ (acc, info) => ({
42
+ lastLevel: info.rawLine.trim() ? info.level : acc.lastLevel,
43
+ nextLevels: [acc.lastLevel, ...acc.nextLevels]
44
+ }),
45
+ { lastLevel: null, nextLevels: [] }
46
+ );
47
+ const nextNonEmptyLevel = reduceResult.nextLevels;
48
+ lineInfos.forEach((info, index) => {
49
+ const level = info.level;
50
+ const cleanedLine = info.cleanedName;
51
+ if (level === 0 && rootNode.name === "") {
52
+ rootNode.name = cleanedLine;
53
+ return;
54
+ }
55
+ const nextLevelForLine = nextNonEmptyLevel[index];
56
+ const isDirectory = nextLevelForLine != null && nextLevelForLine > level;
57
+ const newNode = {
58
+ id: idPrefix + "node-" + index,
59
+ name: cleanedLine,
60
+ type: isDirectory ? "directory" : "file",
61
+ extension: isDirectory ? void 0 : getExtension(cleanedLine),
62
+ level,
63
+ children: isDirectory ? [] : void 0
64
+ };
65
+ while (stack.length > 0 && stack[stack.length - 1].level >= level) {
66
+ stack.pop();
67
+ }
68
+ if (stack[stack.length - 1] === void 0) {
69
+ throw new Error("Tree parsing failed");
70
+ }
71
+ const parentNode = stack[stack.length - 1].node;
72
+ parentNode.children = parentNode.children || [];
73
+ parentNode.children.push(newNode);
74
+ if (newNode.type === "directory") {
75
+ stack.push({ node: newNode, level });
76
+ }
77
+ });
78
+ return rootNode;
79
+ } catch {
80
+ return null;
81
+ }
82
+ }
83
+ var parse_tree_output_default = parseTreeOutput;
84
+ export {
85
+ parse_tree_output_default as default,
86
+ parseTreeOutput
87
+ };
@@ -1,26 +1,39 @@
1
- import { transformerNotationDiff, transformerNotationWordHighlight } from "@shikijs/transformers";
1
+ import {
2
+ transformerNotationDiff,
3
+ transformerNotationWordHighlight,
4
+ transformerRemoveNotationEscape,
5
+ transformerNotationHighlight
6
+ } from "@shikijs/transformers";
2
7
  import { cache } from "react";
3
- import { bundledLanguages, bundledThemes, getSingletonHighlighter } from "shiki";
8
+ import { bundledLanguages, getSingletonHighlighterCore } from "shiki/bundle/web";
9
+ import { createJavaScriptRegexEngine } from "shiki/engine/javascript";
4
10
  async function highlighteCode(code, language) {
5
11
  const highlighter = await getShikiHighlighter();
6
- const shikiLang = Object.keys(bundledLanguages).find((lang) => lang === language);
12
+ const shikiLangs = highlighter.getLoadedLanguages();
13
+ const shikiLang = shikiLangs.find((lang) => lang === language);
7
14
  if (shikiLang === void 0 && language !== "text") {
8
15
  return null;
9
16
  }
10
- const html = highlighter.codeToHtml(code, {
17
+ const html = highlighter.codeToHtml(code.trim(), {
11
18
  lang: shikiLang || "text",
12
19
  themes: {
13
20
  light: "github-light",
14
21
  dark: "github-dark-dimmed"
15
22
  },
16
- transformers: [transformerNotationDiff(), transformerNotationWordHighlight()]
23
+ transformers: [
24
+ transformerNotationDiff(),
25
+ transformerNotationHighlight(),
26
+ transformerNotationWordHighlight(),
27
+ transformerRemoveNotationEscape()
28
+ ]
17
29
  });
18
30
  return html;
19
31
  }
20
32
  const getShikiHighlighter = cache(async () => {
21
- return getSingletonHighlighter({
22
- themes: Object.keys(bundledThemes),
23
- langs: Object.keys(bundledLanguages)
33
+ return getSingletonHighlighterCore({
34
+ themes: [import("@shikijs/themes/github-light"), import("@shikijs/themes/github-dark-dimmed")],
35
+ langs: Object.values(bundledLanguages),
36
+ engine: createJavaScriptRegexEngine()
24
37
  });
25
38
  });
26
39
  export {
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { GistComponentProps } from '@hackersheet/react-document-content';
3
+
4
+ declare function Gist({ gistId, username, filename }: GistComponentProps): Promise<React.JSX.Element>;
5
+
6
+ export { Gist as default };
@@ -0,0 +1,25 @@
1
+ import Script from "next/script";
2
+ import React from "react";
3
+ async function Gist({ gistId, username, filename }) {
4
+ const gistUrl = (() => {
5
+ const base = `https://gist.github.com/${username}/${gistId}.json`;
6
+ if (filename) {
7
+ return base + `?file=${filename}`;
8
+ }
9
+ return base;
10
+ })();
11
+ const result = await fetch(gistUrl);
12
+ const json = await result.json();
13
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
14
+ "div",
15
+ {
16
+ className: "gist-block",
17
+ dangerouslySetInnerHTML: {
18
+ __html: json.div
19
+ }
20
+ }
21
+ ), /* @__PURE__ */ React.createElement(Script, { stylesheets: [json.stylesheet] }));
22
+ }
23
+ export {
24
+ Gist as default
25
+ };
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { HeadingComponentProps } from '@hackersheet/react-document-content';
3
+
4
+ declare function Heading({ HeadingTag, id, children }: HeadingComponentProps): React.JSX.Element;
5
+
6
+ export { Heading as default };
@@ -0,0 +1,9 @@
1
+ import Link from "next/link";
2
+ import React from "react";
3
+ import { MdLink } from "react-icons/md";
4
+ function Heading({ HeadingTag, id, children }) {
5
+ return /* @__PURE__ */ React.createElement(HeadingTag, { id, className: "heading" }, /* @__PURE__ */ React.createElement(Link, { href: `#${id}`, prefetch: false }, /* @__PURE__ */ React.createElement("span", { className: "heading-label" }, children), /* @__PURE__ */ React.createElement("span", { className: "heading-link-icon" }, /* @__PURE__ */ React.createElement(MdLink, null))));
6
+ }
7
+ export {
8
+ Heading as default
9
+ };
@@ -1,7 +1,6 @@
1
- import NextImage from "next/image";
2
1
  import React from "react";
3
2
  function Image({ src, width, height, alt }) {
4
- return /* @__PURE__ */ React.createElement(NextImage, { src, width, height, alt });
3
+ return /* @__PURE__ */ React.createElement("picture", null, /* @__PURE__ */ React.createElement("img", { src, width, height, alt }));
5
4
  }
6
5
  export {
7
6
  Image as default
@@ -1,7 +1,7 @@
1
1
  import NextLink from "next/link";
2
2
  import React from "react";
3
3
  function Link({ href, id, children }) {
4
- return /* @__PURE__ */ React.createElement(NextLink, { href, id }, children);
4
+ return /* @__PURE__ */ React.createElement(NextLink, { href, id, prefetch: false }, children);
5
5
  }
6
6
  export {
7
7
  Link as default
@@ -1,4 +1,3 @@
1
- import Image from "next/image";
2
1
  import React from "react";
3
2
  function LinkCard({
4
3
  domain,
@@ -10,7 +9,7 @@ function LinkCard({
10
9
  imageWidth
11
10
  }) {
12
11
  const faviconUrl = `https://t1.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://${domain}&size=16`;
13
- return /* @__PURE__ */ React.createElement("a", { href: url, className: "link-card" }, /* @__PURE__ */ React.createElement("div", { className: "link-card-main" }, /* @__PURE__ */ React.createElement("div", { className: "link-card-title" }, title), /* @__PURE__ */ React.createElement("div", { className: "link-card-description" }, description), /* @__PURE__ */ React.createElement("div", { className: "link-card-domain" }, /* @__PURE__ */ React.createElement("picture", null, /* @__PURE__ */ React.createElement("img", { src: faviconUrl, alt: `${domain} favicon`, width: 16, height: 16 })), /* @__PURE__ */ React.createElement("div", null, domain))), imageUrl && /* @__PURE__ */ React.createElement("div", { className: "link-card-image" }, /* @__PURE__ */ React.createElement(Image, { alt: title, src: imageUrl, height: imageHeight, width: imageWidth })));
12
+ return /* @__PURE__ */ React.createElement("a", { href: url, className: "link-card" }, /* @__PURE__ */ React.createElement("div", { className: "link-card-main" }, /* @__PURE__ */ React.createElement("div", { className: "link-card-title-container" }, /* @__PURE__ */ React.createElement("div", { className: "link-card-title" }, title)), /* @__PURE__ */ React.createElement("div", { className: "link-card-description" }, description), /* @__PURE__ */ React.createElement("div", { className: "link-card-domain" }, /* @__PURE__ */ React.createElement("picture", null, /* @__PURE__ */ React.createElement("img", { src: faviconUrl, alt: `${domain} favicon`, width: 16, height: 16 })), /* @__PURE__ */ React.createElement("div", null, domain))), imageUrl && /* @__PURE__ */ React.createElement("picture", { className: "link-card-image" }, /* @__PURE__ */ React.createElement("img", { alt: title, src: imageUrl, height: imageHeight, width: imageWidth })));
14
13
  }
15
14
  export {
16
15
  LinkCard as default
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { MermaidComponentProps } from '@hackersheet/react-document-content';
3
+
4
+ declare function Mermaid({ code }: MermaidComponentProps): React.JSX.Element;
5
+
6
+ export { Mermaid as default };
@@ -8,7 +8,7 @@ function createId(code) {
8
8
  hash.update(code);
9
9
  return "id-" + hash.digest("hex");
10
10
  }
11
- function CodeBlockMermaid({ code }) {
11
+ function Mermaid({ code }) {
12
12
  const ref = useRef(null);
13
13
  const [mounted, setMounted] = useState(false);
14
14
  const [svg, setSvg] = useState("");
@@ -32,10 +32,11 @@ function CodeBlockMermaid({ code }) {
32
32
  };
33
33
  renderMermaid();
34
34
  }, [mounted, code, id, theme, systemTheme, setSvg, setMounted]);
35
- if (!mounted)
36
- return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", null, "Loading..."));
37
- return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { dangerouslySetInnerHTML: { __html: svg }, ref }));
35
+ if (!mounted) {
36
+ return /* @__PURE__ */ React.createElement("div", { className: "mermaid-block mermaid-loading" }, /* @__PURE__ */ React.createElement("div", null, "Loading..."));
37
+ }
38
+ return /* @__PURE__ */ React.createElement("div", { className: "mermaid-block", dangerouslySetInnerHTML: { __html: svg }, ref });
38
39
  }
39
40
  export {
40
- CodeBlockMermaid as default
41
+ Mermaid as default
41
42
  };