@jogak/ui 0.1.0-alpha.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/CHANGELOG.md +86 -0
- package/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/app/App.d.ts +18 -0
- package/dist/components/Actions/index.d.ts +2 -0
- package/dist/components/Controls/index.d.ts +8 -0
- package/dist/components/Preview/index.d.ts +27 -0
- package/dist/components/Sidebar/index.d.ts +11 -0
- package/dist/hooks/useRegistry.d.ts +7 -0
- package/dist/host/index.d.ts +73 -0
- package/dist/host/index.js +1 -0
- package/dist/host/index.mjs +99 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +1 -0
- package/dist/index.mjs +1217 -0
- package/index.html +16 -0
- package/package.json +92 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Jogak packages are documented here. The repository follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
Version numbers apply to all packages in the workspace (synchronized release).
|
|
7
|
+
|
|
8
|
+
## [0.1.0-alpha.0] — 2026-05-07
|
|
9
|
+
|
|
10
|
+
First public preview release. API is not yet stable.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Lazy virtual modules** (`@jogak/core`)
|
|
15
|
+
- `virtual:jogak` index module exposes only entry metadata; no user component imports.
|
|
16
|
+
- `virtual:jogak/entry/<slug>` per-entry virtual module dynamically imported on demand.
|
|
17
|
+
- `defaultRegistry` hydration state machine: `unknown → meta → pending → hydrated`.
|
|
18
|
+
- New API: `registerMeta`, `hydrateEntry`, `requestEntry`, `invalidateEntry`,
|
|
19
|
+
`getAllMeta`, `getMetaTree`, `getEntryState`, `setEntryLoader`, `subscribe`.
|
|
20
|
+
- `RegistryEntryMeta` type for sidebar metadata without component identity.
|
|
21
|
+
|
|
22
|
+
- **In-place HMR** (`@jogak/core` + `@jogak/react`)
|
|
23
|
+
- `*.jogak.tsx` edits trigger entry virtual module self-accept → automatic
|
|
24
|
+
rehydration. Sidebar metadata patched via `jogak:meta-update` ws custom event.
|
|
25
|
+
- `useEntry(id)` subscribes to registry mutations and re-renders on hydrate.
|
|
26
|
+
- meta-only vs structural change classification by `(title, jogakNamesKey)` signature.
|
|
27
|
+
|
|
28
|
+
- **child_process-isolated ts-morph extractor** (`@jogak/core`)
|
|
29
|
+
- Props extraction runs in a separate child process via IPC.
|
|
30
|
+
- Idle 5 s SIGTERM → OS reclaims memory immediately; no V8 isolate growth.
|
|
31
|
+
- Lazy spawn on first `extract()` call; pending requests rejected on child exit.
|
|
32
|
+
|
|
33
|
+
- **Vite cache auto-invalidation** (`@jogak/core/vite`)
|
|
34
|
+
- On dev boot, plugin compares jogak dist mtime vs `.vite/deps/_metadata.json`.
|
|
35
|
+
- Stale cache is purged automatically with an info log.
|
|
36
|
+
- Opt-out: `JogakPluginOptions.disableCacheValidation`.
|
|
37
|
+
|
|
38
|
+
- **`@jogak/react` hooks**
|
|
39
|
+
- `useEntry(id): UseEntryState` — `loading | ready | error | unknown` discriminated union.
|
|
40
|
+
- `useRegistryMeta(): UseRegistryMetaReturn` — backed by `useSyncExternalStore`,
|
|
41
|
+
referential identity guaranteed.
|
|
42
|
+
- `useRegistry()`, `JogakProvider`, `reactAdapter` (preserved signatures).
|
|
43
|
+
|
|
44
|
+
- **`@jogak/ui` library mode**
|
|
45
|
+
- `JogakApp`, `Sidebar`, `Preview`, `Controls`, `Actions` published as
|
|
46
|
+
pre-built ESM/CJS — no `transpilePackages` needed for Next.js.
|
|
47
|
+
- `JogakAppProps`: `entries` (eager) | `metas` (lazy) | both unset (defaultRegistry).
|
|
48
|
+
|
|
49
|
+
- **CLI** (`@jogak/cli`)
|
|
50
|
+
- `jogak dev` / `jogak build` / `jogak generate` commands.
|
|
51
|
+
- Auto-detects `<cwd>/tsconfig.json` for ts-morph; falls back to manual
|
|
52
|
+
`meta.argTypes` if absent.
|
|
53
|
+
|
|
54
|
+
- **Storybook benchmark suite** (`benchmarks/`)
|
|
55
|
+
- `bench:scale:full` — cold-start / build / bundle vs Storybook 8 (Vite builder).
|
|
56
|
+
- `bench:rss` — idle dev tree RSS vs Storybook.
|
|
57
|
+
- `bench:hmr` — Playwright-driven HMR latency.
|
|
58
|
+
|
|
59
|
+
### Numbers vs. Storybook 8 (Vite builder)
|
|
60
|
+
|
|
61
|
+
| Metric | size 100 | size 500 |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| dev cold start | **1.7 s** vs 3.3 s | **2.9 s** vs 3.6 s |
|
|
64
|
+
| build time | **2.0 s** vs 2.9 s | **4.1 s** vs 7.6 s |
|
|
65
|
+
| bundle (gzip) | **108 KB** vs 716 KB | **156 KB** vs 1.09 MB |
|
|
66
|
+
| idle RSS (dev) | **321 MB** vs 403 MB | **345 MB** vs 489 MB |
|
|
67
|
+
| HMR (warm median) | **153 ms** | **199 ms** |
|
|
68
|
+
|
|
69
|
+
### Known Limitations
|
|
70
|
+
|
|
71
|
+
- HMR `jogak:meta-update` event only patches `defaultRegistry`. Custom registry
|
|
72
|
+
injections via `<JogakProvider registry={custom}>` fall back to full reload.
|
|
73
|
+
- Boot-time RSS spike (~700 MB) before settling at idle RSS — esbuild prebundle
|
|
74
|
+
+ ts-morph child spawn. Settles within 5 s.
|
|
75
|
+
- `@jogak/core` install pulls ts-morph (~17 MB); only `core/build` and the Vite
|
|
76
|
+
plugin actually use it. Splitting into `@jogak/extractor` is planned for 0.2.0.
|
|
77
|
+
|
|
78
|
+
### Compatibility
|
|
79
|
+
|
|
80
|
+
- Node ≥ 20.18 (`fetch` / `AbortSignal.timeout` stable)
|
|
81
|
+
- React ≥ 18 (peer)
|
|
82
|
+
- Vite ≥ 6 (peer, optional in `@jogak/core`)
|
|
83
|
+
- Next.js ≥ 14 (peer in `@jogak/next`)
|
|
84
|
+
- TypeScript ≥ 5.5 (build-time props extraction)
|
|
85
|
+
|
|
86
|
+
[0.1.0-alpha.0]: https://github.com/devclib/jogak/releases/tag/v0.1.0-alpha.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 devclib
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR DEALING IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# @jogak/ui
|
|
2
|
+
|
|
3
|
+
Showcase viewer UI for [Jogak](https://github.com/devclib/jogak) — `Sidebar` / `Preview` / `Controls` / `Actions` and the `JogakApp` shell.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @jogak/ui @jogak/core @jogak/react react react-dom
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`react` / `react-dom` are peer dependencies (>=18). `vite` and `@vitejs/plugin-react` are optional peers (only when using the Vite plugin).
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Embed into a Vite SPA
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// vite.config.ts
|
|
19
|
+
import { jogak } from '@jogak/core/vite'
|
|
20
|
+
|
|
21
|
+
export default defineConfig({
|
|
22
|
+
plugins: [react(), jogak({ codeTheme: 'vsDark' })],
|
|
23
|
+
})
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```tsx
|
|
27
|
+
// main.tsx
|
|
28
|
+
import 'virtual:jogak'
|
|
29
|
+
import { _jogakCodeTheme } from 'virtual:jogak'
|
|
30
|
+
import { JogakApp } from '@jogak/ui'
|
|
31
|
+
import { createRoot } from 'react-dom/client'
|
|
32
|
+
|
|
33
|
+
createRoot(document.getElementById('root')!).render(
|
|
34
|
+
<JogakApp codeTheme={_jogakCodeTheme} />,
|
|
35
|
+
)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Static catalog (Next.js / any host bundler)
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { JogakApp } from '@jogak/ui'
|
|
42
|
+
import { entries } from '../.jogak/registry'
|
|
43
|
+
|
|
44
|
+
export default function Page() {
|
|
45
|
+
return <JogakApp entries={entries} codeTheme="vsDark" />
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`@jogak/ui` ships pre-built ESM/CJS — no `transpilePackages` required for Next.js.
|
|
50
|
+
|
|
51
|
+
### Sub-paths
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { runHost } from '@jogak/ui/host' // Node-only, used by @jogak/cli
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
> ⚠️ `@jogak/ui/host` requires `vite` and `@vitejs/plugin-react` at runtime. They are declared as **optional peers** because the main `JogakApp` export does not need them — install them only when using `runHost`:
|
|
58
|
+
>
|
|
59
|
+
> ```bash
|
|
60
|
+
> pnpm add -D vite @vitejs/plugin-react
|
|
61
|
+
> ```
|
|
62
|
+
|
|
63
|
+
See the [main README](https://github.com/devclib/jogak#readme) for the full host embedding guide.
|
|
64
|
+
|
|
65
|
+
- Repository: https://github.com/devclib/jogak
|
|
66
|
+
- Issues: https://github.com/devclib/jogak/issues
|
|
67
|
+
- License: [MIT](./LICENSE)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { RegistryEntry, RegistryEntryMeta } from '@jogak/core';
|
|
2
|
+
import { ReactElement } from 'react';
|
|
3
|
+
/**
|
|
4
|
+
* `JogakApp` props.
|
|
5
|
+
*
|
|
6
|
+
* - `entries`: 기존 — eager 모드. 정적 빌드 / 테스트용. 새 `ComponentRegistry`에 즉시 register.
|
|
7
|
+
* - `metas` : NEW — lazy 모드. `defaultRegistry`를 그대로 사용하면서 metas를 `registerMeta`로 등록.
|
|
8
|
+
* - 둘 다 미지정 → `defaultRegistry` 그대로 사용 (인덱스 가상모듈 `import 'virtual:jogak'`이 채웠다고 가정).
|
|
9
|
+
* - 둘 다 지정 → console.warn 후 `entries` 우선 (eager 우선, breaking 회피).
|
|
10
|
+
*
|
|
11
|
+
* 외부 호환을 위해 `entries`는 optional로만 변경되며 나머지 시그니처는 그대로 유지된다.
|
|
12
|
+
*/
|
|
13
|
+
export interface JogakAppProps {
|
|
14
|
+
readonly entries?: readonly RegistryEntry[];
|
|
15
|
+
readonly metas?: readonly RegistryEntryMeta[];
|
|
16
|
+
readonly codeTheme?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function JogakApp({ entries, metas, codeTheme, }?: JogakAppProps): ReactElement;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { ArgType } from '@jogak/core';
|
|
3
|
+
export interface ControlsProps {
|
|
4
|
+
readonly args: Readonly<Record<string, unknown>>;
|
|
5
|
+
readonly argTypes: Readonly<Record<string, ArgType>>;
|
|
6
|
+
readonly onArgChange: (key: string, value: unknown) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function Controls({ args, argTypes, onArgChange }: ControlsProps): ReactElement;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
import { UseEntryState } from '@jogak/react';
|
|
3
|
+
export interface PreviewProps {
|
|
4
|
+
readonly entryId: string;
|
|
5
|
+
readonly jogakName: string | null;
|
|
6
|
+
readonly overrideArgs: Readonly<Record<string, unknown>>;
|
|
7
|
+
readonly onArgChange: (key: string, value: unknown) => void;
|
|
8
|
+
readonly onReset: () => void;
|
|
9
|
+
readonly codeTheme: string;
|
|
10
|
+
/**
|
|
11
|
+
* URL deep link `?entry=<id>` (jogak 미지정) 케이스에서 entry hydrate 후
|
|
12
|
+
* 첫 jogak로 자동 보정하기 위한 콜백. 부모가 selectedJogakName / URL을 갱신.
|
|
13
|
+
*/
|
|
14
|
+
readonly onResolveJogak?: (entryId: string, jogakName: string) => void;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Preview — `useEntry(entryId)`의 status에 따라 분기 (계약 §5.4).
|
|
18
|
+
*
|
|
19
|
+
* - `loading` → 메타로 헤더(title, jogak 이름)만 표시, 캔버스에 skeleton
|
|
20
|
+
* - `ready` → 현행 렌더 (entry.jogaks/component 사용)
|
|
21
|
+
* - `error` → 에러 패널
|
|
22
|
+
* - `unknown` → "Entry not found" placeholder
|
|
23
|
+
*
|
|
24
|
+
* Layout shift 방지를 위해 캔버스 영역 minHeight 유지.
|
|
25
|
+
*/
|
|
26
|
+
export declare function Preview({ entryId, jogakName, overrideArgs, onArgChange, onReset, codeTheme, onResolveJogak, }: PreviewProps): ReactElement;
|
|
27
|
+
export type { UseEntryState };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ReactElement } from 'react';
|
|
2
|
+
export interface SidebarProps {
|
|
3
|
+
readonly selectedEntryId: string | null;
|
|
4
|
+
readonly selectedJogakName: string | null;
|
|
5
|
+
readonly onSelect: (entryId: string, jogakName: string) => void;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Sidebar — `useRegistryMeta`로 전환되어 lazy 모드에서도 모든 entry의 메타가 즉시 보인다.
|
|
9
|
+
* 계약 §10: hydrated 여부를 표시하지 않는다 — 사용자에겐 모든 entry가 동일하게 보임.
|
|
10
|
+
*/
|
|
11
|
+
export declare function Sidebar({ selectedEntryId, selectedJogakName, onSelect, }: SidebarProps): ReactElement;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { CategoryTree, RegistryEntry } from '@jogak/core';
|
|
2
|
+
export interface UseRegistryReturn {
|
|
3
|
+
readonly entries: readonly RegistryEntry[];
|
|
4
|
+
readonly tree: CategoryTree;
|
|
5
|
+
readonly search: (query: string) => readonly RegistryEntry[];
|
|
6
|
+
}
|
|
7
|
+
export declare function useRegistry(): UseRegistryReturn;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @jogak/ui/host — Node.js 전용 entry.
|
|
3
|
+
*
|
|
4
|
+
* `@jogak/cli`(또는 사용자가 직접) 이 모듈의 `runHost()`를 호출하여
|
|
5
|
+
* 쇼케이스 SPA를 dev server 또는 정적 빌드 결과물로 실행한다.
|
|
6
|
+
*
|
|
7
|
+
* 주의:
|
|
8
|
+
* - 이 파일은 Node.js 환경에서만 import되어야 한다.
|
|
9
|
+
* - `vite`, `@vitejs/plugin-react`, `@jogak/core/vite`는 모두 dynamic import로
|
|
10
|
+
* 로드한다 — `@jogak/ui` 메인 entry(브라우저 SPA)에서 우연히 host를 import
|
|
11
|
+
* 하더라도 vite가 브라우저 번들에 포함되지 않게 하기 위함.
|
|
12
|
+
*/
|
|
13
|
+
/** UI SPA의 entry HTML 절대경로. Vite의 `root`로 사용된다. */
|
|
14
|
+
export declare const UI_HTML_ENTRY: string;
|
|
15
|
+
/** UI SPA의 entry main.tsx 절대경로 (참고용). */
|
|
16
|
+
export declare const UI_MAIN_ENTRY: string;
|
|
17
|
+
export interface HostLogger {
|
|
18
|
+
info(msg: string): void;
|
|
19
|
+
warn(msg: string): void;
|
|
20
|
+
error(msg: string): void;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* dev/build 양쪽이 공유하는 사용자 입력.
|
|
24
|
+
*/
|
|
25
|
+
export interface JogakHostOptionsBase {
|
|
26
|
+
/** 사용자 프로젝트 루트 (절대경로). */
|
|
27
|
+
readonly userRoot: string;
|
|
28
|
+
/** 쇼케이스 파일 패턴. cwd는 `userRoot` 기준. */
|
|
29
|
+
readonly patterns: readonly string[];
|
|
30
|
+
/** ts-morph용 tsconfig 절대 경로. 미지정 시 jogak plugin이 자동 감지. */
|
|
31
|
+
readonly tsConfigFilePath?: string;
|
|
32
|
+
/** prism-react-renderer 테마. 기본 'vsDark'. */
|
|
33
|
+
readonly codeTheme?: string;
|
|
34
|
+
/**
|
|
35
|
+
* 호스트가 추가로 적용할 Vite 사용자 플러그인.
|
|
36
|
+
* Phase 2에서 jogak.config.ts에 plugins 옵션을 노출할 때 사용.
|
|
37
|
+
*/
|
|
38
|
+
readonly extraPlugins?: readonly unknown[];
|
|
39
|
+
/** stdout/stderr 출력 stream (테스트 시 주입). */
|
|
40
|
+
readonly logger?: HostLogger;
|
|
41
|
+
}
|
|
42
|
+
export interface JogakDevOptions extends JogakHostOptionsBase {
|
|
43
|
+
readonly mode: 'dev';
|
|
44
|
+
readonly port?: number;
|
|
45
|
+
readonly host?: string | boolean;
|
|
46
|
+
readonly open?: boolean | string;
|
|
47
|
+
}
|
|
48
|
+
export interface JogakBuildOptions extends JogakHostOptionsBase {
|
|
49
|
+
readonly mode: 'build';
|
|
50
|
+
/** 절대경로. */
|
|
51
|
+
readonly outDir: string;
|
|
52
|
+
readonly base?: string;
|
|
53
|
+
readonly minify?: boolean | 'esbuild' | 'terser';
|
|
54
|
+
readonly sourcemap?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export type JogakHostOptions = JogakDevOptions | JogakBuildOptions;
|
|
57
|
+
export interface DevHandle {
|
|
58
|
+
/** ex) 'http://localhost:5173/' */
|
|
59
|
+
readonly url: string;
|
|
60
|
+
readonly port: number;
|
|
61
|
+
/** 멱등 보장 — 여러 번 호출되어도 안전. */
|
|
62
|
+
close(): Promise<void>;
|
|
63
|
+
printUrls(): void;
|
|
64
|
+
}
|
|
65
|
+
export interface BuildResult {
|
|
66
|
+
readonly outDir: string;
|
|
67
|
+
readonly elapsedMs: number;
|
|
68
|
+
readonly assetCount: number;
|
|
69
|
+
readonly totalBytes: number;
|
|
70
|
+
}
|
|
71
|
+
export declare function runHost(opts: JogakDevOptions): Promise<DevHandle>;
|
|
72
|
+
export declare function runHost(opts: JogakBuildOptions): Promise<BuildResult>;
|
|
73
|
+
export declare function runHost(opts: JogakHostOptions): Promise<DevHandle | BuildResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var L=Object.create;var g=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var S=Object.getOwnPropertyNames;var k=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var B=(t,e,o,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of S(e))!A.call(t,n)&&n!==o&&g(t,n,{get:()=>e[n],enumerable:!(r=M(e,n))||r.enumerable});return t};var a=(t,e,o)=>(o=t!=null?L(k(t)):{},B(e||!t||!t.__esModule?g(o,"default",{value:t,enumerable:!0}):o,t));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const H=require("node:url"),i=require("node:path");var l=typeof document<"u"?document.currentScript:null;const N=H.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:l&&l.tagName.toUpperCase()==="SCRIPT"&&l.src||new URL("host/index.js",document.baseURI).href),u=i.resolve(i.dirname(N),"..",".."),x=i.resolve(u,"index.html"),F=i.resolve(u,"src/app/main.tsx");async function E(t){const e=await import("vite"),o=await import("@vitejs/plugin-react"),r=await import("@jogak/core/vite"),{createServer:n,build:h}=e,b=o.default,{jogak:v}=r,_=t.codeTheme??"vsDark",f={patterns:t.patterns,codeTheme:_,cwd:t.userRoot};t.tsConfigFilePath!==void 0&&(f.tsConfigFilePath=t.tsConfigFilePath);const R=t.extraPlugins??[],d={root:u,configFile:!1,plugins:[b(),v(f),...R],optimizeDeps:{include:["react","react-dom/client","@jogak/core","@jogak/react"]}};if(t.mode==="dev"){const O={port:t.port??5173,host:t.host??"localhost",open:t.open??!1,fs:{allow:[u,t.userRoot]}},j={...d,server:O},s=await n(j);await s.listen();const p=s.config.server.port??t.port??5173,c=t.host??"localhost",D=`http://${typeof c=="boolean"?c?"0.0.0.0":"localhost":c}:${p.toString()}/`;let y=!1;return{url:D,port:p,close:async()=>{y||(y=!0,await s.close())},printUrls:()=>{s.printUrls()}}}const w={...d,base:t.base??"./",build:{outDir:t.outDir,emptyOutDir:!0,sourcemap:t.sourcemap??!1,minify:t.minify??"esbuild"}},C=Date.now(),T=await h(w),U=Date.now()-C,{assetCount:P,totalBytes:I}=Y(T);return{outDir:t.outDir,elapsedMs:U,assetCount:P,totalBytes:I}}function Y(t){const e=q(t);if(e===void 0)return{assetCount:0,totalBytes:0};let o=0,r=0;for(const n of e)o+=1,r+=z(n);return{assetCount:o,totalBytes:r}}function m(t){return typeof t=="object"&&t!==null&&Array.isArray(t.output)}function q(t){if(Array.isArray(t)){const e=[];for(const o of t)m(o)&&e.push(...o.output);return e}if(m(t))return t.output}function z(t){if(typeof t!="object"||t===null)return 0;const e=t;if(e.type==="chunk"&&typeof e.code=="string")return Buffer.byteLength(e.code,"utf8");if(e.type==="asset"){const o=e.source;if(typeof o=="string")return Buffer.byteLength(o,"utf8");if(o instanceof Uint8Array)return o.byteLength}return 0}exports.UI_HTML_ENTRY=x;exports.UI_MAIN_ENTRY=F;exports.runHost=E;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { fileURLToPath as k } from "node:url";
|
|
2
|
+
import { resolve as u, dirname as B } from "node:path";
|
|
3
|
+
const T = k(import.meta.url), s = u(B(T), "..", ".."), F = u(s, "index.html"), z = u(s, "src/app/main.tsx");
|
|
4
|
+
async function N(t) {
|
|
5
|
+
const e = await import("vite"), o = await import("@vitejs/plugin-react"), r = await import("@jogak/core/vite"), { createServer: i, build: g } = e, m = o.default, { jogak: y } = r, h = t.codeTheme ?? "vsDark", a = {
|
|
6
|
+
patterns: t.patterns,
|
|
7
|
+
codeTheme: h,
|
|
8
|
+
cwd: t.userRoot
|
|
9
|
+
};
|
|
10
|
+
t.tsConfigFilePath !== void 0 && (a.tsConfigFilePath = t.tsConfigFilePath);
|
|
11
|
+
const b = t.extraPlugins ?? [], l = {
|
|
12
|
+
root: s,
|
|
13
|
+
configFile: !1,
|
|
14
|
+
// ui/vite.config.ts 무시
|
|
15
|
+
plugins: [m(), y(a), ...b],
|
|
16
|
+
optimizeDeps: {
|
|
17
|
+
include: ["react", "react-dom/client", "@jogak/core", "@jogak/react"]
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
if (t.mode === "dev") {
|
|
21
|
+
const R = {
|
|
22
|
+
port: t.port ?? 5173,
|
|
23
|
+
host: t.host ?? "localhost",
|
|
24
|
+
open: t.open ?? !1,
|
|
25
|
+
fs: { allow: [s, t.userRoot] }
|
|
26
|
+
}, _ = {
|
|
27
|
+
...l,
|
|
28
|
+
server: R
|
|
29
|
+
}, n = await i(_);
|
|
30
|
+
await n.listen();
|
|
31
|
+
const f = n.config.server.port ?? t.port ?? 5173, c = t.host ?? "localhost", j = `http://${typeof c == "boolean" ? c ? "0.0.0.0" : "localhost" : c}:${f.toString()}/`;
|
|
32
|
+
let d = !1;
|
|
33
|
+
return {
|
|
34
|
+
url: j,
|
|
35
|
+
port: f,
|
|
36
|
+
close: async () => {
|
|
37
|
+
d || (d = !0, await n.close());
|
|
38
|
+
},
|
|
39
|
+
printUrls: () => {
|
|
40
|
+
n.printUrls();
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const v = {
|
|
45
|
+
...l,
|
|
46
|
+
base: t.base ?? "./",
|
|
47
|
+
build: {
|
|
48
|
+
outDir: t.outDir,
|
|
49
|
+
emptyOutDir: !0,
|
|
50
|
+
sourcemap: t.sourcemap ?? !1,
|
|
51
|
+
minify: t.minify ?? "esbuild"
|
|
52
|
+
}
|
|
53
|
+
}, w = Date.now(), C = await g(v), P = Date.now() - w, { assetCount: D, totalBytes: O } = U(C);
|
|
54
|
+
return {
|
|
55
|
+
outDir: t.outDir,
|
|
56
|
+
elapsedMs: P,
|
|
57
|
+
assetCount: D,
|
|
58
|
+
totalBytes: O
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function U(t) {
|
|
62
|
+
const e = A(t);
|
|
63
|
+
if (e === void 0)
|
|
64
|
+
return { assetCount: 0, totalBytes: 0 };
|
|
65
|
+
let o = 0, r = 0;
|
|
66
|
+
for (const i of e)
|
|
67
|
+
o += 1, r += L(i);
|
|
68
|
+
return { assetCount: o, totalBytes: r };
|
|
69
|
+
}
|
|
70
|
+
function p(t) {
|
|
71
|
+
return typeof t == "object" && t !== null && Array.isArray(t.output);
|
|
72
|
+
}
|
|
73
|
+
function A(t) {
|
|
74
|
+
if (Array.isArray(t)) {
|
|
75
|
+
const e = [];
|
|
76
|
+
for (const o of t)
|
|
77
|
+
p(o) && e.push(...o.output);
|
|
78
|
+
return e;
|
|
79
|
+
}
|
|
80
|
+
if (p(t))
|
|
81
|
+
return t.output;
|
|
82
|
+
}
|
|
83
|
+
function L(t) {
|
|
84
|
+
if (typeof t != "object" || t === null) return 0;
|
|
85
|
+
const e = t;
|
|
86
|
+
if (e.type === "chunk" && typeof e.code == "string")
|
|
87
|
+
return Buffer.byteLength(e.code, "utf8");
|
|
88
|
+
if (e.type === "asset") {
|
|
89
|
+
const o = e.source;
|
|
90
|
+
if (typeof o == "string") return Buffer.byteLength(o, "utf8");
|
|
91
|
+
if (o instanceof Uint8Array) return o.byteLength;
|
|
92
|
+
}
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
F as UI_HTML_ENTRY,
|
|
97
|
+
z as UI_MAIN_ENTRY,
|
|
98
|
+
N as runHost
|
|
99
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { JogakApp } from './app/App.js';
|
|
2
|
+
export { Sidebar } from './components/Sidebar/index.js';
|
|
3
|
+
export { Preview } from './components/Preview/index.js';
|
|
4
|
+
export { Controls } from './components/Controls/index.js';
|
|
5
|
+
export { Actions } from './components/Actions/index.js';
|
|
6
|
+
export { useRegistry } from './hooks/useRegistry.js';
|
|
7
|
+
export type { JogakAppProps } from './app/App.js';
|
|
8
|
+
export type { SidebarProps } from './components/Sidebar/index.js';
|
|
9
|
+
export type { PreviewProps } from './components/Preview/index.js';
|
|
10
|
+
export type { ControlsProps } from './components/Controls/index.js';
|
|
11
|
+
export type { UseRegistryReturn } from './hooks/useRegistry.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),c=require("react"),k=require("@jogak/core"),j=require("@jogak/react"),z=require("prism-react-renderer");function I({selectedEntryId:t,selectedJogakName:n,onSelect:o}){const[i,s]=c.useState(""),{metaTree:r,searchMeta:l}=j.useRegistryMeta(),d=i.trim().length>0?l(i):null;return e.jsxs("aside",{"data-testid":"sidebar",style:{borderRight:"1px solid #e5e7eb",height:"100%",overflow:"auto",display:"flex",flexDirection:"column"},children:[e.jsx("div",{style:{padding:"12px",borderBottom:"1px solid #e5e7eb"},children:e.jsx("input",{type:"search",placeholder:"Search components...",value:i,onChange:a=>{s(a.target.value)},style:{width:"100%",padding:"6px 8px",border:"1px solid #d1d5db",borderRadius:4},"aria-label":"Search components"})}),e.jsx("nav",{style:{flex:1,overflow:"auto",padding:"8px 0"},children:d!==null?e.jsx(J,{metas:d,selectedEntryId:t,selectedJogakName:n,onSelect:o}):e.jsx(O,{node:r,selectedEntryId:t,selectedJogakName:n,onSelect:o})})]})}function J({metas:t,selectedEntryId:n,selectedJogakName:o,onSelect:i}){return t.length===0?e.jsx("p",{style:{padding:"0 12px",color:"#9ca3af",fontSize:13},children:"No results"}):e.jsx("ul",{style:{listStyle:"none",margin:0,padding:0},children:t.map(s=>e.jsx("li",{children:e.jsx($,{meta:s,selectedEntryId:n,selectedJogakName:o,onSelect:i,indent:0})},s.id))})}function O({node:t,selectedEntryId:n,selectedJogakName:o,onSelect:i,depth:s=0}){return e.jsx("ul",{style:{listStyle:"none",margin:0,padding:`0 0 0 ${s*12}px`},children:Object.entries(t).map(([r,l])=>e.jsx("li",{children:"id"in l?e.jsx($,{meta:l,selectedEntryId:n,selectedJogakName:o,onSelect:i,indent:0}):e.jsx(V,{label:r,node:l,selectedEntryId:n,selectedJogakName:o,onSelect:i,depth:s+1})},r))})}function V({label:t,node:n,selectedEntryId:o,selectedJogakName:i,onSelect:s,depth:r}){const[l,d]=c.useState(!0);return e.jsxs("div",{children:[e.jsxs("button",{type:"button",onClick:()=>{d(a=>!a)},style:{display:"flex",alignItems:"center",gap:4,width:"100%",padding:"4px 12px",background:"none",border:"none",cursor:"pointer",fontSize:12,fontWeight:600,color:"#6b7280",textTransform:"uppercase",letterSpacing:"0.05em"},"aria-expanded":l,children:[e.jsx("span",{children:l?"▾":"▸"}),t]}),l&&e.jsx(O,{node:n,selectedEntryId:o,selectedJogakName:i,onSelect:s,depth:r})]})}function $({meta:t,selectedEntryId:n,selectedJogakName:o,onSelect:i,indent:s}){const r=t.id===n,[l,d]=c.useState(r);c.useEffect(()=>{r&&d(!0)},[r]);const a=t.title.split("/").pop()??t.title,b=16+s*12;return e.jsxs("div",{children:[e.jsxs("button",{type:"button",onClick:()=>{if(r)d(p=>!p);else{d(!0);const p=t.jogakNames[0];p!==void 0&&i(t.id,p)}},style:{display:"flex",alignItems:"center",gap:6,width:"100%",padding:`5px 12px 5px ${b}px`,background:r?"#eff6ff":"none",border:"none",cursor:"pointer",fontSize:13,color:r?"#2563eb":"#374151",fontWeight:r?500:400,textAlign:"left"},"aria-expanded":l,children:[e.jsx("span",{style:{fontSize:10,flexShrink:0,lineHeight:1},children:l?"▾":"▸"}),a]}),l&&e.jsx("ul",{style:{listStyle:"none",margin:0,padding:0},children:t.jogakNames.map(p=>{const x=r&&p===o;return e.jsx("li",{children:e.jsx("button",{type:"button",onClick:()=>{i(t.id,p)},style:{display:"block",width:"100%",textAlign:"left",padding:`4px 12px 4px ${b+18}px`,background:x?"#dbeafe":"none",border:"none",cursor:"pointer",fontSize:12,color:x?"#1d4ed8":"#6b7280",fontWeight:x?500:400},"aria-current":x?"true":void 0,children:p})},p)})})]})}function q(t,n){const o=n==null?void 0:n.control,i=(n==null?void 0:n.action)!==void 0&&n.action!==!1,s=(n==null?void 0:n.type)==="function"||typeof t=="function";return i||s?"action":o==="boolean"||typeof t=="boolean"?"boolean":o==="number"||o==="range"||typeof t=="number"?"number":o==="select"||o==="radio"||(n==null?void 0:n.options)!==void 0&&n.options.length>0?"select":o==="text"||o==="color"||typeof t=="string"?"text":"json"}function U({argKey:t,value:n,argType:o,onArgChange:i}){switch(q(n,o)){case"boolean":return e.jsx("input",{type:"checkbox",checked:n===!0,onChange:r=>{i(t,r.target.checked)},style:{cursor:"pointer",width:16,height:16,accentColor:"#2563eb"}});case"number":return e.jsx("input",{type:"number",value:typeof n=="number"?n:"",onChange:r=>{i(t,r.target.valueAsNumber)},style:w});case"select":{const r=(o==null?void 0:o.options)??[];return e.jsx("select",{value:String(n??""),onChange:l=>{i(t,l.target.value)},style:w,children:r.map(l=>e.jsx("option",{value:String(l),children:String(l)},String(l)))})}case"text":return e.jsx("input",{type:"text",value:typeof n=="string"?n:String(n??""),onChange:r=>{i(t,r.target.value)},style:w});case"action":return e.jsx("span",{style:{display:"inline-block",padding:"2px 8px",fontSize:11,fontWeight:600,color:"#7c3aed",background:"#f5f3ff",border:"1px solid #ddd6fe",borderRadius:4,fontFamily:"monospace"},children:"(action)"});case"json":return e.jsx("code",{style:{fontSize:12,color:"#6b7280",fontFamily:"monospace"},children:JSON.stringify(n)})}}const w={padding:"4px 8px",border:"1px solid #d1d5db",borderRadius:4,fontSize:13,width:"100%",maxWidth:280},C={padding:"6px 20px",textAlign:"left",color:"#6b7280",fontWeight:500,fontSize:12,borderBottom:"1px solid #e5e7eb"},R={padding:"8px 20px",verticalAlign:"middle",borderBottom:"1px solid #f3f4f6"};function F({args:t,argTypes:n,onArgChange:o}){const s=Array.from(new Set([...Object.keys(t),...Object.keys(n)])).map(r=>[r,t[r]]);return e.jsxs("div",{style:{borderTop:"2px solid #e5e7eb"},children:[e.jsx("div",{style:{padding:"6px 20px",fontSize:11,fontWeight:700,color:"#9ca3af",textTransform:"uppercase",letterSpacing:"0.08em",borderBottom:"1px solid #e5e7eb",background:"#f9fafb"},children:"Controls"}),s.length===0?e.jsx("div",{style:{padding:"12px 20px",color:"#9ca3af",fontSize:13},children:"No args defined"}):e.jsxs("table",{style:{width:"100%",borderCollapse:"collapse",fontSize:13},children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{style:C,children:"Name"}),e.jsx("th",{style:C,children:"Control"}),e.jsx("th",{style:C,children:"Description"})]})}),e.jsx("tbody",{children:s.map(([r,l])=>{const d=n[r];return e.jsxs("tr",{children:[e.jsx("td",{style:{...R,fontFamily:"monospace",fontSize:12,color:"#374151",whiteSpace:"nowrap"},children:r}),e.jsx("td",{style:R,children:e.jsx(U,{argKey:r,value:l,argType:d,onArgChange:o})}),e.jsx("td",{style:{...R,color:"#9ca3af"},children:(d==null?void 0:d.description)??""})]},r)})})]})]})}function _(t){if(t.length===0)return"()";try{return t.map(n=>{var o;if(n===null)return"null";if(n===void 0)return"undefined";if(typeof n=="function")return"[Function]";if(typeof n=="object"){const i=((o=n.constructor)==null?void 0:o.name)??"Object";return i!=="Object"&&i!=="Array"?`[${i}]`:JSON.stringify(n)}return JSON.stringify(n)}).join(", ")}catch{return"[unserializable]"}}function G(t){const n=new Date(t),o=n.getHours().toString().padStart(2,"0"),i=n.getMinutes().toString().padStart(2,"0"),s=n.getSeconds().toString().padStart(2,"0"),r=n.getMilliseconds().toString().padStart(3,"0");return`${o}:${i}:${s}.${r}`}function L(){const[t,n]=c.useState(()=>k.defaultActionChannel.getLogs());return c.useEffect(()=>k.defaultActionChannel.subscribe(n),[]),e.jsxs("div",{style:{height:"100%",display:"flex",flexDirection:"column"},children:[e.jsxs("div",{style:{padding:"6px 20px",fontSize:11,fontWeight:700,color:"#9ca3af",textTransform:"uppercase",letterSpacing:"0.08em",borderBottom:"1px solid #e5e7eb",background:"#f9fafb",display:"flex",alignItems:"center",justifyContent:"space-between",flexShrink:0},children:[e.jsxs("span",{children:["Actions ",t.length>0&&`(${t.length.toString()})`]}),e.jsx("button",{type:"button",onClick:()=>{k.defaultActionChannel.clear()},disabled:t.length===0,style:{fontSize:10,fontWeight:600,padding:"2px 8px",border:"1px solid #d1d5db",borderRadius:3,background:"#fff",color:t.length===0?"#9ca3af":"#374151",cursor:t.length===0?"default":"pointer",textTransform:"none",letterSpacing:0},children:"Clear"})]}),e.jsx("div",{style:{flex:1,overflow:"auto"},children:t.length===0?e.jsx("div",{style:{padding:"12px 20px",color:"#9ca3af",fontSize:13},children:"함수 prop이 호출되면 여기에 기록됩니다"}):e.jsx("ul",{style:{listStyle:"none",margin:0,padding:0,fontFamily:"monospace",fontSize:12},children:t.map(o=>e.jsxs("li",{style:{display:"flex",alignItems:"baseline",gap:10,padding:"6px 20px",borderBottom:"1px solid #f3f4f6"},children:[e.jsx("span",{style:{color:"#9ca3af",fontSize:11,minWidth:92},children:G(o.timestamp)}),e.jsx("span",{style:{color:"#7c3aed",fontWeight:600},children:o.name}),e.jsxs("span",{style:{color:"#374151",wordBreak:"break-all",flex:1},children:["(",_(o.args),")"]})]},o.id))})})]})}const H={mobile:375,tablet:768,desktop:"none"},T={mobile:"Mobile",tablet:"Tablet",desktop:"Desktop"},W={white:{background:"#ffffff"},dark:{background:"#1f2937"},transparent:{backgroundImage:["linear-gradient(45deg, #e2e8f0 25%, transparent 25%)","linear-gradient(-45deg, #e2e8f0 25%, transparent 25%)","linear-gradient(45deg, transparent 75%, #e2e8f0 75%)","linear-gradient(-45deg, transparent 75%, #e2e8f0 75%)"].join(", "),backgroundSize:"16px 16px",backgroundPosition:"0 0, 0 8px, 8px -8px, -8px 0px",backgroundColor:"#ffffff"}},A=320;function Q(t){return z.themes[t]??z.themes.vsDark}function D({entryId:t,jogakName:n,overrideArgs:o,onArgChange:i,onReset:s,codeTheme:r,onResolveJogak:l}){const d=j.useEntry(t),[a,b]=c.useState("desktop"),[p,x]=c.useState("white"),[y,h]=c.useState("controls"),m=Q(r);return d.status==="unknown"?e.jsxs("div",{"data-testid":"preview-not-found",style:{padding:24,color:"#ef4444"},children:["Entry not found: ",t]}):d.status==="error"?e.jsxs("div",{"data-testid":"preview-error",style:{padding:24,color:"#b91c1c",background:"#fef2f2",height:"100%",display:"flex",flexDirection:"column",gap:12,alignItems:"flex-start"},children:[e.jsxs("div",{style:{fontWeight:600},children:["Failed to load entry: ",t]}),e.jsx("pre",{style:{margin:0,padding:12,background:"#fff",border:"1px solid #fecaca",borderRadius:6,fontSize:12,whiteSpace:"pre-wrap",maxWidth:"100%"},children:d.error.message})]}):d.status==="loading"?e.jsx(Y,{meta:d.meta,jogakName:n,viewport:a,bgMode:p,onViewportChange:b,onBgModeChange:x}):e.jsx(X,{entry:d.entry,jogakName:n,overrideArgs:o,onArgChange:i,onReset:s,onResolveJogak:l,viewport:a,bgMode:p,bottomTab:y,onViewportChange:b,onBgModeChange:x,onBottomTabChange:h,prismTheme:m})}function Y({meta:t,jogakName:n,viewport:o,bgMode:i,onViewportChange:s,onBgModeChange:r}){const l=n??t.jogakNames[0]??"...",d=H[o];return e.jsxs("div",{"data-testid":"preview-loading",style:{display:"flex",flexDirection:"column",height:"100%"},children:[e.jsx(N,{title:t.title,jogakName:l,viewport:o,bgMode:i,onViewportChange:s,onBgModeChange:r,showReset:!1,onReset:()=>{}}),e.jsx("div",{style:{flex:1,minHeight:A,overflow:"auto",...W[i]},children:e.jsx("div",{style:{maxWidth:d==="none"?"100%":d,margin:"0 auto",padding:24},children:e.jsxs("div",{style:{border:"1px dashed #e5e7eb",borderRadius:8,padding:16,minHeight:A-64,display:"flex",alignItems:"center",justifyContent:"center",color:"#9ca3af",fontSize:13,background:"linear-gradient(90deg, rgba(229,231,235,0) 0%, rgba(229,231,235,0.45) 50%, rgba(229,231,235,0) 100%)",backgroundSize:"200% 100%",animation:"jogakSkeleton 1.4s ease-in-out infinite"},children:["Loading ",t.title,"…"]})})}),e.jsx("style",{children:"@keyframes jogakSkeleton { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }"})]})}function X({entry:t,jogakName:n,overrideArgs:o,onArgChange:i,onReset:s,onResolveJogak:r,viewport:l,bgMode:d,bottomTab:a,onViewportChange:b,onBgModeChange:p,onBottomTabChange:x,prismTheme:y}){var B;const h=n??((B=t.jogaks[0])==null?void 0:B.name)??null;if(c.useEffect(()=>{n===null&&h!==null&&r!==void 0&&r(t.id,h)},[n,h,t.id,r]),h===null)return e.jsxs("div",{style:{padding:24,color:"#ef4444"},children:["Entry has no jogaks: ",t.id]});const m=t.jogaks.find(S=>S.name===h);if(m===void 0)return e.jsxs("div",{style:{padding:24,color:"#ef4444"},children:["Jogak not found: ",h]});const f={...m.args??{},...o},g={...t.meta.argTypes??{},...m.argTypes??{}},P=Object.keys(o).length>0,M=H[l];return e.jsxs("div",{style:{display:"flex",flexDirection:"column",height:"100%"},children:[e.jsx(N,{title:t.title,jogakName:m.name,viewport:l,bgMode:d,onViewportChange:b,onBgModeChange:p,showReset:P,onReset:s}),e.jsx("div",{style:{flex:1,minHeight:A,overflow:"auto",...W[d]},children:e.jsx("div",{style:{maxWidth:M==="none"?"100%":M,margin:"0 auto",padding:24},children:e.jsx(Z,{entry:t,args:f,source:t.source,theme:y},`${t.id}/${m.name}`)})}),e.jsxs("div",{style:{height:260,flexShrink:0,display:"flex",flexDirection:"column",borderTop:"2px solid #e5e7eb"},children:[e.jsx("div",{role:"tablist",style:{display:"flex",gap:4,padding:"4px 12px 0",background:"#fff",borderBottom:"1px solid #e5e7eb",flexShrink:0},children:["controls","actions"].map(S=>{const v=a===S;return e.jsx("button",{type:"button",role:"tab","aria-selected":v,onClick:()=>{x(S)},style:{padding:"6px 14px",fontSize:12,fontWeight:v?600:500,color:v?"#111827":"#6b7280",background:"transparent",border:"none",borderBottom:v?"2px solid #2563eb":"2px solid transparent",marginBottom:-1,cursor:"pointer",textTransform:"capitalize"},children:S},S)})}),e.jsx("div",{style:{flex:1,minHeight:0,overflow:"auto"},children:a==="controls"?e.jsx(F,{args:f,argTypes:g,onArgChange:i}):e.jsx(L,{})})]})]})}function N({title:t,jogakName:n,viewport:o,bgMode:i,onViewportChange:s,onBgModeChange:r,showReset:l,onReset:d}){return e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:10,padding:"7px 14px",borderBottom:"1px solid #e5e7eb",background:"#fff",flexShrink:0},children:[e.jsxs("div",{style:{flex:1,fontSize:13},children:[e.jsx("span",{style:{color:"#9ca3af"},children:t}),e.jsx("span",{style:{color:"#d1d5db",margin:"0 6px"},children:"/"}),e.jsx("span",{style:{color:"#111827",fontWeight:600},children:n})]}),e.jsx("div",{style:{display:"flex",gap:2,background:"#f3f4f6",borderRadius:6,padding:2},children:["mobile","tablet","desktop"].map(a=>e.jsx("button",{type:"button",onClick:()=>{s(a)},"aria-pressed":o===a,style:{padding:"3px 9px",fontSize:12,border:"none",borderRadius:4,cursor:"pointer",background:o===a?"#fff":"transparent",color:o===a?"#111827":"#6b7280",fontWeight:o===a?600:400,boxShadow:o===a?"0 1px 2px rgba(0,0,0,0.08)":"none",transition:"all 0.1s"},children:T[a]},a))}),e.jsx("div",{style:{display:"flex",gap:4,alignItems:"center"},children:["white","dark","transparent"].map(a=>e.jsx("button",{type:"button",onClick:()=>{r(a)},"aria-pressed":i===a,"aria-label":`${a} background`,style:{width:20,height:20,borderRadius:4,border:i===a?"2px solid #2563eb":"2px solid #d1d5db",cursor:"pointer",padding:0,flexShrink:0,...W[a]}},a))}),l&&e.jsx("button",{type:"button",onClick:d,style:{padding:"3px 10px",fontSize:12,border:"1px solid #d1d5db",borderRadius:4,background:"#fff",cursor:"pointer",color:"#374151"},children:"Reset"})]})}function Z({entry:t,args:n,source:o,theme:i}){const s=c.useRef(null),[r,l]=c.useState(!1);return c.useEffect(()=>{const d=s.current;if(d!==null)return j.reactAdapter.render(t,n,d),()=>{j.reactAdapter.unmount(d)}},[t]),c.useEffect(()=>{const d=s.current;d!==null&&j.reactAdapter.render(t,n,d)},[t,n]),e.jsxs("div",{children:[e.jsxs("div",{style:{position:"relative"},children:[e.jsx("div",{ref:s,"data-testid":"preview-content",style:{border:"1px dashed #e5e7eb",borderRadius:8,padding:16,paddingBottom:36}}),e.jsx("button",{type:"button",onClick:()=>{l(d=>!d)},"aria-pressed":r,"aria-label":r?"Hide source code":"Show source code",style:{position:"absolute",bottom:8,right:8,padding:"4px 9px",fontSize:11,fontFamily:"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",fontWeight:600,letterSpacing:"0.02em",background:r?"#2563eb":"#1e293b",color:"#fff",border:"none",borderRadius:5,cursor:"pointer",boxShadow:"0 1px 4px rgba(0,0,0,0.2)",transition:"background 0.15s"},children:"</>"})]}),r&&e.jsx("div",{style:{marginTop:8,borderRadius:8,overflow:"hidden",height:320,boxShadow:"0 0 0 1px rgba(0,0,0,0.08), 0 4px 16px rgba(0,0,0,0.12)"},children:e.jsx(K,{source:o,theme:i})})]})}function K({source:t,theme:n}){const[o,i]=c.useState(!1),s=n.plain.backgroundColor??"#1e293b";if(t===void 0)return e.jsx("div",{style:{height:"100%",display:"flex",alignItems:"center",justifyContent:"center",background:s,color:"#94a3b8",fontSize:13},children:"Source not available"});const r=()=>{navigator.clipboard.writeText(t).then(()=>{i(!0),setTimeout(()=>{i(!1)},2e3)})};return e.jsxs("div",{style:{position:"relative",height:"100%"},children:[e.jsx("button",{type:"button",onClick:r,style:{position:"absolute",top:10,right:12,zIndex:1,padding:"3px 9px",fontSize:11,background:"rgba(255,255,255,0.1)",color:"#e2e8f0",border:"1px solid rgba(255,255,255,0.18)",borderRadius:4,cursor:"pointer"},children:o?"✓ Copied":"Copy"}),e.jsx(z.Highlight,{code:t.trim(),language:"tsx",theme:n,children:({style:l,tokens:d,getLineProps:a,getTokenProps:b})=>e.jsx("pre",{style:{...l,margin:0,padding:"12px 0",fontSize:12.5,lineHeight:1.7,fontFamily:"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",height:"100%",boxSizing:"border-box",overflow:"auto"},children:d.map((p,x)=>e.jsxs("div",{...a({line:p}),style:{...a({line:p}).style,display:"flex",paddingRight:24},children:[e.jsx("span",{style:{userSelect:"none",minWidth:40,paddingLeft:14,paddingRight:14,textAlign:"right",color:"rgba(148,163,184,0.45)",flexShrink:0},children:x+1}),e.jsx("span",{children:p.map((y,h)=>e.jsx("span",{...b({token:y})},h))})]},x))})})]})}function E(){if(typeof window>"u")return null;const t=new URLSearchParams(window.location.search),n=t.get("entry");if(n===null)return null;const o=t.get("jogak");return{entryId:n,jogakName:o}}function ee(t,n){const o=new URLSearchParams;o.set("entry",t),o.set("jogak",n),window.history.pushState({},"",`?${o.toString()}`)}function te({entries:t,metas:n,codeTheme:o="vsDark"}={}){const i=c.useMemo(()=>{if(t!==void 0){n!==void 0&&console.warn("[jogak] JogakApp received both `entries` and `metas` — `entries` (eager) takes precedence.");const u=new k.ComponentRegistry;for(const f of t)u.register(f);return u}if(n!==void 0)for(const u of n)k.defaultRegistry.registerMeta(u);return k.defaultRegistry},[t,n]),s=c.useMemo(()=>E(),[]),[r,l]=c.useState((s==null?void 0:s.entryId)??null),[d,a]=c.useState((s==null?void 0:s.jogakName)??null),[b,p]=c.useState({});c.useEffect(()=>{const u=()=>{const f=E();f!==null?(l(f.entryId),a(f.jogakName),p({})):(l(null),a(null))};return window.addEventListener("popstate",u),()=>{window.removeEventListener("popstate",u)}},[]);const x=c.useCallback((u,f)=>{l(u),a(f),p({}),ee(u,f)},[]),y=c.useCallback((u,f)=>{if(l(g=>g===u?u:g),a(g=>g??f),typeof window<"u"){const g=new URLSearchParams(window.location.search);g.get("entry")===u&&g.get("jogak")===null&&(g.set("jogak",f),window.history.replaceState({},"",`?${g.toString()}`))}},[]),h=c.useCallback((u,f)=>{p(g=>({...g,[u]:f}))},[]),m=c.useCallback(()=>{p({})},[]);return e.jsx(j.JogakProvider,{registry:i,children:e.jsxs("div",{style:{display:"grid",gridTemplateColumns:"260px 1fr",height:"100dvh",overflow:"hidden"},children:[e.jsx(I,{selectedEntryId:r,selectedJogakName:d,onSelect:x}),e.jsx("main",{style:{overflow:"hidden",minHeight:0},children:r!==null?e.jsx(D,{entryId:r,jogakName:d,overrideArgs:b,onArgChange:h,onReset:m,codeTheme:o,onResolveJogak:y}):e.jsx("div",{style:{display:"flex",alignItems:"center",justifyContent:"center",height:"100%",color:"#9ca3af"},children:"Select a component from the sidebar"})})]})})}function ne(){const t=j.useRegistry(),n=c.useMemo(()=>t.getAll(),[t]),o=c.useMemo(()=>t.getTree(),[t]),i=c.useMemo(()=>s=>t.search(s),[t]);return{entries:n,tree:o,search:i}}exports.Actions=L;exports.Controls=F;exports.JogakApp=te;exports.Preview=D;exports.Sidebar=I;exports.useRegistry=ne;
|