Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 99 additions & 27 deletions Examples/PlayBridgeJS/Sources/JavaScript/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { EditorSystem } from './editor.js';
import ts from 'typescript';
import { TypeProcessor } from './processor.js';
import { CodeShareManager } from './code-share.js';
import {
createSystem,
createDefaultMapFromCDN,
createVirtualCompilerHost
} from '@typescript/vfs';

/**
* @typedef {import('../../.build/plugins/PackageToJS/outputs/Package/bridge-js.js').PlayBridgeJS} PlayBridgeJS
Expand Down Expand Up @@ -38,6 +43,14 @@ export class BridgeJSPlayground {
this.copyButton = /** @type {HTMLButtonElement} */ (document.getElementById('copyButton'));
/** @type {HTMLButtonElement} */
this.closeShareDialogButton = /** @type {HTMLButtonElement} */ (document.getElementById('closeShareDialog'));

// Progress UI elements
/** @type {HTMLDivElement | null} */
this.progressBar = /** @type {HTMLDivElement} */ (document.getElementById('progressBar'));
/** @type {HTMLDivElement | null} */
this.progressFill = /** @type {HTMLDivElement} */ (document.getElementById('progressFill'));
/** @type {HTMLDivElement | null} */
this.progressLabel = /** @type {HTMLDivElement} */ (document.getElementById('progressLabel'));
}

