@jogak/ui 0.1.0-alpha.8 → 0.1.0-alpha.9.1

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 CHANGED
@@ -5,152 +5,36 @@ All notable changes to Jogak packages are documented here. The repository follow
5
5
 
6
6
  Version numbers apply to all packages in the workspace (synchronized release).
7
7
 
8
- ## [0.1.0-alpha.8] — 2026-05-09
9
-
10
- ### Added
11
-
12
- - **`JogakHostOptions.userViteUrl`** — 사용자 vite spawn URL을 jogak SPA host에 전달.
13
- CLI의 `spawnUserVite` 결과가 `runHost`에 자동 전달되며 jogak() plugin의
14
- `_jogakUserViteUrl`로 emit됨 → `IframeMount`가 iframe `src` base로 사용.
15
- - **`IframeMount` postMessage 통신 재작성** — cross-origin 환경(사용자 vite ≠ jogak
16
- SPA)에서 `entry.id`를 메시지로 전달, iframe 안에서 `defaultRegistry.requestEntry(id)`로
17
- dynamic import.
18
-
19
- ### Changed (의도된 default 변경)
20
-
21
- - **`previewIsolation` default `'shadow'` → `'iframe'`** — 사용자 vite scope에서
22
- 사용자 컴포넌트가 사용자 디자인 그대로 보이는 것이 default 동작.
23
- - **`main.tsx` 단순화** — 사용자 globalCss는 사용자 vite scope에서만 처리되므로 jogak
24
- SPA outer document inject는 `'none'` 모드(deprecated)에서만.
25
-
26
- ### Notes
27
-
28
- - jogak-test-app(React + Vite + Tailwind v4 + shadcn) 검증: Badge가 사용자 디자인 그대로
29
- 표시 + chrome 침범 zero 입증.
30
-
31
- ## [0.1.0-alpha.7.1] — 2026-05-09
8
+ ## [0.1.0-alpha.9.1] — 2026-05-09
32
9
 
33
10
  ### Fixed
34
11
 
35
- - **`previewIsolation` 격리 통로 정정** 알파.7은 `main.tsx`가 isolation 모드와
36
- 무관하게 사용자 globalCss를 outer document에 무조건 inject해서 jogak chrome
37
- utility를 사용자 reset/preflight가 무력화하던 결함이 있었음. 알파.7.1:
38
- - `main.tsx`: `_jogakPreviewIsolation === 'none'`일 때만 사용자 globalCss를
39
- dynamic import. 다른 모드에서는 outer document inject 차단 → chrome 침범 zero.
40
- - `ShadowMount`: `adoptedStyleSheets` 흡수 + MutationObserver HMR sync 로직 제거.
41
- ShadowMount는 양방향 격리만 책임 (사용자 globalCss는 shadow scope에 inject 안 됨).
42
- - 사용자 컴포넌트 styling 통로(사용자 디자인 토큰/Tailwind utility 적용)는 알파.8
43
- 사이클에서 사용자 vite 통합으로 별도 도입 예정.
44
- - **`Preview` cleanup race condition** — `NoneAdapterContent` / `ShadowAdapterContent`
45
- / `IframeMount`의 unmount race(`Attempted to synchronously unmount...`)를
46
- `queueMicrotask`로 defer해 회피.
12
+ - **CI**: `release.yml`의 pack 단계가 `core/react/ui/web-components/next/cli`만 포함했고 알파.9에서 신규 추가된 4개 어댑터(`vite-adapter` / `next-adapter` / `webpack-adapter` / `standalone-adapter`)를 누락. v0.1.0-alpha.9 태그로 부분 publish됐으나 어댑터들이 npm에 올라가지 않아 사용자가 import 불가. 4개 어댑터를 pack 목록에 추가 후 alpha.9.1로 재발행.
47
13
 
48
- ### Changed (의도된 default 변경)
14
+ 기타 패키지: source 변경 없음, synchronized release 유지를 위해 버전만 bump.
49
15
 
50
- - **`JogakHostOptionsBase.previewIsolation` default `'none'` → `'shadow'`** —
51
- 양방향 격리가 default. back-compat은 `previewIsolation: 'none'` 명시.
52
- - **`JogakApp` / `Preview` `previewIsolation` prop default `'none'` → `'shadow'`**.
53
-
54
- ### README 업데이트
55
-
56
- - "previewIsolation 사용 가이드" 섹션 재작성 — 3 모드 비교표 + `'shadow'` default
57
- 동작/한계 + `'iframe'` 주의 + `'none'` back-compat 사용법.
58
- - "격리 보장" 섹션 — default 표시 갱신 (`'none'` → `'shadow'`).
59
- - 로드맵 표 — alpha.7.1 entry 추가.
60
-
61
- ## [0.1.0-alpha.7] — 2026-05-09
16
+ ## [0.1.0-alpha.9] 2026-05-09
62
17
 
63
18
  ### Added
64
19
 
65
- - **`JogakHostOptionsBase`에 `globalCss` / `previewIsolation` 필드** `runHost({ globalCss: true,
66
- previewIsolation: 'shadow' })` 형태로 programmatic API에서도 옵션 사용 가능.
67
- - **`Preview` Shadow / iframe 마운트 분기**
68
- - `previewIsolation: 'none'` (default, 알파.6과 동일) 같은 document에 마운트
69
- - `'shadow'` `attachShadow` + `createPortal` + `adoptedStyleSheets`로 외부 css/font 흡수,
70
- `MutationObserver`로 외부 `<style>` HMR 동기화
71
- - `'iframe'` — `/preview-frame.html` + `contentWindow.__jogak_setProps__` 직접 호출,
72
- 완벽 격리 (props 직렬화 불필요)
73
- - **`preview-frame.html` + `src/app/preview-frame.tsx`** — iframe-mode 전용 최소 entry.
74
- `virtual:jogak/global-css`만 import (jogak chrome css는 미포함, 격리 보장).
75
- - **README "previewIsolation 모드 비교" + "알파.6 → 알파.7 마이그레이션" 섹션** — 3 모드의
76
- trade-off / Radix portal 한계 / `jogak.config.ts` 패턴으로의 마이그레이션 안내.
77
-
78
- ### Fixed
79
-
80
- - **알파.6 README의 `vite.config.ts` 가이드 정정** — 알파.6는 `vite.config.ts`에서
81
- `jogak({ globalCss: true })`를 호출하라고 안내했으나 `runHost`가 `configFile: false`로
82
- 사용자 vite config를 무시해 옵션이 적용되지 않았음. 알파.7부터는 `jogak.config.ts`에
83
- `defineJogakConfig({ globalCss: true })`로 작성.
84
-
85
- ## [0.1.0-alpha.6] — 2026-05-09
86
-
87
- ### Added
88
-
89
- - **`main.tsx` 에 `import 'virtual:jogak/global-css'` 추가** — `@jogak/core`의
90
- `JogakPluginOptions.globalCss` opt-in 옵션이 켜진 환경에서 사용자 globalCss가
91
- jogak SPA에 적용됨. opt-in이 꺼진 default 환경에서는 빈 모듈이라 SPA 번들 영향 zero.
92
- - **`jogak.css` chrome 보호 rule** — `[data-jogak-shell] :where(button, input, select, textarea):not([data-jogak-content] *)`
93
- rule이 form element의 사용자 reset 침범을 차단. `:where()` specificity 0 +
94
- `revert-layer`로 알파.5 baseline 영향 zero.
95
- - **README "사용자 globalCss 적용 (alpha.6)" 섹션** — 사용법 / 자동 감지 후보
96
- 8종 우선순위 / 격리 보장 3항목 / scope 가이드 / `[data-jogak-shell]` /
97
- `[data-jogak-content]` selector hint / 알려진 한계 4항목.
98
-
99
- ### Notes
100
-
101
- - 알파.4부터 hook으로 도입됐던 `data-jogak-shell` / `data-jogak-content` 속성이
102
- 본 릴리즈에서 처음으로 의미를 갖게 됨 (chrome 보호 rule + scope 가이드 hook).
103
-
104
- ## [0.1.0-alpha.5] — 2026-05-09
20
+ - **`@jogak/vite-adapter`**, **`@jogak/next-adapter`**, **`@jogak/webpack-adapter`**, **`@jogak/standalone-adapter`**: 새 builder-agnostic adapter 패키지군. CLI가 사용자 cwd의 빌더(`next.config`, `vite.config`, `webpack.config`)를 감지하여 해당 adapter를 dynamic import한다. 사용자 컴포넌트는 사용자의 정상 빌더 client에서 평가되므로 utility class compiler(Tailwind v4 등)이 자연스럽게 동작한다.
21
+ - **`@jogak/core`**: `BuilderAdapter` ABI(`adapter.ts`), 빌더 자동 감지(`detectBuilder`, `@jogak/core/server`), preview entry 공통 source(`renderPreviewEntrySource`), postMessage 프로토콜(`@jogak/core/preview-entry/protocol`).
22
+ - **`JogakPluginOptions.userPreviewUrl` / `previewEntryPath`**: adapter dispatch 결과를 host UI iframe src로 주입하는 통로. (`userViteUrl`은 alpha.8 호환을 위해 alias로 유지)
23
+ - **`@jogak/next-adapter`**: Next 14+ App Router에 `<userRoot>/app/jogak-preview/page.tsx` scaffold(`.gitignore` 자동, shutdown cleanup). `next dev` child process spawn + HTTP poll ready 감지. CLI가 사전 생성한 `.jogak/registry.ts`의 entries를 import하여 모듈 평가 시점에 등록.
24
+ - **`@jogak/webpack-adapter`**: `<userRoot>/.jogak/webpack-preview/preview-entry.tsx` scaffold + `webpack-dev-server` programmatic API + `webpack-merge`로 사용자 webpack.config 통합.
105
25
 
