hakoniwa-term 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
- # hakoniwa-term (箱庭-term)
2
-
3
- A programmable, retro hacker-style terminal UI component for React applications with complete style isolation.
4
-
5
- ## what is hakoniwa(箱庭)?
6
- >In Japanese, 「箱庭(はこにわ / hakoniwa)」literally means “box garden.”
7
- Originally it refers to a small, self‑contained miniature garden or landscape arranged inside a box or tray—like tiny rocks, plants, and buildings forming a little world you can look into from the outside.
8
-
9
- ## screenshot
10
- ![screenshot](resources/screenshot_hakoniwa_term.png)
11
-
12
- ## sample
13
- codesandbox: https://codesandbox.io/p/sandbox/my9kn2
1
+ # hakoniwa-term (箱庭-term)
2
+
3
+ A programmable, retro hacker-style terminal UI component for React applications with complete style isolation.
4
+
5
+ ## what is hakoniwa(箱庭)?
6
+ >In Japanese, 「箱庭(はこにわ / hakoniwa)」literally means “box garden.”
7
+ Originally it refers to a small, self‑contained miniature garden or landscape arranged inside a box or tray—like tiny rocks, plants, and buildings forming a little world you can look into from the outside.
8
+
9
+ ## screenshot
10
+ ![screenshot](resources/screenshot_hakoniwa_term.png)
11
+
12
+ ## sample
13
+ codesandbox: https://codesandbox.io/p/sandbox/my9kn2
package/package.json CHANGED
@@ -1,55 +1,55 @@
1
- {
2
- "name": "hakoniwa-term",
3
- "version": "0.0.2",
4
- "description": "A robust, pluggable retro terminal engine for React, powered by CSS Modules and Async Generators.",
5
- "author": "koji <baxin1919@gmail.com>",
6
- "homepage": "https://github.com/koji/hakoniwa-term",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/koji/hakoniwa-term.git"
10
- },
11
- "main": "./dist/index.cjs",
12
- "module": "./dist/index.js",
13
- "types": "./dist/index.d.ts",
14
- "exports": {
15
- ".": {
16
- "require": "./dist/index.cjs",
17
- "import": "./dist/index.js",
18
- "types": "./dist/index.d.ts"
19
- },
20
- "./dist/index.css": "./dist/index.css"
21
- },
22
- "files": [
23
- "dist"
24
- ],
25
- "scripts": {
26
- "build": "vite build"
27
- },
28
- "peerDependencies": {
29
- "react": "^18.0.0 || ^19.0.0",
30
- "react-dom": "^18.0.0 || ^19.0.0"
31
- },
32
- "dependencies": {
33
- "lucide-react": "^0.470.0"
34
- },
35
- "devDependencies": {
36
- "@types/react": "^19.0.0",
37
- "@vitejs/plugin-react": "^4.3.0",
38
- "typescript": "^5.9.3",
39
- "vite": "8.1.3",
40
- "vite-plugin-dts": "^4.4.0"
41
- },
42
- "keywords": [
43
- "react",
44
- "terminal",
45
- "cli-ui",
46
- "css-modules",
47
- "async-generator",
48
- "typescript",
49
- "vite"
50
- ],
51
- "license": "MIT",
52
- "publishConfig": {
53
- "access": "public"
54
- }
55
- }
1
+ {
2
+ "name": "hakoniwa-term",
3
+ "version": "0.0.3",
4
+ "description": "A robust, pluggable retro terminal engine for React, powered by CSS Modules and Async Generators.",
5
+ "author": "koji <baxin1919@gmail.com>",
6
+ "homepage": "https://github.com/koji/hakoniwa-term",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/koji/hakoniwa-term.git"
10
+ },
11
+ "main": "./dist/index.cjs",
12
+ "module": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "require": "./dist/index.cjs",
17
+ "import": "./dist/index.js",
18
+ "types": "./dist/index.d.ts"
19
+ },
20
+ "./dist/index.css": "./dist/index.css"
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "scripts": {
26
+ "build": "vite build"
27
+ },
28
+ "peerDependencies": {
29
+ "react": "^18.0.0 || ^19.0.0",
30
+ "react-dom": "^18.0.0 || ^19.0.0"
31
+ },
32
+ "dependencies": {
33
+ "lucide-react": "^0.470.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/react": "^19.0.0",
37
+ "@vitejs/plugin-react": "^4.3.0",
38
+ "typescript": "^5.9.3",
39
+ "vite": "8.1.3",
40
+ "vite-plugin-dts": "^4.4.0"
41
+ },
42
+ "keywords": [
43
+ "react",
44
+ "terminal",
45
+ "cli-ui",
46
+ "css-modules",
47
+ "async-generator",
48
+ "typescript",
49
+ "vite"
50
+ ],
51
+ "license": "MIT",
52
+ "publishConfig": {
53
+ "access": "public"
54
+ }
55
+ }
package/dist/index.cjs DELETED
@@ -1 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require("react");c=s(c);let l=require("lucide-react"),u=require("react/jsx-runtime");var d={terminalRoot:`_terminalRoot_16n8k_1`,titleBar:`_titleBar_16n8k_33`,titleLeft:`_titleLeft_16n8k_53`,titleText:`_titleText_16n8k_65`,titleRight:`_titleRight_16n8k_79`,closeButton:`_closeButton_16n8k_91`,contentBox:`_contentBox_16n8k_123`,logRow:`_logRow_16n8k_151`,logInput:`_logInput_16n8k_163`,logError:`_logError_16n8k_165`,logSuccess:`_logSuccess_16n8k_167`,logOutput:`_logOutput_16n8k_169`,progressBarContainer:`_progressBarContainer_16n8k_173`,progressHeader:`_progressHeader_16n8k_181`,progressTrack:`_progressTrack_16n8k_199`,progressBar:`_progressBar_16n8k_173`,inputForm:`_inputForm_16n8k_229`,prompt:`_prompt_16n8k_247`,inputField:`_inputField_16n8k_257`,submitButton:`_submitButton_16n8k_287`};function f({promptString:e=`user@terminal:~$`,placeholder:t=`Type a command...`,systemLockedText:n=`System locked during execution...`,commandNotFoundFormatter:r=e=>`Command not found: "${e}".`,initialHistory:i=[],commands:a,title:o=`terminal`,showCloseButton:s=!0,onClose:f,headerRightActions:p}){let[m,h]=(0,c.useState)(``),[g,_]=(0,c.useState)(i),[v,y]=(0,c.useState)(!1),[b,x]=(0,c.useState)(null),[S,C]=(0,c.useState)(``),w=(0,c.useRef)(null),T=(0,c.useRef)(null);(0,c.useEffect)(()=>{w.current&&(w.current.scrollTop=w.current.scrollHeight)},[g,b,S,v]);let E=()=>{T.current&&T.current.focus()},D=async t=>{t.preventDefault();let n=m.trim();if(!n||v)return;_(t=>[...t,{type:`input`,text:`${e} ${n}`}]),h(``);let i=n.split(` `),o=i[0].toLowerCase();if(o===`clear`){_([]);return}if(a&&a[o]){y(!0);try{let e=a[o](i);for await(let t of e)t.type===`log`?_(e=>[...e,t.log]):t.type===`progress`&&(x(t.percent),t.text&&C(t.text))}catch(e){_(t=>[...t,{type:`error`,text:`Execution error: ${e instanceof Error?e.message:String(e)}`}])}finally{y(!1),x(null),C(``)}}else _(e=>[...e,{type:`error`,text:r(o)}])},O=e=>e===`input`?d.logInput:e===`error`?d.logError:e===`success`?d.logSuccess:d.logOutput;return(0,u.jsxs)(`div`,{className:d.terminalRoot,onClick:E,children:[(0,u.jsxs)(`div`,{className:d.titleBar,children:[(0,u.jsxs)(`div`,{className:d.titleLeft,children:[(0,u.jsx)(l.Terminal,{className:`w-4 h-4`,style:{color:`#10b981`}}),(0,u.jsx)(`span`,{className:d.titleText,children:o})]}),(0,u.jsxs)(`div`,{className:d.titleRight,children:[p,s&&f&&(0,u.jsx)(`button`,{onClick:e=>{e.stopPropagation(),f()},className:d.closeButton,children:(0,u.jsx)(l.X,{className:`w-4 h-4`})})]})]}),(0,u.jsxs)(`div`,{ref:w,className:d.contentBox,children:[g.map((e,t)=>(0,u.jsx)(`div`,{className:`${d.logRow} ${O(e.type)}`,children:e.text},t)),b!==null&&(0,u.jsxs)(`div`,{className:d.progressBarContainer,children:[(0,u.jsxs)(`div`,{className:d.progressHeader,children:[(0,u.jsx)(`span`,{children:S}),(0,u.jsxs)(`span`,{children:[b,`%`]})]}),(0,u.jsx)(`div`,{className:d.progressTrack,children:(0,u.jsx)(`div`,{className:d.progressBar,style:{width:`${b}%`}})})]}),(0,u.jsxs)(`form`,{onSubmit:D,className:d.inputForm,children:[(0,u.jsx)(`span`,{className:d.prompt,children:e}),(0,u.jsx)(`input`,{ref:T,type:`text`,value:m,onChange:e=>h(e.target.value),disabled:v,placeholder:v?n:t,className:d.inputField,autoComplete:`off`,autoCorrect:`off`,autoCapitalize:`off`,spellCheck:`false`}),(0,u.jsx)(`button`,{type:`submit`,className:d.submitButton,children:(0,u.jsx)(l.CornerDownLeft,{className:`w-4 h-4`})})]})]})]})}exports.Terminal=f;
package/dist/index.css DELETED
@@ -1,2 +0,0 @@
1
- ._terminalRoot_16n8k_1{color:#34d399e6;z-index:10;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);background-color:#090a0ff2;border:1px solid #10b9814d;border-radius:.5rem;width:100%;max-width:56rem;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.875rem;position:relative;overflow:hidden;box-shadow:0 25px 50px -12px #00000040}._titleBar_16n8k_33{-webkit-user-select:none;user-select:none;background-color:#0e1017;border-bottom:1px solid #10b98133;justify-content:space-between;align-items:center;padding:.625rem 1rem;display:flex}._titleLeft_16n8k_53{align-items:center;gap:.5rem;display:flex}._titleText_16n8k_65{letter-spacing:.05em;color:#9ca3af;font-size:.75rem;font-weight:600}._titleRight_16n8k_79{align-items:center;gap:.5rem;display:flex}._closeButton_16n8k_91{cursor:pointer;color:#ef4444;background:0 0;border:none;border-radius:.25rem;align-items:center;padding:.125rem;transition:background-color .2s;display:flex}._closeButton_16n8k_91:hover{background-color:#ef444433}._contentBox_16n8k_123{height:24rem;padding:1.25rem;overflow-y:auto}._contentBox_16n8k_123::-webkit-scrollbar{width:6px}._contentBox_16n8k_123::-webkit-scrollbar-thumb{background-color:#10b9811a;border-radius:3px}._logRow_16n8k_151{white-space:pre-wrap;margin-bottom:.625rem;line-height:1.625}._logInput_16n8k_163{color:#f3f4f6;font-weight:600}._logError_16n8k_165{color:#f87171}._logSuccess_16n8k_167{color:#6ee7b7;font-weight:700}._logOutput_16n8k_169{color:#34d399cc}._progressBarContainer_16n8k_173{padding:.5rem 0}._progressHeader_16n8k_181{color:#9ca3af;justify-content:space-between;align-items:center;margin-bottom:.25rem;font-size:.75rem;display:flex}._progressTrack_16n8k_199{background-color:#064e3b66;border:1px solid #10b98133;border-radius:.25rem;width:100%;height:.5rem;overflow:hidden}._progressBar_16n8k_173{background-color:#10b981;height:100%;transition:width .3s}._inputForm_16n8k_229{border-top:1px solid #10b9811a;align-items:center;gap:.5rem;margin-top:.5rem;padding-top:.5rem;display:flex}._prompt_16n8k_247{color:#10b981;font-weight:700}._inputField_16n8k_257{color:#f3f4f6;background:0 0;border:none;outline:none;flex:1;padding:0;font-family:inherit;font-size:.875rem}._inputField_16n8k_257::placeholder{color:#9ca3af80}._submitButton_16n8k_287{color:#10b98180;cursor:pointer;background:0 0;border:none;align-items:center;transition:color .2s;display:flex}._submitButton_16n8k_287:hover{color:#34d399}
2
- /*$vite$:1*/
package/dist/index.d.ts DELETED
@@ -1,34 +0,0 @@
1
- import { default as default_2 } from 'react';
2
-
3
- export declare type CommandAction = (args: string[]) => AsyncGenerator<YieldChunk, void, unknown>;
4
-
5
- export declare interface CommandLog {
6
- type: 'input' | 'output' | 'error' | 'success';
7
- text: string;
8
- }
9
-
10
- export declare function Terminal({ promptString, placeholder, systemLockedText, commandNotFoundFormatter, initialHistory, commands, title, showCloseButton, onClose, headerRightActions, }: TerminalProps): default_2.JSX.Element;
11
-
12
- export declare interface TerminalProps {
13
- promptString?: string;
14
- placeholder?: string;
15
- systemLockedText?: string;
16
- commandNotFoundFormatter?: (cmd: string) => string;
17
- initialHistory?: CommandLog[];
18
- commands: Record<string, CommandAction>;
19
- title?: default_2.ReactNode;
20
- showCloseButton?: boolean;
21
- onClose?: () => void;
22
- headerRightActions?: default_2.ReactNode;
23
- }
24
-
25
- export declare type YieldChunk = {
26
- type: 'log';
27
- log: CommandLog;
28
- } | {
29
- type: 'progress';
30
- percent: number;
31
- text?: string;
32
- };
33
-
34
- export { }
package/dist/index.js DELETED
@@ -1,149 +0,0 @@
1
- import { useEffect as e, useRef as t, useState as n } from "react";
2
- import { CornerDownLeft as r, Terminal as i, X as a } from "lucide-react";
3
- import { jsx as o, jsxs as s } from "react/jsx-runtime";
4
- var c = {
5
- terminalRoot: "_terminalRoot_16n8k_1",
6
- titleBar: "_titleBar_16n8k_33",
7
- titleLeft: "_titleLeft_16n8k_53",
8
- titleText: "_titleText_16n8k_65",
9
- titleRight: "_titleRight_16n8k_79",
10
- closeButton: "_closeButton_16n8k_91",
11
- contentBox: "_contentBox_16n8k_123",
12
- logRow: "_logRow_16n8k_151",
13
- logInput: "_logInput_16n8k_163",
14
- logError: "_logError_16n8k_165",
15
- logSuccess: "_logSuccess_16n8k_167",
16
- logOutput: "_logOutput_16n8k_169",
17
- progressBarContainer: "_progressBarContainer_16n8k_173",
18
- progressHeader: "_progressHeader_16n8k_181",
19
- progressTrack: "_progressTrack_16n8k_199",
20
- progressBar: "_progressBar_16n8k_173",
21
- inputForm: "_inputForm_16n8k_229",
22
- prompt: "_prompt_16n8k_247",
23
- inputField: "_inputField_16n8k_257",
24
- submitButton: "_submitButton_16n8k_287"
25
- };
26
- //#endregion
27
- //#region src/Terminal.tsx
28
- function l({ promptString: l = "user@terminal:~$", placeholder: u = "Type a command...", systemLockedText: d = "System locked during execution...", commandNotFoundFormatter: f = (e) => `Command not found: "${e}".`, initialHistory: p = [], commands: m, title: h = "terminal", showCloseButton: g = !0, onClose: _, headerRightActions: v }) {
29
- let [y, b] = n(""), [x, S] = n(p), [C, w] = n(!1), [T, E] = n(null), [D, O] = n(""), k = t(null), A = t(null);
30
- e(() => {
31
- k.current && (k.current.scrollTop = k.current.scrollHeight);
32
- }, [
33
- x,
34
- T,
35
- D,
36
- C
37
- ]);
38
- let j = () => {
39
- A.current && A.current.focus();
40
- }, M = async (e) => {
41
- e.preventDefault();
42
- let t = y.trim();
43
- if (!t || C) return;
44
- S((e) => [...e, {
45
- type: "input",
46
- text: `${l} ${t}`
47
- }]), b("");
48
- let n = t.split(" "), r = n[0].toLowerCase();
49
- if (r === "clear") {
50
- S([]);
51
- return;
52
- }
53
- if (m && m[r]) {
54
- w(!0);
55
- try {
56
- let e = m[r](n);
57
- for await (let t of e) t.type === "log" ? S((e) => [...e, t.log]) : t.type === "progress" && (E(t.percent), t.text && O(t.text));
58
- } catch (e) {
59
- S((t) => [...t, {
60
- type: "error",
61
- text: `Execution error: ${e instanceof Error ? e.message : String(e)}`
62
- }]);
63
- } finally {
64
- w(!1), E(null), O("");
65
- }
66
- } else S((e) => [...e, {
67
- type: "error",
68
- text: f(r)
69
- }]);
70
- }, N = (e) => e === "input" ? c.logInput : e === "error" ? c.logError : e === "success" ? c.logSuccess : c.logOutput;
71
- return /* @__PURE__ */ s("div", {
72
- className: c.terminalRoot,
73
- onClick: j,
74
- children: [/* @__PURE__ */ s("div", {
75
- className: c.titleBar,
76
- children: [/* @__PURE__ */ s("div", {
77
- className: c.titleLeft,
78
- children: [/* @__PURE__ */ o(i, {
79
- className: "w-4 h-4",
80
- style: { color: "#10b981" }
81
- }), /* @__PURE__ */ o("span", {
82
- className: c.titleText,
83
- children: h
84
- })]
85
- }), /* @__PURE__ */ s("div", {
86
- className: c.titleRight,
87
- children: [v, g && _ && /* @__PURE__ */ o("button", {
88
- onClick: (e) => {
89
- e.stopPropagation(), _();
90
- },
91
- className: c.closeButton,
92
- children: /* @__PURE__ */ o(a, { className: "w-4 h-4" })
93
- })]
94
- })]
95
- }), /* @__PURE__ */ s("div", {
96
- ref: k,
97
- className: c.contentBox,
98
- children: [
99
- x.map((e, t) => /* @__PURE__ */ o("div", {
100
- className: `${c.logRow} ${N(e.type)}`,
101
- children: e.text
102
- }, t)),
103
- T !== null && /* @__PURE__ */ s("div", {
104
- className: c.progressBarContainer,
105
- children: [/* @__PURE__ */ s("div", {
106
- className: c.progressHeader,
107
- children: [/* @__PURE__ */ o("span", { children: D }), /* @__PURE__ */ s("span", { children: [T, "%"] })]
108
- }), /* @__PURE__ */ o("div", {
109
- className: c.progressTrack,
110
- children: /* @__PURE__ */ o("div", {
111
- className: c.progressBar,
112
- style: { width: `${T}%` }
113
- })
114
- })]
115
- }),
116
- /* @__PURE__ */ s("form", {
117
- onSubmit: M,
118
- className: c.inputForm,
119
- children: [
120
- /* @__PURE__ */ o("span", {
121
- className: c.prompt,
122
- children: l
123
- }),
124
- /* @__PURE__ */ o("input", {
125
- ref: A,
126
- type: "text",
127
- value: y,
128
- onChange: (e) => b(e.target.value),
129
- disabled: C,
130
- placeholder: C ? d : u,
131
- className: c.inputField,
132
- autoComplete: "off",
133
- autoCorrect: "off",
134
- autoCapitalize: "off",
135
- spellCheck: "false"
136
- }),
137
- /* @__PURE__ */ o("button", {
138
- type: "submit",
139
- className: c.submitButton,
140
- children: /* @__PURE__ */ o(r, { className: "w-4 h-4" })
141
- })
142
- ]
143
- })
144
- ]
145
- })]
146
- });
147
- }
148
- //#endregion
149
- export { l as Terminal };