Skip to content

Commit

Permalink
✨ Bento amp-gist (#37333)
Browse files Browse the repository at this point in the history
* ✨ Add Bento gist component

* Add unit test cases for the amp-gist component

* Add support for data-file attribute

* Add npm property to amp-gist in bundles config

* Add file attribute to type definition

* Remove debug code

* Add test case and storybook example for file attribute

* Update amp-gist validator test files

* Add readme.md file for bento amp-gist component

* Remove dict
  • Loading branch information
deepaklalwani97 committed Feb 14, 2022
1 parent c8ea23b commit 72a69cf
Show file tree
Hide file tree
Showing 13 changed files with 623 additions and 0 deletions.
9 changes: 9 additions & 0 deletions build-system/compile/bundles.config.extensions.json
Expand Up @@ -482,6 +482,15 @@
"version": "0.1",
"latestVersion": "0.1"
},
{
"name": "amp-gist",
"version": "1.0",
"options": {
"hasCss": true,
"bento": true,
"npm": true
}
},
{
"name": "amp-google-document-embed",
"version": "0.1",
Expand Down
187 changes: 187 additions & 0 deletions extensions/amp-gist/1.0/README.md
@@ -0,0 +1,187 @@
# Bento Gist

Creates an iframe and displays a [GitHub Gist](https://docs.github.com/en/github/writing-on-github/creating-gists).

## Web Component

You must include each Bento component's required CSS library to guarantee proper loading and before adding custom styles. Or use the light-weight pre-upgrade styles available inline. See [Layout and style](#layout-and-style).

### Import via npm

```sh
npm install @bentoproject/gist
```

```javascript
import {defineElement as defineBentoGist} from '@bentoproject/gist';
defineBentoGist();
```

### Include via `<script>`

```html
<script type="module" src="https://cdn.ampproject.org/bento.mjs" crossorigin="anonymous"></script>
<script nomodule src="https://cdn.ampproject.org/bento.js" crossorigin="anonymous"></script>
<script type="module" src="https://cdn.ampproject.org/v0/bento-gist-1.0.mjs" crossorigin="anonymous"></script>
<script nomodule src="https://cdn.ampproject.org/v0/bento-gist-1.0.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.ampproject.org/v0/bento-gist-1.0.css" crossorigin="anonymous">
```

### Example

<!--% example %-->

```html
<!DOCTYPE html>
<html>
<head>
<script
type="module"
async
src="https://cdn.ampproject.org/bento.mjs"
></script>
<script nomodule src="https://cdn.ampproject.org/bento.js"></script>
<script
type="module"
async
src="https://cdn.ampproject.org/v0/bento-gist-1.0.mjs"
></script>
<script
nomodule
async
src="https://cdn.ampproject.org/v0/bento-gist-1.0.js"
></script>
<link
rel="stylesheet"
type="text/css"
href="https://cdn.ampproject.org/v0/bento-gist-1.0.css"
/>
<style>
bento-gist {
width: 300px;
height: 300px;
}
</style>
</head>
<body>
<bento-gist
id="my-track"
data-gistid="a19e811dcd7df10c4da0931641538497"
></bento-gist>
</body>
</html>
```

### Layout and style

Each Bento component has a small CSS library you must include to guarantee proper loading without [content shifts](https://web.dev/cls/). Because of order-based specificity, you must manually ensure that stylesheets are included before any custom styles.

```html
<link
rel="stylesheet"
type="text/css"
href="https://cdn.ampproject.org/v0/bento-gist-1.0.css"
/>
```

Alternatively, you may also make the light-weight pre-upgrade styles available inline:

```html
<style>
bento-gist {
display: block;
overflow: hidden;
position: relative;
}
</style>
```

#### Container type

The `bento-gist` component has a defined layout size type. To ensure the component renders correctly, be sure to apply a size to the component and its immediate children (slides) via a desired CSS layout (such as one defined with `height`, `width`, `aspect-ratio`, or other such properties):

```css
bento-gist {
height: 100px;
width: 100%;
}
```

### Attributes

##### data-gistid

The ID of the gist to embed.

##### data-file (optional)

If specified, display only one file in a gist.

#### title (optional)

Define a `title` attribute for the component to propagate to the underlying `<iframe>` element. The default value is `"Github Gist"`.

---

## Preact/React Component

### Import via npm

```sh
npm install @bentoproject/gist
```

```javascript
import React from 'react';
import {BentoGist} from '@bentoproject/gist/react';
import '@bentoproject/gist/styles.css';

function App() {
return <BentoGist gistId="a19e811dcd7df10c4da0931641538497"></BentoGist>;
}
```

### Layout and style

#### Container type

The `BentoGist` component has a defined layout size type. To ensure the component renders correctly, be sure to apply a size to the component and its immediate children via a desired CSS layout (such as one defined with `height`, `width`, `aspect-ratio`, or other such properties). These can be applied inline:

```jsx
<BentoGist
style={{height: 500}}
gistId="a19e811dcd7df10c4da0931641538497"
file="index.js"
></BentoGist>
```

Or via `className`:

```jsx
<BentoGist
className="custom-styles"
gistId="a19e811dcd7df10c4da0931641538497"
file="index.js"
></BentoGist>
```

```css
.custom-styles {
height: 100px;
width: 100%;
}
```

### Props

##### gistId

The ID of the gist to embed.

##### file (optional)

If specified, display only one file in a gist.

#### title (optional)

Define a `title` attribute for the component to propagate to the underlying `<iframe>` element. The default value is `"Github Gist"`.
17 changes: 17 additions & 0 deletions extensions/amp-gist/1.0/amp-gist.css
@@ -0,0 +1,17 @@
/*
* Pre-upgrade:
* - display:block element
* - size-defined element
*/
amp-gist {
display: block;
overflow: hidden;
position: relative;
}

/* Pre-upgrade: size-defining element - hide children. */
amp-gist:not(.i-amphtml-built)
> :not([placeholder]):not(.i-amphtml-svc) {
display: none;
content-visibility: hidden;
}
40 changes: 40 additions & 0 deletions extensions/amp-gist/1.0/amp-gist.js
@@ -0,0 +1,40 @@
import {Layout_Enum} from '#core/dom/layout';

import {isExperimentOn} from '#experiments';

import {userAssert} from '#utils/log';

import {BaseElement} from './base-element';

import {CSS} from '../../../build/amp-gist-1.0.css';

/** @const {string} */
const TAG = 'amp-gist';

class AmpGist extends BaseElement {
/** @override */
init() {
return {
'requestResize': (height) => this.attemptChangeHeight(height),
};
}

/** @override @nocollapse */
static getPreconnects() {
return ['https://gist.github.com'];
}

/** @override */
isLayoutSupported(layout) {
userAssert(
isExperimentOn(this.win, 'bento') ||
isExperimentOn(this.win, 'bento-gist'),
'expected global "bento" or specific "bento-gist" experiment to be enabled'
);
return layout == Layout_Enum.FIXED_HEIGHT;
}
}

AMP.extension(TAG, '1.0', (AMP) => {
AMP.registerElement(TAG, AmpGist, CSS);
});
20 changes: 20 additions & 0 deletions extensions/amp-gist/1.0/base-element.js
@@ -0,0 +1,20 @@
import {PreactBaseElement} from '#preact/base-element';

import {BentoGist} from './component';

export class BaseElement extends PreactBaseElement {}

/** @override */
BaseElement['Component'] = BentoGist;

/** @override */
BaseElement['props'] = {
'gistId': {attr: 'data-gistid'},
'file': {attr: 'data-file'},
};

/** @override */
BaseElement['layoutSizeDefined'] = true;

/** @override */
BaseElement['usesShadowDom'] = true;
66 changes: 66 additions & 0 deletions extensions/amp-gist/1.0/component.js
@@ -0,0 +1,66 @@
import {MessageType_Enum, deserializeMessage} from '#core/3p-frame-messaging';

import * as Preact from '#preact';
import {useCallback, useEffect, useMemo, useRef, useState} from '#preact';
import {ProxyIframeEmbed} from '#preact/component/3p-frame';

const TYPE = 'github';
const DEFAULT_TITLE = 'Github Gist';
const FULL_HEIGHT = '100%';

/**
* @param {!BentoGist.Props} props
* @return {PreactDef.Renderable}
*/
export function BentoGist({
gistId,
file,
title = DEFAULT_TITLE,
requestResize,
style,
...rest
}) {
const iframeRef = useRef(null);
const [height, setHeight] = useState(null);
const messageHandler = useCallback(
(event) => {
const data = deserializeMessage(event.data);
if (data['type'] == MessageType_Enum.EMBED_SIZE) {
const height = data['height'];
if (requestResize) {
requestResize(height);
setHeight(FULL_HEIGHT);
} else {
setHeight(height);
}
}
},
[requestResize]
);
useEffect(() => {
/** Unmount Procedure */
return () => {
// Release iframe resources
iframeRef.current = null;
};
}, []);
const options = useMemo(
() => ({
gistid: gistId,
file,
}),
[gistId, file]
);

return (
<ProxyIframeEmbed
title={title}
options={options}
ref={iframeRef}
type={TYPE}
messageHandler={messageHandler}
style={height ? {...style, height} : style}
{...rest}
/>
);
}
15 changes: 15 additions & 0 deletions extensions/amp-gist/1.0/component.type.js
@@ -0,0 +1,15 @@
/** @externs */

/** @const */
var BentoGistDef = {};

/**
* @typedef {{
* onLoad: (function():undefined|undefined),
* requestResize: (function(number):*|undefined),
* title: (string|undefined),
* gistId: (string),
* file: (string|undefined),
* }}
*/
BentoGistDef.Props;

0 comments on commit 72a69cf

Please sign in to comment.