Skip to content
Draft
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
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,13 @@ All-in-one project, editor, file switcher, and preview with a horizontal side-by
| `default` | Inline files ([details](#inline-scripts)). |
| `extensions` | Declarative CodeMirror extensions ([details](#extending-the-editor)). |

### Events

| Event | Description |
| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tabchange` | A tab has been activated. |
| `change` | User made an edit to the active file (note: this event is not fired for programmatic changes to the value property nor for the user changing tabs) |

---

## `<playground-project>`
Expand Down Expand Up @@ -813,6 +820,12 @@ project element.

---

### Events

| Event | Description |
| ----------- | ------------------------- |
| `tabchange` | A tab has been activated. |

## `<playground-file-editor>`

### Properties
Expand All @@ -834,6 +847,12 @@ project element.
| ------------ | --------------------------------------------------------------------- |
| `extensions` | Declarative CodeMirror extensions ([details](#extending-the-editor)). |

### Events

| Event | Description |
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `change` | User made an edit to the active file (note: this event is not fired for programmatic changes to the value property nor for the user changing tabs) |

---

## `<playground-code-editor>`
Expand Down
7 changes: 5 additions & 2 deletions src/playground-file-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {Extension} from '@codemirror/state';
import {PlaygroundProject} from './playground-project.js';
import {PlaygroundCodeEditor} from './playground-code-editor.js';
import {CodeEditorChangeData} from './shared/worker-api.js';
import {refireEvent} from './shared/util.js';

/**
* A text editor associated with a <playground-project>.
Expand Down Expand Up @@ -172,7 +173,7 @@ export class PlaygroundFileEditor extends PlaygroundConnectedElement {
)}
.extensions=${this.extensions}
.noCompletions=${this.noCompletions}
@change=${this._onEdit}
@change=${this._onChange}
@request-completions=${this._onRequestCompletions}
>
<slot name="extensions" slot="extensions"></slot>
Expand All @@ -197,7 +198,7 @@ export class PlaygroundFileEditor extends PlaygroundConnectedElement {
this.requestUpdate();
};

private _onEdit() {
private _onChange(event: Event) {
if (
this._project === undefined ||
this._currentFile === undefined ||
Expand All @@ -206,6 +207,8 @@ export class PlaygroundFileEditor extends PlaygroundConnectedElement {
return;
}
this._project.editFile(this._currentFile, this._editor.value);
// Re-fire the change event on the host element for external consumers
refireEvent(this, event);
}

private async _onRequestCompletions(e: CustomEvent) {
Expand Down
13 changes: 13 additions & 0 deletions src/playground-ide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import './playground-preview.js';
import {PlaygroundProject} from './playground-project.js';
import {ProjectManifest} from './shared/worker-api.js';
import {npmVersion, serviceWorkerHash} from './shared/version.js';
import {refireEvent} from './shared/util.js';

/**
* A multi-file code editor component with live preview that works without a
Expand Down Expand Up @@ -327,6 +328,7 @@ export class PlaygroundIde extends LitElement {
.project=${projectId}
.editor=${editorId}
.editableFileSystem=${this.editableFileSystem}
@tabchange=${this._onTabChange}
>
</playground-tab-bar>

Expand All @@ -339,6 +341,7 @@ export class PlaygroundIde extends LitElement {
.pragmas=${this.pragmas}
.noCompletions=${this.noCompletions}
.extensions=${this.extensions}
@change=${this._onChange}
>
<slot name="extensions" slot="extensions"></slot>
</playground-file-editor>
Expand Down Expand Up @@ -388,6 +391,16 @@ export class PlaygroundIde extends LitElement {
super.update(changedProperties);
}

private _onTabChange(event: Event) {
// Re-fire the tabchange event on the host element for external consumers
refireEvent(this, event);
}

private _onChange(event: Event) {
// Re-fire the change event on the host element for external consumers
refireEvent(this, event);
}

private _onResizeBarPointerdown({pointerId}: PointerEvent) {
const bar = this._resizeBar;
bar.setPointerCapture(pointerId);
Expand Down
8 changes: 8 additions & 0 deletions src/playground-tab-bar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {PlaygroundConnectedElement} from './playground-connected-element.js';
import {PlaygroundFileEditor} from './playground-file-editor.js';
import {PlaygroundFileSystemControls} from './playground-file-system-controls.js';
import {FilesChangedEvent, PlaygroundProject} from './playground-project.js';
import {refireEvent} from './shared/util.js';
import {PlaygroundInternalTab} from './internal/tab.js';

/**
Expand Down Expand Up @@ -257,6 +258,13 @@ export class PlaygroundTabBar extends PlaygroundConnectedElement {
if (name !== this._activeFileName) {
this._activeFileName = name;
this._activeFileIndex = index;
// Re-fire the tabchange event on the host element for external consumers
refireEvent(
this,
new CustomEvent('tabchange', {
detail: {filename: name},
})
);
}
}

Expand Down
20 changes: 20 additions & 0 deletions src/shared/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,23 @@ export const forceSkypackRawMode = (url: URL): URL => {
export type Result<V, E> =
| {result: V; error?: undefined}
| {result?: undefined; error: E};

/**
* Re-fires an event on the given element, without bubbles or composed flags.
* This is useful for re-firing internal events on public component boundaries
* to avoid them crossing shadow DOM boundaries while still making them available
* to external consumers.
*/
export const refireEvent = (
element: EventTarget,
event: Event | CustomEvent
): void => {
const detail = (event as CustomEvent).detail;
element.dispatchEvent(
new CustomEvent(event.type, {
detail,
bubbles: false,
composed: false,
})
);
};
Loading