Skip to content

Commit

Permalink
Merge pull request #132 from gridaco/staging
Browse files Browse the repository at this point in the history
Add native html iframe support (Youtube, Google maps, Webcam), html progress support
  • Loading branch information
softmarshmallow authored Mar 29, 2022
2 parents 0c6b81e + 7a6cc5a commit b381d8e
Show file tree
Hide file tree
Showing 42 changed files with 1,432 additions and 74 deletions.
2 changes: 1 addition & 1 deletion editor/components/app-runner/vanilla-app-runner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export function VanillaRunner({
<iframe
ref={ref}
style={style}
sandbox="allow-same-origin"
sandbox="allow-same-origin allow-scripts"
srcDoc={inlinesource}
width={width}
height={height}
Expand Down
2 changes: 1 addition & 1 deletion externals/reflect-core
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { HtmlIframe } from "../html-iframe";
import type { IIframeProps } from "../html-iframe";
import type { IWHStyleWidget } from "@reflect-ui/core";
import type { WidgetKey } from "../../widget-key";

type FigmaProps = Omit<IIframeProps, "src" | "srcDoc"> & {
latlng: string;
};

export class HtmlIframeFigma extends HtmlIframe {
constructor({
key,
loading = "lazy",
allow = "fullscreen",
latlng,
...rest
}: { key: WidgetKey } & FigmaProps & IWHStyleWidget) {
super({
key,
...rest,
loading,
allow,
src: figmaurl(latlng),
});
}
}

function figmaurl(url: string): string {
const re =
/https:\/\/([\w\.-]+\.)?figma.com\/(file|proto)\/([0-9a-zA-Z]{22,128})(?:\/.*)?$/;
if (re.test(url)) {
return `https://www.figma.com/embed?embed_host=astra&url=${url}`;
} else {
return "https://figma.com/";
//
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { HtmlIframe } from "../html-iframe";
import type { IIframeProps } from "../html-iframe";
import type { IWHStyleWidget } from "@reflect-ui/core";
import type { WidgetKey } from "../../widget-key";

type GoogleMapsProps = Omit<IIframeProps, "src" | "srcDoc"> & {
q: string;
};

export class HtmlIframeGoogleMaps extends HtmlIframe {
constructor({
key,
loading = "lazy",
referrerpolicy = "no-referrer-when-downgrade",
sandbox = "allow-scripts",
q,
...rest
}: { key: WidgetKey } & GoogleMapsProps & IWHStyleWidget) {
super({
key,
...rest,
loading,
sandbox,
referrerpolicy,
src: gmapurl(q),
});
}
}

function gmapurl(q: string, apikey?: string): string {
// build query param
const query = {};
query["q"] = q;
if (apikey) {
query["key"] = apikey;
return `https://www.google.com/maps/embed/v1/place?${buildq(query)}`;
} else {
query["output"] = "embed";
return `https://maps.google.com/maps?${buildq(query)}`;
}
}

const buildq = (q: object): string =>
Object.keys(q)
.map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(q[k])}`)
.join("&");
31 changes: 31 additions & 0 deletions packages/builder-web-core/widgets-native/html-iframe-osm/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { HtmlIframe } from "../html-iframe";
import type { IIframeProps } from "../html-iframe";
import type { IWHStyleWidget } from "@reflect-ui/core";
import type { WidgetKey } from "../../widget-key";

type OsmProps = Omit<IIframeProps, "src" | "srcDoc"> & {
latlng: string;
};

export class HtmlIframeOpenStreetMap extends HtmlIframe {
constructor({
key,
loading = "lazy",
referrerpolicy = "no-referrer-when-downgrade",
latlng,
...rest
}: { key: WidgetKey } & OsmProps & IWHStyleWidget) {
super({
key,
...rest,
loading,
referrerpolicy,
src: osmurl(latlng),
});
}
}

function osmurl(latlng: string | { lat: number; lng: number }): string {
const p = typeof latlng === "string" ? latlng : `${latlng.lat},${latlng.lng}`;
return `https://www.openstreetmap.org/export/embed.html?bbox=${p}`;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { HtmlIframe } from "../html-iframe";
import type { IIframeProps } from "../html-iframe";
import type { IWHStyleWidget } from "@reflect-ui/core";
import type { WidgetKey } from "../../widget-key";

const webcamurl = "https://frames-appbox.vercel.app/webcam";

type WebcamProps = Omit<IIframeProps, "src" | "srcDoc"> & {};

export class HtmlIframeWebcam extends HtmlIframe {
constructor({
key,
allow = "camera",
loading = "lazy",
referrerpolicy = "no-referrer-when-downgrade",
sandbox = ["allow-scripts", "allow-same-origin"],
...rest
}: { key: WidgetKey } & WebcamProps & IWHStyleWidget) {
super({
key,
...rest,
allow,
loading,
sandbox,
referrerpolicy,
src: webcamurl,
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { HtmlIframe } from "../html-iframe";
import type { IIframeProps } from "../html-iframe";
import type { IWHStyleWidget } from "@reflect-ui/core";
import type { WidgetKey } from "../../widget-key";

type YoutubeProps = Omit<IIframeProps, "src" | "srcDoc"> & {
video: string;
};

export class HtmlIframeYoutube extends HtmlIframe {
constructor({
key,
loading = "lazy",
referrerpolicy = "no-referrer-when-downgrade",
sandbox = ["allow-scripts", "allow-same-origin"],
video,
...rest
}: { key: WidgetKey } & YoutubeProps & IWHStyleWidget) {
super({
key,
...rest,
loading,
sandbox,
referrerpolicy,
src: yturl(video),
});
}
}

function yturl(video: string): string {
return `https://www.youtube.com/embed/${video}`;
}
167 changes: 167 additions & 0 deletions packages/builder-web-core/widgets-native/html-iframe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import type { ElementCssStyleData } from "@coli.codes/css";
import type { DimensionLength, IWHStyleWidget } from "@reflect-ui/core";
import { WidgetKey } from "../../widget-key";
import type { StylableJSXElementConfig } from "../../widget-core";
import { Container } from "../container";
import * as css from "@web-builder/styles";
import { JSX, JSXAttribute, StringLiteral } from "coli";

type IframeAttrSandbox =
| "allow-downloads-without-user-activation"
| "allow-downloads"
| "allow-forms"
| "allow-modals"
| "allow-orientation-lock"
| "allow-pointer-lock"
| "allow-popups"
| "allow-popups-to-escape-sandbox"
| "allow-presentation"
| "allow-same-origin"
| "allow-scripts"
| "allow-storage-access-by-user-activation"
| "allow-top-navigation"
| "allow-top-navigation-by-user-activation";

type IframeAttrReferrerPolicy =
| "no-referrer"
| "no-referrer-when-downgrade"
| "origin"
| "origin-when-cross-origin"
| "same-origin"
| "strict-origin"
| "strict-origin-when-cross-origin"
| "unsafe-url";

export interface IIframeProps {
readonly id?: string;
readonly title?: string;

readonly src?: string;
readonly srcdoc?: string;
readonly fwidth?: DimensionLength;
readonly fheight?: DimensionLength;

readonly allow?: string;
readonly loading?: "eager" | "lazy";
readonly name?: string;
readonly referrerpolicy?: IframeAttrReferrerPolicy;
readonly sandbox?: IframeAttrSandbox | ReadonlyArray<IframeAttrSandbox>;
}

export class HtmlIframe extends Container implements IIframeProps {
readonly id?: string;
readonly title?: string;

readonly src?: string;
readonly srcdoc?: string;
readonly fwidth?: DimensionLength;
readonly fheight?: DimensionLength;

readonly allow?: string;
readonly loading?: "eager" | "lazy";
readonly name?: string;
readonly referrerpolicy?: IframeAttrReferrerPolicy;
readonly sandbox?: IframeAttrSandbox | ReadonlyArray<IframeAttrSandbox>;

constructor({
key,
id,
title,
src,
srcdoc,
fwidth,
fheight,
allow,
loading,
name,
referrerpolicy,
sandbox,
...rest
}: { key: WidgetKey } & IIframeProps & IWHStyleWidget) {
super({ key, ...rest });

this.id = id;
this.title = title;
this.src = src;
this.srcdoc = srcdoc;
this.fwidth = fwidth;
this.fheight = fheight;
this.allow = allow;
this.loading = loading;
this.name = name;
this.referrerpolicy = referrerpolicy;
this.sandbox = sandbox;
}
//

styleData(): ElementCssStyleData {
const containerstyle = super.styleData();

return {
// general layouts, continer ---------------------
...containerstyle,
// -------------------------------------------------

/* Override default CSS styles */
border: containerstyle.border ?? "none",
overflow: containerstyle.overflow ?? "hidden",
/* --------------------------- */

// ----------------------
};
}

jsxConfig(): StylableJSXElementConfig {
const attrs = [
this.id && new JSXAttribute("id", new StringLiteral(this.id)),
this.title && new JSXAttribute("title", new StringLiteral(this.title)),
this.src && new JSXAttribute("src", new StringLiteral(this.src)),
this.srcdoc && new JSXAttribute("srcdoc", new StringLiteral(this.srcdoc)),

this.fwidth &&
new JSXAttribute("width", new StringLiteral(css.length(this.fwidth))),
this.fheight &&
new JSXAttribute("height", new StringLiteral(css.length(this.fheight))),

this.sandbox?.length > 0 &&
new JSXAttribute(
"sandbox",
new StringLiteral(
Array.isArray(this.sandbox)
? this.sandbox.join(" ")
: (this.sandbox as string)
)
),

this.allow && new JSXAttribute("allow", new StringLiteral(this.allow)),
].filter(Boolean);

return <StylableJSXElementConfig>{
type: "tag-and-attr",
tag: JSX.identifier("iframe"),
attributes: attrs,
};
}

get finalStyle() {
const superstyl = super.finalStyle;

// width override. ------------------------------------------------------------------------------------------
// iframe element's width needs to be specified if the position is absolute and the left & right is specified.
let width = superstyl.width;
if (
width === undefined &&
superstyl.position === "absolute" &&
superstyl.left !== undefined &&
superstyl.right !== undefined
) {
width = "calc(100% - " + superstyl.left + " - " + superstyl.right + ")";
}
// ----------------------------------------------------------------------------------------------------------

return {
...superstyl,
width,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import type {
import type { StylableJSXElementConfig } from "../../widget-core";
import { WidgetKey } from "../../widget-key";
import { Container } from "../container";
import { JSX, JSXAttribute, NumericLiteral, StringLiteral } from "coli";
import { JSX, JSXAttribute, StringLiteral } from "coli";
import * as css from "@web-builder/styles";
import { RoundSliderThumbShape } from "@reflect-ui/core/lib/slider.thumb";

Expand Down
Loading

1 comment on commit b381d8e

@vercel
Copy link

@vercel vercel bot commented on b381d8e Mar 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.