106
26
  ### Changed
107
27
 
108
- - **컴포넌트 4개 + App shell 전면 마이그레이션** Sidebar / Preview / Controls / Actions /
109
- JogakApp의 inline style을 `jogak:` prefix Tailwind class로 변경 완료. Playwright VR 9
110
- 시나리오 multi-run 결정성으로 픽셀 동등 입증. alpha.4 baseline 대비 8/9 unchanged.
111
- - **잔존 inline style 11건** 모두 화이트리스트 (CSS variable 주입 + prism external interface).
112
- 라인 `eslint-disable-next-line no-restricted-syntax -- jogak: <카테고리>` 주석.
113
- - **dist 사이즈 감소** — mjs raw 35.3 → 33.9 KB / gzip 8.36 → 7.64 KB (skeleton inline
114
- 객체 + `<style>` 태그 제거 효과).
115
-
116
- ### Added
117
-
118
- - 신규 dependency: `clsx@^2.1.1` (boolean variant 결합용).
119
- - `--jogak-radius-sm` CSS variable 첫 사용 (Clear 버튼).
120
- - `.jogak-skeleton-shimmer` class + `@keyframes jogakSkeleton` (jogak.css `@layer components`).
121
-
122
- ### Removed
123
-
124
- - `--jogak-text-{xs,sm,base,md,lg}` 5개 CSS variable — 사용처 zero. font-size 픽셀 literal
125
- 채택 후 의미 상실. v4 `text-[var(--my-text-var)]` arbitrary value의 line-height 페어링
126
- 부수효과 회피 위해 픽셀 literal 정책 채택 (PR 1에서 발견).
127
- - `--jogak-sidebar-width` CSS variable — App grid 픽셀 literal 채택 후 사용처 zero.
28
+ - **`@jogak/core`**: `fs`/`path`를 사용하는 server-only utility(`detectBuilder`, `resolveGlobalCssPaths`, `detectUserGlobalCss`)를 `@jogak/core/server` subpath로 분리. client bundle에 Node 모듈이 leak되는 문제를 차단.
29
+ - **`@jogak/core`**, **`@jogak/ui`**, all adapters: CJS 산출물 확장자를 `.js` `.cjs`로 변경. `"type": "module"` 환경에서 `.js`가 ESM으로 해석되어 발생하던 `exports is not defined in ES module scope` 오류를 해소.
30
+ - **`previewIsolation`** default: `'shadow'` `'iframe'`. shadow DOM 모드는 일부 portal 라이브러리(Radix 등)와 호환성 이슈가 있어 iframe 격리를 표준으로.
31
+ - **`@jogak/ui`** preview-frame: 기존 `__jogak_setProps__` 직접 호출 프로토콜 → postMessage(`jogak:setProps` / `jogak:rendered` / `jogak:error`)로 통일. 모든 어댑터의 iframe entry가 동일 프로토콜을 따른다.
32
+ - **`@jogak/cli`**: `jogak dev`가 registry 생성 완료를 대기한 뒤 어댑터를 spawn (이전: fire-and-forget). non-vite 어댑터의 scaffold가 비어있는 registry를 import하던 race condition 해소.
128
33
 
129
34
  ### Fixed
130
35
 
131
- - Preview source toggle / prism `<pre>` / Controls action span / json code / td name cell
132
- 5곳에서 `font-[var(--jogak-font-mono)]`가 v4에서 `font-weight: var(...)`로 잘못 컴파일되던
133
- 문제. `font-[family-name:var(--jogak-font-mono)]` hint로 차단.
134
- - Preview viewport toggle / bottom-panel tab button에 `leading-none` 적용 시 flex 부모
135
- 높이가 1~2px 단축되던 문제. padding 보유 button에는 leading 미적용으로 baseline 정합.
136
-
137
- ## [0.1.0-alpha.4] — 2026-05-08
138
-
139
- ### Internal
140
-
141
- - `@jogak/ui` SPA 빌드 파이프라인에 Tailwind v4 + `prefix(jogak)` 도입 (인프라 단계).
142
- 사용자 번들 / publish 산출물에는 영향 없음.
143
- - jogak 디자인 토큰을 `--jogak-*` CSS variable로 정의 (알파.5 컴포넌트 마이그레이션 대비).
144
- - jogak SPA에 `data-jogak-shell` / `data-jogak-content` wrapper 추가 (알파.6 사용자 globalCss
145
- scope 정책 hook).
146
-
147
- ### Notes
148
-
149
- - jogak UI 컴포넌트(Sidebar/Preview/Controls/Actions)는 여전히 inline style 사용. Tailwind class
150
- 마이그레이션은 알파.5에서 진행.
151
- - 사용자 프로젝트의 globalCss(예: `src/index.css`)는 **현재 jogak SPA에 적용되지 않습니다**. 알파.6에서
152
- `JogakPluginOptions.globalCss` opt-in으로 지원 예정.
153
- - 사용자 프로젝트가 Tailwind를 사용해도 jogak prefix(`jogak:`)와 충돌하지 않음.
36
+ - **`@jogak/cli`**: 어댑터 dynamic import `import.meta.resolve`/`createRequire`가 cli/dist 기준으로 해석돼 사용자 cwd의 어댑터 패키지를 찾지 못하던 문제. `<cwd>/node_modules/@jogak/${name}-adapter/package.json`을 직접 읽어 `exports['.'].import` 경로로 해석하도록 변경.
37
+ - **`@jogak/next-adapter`**: 이전 시도의 `__jogak_preview__` 경로는 Next App Router의 private folder convention(`_`로 시작하는 폴더는 라우팅 제외) 충돌해 404. `jogak-preview`로 변경.
154
38
 
155
39
  ## [0.1.0-alpha.3] — 2026-05-07
156
40
 
package/dist/app/App.d.ts CHANGED
@@ -25,9 +25,17 @@ export interface JogakAppProps {
25
25
  */
26
26
  readonly previewIsolation?: 'none' | 'shadow' | 'iframe';
27
27
  /**
28
- * 알파.8: 사용자 vite spawn URL. iframe `src` base로 사용.
28
+ * 알파.9: 어댑터 dev URL. iframe `src` base.
29
29
  * 빈 문자열 시 fallback (jogak SPA Vite scope의 preview-frame.tsx).
30
30
  */
31
+ readonly userPreviewUrl?: string;
32
+ /**
33
+ * 알파.9: iframe entry path (예: `/__jogak_preview__/index.html`).
34
+ */
35
+ readonly previewEntryPath?: string;
36
+ /**
37
+ * @deprecated 알파.10 제거 예정. `userPreviewUrl` 사용.
38
+ */
31
39
  readonly userViteUrl?: string;
32
40
  }