/**
Expand All @@ -50,44 +63,53 @@ export class BridgeJSPlayground {
}

try {
this.showProgress('Starting…', 5);
// Initialize editor system
await this.editorSystem.init();
this.setProgress('Editor ready', 30);

// Initialize BridgeJS
await this.initializeBridgeJS();
this.setProgress('BridgeJS ready', 70);

// Set up event listeners
this.setupEventListeners();

// Check for shared code in URL
this.setProgress('Checking shared code…', 80);
const sharedCode = await CodeShareManager.extractCodeFromUrl();
if (sharedCode) {
this.editorSystem.setInputs(sharedCode);
} else {
// Load sample code
this.editorSystem.setInputs(sampleCode);
}

this.setProgress('Finalizing…', 95);
this.isInitialized = true;
console.log('BridgeJS Playground initialized successfully');
this.setProgress('Ready', 100);
setTimeout(() => this.hideProgress(), 400);
} catch (error) {
console.error('Failed to initialize BridgeJS Playground:', error);
this.showError('Failed to initialize application: ' + error.message);
this.hideProgress();
}
}

// Initialize BridgeJS
async initializeBridgeJS() {
try {
// Import the BridgeJS module
this.setProgress('Loading BridgeJS…', 50);
const { init } = await import("../../.build/plugins/PackageToJS/outputs/Package/index.js");
const virtualHost = await this.createTS2SkeletonFactory();
this.setProgress('Preparing TypeScript host…', 60);
const { exports } = await init({
getImports: () => {
return {
createTS2Skeleton: this.createTS2Skeleton
};
}
getImports: () => ({
createTS2Skeleton: () => this.createTS2Skeleton(virtualHost)
})
});
this.setProgress('Creating runtime…', 65);
this.playBridgeJS = new exports.PlayBridgeJS();
console.log('BridgeJS initialized successfully');
} catch (error) {
Expand Down Expand Up @@ -171,32 +193,44 @@ export class BridgeJSPlayground {
});
}

createTS2Skeleton() {
async createTS2SkeletonFactory() {
const createVirtualHost = async () => {
const fsMap = await createDefaultMapFromCDN(
{ target: ts.ScriptTarget.ES2015 },
ts.version,
true,
ts
);

const system = createSystem(fsMap);

const compilerOptions = {
target: ts.ScriptTarget.ES2015,
lib: ["es2015", "dom"],
};

return createVirtualCompilerHost(system, compilerOptions, ts);
}
return await createVirtualHost();
}

/**
* @param {ReturnType<typeof createVirtualCompilerHost>} virtualHost
*/
createTS2Skeleton(virtualHost) {
return {
/**
* @param {string} dtsCode
* @returns {string}
*/
convert: (dtsCode) => {
const virtualFilePath = "bridge-js.d.ts"
const virtualHost = {
fileExists: fileName => fileName === virtualFilePath,
readFile: fileName => dtsCode,
getSourceFile: (fileName, languageVersion) => {
const sourceText = dtsCode;
if (sourceText === undefined) return undefined;
return ts.createSourceFile(fileName, sourceText, languageVersion);
},
getDefaultLibFileName: options => "lib.d.ts",
writeFile: (fileName, data) => {
console.log(`[emit] ${fileName}:\n${data}`);
},
getCurrentDirectory: () => "",
getDirectories: () => [],
getCanonicalFileName: fileName => fileName,
getNewLine: () => "\n",
useCaseSensitiveFileNames: () => true
}
// Create TypeScript program from d.ts content
const virtualFilePath = "bridge-js.d.ts"
const sourceFile = ts.createSourceFile(virtualFilePath, dtsCode, ts.ScriptTarget.ES2015);
virtualHost.updateFile(sourceFile);
const tsProgram = ts.createProgram({
rootNames: [virtualFilePath],
host: virtualHost,
host: virtualHost.compilerHost,
options: {
noEmit: true,
declaration: true,
Expand Down Expand Up @@ -268,4 +302,42 @@ export class BridgeJSPlayground {
hideError() {
this.errorDisplay.classList.remove('show');
}

/**
* Shows progress bar.
* @param {string} label
* @param {number} percent
*/
showProgress(label, percent) {
if (this.progressBar) {
this.progressBar.classList.add('show');
this.progressBar.classList.remove('hidden');
}
this.setProgress(label, percent);
}

/**
* Updates progress label and percentage.
* @param {string} label
* @param {number} percent
*/
setProgress(label, percent) {
if (this.progressLabel) {
this.progressLabel.textContent = label;
}
if (this.progressFill) {
const clamped = Math.max(0, Math.min(100, Number(percent) || 0));
this.progressFill.style.width = clamped + '%';
}
}

/**
* Hides progress bar.
*/
hideProgress() {
if (this.progressBar) {
this.progressBar.classList.remove('show');
this.progressBar.classList.add('hidden');
}
}
}
41 changes: 41 additions & 0 deletions Examples/PlayBridgeJS/Sources/JavaScript/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,47 @@ body {
word-break: break-word;
}

/* Progress bar */
.progress {
margin: 16px auto 0 auto;
max-width: 640px;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s ease;
}

.progress.show {
opacity: 1;
visibility: visible;
}

.progress.hidden {
opacity: 0;
visibility: hidden;
}

.progress-track {
height: 8px;
background-color: var(--color-fill-tertiary);
border: 1px solid var(--color-border);
border-radius: 999px;
overflow: hidden;
}

.progress-fill {
height: 100%;
width: 0%;
background-color: var(--color-figure-blue);
transition: width 0.2s ease;
}

.progress-label {
margin-top: 8px;
text-align: center;
font-size: 12px;
color: var(--color-secondary-label);
}

.main-content {
flex: 1;
display: grid;
Expand Down
9 changes: 8 additions & 1 deletion Examples/PlayBridgeJS/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
<script type="importmap">
{
"imports": {
"typescript": "https://esm.sh/[email protected]"
"typescript": "https://esm.sh/[email protected]",
"@typescript/vfs": "https://esm.sh/@typescript/[email protected]"
}
}
</script>
Expand Down Expand Up @@ -41,6 +42,12 @@ <h3>Share Your Code</h3>
</div>
</div>
</div>
<div id="progressBar" class="progress hidden" aria-live="polite">
<div class="progress-track">
<div id="progressFill" class="progress-fill" style="width:0%"></div>
</div>
<div id="progressLabel" class="progress-label">Initializing…</div>
</div>
</header>


Expand Down
5 changes: 5 additions & 0 deletions Examples/PlayBridgeJS/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"devDependencies": {
"@typescript/vfs": "^1.6.1"
}
}