33
- export declare function JogakApp({ entries, metas, codeTheme, previewIsolation, userViteUrl, }?: JogakAppProps): ReactElement;
41
+ export declare function JogakApp({ entries, metas, codeTheme, previewIsolation, userPreviewUrl, previewEntryPath, userViteUrl, }?: JogakAppProps): ReactElement;
@@ -4,10 +4,15 @@ export interface IframeMountProps {
4
4
  readonly entry: RegistryEntry;
5
5
  readonly args: Readonly<Record<string, unknown>>;
6
6
  /**
7
- * 알파.8: 사용자 vite spawn URL (예: `http://localhost:5174`).
7
+ * 알파.9: 어댑터 dev URL (예: `http://localhost:5174`).
8
8
  * 빈 문자열 시 fallback (jogak SPA Vite scope의 `/preview-frame.html`).
9
9
  */
10
- readonly userViteUrl: string;
10
+ readonly userPreviewUrl: string;
11
+ /**
12
+ * 알파.9: iframe entry path (예: `/__jogak_preview__/index.html`).
13
+ * 어댑터의 `previewEntryMeta.devEntryPath`.
14
+ */
15
+ readonly previewEntryPath: string;
11
16
  readonly className?: string;
12
17
  readonly 'data-testid'?: string;
13
18
  }
@@ -27,4 +32,4 @@ export interface IframeMountProps {
27
32
  * dynamic import. 사용자 vite scope의 entry 가상 모듈이 사용자 컴포넌트를 fetch하므로
28
33
  * 사용자 plugins(@tailwindcss/vite, custom alias 등)이 정상 작동.
29
34
  */
30
- export declare function IframeMount({ entry, args, userViteUrl, className, 'data-testid': dataTestId, }: IframeMountProps): ReactElement;
35
+ export declare function IframeMount({ entry, args, userPreviewUrl, previewEntryPath, className, 'data-testid': dataTestId, }: IframeMountProps): ReactElement;
@@ -21,10 +21,14 @@ export interface PreviewProps {
21
21
  */
22
22
  readonly previewIsolation?: 'none' | 'shadow' | 'iframe';
23
23
  /**
24
- * 알파.8: 사용자 vite spawn URL. iframe `src` base.
24
+ * 알파.9: 어댑터 dev URL. iframe `src` base.
25
25
  * 빈 문자열 시 fallback (jogak SPA Vite scope의 `/preview-frame.html`).
26
26
  */
27
- readonly userViteUrl?: string;
27
+ readonly userPreviewUrl?: string;
28
+ /**
29
+ * 알파.9: iframe entry path.
30
+ */
31
+ readonly previewEntryPath?: string;
28
32
  }
29
33
  /**
30
34
  * Preview — `useEntry(entryId)`의 status에 따라 분기 (계약 §5.4).
@@ -36,5 +40,5 @@ export interface PreviewProps {
36
40
  *
37
41
  * Layout shift 방지를 위해 캔버스 영역 minHeight 유지.
38
42
  */
39
- export declare function Preview({ entryId, jogakName, overrideArgs, onArgChange, onReset, codeTheme, onResolveJogak, previewIsolation, userViteUrl, }: PreviewProps): ReactElement;
43
+ export declare function Preview({ entryId, jogakName, overrideArgs, onArgChange, onReset, codeTheme, onResolveJogak, previewIsolation, userPreviewUrl, previewEntryPath, }: PreviewProps): ReactElement;
40
44
  export type { UseEntryState };
@@ -0,0 +1 @@
1
+ "use strict";var S=Object.create;var g=Object.defineProperty;var k=Object.getOwnPropertyDescriptor;var A=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,E=Object.prototype.hasOwnProperty;var H=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of A(t))!E.call(e,o)&&o!==r&&g(e,o,{get:()=>t[o],enumerable:!(n=k(t,o))||n.enumerable});return e};var a=(e,t,r)=>(r=e!=null?S(B(e)):{},H(t||!e||!e.__esModule?g(r,"default",{value:e,enumerable:!0}):r,e));Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const N=require("node:url"),u=require("node:path");var f=typeof document<"u"?document.currentScript:null;const x=N.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:f&&f.tagName.toUpperCase()==="SCRIPT"&&f.src||new URL("host/index.cjs",document.baseURI).href),s=u.resolve(u.dirname(x),"..",".."),F=u.resolve(s,"index.html"),V=u.resolve(s,"src/app/main.tsx");async function Y(e){const t=await import("vite"),r=await import("@vitejs/plugin-react"),n=await import("@jogak/core/vite"),o=await import("@tailwindcss/vite"),{createServer:y,build:h}=t,w=r.default,b=o.default,{jogak:P}=n,U=e.codeTheme??"vsDark",i={patterns:e.patterns,codeTheme:U,cwd:e.userRoot};e.tsConfigFilePath!==void 0&&(i.tsConfigFilePath=e.tsConfigFilePath),e.globalCss!==void 0&&(i.globalCss=e.globalCss),e.previewIsolation!==void 0&&(i.previewIsolation=e.previewIsolation),e.userPreviewUrl!==void 0&&(i.userPreviewUrl=e.userPreviewUrl),e.previewEntryPath!==void 0&&(i.previewEntryPath=e.previewEntryPath),e.userViteUrl!==void 0&&e.userPreviewUrl===void 0&&(i.userViteUrl=e.userViteUrl);const _=e.extraPlugins??[],d={root:s,configFile:!1,plugins:[w(),b(),P(i),..._],optimizeDeps:{include:["react","react-dom/client","@jogak/core","@jogak/react"]}};if(e.mode==="dev"){const D={port:e.port??5173,host:e.host??"localhost",open:e.open??!1,fs:{allow:[s,e.userRoot]}},L={...d,server:D},l=await y(L);await l.listen();const v=l.config.server.port??e.port??5173,c=e.host??"localhost",M=`http://${typeof c=="boolean"?c?"0.0.0.0":"localhost":c}:${v.toString()}/`;let p=!1;return{url:M,port:v,close:async()=>{p||(p=!0,await l.close())},printUrls:()=>{l.printUrls()}}}const C={...d,base:e.base??"./",build:{outDir:e.outDir,emptyOutDir:!0,sourcemap:e.sourcemap??!1,minify:e.minify??"esbuild",rollupOptions:{input:{main:u.resolve(s,"index.html"),preview:u.resolve(s,"preview-frame.html")}}}},R=Date.now(),I=await h(C),T=Date.now()-R,{assetCount:O,totalBytes:j}=q(I);return{outDir:e.outDir,elapsedMs:T,assetCount:O,totalBytes:j}}function q(e){const t=z(e);if(t===void 0)return{assetCount:0,totalBytes:0};let r=0,n=0;for(const o of t)r+=1,n+=$(o);return{assetCount:r,totalBytes:n}}function m(e){return typeof e=="object"&&e!==null&&Array.isArray(e.output)}function z(e){if(Array.isArray(e)){const t=[];for(const r of e)m(r)&&t.push(...r.output);return t}if(m(e))return e.output}function $(e){if(typeof e!="object"||e===null)return 0;const t=e;if(t.type==="chunk"&&typeof t.code=="string")return Buffer.byteLength(t.code,"utf8");if(t.type==="asset"){const r=t.source;if(typeof r=="string")return Buffer.byteLength(r,"utf8");if(r instanceof Uint8Array)return r.byteLength}return 0}exports.UI_HTML_ENTRY=F;exports.UI_MAIN_ENTRY=V;exports.runHost=Y;
@@ -58,12 +58,21 @@ export interface JogakHostOptionsBase {
58
58
  */
59
59
  readonly previewIsolation?: 'none' | 'shadow' | 'iframe';
60
60
  /**
61
- * 알파.8: 사용자 vite 인스턴스의 dev server URL (예: `http://localhost:5174`).
62
- * jogak SPA가 iframe `src` base로 사용한다 (`<iframe src="${userViteUrl}/__jogak_preview__/index.html">`).
61
+ * 알파.9: 어댑터 dev URL (예: `http://localhost:5174`).
62
+ * jogak SPA가 iframe `src` base로 사용한다.
63
63
  *
64
64
  * 미지정/빈 문자열 시 fallback (jogak SPA Vite scope의 preview-frame.tsx).
65
65
  *
66
- * jogak CLI spawnUserVite 결과를 자동 전달 — 사용자가 직접 설정하지 않는다.
66
+ * jogak CLI 어댑터 dispatch 결과 자동 전달 — 사용자가 직접 설정하지 않는다.
67
+ */
68
+ readonly userPreviewUrl?: string;
69
+ /**
70
+ * 알파.9: iframe entry path (예: `/__jogak_preview__/index.html`).
71
+ * `BuilderAdapter.previewEntryMeta.devEntryPath` 값. CLI 자동 전달.
72
+ */
73
+ readonly previewEntryPath?: string;
74
+ /**
75
+ * @deprecated 알파.10 제거 예정. `userPreviewUrl` 사용.
67
76
  */
68
77
  readonly userViteUrl?: string;
69
78
  }
@@ -1,18 +1,18 @@
1
1
  import { fileURLToPath as k } from "node:url";
2
- import { resolve as i, dirname as B } from "node:path";
3
- const T = k(import.meta.url), r = i(B(T), "..", ".."), z = i(r, "index.html"), N = i(r, "src/app/main.tsx");
4
- async function S(t) {
5
- const e = await import("vite"), o = await import("@vitejs/plugin-react"), s = await import("@jogak/core/vite"), l = await import("@tailwindcss/vite"), { createServer: m, build: g } = e, y = o.default, h = l.default, { jogak: v } = s, w = t.codeTheme ?? "vsDark", n = {
2
+ import { resolve as n, dirname as B } from "node:path";
3
+ const T = k(import.meta.url), i = n(B(T), "..", ".."), V = n(i, "index.html"), z = n(i, "src/app/main.tsx");
4
+ async function N(t) {
5
+ const e = await import("vite"), o = await import("@vitejs/plugin-react"), s = await import("@jogak/core/vite"), l = await import("@tailwindcss/vite"), { createServer: v, build: m } = e, g = o.default, y = l.default, { jogak: w } = s, h = t.codeTheme ?? "vsDark", r = {
6
6
  patterns: t.patterns,
7
- codeTheme: w,
7
+ codeTheme: h,
8
8
  cwd: t.userRoot
9
9
  };
10
- t.tsConfigFilePath !== void 0 && (n.tsConfigFilePath = t.tsConfigFilePath), t.globalCss !== void 0 && (n.globalCss = t.globalCss), t.previewIsolation !== void 0 && (n.previewIsolation = t.previewIsolation), t.userViteUrl !== void 0 && (n.userViteUrl = t.userViteUrl);
10
+ t.tsConfigFilePath !== void 0 && (r.tsConfigFilePath = t.tsConfigFilePath), t.globalCss !== void 0 && (r.globalCss = t.globalCss), t.previewIsolation !== void 0 && (r.previewIsolation = t.previewIsolation), t.userPreviewUrl !== void 0 && (r.userPreviewUrl = t.userPreviewUrl), t.previewEntryPath !== void 0 && (r.previewEntryPath = t.previewEntryPath), t.userViteUrl !== void 0 && t.userPreviewUrl === void 0 && (r.userViteUrl = t.userViteUrl);
11
11
  const b = t.extraPlugins ?? [], c = {
12
- root: r,
12
+ root: i,
13
13
  configFile: !1,
14
14
  // ui/vite.config.ts 무시
15
- plugins: [y(), h(), v(n), ...b],
15
+ plugins: [g(), y(), w(r), ...b],
16
16
  optimizeDeps: {
17
17
  include: ["react", "react-dom/client", "@jogak/core", "@jogak/react"]
18
18
  }
@@ -22,11 +22,11 @@ async function S(t) {
22
22
  port: t.port ?? 5173,
23
23
  host: t.host ?? "localhost",
24
24
  open: t.open ?? !1,
25
- fs: { allow: [r, t.userRoot] }
25
+ fs: { allow: [i, t.userRoot] }
26
26
  }, _ = {
27
27
  ...c,
28
28
  server: I
29
- }, a = await m(_);
29
+ }, a = await v(_);
30
30
  await a.listen();
31
31
  const f = a.config.server.port ?? t.port ?? 5173, u = t.host ?? "localhost", j = `http://${typeof u == "boolean" ? u ? "0.0.0.0" : "localhost" : u}:${f.toString()}/`;
32
32
  let d = !1;
@@ -41,7 +41,7 @@ async function S(t) {
41
41
  }
42
42
  };
43
43
  }
44
- const C = {
44
+ const P = {
45
45
  ...c,
46
46
  base: t.base ?? "./",
47
47
  build: {
@@ -51,15 +51,15 @@ async function S(t) {
51
51
  minify: t.minify ?? "esbuild",
52
52
  rollupOptions: {
53
53
  input: {
54
- main: i(r, "index.html"),
55
- preview: i(r, "preview-frame.html")
54
+ main: n(i, "index.html"),
55
+ preview: n(i, "preview-frame.html")
56
56
  }
57
57
  }
58
58
  }
59
- }, P = Date.now(), O = await g(C), U = Date.now() - P, { assetCount: D, totalBytes: R } = x(O);
59
+ }, U = Date.now(), C = await m(P), O = Date.now() - U, { assetCount: D, totalBytes: R } = x(C);
60
60
  return {
61
61
  outDir: t.outDir,
62
- elapsedMs: U,
62
+ elapsedMs: O,
63
63
  assetCount: D,
64
64
  totalBytes: R
65
65
  };
@@ -99,7 +99,7 @@ function L(t) {
99
99
  return 0;
100
100
  }
101
101
  export {
102
- z as UI_HTML_ENTRY,
103
- N as UI_MAIN_ENTRY,
104
- S as runHost
102
+ V as UI_HTML_ENTRY,
103
+ z as UI_MAIN_ENTRY,
104
+ N as runHost
105
105
  };
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("react/jsx-runtime"),l=require("react"),C=require("@jogak/core"),h=require("@jogak/react"),$=require("prism-react-renderer"),Q=require("react-dom");function B(a){var e,t,r="";if(typeof a=="string"||typeof a=="number")r+=a;else if(typeof a=="object")if(Array.isArray(a)){var s=a.length;for(e=0;e<s;e++)a[e]&&(t=B(a[e]))&&(r&&(r+=" "),r+=t)}else for(t in a)a[t]&&(r&&(r+=" "),r+=t);return r}function w(){for(var a,e,t=0,r="",s=arguments.length;t<s;t++)(a=arguments[t])&&(e=B(a))&&(r&&(r+=" "),r+=e);return r}function W({selectedEntryId:a,selectedJogakName:e,onSelect:t}){const[r,s]=l.useState(""),{metaTree:n,searchMeta:g}=h.useRegistryMeta(),j=r.trim().length>0?g(r):null;return o.jsxs("aside",{"data-testid":"sidebar",className:"jogak:flex jogak:flex-col jogak:h-full jogak:overflow-auto jogak:border-r jogak:border-[var(--jogak-color-border)]",children:[o.jsx("div",{className:"jogak:p-3 jogak:border-b jogak:border-[var(--jogak-color-border)]",children:o.jsx("input",{type:"search",placeholder:"Search components...",value:r,onChange:c=>{s(c.target.value)},className:"jogak:w-full jogak:px-2 jogak:py-1.5 jogak:border jogak:border-[var(--jogak-color-border-strong)] jogak:rounded-[var(--jogak-radius-md)]","aria-label":"Search components"})}),o.jsx("nav",{className:"jogak:flex-1 jogak:overflow-auto jogak:py-2",children:j!==null?o.jsx(X,{metas:j,selectedEntryId:a,selectedJogakName:e,onSelect:t}):o.jsx(z,{node:n,selectedEntryId:a,selectedJogakName:e,onSelect:t})})]})}function X({metas:a,selectedEntryId:e,selectedJogakName:t,onSelect:r}){return a.length===0?o.jsx("p",{className:"jogak:px-3 jogak:text-[var(--jogak-color-fg-subtle)] jogak:text-[13px]",children:"No results"}):o.jsx("ul",{className:"jogak:list-none jogak:m-0 jogak:p-0",children:a.map(s=>o.jsx("li",{children:o.jsx(D,{meta:s,selectedEntryId:e,selectedJogakName:t,onSelect:r,indent:0})},s.id))})}function z({node:a,selectedEntryId:e,selectedJogakName:t,onSelect:r,depth:s=0}){return o.jsx("ul",{className:"jogak:list-none jogak:m-0 jogak:pr-0 jogak:py-0 jogak:pl-[var(--jogak-tree-pl)]",style:{"--jogak-tree-pl":`${s*12}px`},children:Object.entries(a).map(([n,g])=>o.jsx("li",{children:"id"in g?o.jsx(D,{meta:g,selectedEntryId:e,selectedJogakName:t,onSelect:r,indent:0}):o.jsx(Y,{label:n,node:g,selectedEntryId:e,selectedJogakName:t,onSelect:r,depth:s+1})},n))})}function Y({label:a,node:e,selectedEntryId:t,selectedJogakName:r,onSelect:s,depth:n}){const[g,j]=l.useState(!0);return o.jsxs("div",{children:[o.jsxs("button",{type:"button",onClick:()=>{j(c=>!c)},className:"jogak:flex jogak:items-center jogak:gap-1 jogak:w-full jogak:px-3 jogak:py-1 jogak:bg-transparent jogak:border-none jogak:cursor-pointer jogak:text-[12px] jogak:font-semibold jogak:text-[var(--jogak-color-fg-muted)] jogak:uppercase jogak:tracking-wider","aria-expanded":g,children:[o.jsx("span",{children:g?"▾":"▸"}),a]}),g&&o.jsx(z,{node:e,selectedEntryId:t,selectedJogakName:r,onSelect:s,depth:n})]})}function D({meta:a,selectedEntryId:e,selectedJogakName:t,onSelect:r,indent:s}){const n=a.id===e,[g,j]=l.useState(n);l.useEffect(()=>{n&&j(!0)},[n]);const c=a.title.split("/").pop()??a.title,d=16+s*12;return o.jsxs("div",{children:[o.jsxs("button",{type:"button",onClick:()=>{if(n)j(k=>!k);else{j(!0);const k=a.jogakNames[0];k!==void 0&&r(a.id,k)}},className:w("jogak:flex jogak:items-center jogak:gap-1.5 jogak:w-full jogak:pr-3 jogak:py-[5px]","jogak:pl-[var(--jogak-entry-pl)]","jogak:border-none jogak:cursor-pointer jogak:text-left jogak:text-[13px]",n?"jogak:bg-[var(--jogak-color-accent-bg)] jogak:text-[var(--jogak-color-accent)] jogak:font-medium":"jogak:bg-transparent jogak:text-[var(--jogak-color-fg)] jogak:font-normal"),style:{"--jogak-entry-pl":`${d}px`},"aria-expanded":g,children:[o.jsx("span",{className:"jogak:text-[10px] jogak:shrink-0 jogak:leading-none",children:g?"▾":"▸"}),c]}),g&&o.jsx("ul",{className:"jogak:list-none jogak:m-0 jogak:p-0",children:a.jogakNames.map(k=>{const i=n&&k===t;return o.jsx("li",{children:o.jsx("button",{type:"button",onClick:()=>{r(a.id,k)},className:w("jogak:block jogak:w-full jogak:text-left jogak:pr-3 jogak:py-1","jogak:pl-[var(--jogak-jogak-pl)]","jogak:border-none jogak:cursor-pointer jogak:text-[12px]",i?"jogak:bg-[var(--jogak-color-accent-bg-soft)] jogak:text-[var(--jogak-color-accent-fg)] jogak:font-medium":"jogak:bg-transparent jogak:text-[var(--jogak-color-fg-muted)] jogak:font-normal"),style:{"--jogak-jogak-pl":`${d+18}px`},"aria-current":i?"true":void 0,children:k})},k)})})]})}function Z(a,e){const t=e==null?void 0:e.control,r=(e==null?void 0:e.action)!==void 0&&e.action!==!1,s=(e==null?void 0:e.type)==="function"||typeof a=="function";return r||s?"action":t==="boolean"||typeof a=="boolean"?"boolean":t==="number"||t==="range"||typeof a=="number"?"number":t==="select"||t==="radio"||(e==null?void 0:e.options)!==void 0&&e.options.length>0?"select":t==="text"||t==="color"||typeof a=="string"?"text":"json"}const A="jogak:px-2 jogak:py-1 jogak:border jogak:border-[var(--jogak-color-border-strong)] jogak:rounded-[var(--jogak-radius-md)] jogak:text-[13px] jogak:w-full jogak:max-w-[280px]",_="jogak:px-5 jogak:py-1.5 jogak:text-left jogak:text-[var(--jogak-color-fg-muted)] jogak:font-medium jogak:text-[12px] jogak:border-b jogak:border-[var(--jogak-color-border)]",E="jogak:px-5 jogak:py-2 jogak:align-middle jogak:border-b jogak:border-[var(--jogak-color-border-muted)]";function K({argKey:a,value:e,argType:t,onArgChange:r}){switch(Z(e,t)){case"boolean":return o.jsx("input",{type:"checkbox",checked:e===!0,onChange:n=>{r(a,n.target.checked)},className:"jogak:cursor-pointer jogak:w-4 jogak:h-4 jogak:accent-[var(--jogak-color-accent)]"});case"number":return o.jsx("input",{type:"number",value:typeof e=="number"?e:"",onChange:n=>{r(a,n.target.valueAsNumber)},className:A});case"select":{const n=(t==null?void 0:t.options)??[];return o.jsx("select",{value:String(e??""),onChange:g=>{r(a,g.target.value)},className:A,children:n.map(g=>o.jsx("option",{value:String(g),children:String(g)},String(g)))})}case"text":return o.jsx("input",{type:"text",value:typeof e=="string"?e:String(e??""),onChange:n=>{r(a,n.target.value)},className:A});case"action":return o.jsx("span",{className:"jogak:inline-block jogak:px-2 jogak:py-0.5 jogak:text-[11px] jogak:font-semibold jogak:text-[var(--jogak-color-violet)] jogak:bg-[var(--jogak-color-violet-bg)] jogak:border jogak:border-[var(--jogak-color-violet-border)] jogak:rounded-[var(--jogak-radius-md)] jogak:font-[family-name:var(--jogak-font-mono)] jogak:leading-none",children:"(action)"});case"json":return o.jsx("code",{className:"jogak:text-[12px] jogak:text-[var(--jogak-color-fg-muted)] jogak:font-[family-name:var(--jogak-font-mono)]",children:JSON.stringify(e)})}}function F({args:a,argTypes:e,onArgChange:t}){const s=Array.from(new Set([...Object.keys(a),...Object.keys(e)])).map(n=>[n,a[n]]);return o.jsxs("div",{className:"jogak:border-t-2 jogak:border-[var(--jogak-color-border)]",children:[o.jsx("div",{className:"jogak:px-5 jogak:py-1.5 jogak:text-[11px] jogak:font-bold jogak:text-[var(--jogak-color-fg-subtle)] jogak:uppercase jogak:tracking-[0.08em] jogak:border-b jogak:border-[var(--jogak-color-border)] jogak:bg-[var(--jogak-color-bg-subtle)]",children:"Controls"}),s.length===0?o.jsx("div",{className:"jogak:px-5 jogak:py-3 jogak:text-[var(--jogak-color-fg-subtle)] jogak:text-[13px]",children:"No args defined"}):o.jsxs("table",{className:"jogak:w-full jogak:border-collapse jogak:text-[13px]",children:[o.jsx("thead",{children:o.jsxs("tr",{children:[o.jsx("th",{className:_,children:"Name"}),o.jsx("th",{className:_,children:"Control"}),o.jsx("th",{className:_,children:"Description"})]})}),o.jsx("tbody",{children:s.map(([n,g])=>{const j=e[n];return o.jsxs("tr",{children:[o.jsx("td",{className:w(E,"jogak:font-[family-name:var(--jogak-font-mono)] jogak:text-[12px] jogak:text-[var(--jogak-color-fg)] jogak:whitespace-nowrap"),children:n}),o.jsx("td",{className:E,children:o.jsx(K,{argKey:n,value:g,argType:j,onArgChange:t})}),o.jsx("td",{className:w(E,"jogak:text-[var(--jogak-color-fg-subtle)]"),children:(j==null?void 0:j.description)??""})]},n)})})]})]})}function T(a){if(a.length===0)return"()";try{return a.map(e=>{var t;if(e===null)return"null";if(e===void 0)return"undefined";if(typeof e=="function")return"[Function]";if(typeof e=="object"){const r=((t=e.constructor)==null?void 0:t.name)??"Object";return r!=="Object"&&r!=="Array"?`[${r}]`:JSON.stringify(e)}return JSON.stringify(e)}).join(", ")}catch{return"[unserializable]"}}function oo(a){const e=new Date(a),t=e.getHours().toString().padStart(2,"0"),r=e.getMinutes().toString().padStart(2,"0"),s=e.getSeconds().toString().padStart(2,"0"),n=e.getMilliseconds().toString().padStart(3,"0");return`${t}:${r}:${s}.${n}`}function H(){const[a,e]=l.useState(()=>C.defaultActionChannel.getLogs());l.useEffect(()=>C.defaultActionChannel.subscribe(e),[]);const t=a.length===0;return o.jsxs("div",{className:"jogak:h-full jogak:flex jogak:flex-col",children:[o.jsxs("div",{className:"jogak:px-5 jogak:py-1.5 jogak:text-[11px] jogak:font-bold jogak:text-[var(--jogak-color-fg-subtle)] jogak:uppercase jogak:tracking-[0.08em] jogak:border-b jogak:border-[var(--jogak-color-border)] jogak:bg-[var(--jogak-color-bg-subtle)] jogak:flex jogak:items-center jogak:justify-between jogak:shrink-0",children:[o.jsxs("span",{children:["Actions ",a.length>0&&`(${a.length.toString()})`]}),o.jsx("button",{type:"button",onClick:()=>{C.defaultActionChannel.clear()},disabled:t,className:w("jogak:text-[10px] jogak:font-semibold jogak:px-2 jogak:py-0.5 jogak:border jogak:border-[var(--jogak-color-border-strong)] jogak:rounded-[var(--jogak-radius-sm)] jogak:bg-[var(--jogak-color-bg)] jogak:normal-case jogak:tracking-normal",t?"jogak:text-[var(--jogak-color-fg-subtle)] jogak:cursor-default":"jogak:text-[var(--jogak-color-fg)] jogak:cursor-pointer"),children:"Clear"})]}),o.jsx("div",{className:"jogak:flex-1 jogak:overflow-auto",children:t?o.jsx("div",{className:"jogak:px-5 jogak:py-3 jogak:text-[var(--jogak-color-fg-subtle)] jogak:text-[13px] jogak:leading-none",children:"함수 prop이 호출되면 여기에 기록됩니다"}):o.jsx("ul",{className:"jogak:list-none jogak:m-0 jogak:p-0 jogak:font-[family-name:var(--jogak-font-mono)] jogak:text-[12px]",children:a.map(r=>o.jsxs("li",{className:"jogak:flex jogak:items-baseline jogak:gap-[10px] jogak:px-5 jogak:py-1.5 jogak:border-b jogak:border-[var(--jogak-color-border-muted)]",children:[o.jsx("span",{className:"jogak:text-[var(--jogak-color-fg-subtle)] jogak:text-[11px] jogak:min-w-[92px]",children:oo(r.timestamp)}),o.jsx("span",{className:"jogak:text-[var(--jogak-color-violet)] jogak:font-semibold",children:r.name}),o.jsxs("span",{className:"jogak:text-[var(--jogak-color-fg)] jogak:break-all jogak:flex-1",children:["(",T(r.args),")"]})]},r.id))})})]})}function ao({children:a,className:e,style:t,"data-testid":r}){const s=l.useRef(null),[n,g]=l.useState(null);return l.useEffect(()=>{const j=s.current;if(j===null)return;const c=j.shadowRoot??j.attachShadow({mode:"open"});g(c)},[]),o.jsx("div",{ref:s,className:e,"data-testid":r,style:t,children:n!==null?Q.createPortal(a,n):null})}function eo({entry:a,args:e,userPreviewUrl:t,previewEntryPath:r,className:s,"data-testid":n}){const g=l.useRef(null),[j,c]=l.useState(!1),d=t!==""?`${t}${r}`:"/preview-frame.html";return l.useEffect(()=>{const k=i=>{const m=g.current;if(m===null||i.source!==m.contentWindow)return;const x=i.data;x==null||typeof x!="object"||x.type==="jogak:ready"&&c(!0)};return window.addEventListener("message",k),()=>{window.removeEventListener("message",k)}},[]),l.useEffect(()=>{var i;if(!j)return;const k=g.current;k!==null&&((i=k.contentWindow)==null||i.postMessage({type:"jogak:setProps",entryId:a.id,args:e},"*"))},[j,a,e]),l.useEffect(()=>{const k=g.current;return()=>{k!==null&&queueMicrotask(()=>{var i;(i=k.contentWindow)==null||i.postMessage({type:"jogak:unmount"},"*")})}},[]),o.jsx("iframe",{ref:g,src:d,title:"Preview",className:s,"data-testid":n})}const U={mobile:375,tablet:768,desktop:"none"},to={mobile:"Mobile",tablet:"Tablet",desktop:"Desktop"},O={white:{"--jogak-canvas-bg":"#ffffff","--jogak-canvas-bg-image":"none","--jogak-canvas-bg-size":"auto","--jogak-canvas-bg-position":"0 0"},dark:{"--jogak-canvas-bg":"#1f2937","--jogak-canvas-bg-image":"none","--jogak-canvas-bg-size":"auto","--jogak-canvas-bg-position":"0 0"},transparent:{"--jogak-canvas-bg":"#ffffff","--jogak-canvas-bg-image":"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%)","--jogak-canvas-bg-size":"16px 16px","--jogak-canvas-bg-position":"0 0, 0 8px, 8px -8px, -8px 0px"}},L="jogak:bg-[var(--jogak-canvas-bg)] jogak:bg-[image:var(--jogak-canvas-bg-image)] jogak:bg-[length:var(--jogak-canvas-bg-size)] jogak:bg-[position:var(--jogak-canvas-bg-position)]";function ro(a){return $.themes[a]??$.themes.vsDark}function G({entryId:a,jogakName:e,overrideArgs:t,onArgChange:r,onReset:s,codeTheme:n,onResolveJogak:g,previewIsolation:j="iframe",userPreviewUrl:c="",previewEntryPath:d="/__jogak_preview__/index.html"}){const k=h.useEntry(a),[i,m]=l.useState("desktop"),[x,y]=l.useState("white"),[N,b]=l.useState("controls"),v=ro(n);return k.status==="unknown"?o.jsxs("div",{"data-testid":"preview-not-found",className:"jogak:p-6 jogak:text-[var(--jogak-color-error)]",children:["Entry not found: ",a]}):k.status==="error"?o.jsxs("div",{"data-testid":"preview-error",className:"jogak:p-6 jogak:text-[var(--jogak-color-error-fg)] jogak:bg-[var(--jogak-color-bg-error)] jogak:h-full jogak:flex jogak:flex-col jogak:gap-3 jogak:items-start",children:[o.jsxs("div",{className:"jogak:font-semibold",children:["Failed to load entry: ",a]}),o.jsx("pre",{className:"jogak:m-0 jogak:p-3 jogak:bg-[var(--jogak-color-bg)] jogak:border jogak:border-[var(--jogak-color-error-border)] jogak:rounded-[var(--jogak-radius-lg)] jogak:text-[12px] jogak:whitespace-pre-wrap jogak:max-w-full",children:k.error.message})]}):k.status==="loading"?o.jsx(no,{meta:k.meta,jogakName:e,viewport:i,bgMode:x,onViewportChange:m,onBgModeChange:y}):o.jsx(so,{entry:k.entry,jogakName:e,overrideArgs:t,onArgChange:r,onReset:s,onResolveJogak:g,viewport:i,bgMode:x,bottomTab:N,onViewportChange:m,onBgModeChange:y,onBottomTabChange:b,prismTheme:v,previewIsolation:j,userPreviewUrl:c,previewEntryPath:d})}function no({meta:a,jogakName:e,viewport:t,bgMode:r,onViewportChange:s,onBgModeChange:n}){const g=e??a.jogakNames[0]??"...",j=U[t];return o.jsxs("div",{"data-testid":"preview-loading",className:"jogak:flex jogak:flex-col jogak:h-full",children:[o.jsx(I,{title:a.title,jogakName:g,viewport:t,bgMode:r,onViewportChange:s,onBgModeChange:n,showReset:!1,onReset:()=>{}}),o.jsx("div",{className:`jogak:flex-1 jogak:overflow-auto jogak:min-h-[320px] ${L}`,style:O[r],children:o.jsx("div",{className:"jogak:mx-auto jogak:p-6 jogak:max-w-[var(--jogak-canvas-mw)]",style:{"--jogak-canvas-mw":j==="none"?"100%":`${j}px`},children:o.jsxs("div",{className:"jogak-skeleton-shimmer jogak:border jogak:border-dashed jogak:border-[var(--jogak-color-border)] jogak:rounded-[var(--jogak-radius-xl)] jogak:p-4 jogak:flex jogak:items-center jogak:justify-center jogak:text-[var(--jogak-color-fg-subtle)] jogak:text-[13px] jogak:min-h-[256px]",children:["Loading ",a.title,"…"]})})})]})}function so({entry:a,jogakName:e,overrideArgs:t,onArgChange:r,onReset:s,onResolveJogak:n,viewport:g,bgMode:j,bottomTab:c,onViewportChange:d,onBgModeChange:k,onBottomTabChange:i,prismTheme:m,previewIsolation:x,userPreviewUrl:y,previewEntryPath:N}){var J;const b=e??((J=a.jogaks[0])==null?void 0:J.name)??null;if(l.useEffect(()=>{e===null&&b!==null&&n!==void 0&&n(a.id,b)},[e,b,a.id,n]),b===null)return o.jsxs("div",{className:"jogak:p-6 jogak:text-[var(--jogak-color-error)]",children:["Entry has no jogaks: ",a.id]});const v=a.jogaks.find(S=>S.name===b);if(v===void 0)return o.jsxs("div",{className:"jogak:p-6 jogak:text-[var(--jogak-color-error)]",children:["Jogak not found: ",b]});const R={...v.args??{},...t},u={...a.meta.argTypes??{},...v.argTypes??{}},p=Object.keys(t).length>0,f=U[g];return o.jsxs("div",{className:"jogak:flex jogak:flex-col jogak:h-full",children:[o.jsx(I,{title:a.title,jogakName:v.name,viewport:g,bgMode:j,onViewportChange:d,onBgModeChange:k,showReset:p,onReset:s}),o.jsx("div",{className:`jogak:flex-1 jogak:overflow-auto jogak:min-h-[320px] ${L}`,style:O[j],children:o.jsx("div",{"data-jogak-content":!0,className:"jogak:mx-auto jogak:p-6 jogak:max-w-[var(--jogak-canvas-mw)]",style:{"--jogak-canvas-mw":f==="none"?"100%":`${f}px`},children:o.jsx(go,{entry:a,args:R,source:a.source,theme:m,previewIsolation:x,userPreviewUrl:y,previewEntryPath:N},`${a.id}/${v.name}`)})}),o.jsxs("div",{"data-testid":"bottom-panel",className:"jogak:h-[260px] jogak:shrink-0 jogak:flex jogak:flex-col jogak:border-t-2 jogak:border-[var(--jogak-color-border)]",children:[o.jsx("div",{role:"tablist",className:"jogak:flex jogak:gap-1 jogak:pt-1 jogak:px-3 jogak:pb-0 jogak:bg-[var(--jogak-color-bg)] jogak:border-b jogak:border-[var(--jogak-color-border)] jogak:shrink-0",children:["controls","actions"].map(S=>{const q=c===S;return o.jsx("button",{type:"button",role:"tab","aria-selected":q,onClick:()=>{i(S)},className:w("jogak:px-[14px] jogak:py-[6px] jogak:text-[12px] jogak:bg-transparent jogak:border-x-0 jogak:border-t-0 jogak:border-b-2 jogak:border-solid jogak:-mb-px jogak:cursor-pointer jogak:capitalize",q?"jogak:font-semibold jogak:text-[var(--jogak-color-fg-strong)] jogak:border-[var(--jogak-color-accent)]":"jogak:font-medium jogak:text-[var(--jogak-color-fg-muted)] jogak:border-transparent"),children:S},S)})}),o.jsx("div",{className:"jogak:flex-1 jogak:min-h-0 jogak:overflow-auto",children:c==="controls"?o.jsx(F,{args:R,argTypes:u,onArgChange:r}):o.jsx(H,{})})]})]})}function I({title:a,jogakName:e,viewport:t,bgMode:r,onViewportChange:s,onBgModeChange:n,showReset:g,onReset:j}){return o.jsxs("div",{className:"jogak:flex jogak:items-center jogak:gap-[10px] jogak:px-[14px] jogak:py-[7px] jogak:border-b jogak:border-[var(--jogak-color-border)] jogak:bg-[var(--jogak-color-bg)] jogak:shrink-0",children:[o.jsxs("div",{className:"jogak:flex-1 jogak:text-[13px]",children:[o.jsx("span",{className:"jogak:text-[var(--jogak-color-fg-subtle)]",children:a}),o.jsx("span",{className:"jogak:text-[var(--jogak-color-border-strong)] jogak:mx-1.5 jogak:leading-none",children:"/"}),o.jsx("span",{className:"jogak:text-[var(--jogak-color-fg-strong)] jogak:font-semibold",children:e})]}),o.jsx("div",{className:"jogak:flex jogak:gap-0.5 jogak:bg-[var(--jogak-color-bg-subtle)] jogak:rounded-[var(--jogak-radius-lg)] jogak:p-0.5",children:["mobile","tablet","desktop"].map(c=>o.jsx("button",{type:"button",onClick:()=>{s(c)},"aria-pressed":t===c,className:w("jogak:px-[9px] jogak:py-[3px] jogak:text-[12px] jogak:border-none jogak:rounded-[var(--jogak-radius-md)] jogak:cursor-pointer jogak:transition-all jogak:duration-100",t===c?"jogak:bg-[var(--jogak-color-bg-elevated)] jogak:text-[var(--jogak-color-fg-strong)] jogak:font-semibold jogak:shadow-[0_1px_2px_rgba(0,0,0,0.08)]":"jogak:bg-transparent jogak:text-[var(--jogak-color-fg-muted)] jogak:font-normal jogak:shadow-none"),children:to[c]},c))}),o.jsx("div",{className:"jogak:flex jogak:gap-1 jogak:items-center",children:["white","dark","transparent"].map(c=>o.jsx("button",{type:"button",onClick:()=>{n(c)},"aria-pressed":r===c,"aria-label":`${c} background`,className:w("jogak:w-5 jogak:h-5 jogak:rounded-[var(--jogak-radius-md)] jogak:border-2 jogak:cursor-pointer jogak:p-0 jogak:shrink-0",L,r===c?"jogak:border-[var(--jogak-color-accent)]":"jogak:border-[var(--jogak-color-border-strong)]"),style:O[c]},c))}),g&&o.jsx("button",{type:"button",onClick:j,className:"jogak:px-[10px] jogak:py-[3px] jogak:text-[12px] jogak:border jogak:border-[var(--jogak-color-border-strong)] jogak:rounded-[var(--jogak-radius-md)] jogak:bg-[var(--jogak-color-bg)] jogak:cursor-pointer jogak:text-[var(--jogak-color-fg)] jogak:leading-none",children:"Reset"})]})}function go({entry:a,args:e,source:t,theme:r,previewIsolation:s,userPreviewUrl:n,previewEntryPath:g}){const[j,c]=l.useState(!1),d=o.jsxs("div",{className:"jogak:relative",children:[o.jsx(jo,{entry:a,args:e,previewIsolation:s,userPreviewUrl:n,previewEntryPath:g}),o.jsx("button",{type:"button",onClick:()=>{c(k=>!k)},"aria-pressed":j,"aria-label":j?"Hide source code":"Show source code",className:w("jogak:absolute jogak:bottom-2 jogak:right-2 jogak:px-[9px] jogak:py-1","jogak:text-[11px] jogak:font-[family-name:var(--jogak-font-mono)] jogak:font-semibold jogak:tracking-[0.02em]","jogak:text-[var(--jogak-color-bg)] jogak:border-none jogak:rounded-[5px] jogak:cursor-pointer","jogak:shadow-[0_1px_4px_rgba(0,0,0,0.2)] jogak:transition-[background-color] jogak:duration-150 jogak:leading-none",j?"jogak:bg-[var(--jogak-color-accent)]":"jogak:bg-[#1e293b]"),children:"</>"})]});return o.jsxs("div",{children:[d,j&&o.jsx("div",{className:"jogak:mt-2 jogak:rounded-[var(--jogak-radius-xl)] jogak:overflow-hidden jogak:h-[320px] jogak:shadow-[0_0_0_1px_rgba(0,0,0,0.08),_0_4px_16px_rgba(0,0,0,0.12)]",children:o.jsx(co,{source:t,theme:r})})]})}const M="jogak:border jogak:border-dashed jogak:border-[var(--jogak-color-border)] jogak:rounded-[var(--jogak-radius-xl)] jogak:p-4 jogak:pb-9";function jo({entry:a,args:e,previewIsolation:t,userPreviewUrl:r,previewEntryPath:s}){return t==="shadow"?o.jsx(ao,{"data-testid":"preview-content",className:M,children:o.jsx(ko,{entry:a,args:e})}):t==="iframe"?o.jsx(eo,{entry:a,args:e,userPreviewUrl:r,previewEntryPath:s,"data-testid":"preview-content",className:`${M} jogak:block jogak:w-full jogak:bg-transparent jogak:min-h-[256px]`}):o.jsx(lo,{entry:a,args:e})}function lo({entry:a,args:e}){const t=l.useRef(null);return l.useEffect(()=>{const r=t.current;if(r!==null)return h.reactAdapter.render(a,e,r),()=>{queueMicrotask(()=>{h.reactAdapter.unmount(r)})}},[a]),l.useEffect(()=>{const r=t.current;r!==null&&h.reactAdapter.render(a,e,r)},[a,e]),o.jsx("div",{ref:t,"data-testid":"preview-content",className:M})}function ko({entry:a,args:e}){const t=l.useRef(null);return l.useEffect(()=>{const r=t.current;if(r!==null)return h.reactAdapter.render(a,e,r),()=>{queueMicrotask(()=>{h.reactAdapter.unmount(r)})}},[a]),l.useEffect(()=>{const r=t.current;r!==null&&h.reactAdapter.render(a,e,r)},[a,e]),o.jsx("div",{ref:t,"data-testid":"preview-content-shadow"})}function co({source:a,theme:e}){const[t,r]=l.useState(!1),s=e.plain.backgroundColor??"#1e293b";if(a===void 0)return o.jsx("div",{className:"jogak:h-full jogak:flex jogak:items-center jogak:justify-center jogak:bg-[var(--jogak-source-bg)] jogak:text-[#94a3b8] jogak:text-[13px]",style:{"--jogak-source-bg":s},children:"Source not available"});const n=()=>{navigator.clipboard.writeText(a).then(()=>{r(!0),setTimeout(()=>{r(!1)},2e3)})};return o.jsxs("div",{className:"jogak:relative jogak:h-full",children:[o.jsx("button",{type:"button",onClick:n,className:"jogak:absolute jogak:top-[10px] jogak:right-3 jogak:z-[1] jogak:px-[9px] jogak:py-[3px] jogak:text-[11px] jogak:bg-[rgba(255,255,255,0.1)] jogak:text-[#e2e8f0] jogak:border jogak:border-[rgba(255,255,255,0.18)] jogak:rounded-[var(--jogak-radius-md)] jogak:cursor-pointer jogak:leading-none",children:t?"✓ Copied":"Copy"}),o.jsx($.Highlight,{code:a.trim(),language:"tsx",theme:e,children:({style:g,tokens:j,getLineProps:c,getTokenProps:d})=>o.jsx("pre",{className:"jogak:m-0 jogak:py-3 jogak:px-0 jogak:text-[12.5px] jogak:leading-[1.7] jogak:font-[family-name:var(--jogak-font-mono)] jogak:h-full jogak:box-border jogak:overflow-auto",style:g,children:j.map((k,i)=>o.jsxs("div",{...c({line:k}),className:"jogak:flex jogak:pr-6",style:c({line:k}).style,children:[o.jsx("span",{className:"jogak:select-none jogak:min-w-10 jogak:pl-[14px] jogak:pr-[14px] jogak:text-right jogak:text-[rgba(148,163,184,0.45)] jogak:shrink-0 jogak:leading-[1.7]",children:i+1}),o.jsx("span",{children:k.map((m,x)=>o.jsx("span",{...d({token:m})},x))})]},i))})})]})}function V(){if(typeof window>"u")return null;const a=new URLSearchParams(window.location.search),e=a.get("entry");if(e===null)return null;const t=a.get("jogak");return{entryId:e,jogakName:t}}function io(a,e){const t=new URLSearchParams;t.set("entry",a),t.set("jogak",e),window.history.pushState({},"",`?${t.toString()}`)}function uo({entries:a,metas:e,codeTheme:t="vsDark",previewIsolation:r="iframe",userPreviewUrl:s="",previewEntryPath:n="/__jogak_preview__/index.html",userViteUrl:g}={}){const j=s!==""?s:g??"",c=l.useMemo(()=>{if(a!==void 0){e!==void 0&&console.warn("[jogak] JogakApp received both `entries` and `metas` — `entries` (eager) takes precedence.");const u=new C.ComponentRegistry;for(const p of a)u.register(p);return u}if(e!==void 0)for(const u of e)C.defaultRegistry.registerMeta(u);return C.defaultRegistry},[a,e]),d=l.useMemo(()=>V(),[]),[k,i]=l.useState((d==null?void 0:d.entryId)??null),[m,x]=l.useState((d==null?void 0:d.jogakName)??null),[y,N]=l.useState({});l.useEffect(()=>{const u=()=>{const p=V();p!==null?(i(p.entryId),x(p.jogakName),N({})):(i(null),x(null))};return window.addEventListener("popstate",u),()=>{window.removeEventListener("popstate",u)}},[]);const b=l.useCallback((u,p)=>{i(u),x(p),N({}),io(u,p)},[]),v=l.useCallback((u,p)=>{if(i(f=>f===u?u:f),x(f=>f??p),typeof window<"u"){const f=new URLSearchParams(window.location.search);f.get("entry")===u&&f.get("jogak")===null&&(f.set("jogak",p),window.history.replaceState({},"",`?${f.toString()}`))}},[]),P=l.useCallback((u,p)=>{N(f=>({...f,[u]:p}))},[]),R=l.useCallback(()=>{N({})},[]);return o.jsx(h.JogakProvider,{registry:c,children:o.jsxs("div",{"data-jogak-shell":!0,className:"jogak:grid jogak:grid-cols-[260px_1fr] jogak:h-dvh jogak:overflow-hidden",children:[o.jsx(W,{selectedEntryId:k,selectedJogakName:m,onSelect:b}),o.jsx("main",{className:"jogak:overflow-hidden jogak:min-h-0",children:k!==null?o.jsx(G,{entryId:k,jogakName:m,overrideArgs:y,onArgChange:P,onReset:R,codeTheme:t,onResolveJogak:v,previewIsolation:r,userPreviewUrl:j,previewEntryPath:n}):o.jsx("div",{className:"jogak:flex jogak:items-center jogak:justify-center jogak:h-full jogak:text-[var(--jogak-color-fg-subtle)]",children:"Select a component from the sidebar"})})]})})}function xo(){const a=h.useRegistry(),e=l.useMemo(()=>a.getAll(),[a]),t=l.useMemo(()=>a.getTree(),[a]),r=l.useMemo(()=>s=>a.search(s),[a]);return{entries:e,tree:t,search:r}}exports.Actions=H;exports.Controls=F;exports.JogakApp=uo;exports.Preview=G;exports.Sidebar=W;exports.useRegistry=xo;