@phun-ky/frameport 2.0.20 → 2.0.22

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/README.md CHANGED
@@ -2,23 +2,25 @@
2
2
 
3
3
  ![logo](./public/logo-frameport-colored-package.svg)
4
4
 
5
- > Frameport enables you to fake and display your responsive components in real life media queries!
5
+ > Create interactive, responsive component previews for your style guides using real device viewports and media queries.
6
6
 
7
7
  [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-green.svg)](http://makeapullrequest.com) [![SemVer 2.0](https://img.shields.io/badge/SemVer-2.0-green.svg)](http://semver.org/spec/v2.0.0.html) ![npm version](https://img.shields.io/npm/v/@phun-ky/frameport) ![issues](https://img.shields.io/github/issues/phun-ky/frameport) ![license](https://img.shields.io/npm/l/@phun-ky/frameport) ![size](https://img.shields.io/bundlephobia/min/@phun-ky/frameport) ![npm](https://img.shields.io/npm/dm/%40phun-ky/frameport) ![GitHub Repo stars](https://img.shields.io/github/stars/phun-ky/frameport) [![codecov](https://codecov.io/gh/phun-ky/frameport/graph/badge.svg?token=VA91DL7ZLZ)](https://codecov.io/gh/phun-ky/frameport)
8
8
 
9
9
  - [@phun-ky/frameport](#phun-kyframeport)
10
10
  - [About](#about)
11
+ - [Installation \& Setup](#installation--setup)
11
12
  - [API](#api)
12
13
  - [Demo](#demo)
13
14
  - [Options](#options)
14
15
  - [Usage](#usage)
15
- - [Typescript](#typescript)
16
- - [ESM](#esm)
17
- - [Script](#script)
18
- - [Advanced usage](#advanced-usage)
19
- - [Lazy](#lazy)
16
+ - [Basic usage](#basic-usage)
17
+ - [Typescript](#typescript)
18
+ - [ESM](#esm)
19
+ - [Script](#script)
20
+ - [Advanced usage](#advanced-usage)
21
+ - [Lazy](#lazy)
20
22
  - [Features](#features)
21
- - [Via DOM](#via-dom)
23
+ - [Via DOM](#via-dom)
22
24
  - [Use templates as a target](#use-templates-as-a-target)
23
25
  - [Use targets with different template](#use-targets-with-different-template)
24
26
  - [Allowed tags](#allowed-tags)
@@ -27,12 +29,25 @@
27
29
 
28
30
  ## About
29
31
 
30
- Frameport was created so I could display frameports of components in a style guide. It creates iframes with your component (html, css and javascript) that acts as natural viewports, thus making use of your media queries! It is a zero dependency package!
32
+ Frameport helps you embed live, responsive component previews in your documentation or style guide. It works by generating iframes with your HTML/CSS/JS that respect real media queries—so your components behave just like they do in actual devices.
33
+
34
+ ✅ Zero dependencies
35
+ ✅ Framework agnostic
36
+ ✅ Real device viewport emulation
37
+ ✅ Instant iframe-based previews
38
+
39
+ ## Installation & Setup
31
40
 
32
41
  ```shell-session
33
42
  npm i -S @phun-ky/frameport
34
43
  ```
35
44
 
45
+ or with yarn:
46
+
47
+ ```shell-session
48
+ yarn add @phun-ky/frameport
49
+ ```
50
+
36
51
  ## API
37
52
 
38
53
  Go [here](https://github.com/phun-ky/frameport/blob/main/api/README.md) to read the full API documentation.
@@ -62,11 +77,13 @@ Click [here for a demo on codepen.io](https://codepen.io/phun-ky/full/MWWWvLm)
62
77
 
63
78
  ## Usage
64
79
 
65
- ### Typescript
80
+ ### Basic usage
81
+
82
+ #### Typescript
66
83
 
67
84
  Types can be found in `@phun-ky/frameport/dist/frameport.d.ts`.
68
85
 
69
- ### ESM
86
+ #### ESM
70
87
 
71
88
  Either import and run the required functions:
72
89
 
@@ -80,7 +97,7 @@ frameport(document.getElementById('target'), {
80
97
  });
81
98
  ```
82
99
 
83
- ### Script
100
+ #### Script
84
101
 
85
102
  Or place these `script` in your web page:
86
103
 
@@ -90,7 +107,7 @@ Or place these `script` in your web page:
90
107
 
91
108
  And then follow the steps below that suites your needs :)
92
109
 
93
- ## Advanced usage
110
+ ### Advanced usage
94
111
 
95
112
  If you want to control frameport a bit more, you have some options. Apply one of these attributes to the script element for different types of initialization:
96
113
 
@@ -107,7 +124,7 @@ If you want to control frameport a bit more, you have some options. Apply one of
107
124
 
108
125
  If no attribute is applied, it will default to `data-dom`, as in, it will initialize when `DOMContentLoaded` is fired.
109
126
 
110
- ### Lazy
127
+ #### Lazy
111
128
 
112
129
  If you're importing frameport instead of with a script tag, you can use the following approach to apply lazy loading:
113
130
 
@@ -173,7 +190,7 @@ export const lazy = (): void => {
173
190
 
174
191
  ## Features
175
192
 
176
- ## Via DOM
193
+ ### Via DOM
177
194
 
178
195
  Place the `script` tag at the bottom of your page, right before the `</body>`-tag:
179
196
 
@@ -240,20 +257,20 @@ This approach is useful if you want to use a device decorator to mimic appearanc
240
257
 
241
258
  #### Allowed tags
242
259
 
243
- | tag | description |
244
- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
245
- | data-frameport | To identify this as the template to use for generating the responsive examples. **Required** |
246
- | data-frameport-target | To identify this as a target to use to generate the frameports |
247
- | data-frameport-template | Selector to the template |
248
- | data-frameport-width | The viewport width. **Required** |
249
- | data-frameport-height | The viewport height. |
250
- | data-frameport-css | A CSS file to be appended to the `<head>`-tag of the generated html. **NOTE! This needs to be on the same domain and relative to root!** For example: `/dist/yourcss.css` |
251
- | data-frameport-style | Inline styles (CSS) to be inserted into a `<style>` -tag in the `<head>`-tag of the generated html |
252
- | data-frameport-code | Custom JavaScript code to be inserted into a `<script>`-tag in the `<body>`-tag in the generated html |
253
- | data-frameport-js | A JavaScript file to be inserted in the `<body>`-tag of the generated html. **NOTE! This needs to be on the same domain and relative to root!** For example: `/dist/yourjs.js` |
254
- | data-frameport-class | Class names to be given the generated iframe |
255
- | data-frameport-viewports | The viewports to generate for examples. This is a string `wxh` for example: `375x667`. If you want more viewports, you can separate them with a comma: `375x667,360x740,768x1024`. **Required** |
256
- | data-frameport-headers | An array of HTTP headers to include when fetching the HTML content |
260
+ | tag | description | Required |
261
+ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
262
+ | **data-frameport** | To identify this as the template to use for generating the responsive examples. **Required** | 🔸 |
263
+ | **data-frameport-width** | The viewport width. **Required** | 🔸 |
264
+ | **data-frameport-viewports** | The viewports to generate for examples. This is a string `wxh` for example: `375x667`. If you want more viewports, you can separate them with a comma: `375x667,360x740,768x1024`. **Required** | 🔸 |
265
+ | data-frameport-target | To identify this as a target to use to generate the frameports | |
266
+ | data-frameport-template | Selector to the template | |
267
+ | data-frameport-height | The viewport height. | |
268
+ | data-frameport-css | A CSS file to be appended to the `<head>`-tag of the generated html. **NOTE! This needs to be on the same domain and relative to root!** For example: `/dist/yourcss.css` | |
269
+ | data-frameport-style | Inline styles (CSS) to be inserted into a `<style>` -tag in the `<head>`-tag of the generated html | |
270
+ | data-frameport-code | Custom JavaScript code to be inserted into a `<script>`-tag in the `<body>`-tag in the generated html | |
271
+ | data-frameport-js | A JavaScript file to be inserted in the `<body>`-tag of the generated html. **NOTE! This needs to be on the same domain and relative to root!** For example: `/dist/yourjs.js` | |
272
+ | data-frameport-class | Class names to be given the generated iframe | |
273
+ | data-frameport-headers | An array of HTTP headers to include when fetching the HTML content | |
257
274
 
258
275
  ## Contributing
259
276
 
@@ -28,12 +28,54 @@ declare global {
28
28
  }
29
29
  }
30
30
 
31
+ /**
32
+ * Available initialization modes for frameport usage.
33
+ * Can be triggered manually or via browser lifecycle hooks.
34
+ */
31
35
  declare const modes: {
32
36
  domReady: (frameport: FrameportFunctionType) => void;
33
37
  lazy: () => void;
34
38
  manual: (frameport: FrameportFunctionType) => void;
35
39
  activate: (frameport: FrameportFunctionType) => void;
36
40
  };
41
+ /**
42
+ * Transforms all DOM elements marked with `[data-frameport]` into embedded iframes
43
+ * with sandboxed content based on HTML templates and associated metadata.
44
+ *
45
+ * Also removes any existing `[data-frameport-iframe]` elements from the document,
46
+ * ensuring re-renders are clean.
47
+ *
48
+ * Reads attributes such as:
49
+ * - `data-frameport-template`
50
+ * - `data-frameport-css`
51
+ * - `data-frameport-style`
52
+ * - `data-frameport-code`
53
+ * - `data-frameport-js`
54
+ * - `data-frameport-class`
55
+ * - `data-frameport-headers`
56
+ * - `data-frameport-viewports`
57
+ * - `data-frameport-vh`
58
+ * - `data-frameport-vw`
59
+ *
60
+ * @example
61
+ * ```html
62
+ * <div
63
+ * data-frameport
64
+ * data-frameport-template="#my-template"
65
+ * data-frameport-vh="100"
66
+ * data-frameport-vw="100"
67
+ * data-frameport-css="styles.css"
68
+ * data-frameport-js="script.js"
69
+ * ></div>
70
+ *
71
+ * <template id="my-template">
72
+ * <h1>Hello, sandbox!</h1>
73
+ * </template>
74
+ * ```
75
+ *
76
+ * @function frameport
77
+ * @returns void
78
+ */
37
79
  declare const frameport: () => void;
38
80
 
39
81
  export { frameport as default, modes };
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @phun-ky/frameport
3
- * Create responsive documentation examples on the fly
3
+ * A zero dependency package to effortlessly create responsive component previews in documentation using real media queries. Frameport dynamically generates iframes containing your HTML/CSS/JS, mimicking natural device viewports to test responsiveness, without any build steps or dependencies.
4
4
  * @author Alexander Vassbotn Røyne-Helgesen <alexander+frameport@phun-ky.net>
5
- * @version 2.0.20
5
+ * @version 2.0.22
6
6
  * @license
7
7
  * Copyright (c) 2023 Alexander Vassbotn Røyne-Helgesen
8
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"frameport.esm.js","sources":["../src/utils/iframe.ts","../src/utils/source.ts","../src/utils/css.ts","../src/utils/js.ts","../src/utils/code.ts","../src/utils/style.ts","../src/utils/page.ts","../src/utils/blob.ts","../src/utils/styles.ts","../src/utils/wait.ts","../src/utils/create.ts","../src/constants/index.ts","../src/features/dom.ts","../src/config/generate-viewports.ts","../src/config/generate.ts","../src/utils/headers.ts","../src/config/browser.ts","../src/main.ts"],"sourcesContent":["/**\n * Create and return an iframe element.\n *\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const createIframe = (): HTMLIFrameElement =>\n document.createElement('iframe');\n","import { type FrameportOptionsInterface } from '../types';\n\nimport { getCode } from './code';\nimport { getCSS } from './css';\nimport { getJavaScript } from './js';\nimport { getStyle } from './style';\n\n/**\n * Generate the source code for an HTML page based on the provided options.\n *\n * @param {FrameportOptionsInterface} options - The options for generating the HTML page source.\n * @returns {string} - The generated HTML source code as a string.\n */\nexport const getSource = (options: FrameportOptionsInterface): string => {\n let { style, css, code, javascript } = options;\n\n const { html, headers = [] } = options;\n\n css = getCSS(css);\n javascript = getJavaScript(javascript);\n code = getCode(code);\n style = getStyle(style);\n\n return `<!DOCTYPE html>\n<html>\n<head>\n${headers.join('\\n')}\n${style}\n${css}\n</head>\n<body>\n${html || ''}\n${javascript}\n${code}\n</body>\n</html>`;\n};\n","/**\n * Generate a CSS link tag based on the provided URL.\n *\n * @param {string | undefined} css - The URL of the CSS file.\n * @returns {string} - A CSS link tag.\n */\nexport const getCSS = (css: string | undefined): string => {\n if (css && css !== '') {\n return `<link rel=\"stylesheet\" type=\"text/css\" href=\"${window.location.protocol}//${window.location.host}${css.trim()}\" />`;\n }\n\n return '';\n};\n","/**\n * Generate a script tag for the specified JavaScript file.\n *\n * @param {string | undefined} javascript - The path to the JavaScript file.\n * @returns {string} - The generated script tag or an empty string if no JavaScript path is provided.\n */\nexport const getJavaScript = (javascript: string | undefined): string => {\n if (javascript && javascript !== '') {\n return `<script src=\"${window.location.protocol}//${window.location.host}${javascript.trim()}\"></script>`;\n }\n\n return '';\n};\n","/**\n * Get a script element containing the provided code if available.\n *\n * @param {string | undefined} code - The code to include in the script element.\n * @returns {string} - The script element or an empty string if code is not available.\n */\nexport const getCode = (code: string | undefined): string => {\n if (code && code !== '') {\n return `<script>${code.trim()}</script>`;\n }\n\n return '';\n};\n","/**\n * Generate a style element based on the provided CSS styles.\n *\n * @param {string | undefined} style - The CSS styles to include in the style element.\n * @returns {string} - The style element as a string or an empty string if no styles are provided.\n */\nexport const getStyle = (style: string | undefined): string => {\n if (style && style !== '') {\n return `<style type=\"text/css\">${style}</style>`;\n }\n\n return '';\n};\n","import { getBlobURL } from './blob';\nimport { getSource } from './source';\n\n/**\n * Get the URL of a generated HTML page based on the provided options.\n *\n * @param {object} options - The options for generating the HTML page.\n * @returns {string} - The URL of the generated HTML page as a Blob URL.\n */\nexport const getGeneratedPageURL = (options) => {\n const source = getSource(options);\n\n return getBlobURL(source, 'text/html');\n};\n","/**\n * Generates a Blob URL from HTML content with the specified MIME type.\n *\n * @param {string} html - The HTML content to create a Blob from.\n * @param {string} type - The MIME type of the Blob (e.g., 'text/html', 'image/jpeg').\n * @returns {string} - The generated Blob URL.\n */\nexport const getBlobURL = (html: string, type: string): string => {\n const blob = new Blob([html], { type });\n\n return URL.createObjectURL(blob);\n};\n","/* eslint no-console:0 */\nimport { waitForFrame } from './wait';\n\n/**\n * Adds CSS styles to an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to apply styles to.\n * @param {object | Array<{ key: string; value: string }>} styles - An object or an array of objects containing CSS styles to apply.\n * @returns {Promise<void>} - A Promise that resolves after styles are applied.\n *\n * @example\n * ```ts\n * // Apply styles as an object\n * const element = document.getElementById('my-element');\n * await add(element, { color: 'red', fontSize: '16px' });\n *\n * // Apply styles as an array of objects\n * const styles = [\n * { key: 'color', value: 'blue' },\n * { key: 'backgroundColor', value: 'yellow' }\n * ];\n * await add(element, styles);\n * ```\n */\nexport const add = async (\n el: HTMLElement,\n styles: object | { key: string; value: string }[]\n): Promise<void> => {\n if (\n !el ||\n !styles ||\n typeof styles === 'string' ||\n typeof styles === 'number' ||\n typeof styles === 'boolean' ||\n (Array.isArray(styles) && styles.length === 0) ||\n (Object.keys(styles).length === 0 && styles.constructor === Object)\n ) {\n return;\n }\n\n await waitForFrame();\n\n if (Array.isArray(styles)) {\n styles.forEach(\n (style: { key: string; value: string }) =>\n (el.style[style.key] = style.value)\n );\n } else {\n Object.keys(styles).forEach((key) => (el.style[key] = styles[key]));\n }\n};\n\n/**\n * Gets the computed CSS styles of an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to get computed styles from.\n * @returns {Promise<CSSStyleDeclaration>} - A Promise that resolves with the computed CSS styles.\n *\n * @example\n * ```ts\n * // Get computed styles of an element\n * const element = document.getElementById('my-element');\n * const computedStyles = await get(element);\n * console.log(computedStyles.color); // Logs the color property value\n * ```\n */\nexport const get = async (el: HTMLElement): Promise<CSSStyleDeclaration> => {\n await waitForFrame();\n\n return getComputedStyle(el, null);\n};\n","/**\n * Waits for the next animation frame using requestAnimationFrame.\n *\n * @returns {Promise<number>} - A Promise that resolves with the timestamp of the next animation frame.\n *\n * @example\n * ```ts\n * // Wait for the next animation frame and get the rect\n * await waitForFrame();\n * const rect = el.getBoundingClientRect();\n * // Wait for the next animation frame and get the timestamp\n * const timestamp = await waitForFrame();\n * ```\n */\nexport const waitForFrame = (): Promise<number> =>\n new Promise<number>(requestAnimationFrame);\n","import { type FrameportOptionsInterface } from '../types';\nimport { createIframe } from '../utils/iframe';\nimport { getGeneratedPageURL } from '../utils/page';\nimport { add as addStyles } from '../utils/styles';\n\n/**\n * Create an iframe element with specified options and styles.\n *\n * @param {FrameportOptionsInterface} options - The options for creating the iframe.\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const create = (\n options: FrameportOptionsInterface\n): HTMLIFrameElement => {\n const { className, height, width } = options;\n const url = getGeneratedPageURL(options);\n const iframeElement = createIframe();\n const iframeStyle = {};\n\n iframeElement.src = url;\n iframeElement.setAttribute('data-rde-iframe', '');\n\n if (!className || className === '') {\n iframeStyle['border'] = 'none';\n } else {\n iframeElement.classList.add(className);\n }\n\n iframeStyle['width'] = `${width}px`;\n\n if (height) {\n iframeStyle['height'] = `${height}px`;\n }\n\n addStyles(iframeElement, iframeStyle);\n\n return iframeElement;\n};\n","/**\n * Style object for hiding an element in the HTML.\n *\n * @type {{ clip: string, height: string, margin: string, overflow: string, position: string, width: string }}\n */\nexport const HIDE_TEMPLATE_STYLE: {\n clip: string;\n height: string;\n margin: string;\n overflow: string;\n position: string;\n width: string;\n} = {\n clip: 'rect(1px, 1px, 1px, 1px)',\n height: '1px',\n margin: '0',\n overflow: 'hidden',\n position: 'absolute',\n width: '1px'\n};\n\n/**\n * Default meta headers for an HTML document.\n *\n * @type {string[]}\n */\nexport const DEFAULT_HEADERS: string[] = [\n '<meta charset=\"utf-8\" />',\n '<meta name=\"robots\" content=\"none\" />',\n '<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />'\n];\n","import { generate } from '../config/generate';\nimport { generateViewports } from '../config/generate-viewports';\nimport { HIDE_TEMPLATE_STYLE } from '../constants';\nimport { type FrameportOptionsInterface } from '../types';\nimport { add as addStyles } from '../utils/styles';\n\n/**\n * Generate iframes into the DOM, possibly generating viewports.\n *\n * @param {HTMLElement} targetElement - The target HTML element.\n * @param {FrameportOptionsInterface} options - The options for the iframe.\n * @returns {void}\n */\nconst dom = (\n targetElement: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n if (\n !targetElement ||\n !options ||\n (options && Object.keys(options).length === 0)\n )\n return;\n\n const { html, viewports, templateElement } = options;\n\n if (!html || html === '') return;\n\n addStyles(templateElement as HTMLElement, HIDE_TEMPLATE_STYLE);\n\n if (viewports) {\n generateViewports(targetElement, options);\n } else {\n generate(targetElement, options);\n }\n};\n\nexport default dom;\n","import { type FrameportOptionsInterface } from '../types';\nimport { create } from '../utils/create';\n\n/**\n * Generate multiple iframe elements for different viewports and append them to a target element.\n *\n * @param {HTMLElement} target - The target HTML element to insert iframes after.\n * @param {FrameportOptionsInterface} options - The options for generating the iframes.\n * @returns {void}\n */\nexport const generateViewports = (\n target: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n const { viewports } = options;\n\n if (!viewports || viewports === '') return;\n\n let screens: string[] = [];\n\n if (viewports.includes(',')) screens = [...screens, ...viewports.split(',')];\n else screens.push(viewports);\n\n for (const viewPort of screens) {\n const values = viewPort.split('x');\n const [width, height] = values;\n const iframeElement = create({ ...options, height, width });\n\n target.insertAdjacentElement('afterend', iframeElement);\n }\n};\n","import { type FrameportOptionsInterface } from '../types';\nimport { create } from '../utils/create';\n\n/**\n * Generate an iframe with the given options and append it to a target element.\n *\n * @param {HTMLElement} targetElement - The target HTML element to append the iframe to.\n * @param {FrameportOptionsInterface} options - The options for generating the iframe.\n * @returns {void}\n */\nexport const generate = (\n targetElement: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n const { width } = options;\n\n if (!width) return;\n\n const iframeElement = create(options);\n\n targetElement.append(iframeElement);\n};\n","import { DEFAULT_HEADERS } from '../constants';\n\n/**\n * Get headers for the iframe generated\n *\n * @param {string|string[]|null|undefined} rdeHeaders - The custom headers to include.\n * @returns {string[]} - An array of headers, including default and custom headers.\n */\nexport const getHeaders = (\n rdeHeaders: string | string[] | null | undefined\n): string[] => {\n let headers: string[] = [...DEFAULT_HEADERS];\n\n if (rdeHeaders) {\n if (Array.isArray(rdeHeaders)) {\n headers = [...headers, ...rdeHeaders].map((h) => h.trim());\n } else if (rdeHeaders.includes(',')) {\n headers = [...headers, ...rdeHeaders.split(',')].map((h) => h.trim());\n } else if (rdeHeaders !== '') {\n headers.push(rdeHeaders.trim());\n }\n }\n\n return headers;\n};\n","/* eslint no-console:0 */\nimport dom from '../features/dom';\nimport { type FrameportFunctionType } from '../types';\nimport { getHeaders } from '../utils/headers';\n\n/**\n * A function to initialize frameport when the DOM is ready.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // domReady(myRDE);\n * ```\n */\nexport const domReady = (frameport: FrameportFunctionType): void => {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n frameport();\n });\n } else {\n // `DOMContentLoaded` already fired\n frameport();\n }\n};\n\n/**\n * A function to initialize lazy frameport functionality.\n *\n * @example\n * ```ts\n * // Usage example:\n * // lazy();\n * ```\n */\nexport const lazy = (): void => {\n const frameportObserverTarget = new IntersectionObserver((els, observer) => {\n els.forEach((el: IntersectionObserverEntry) => {\n if (el.intersectionRatio > 0) {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports\n }\n } = el.target as HTMLElement;\n\n let html = el.target.innerHTML;\n let templateElementToUse = el.target as HTMLElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports\n };\n\n dom(el.target as HTMLElement, options);\n observer.unobserve(el.target);\n }\n });\n });\n\n document.querySelectorAll('[data-frameport]').forEach((el) => {\n frameportObserverTarget.observe(el);\n });\n};\n\n/**\n * A function to manually activate frameport.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // manual(myRDE);\n * ```\n */\nexport const manual = (frameport: FrameportFunctionType): void => {\n window.frameport = frameport;\n};\n\n/**\n * A function to activate frameport based on script attributes.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // activate(myRDE);\n * ```\n */\nexport const activate = (frameport: FrameportFunctionType): void => {\n const script = document.currentScript;\n\n if (script) {\n const frameportScriptSrc = script.getAttribute('src');\n\n if (frameportScriptSrc && frameportScriptSrc.includes('frameport.js')) {\n if (script.hasAttribute('data-manual')) {\n manual(frameport);\n } else if (script.hasAttribute('data-instant')) {\n frameport();\n } else if (script.hasAttribute('data-dom')) {\n domReady(frameport);\n } else if (script.hasAttribute('data-lazy')) {\n lazy();\n } else {\n domReady(frameport);\n }\n }\n }\n};\n","/* eslint-disable import/no-unused-modules */\nimport { domReady, lazy, manual, activate } from './config/browser';\nimport dom from './features/dom';\nimport { getHeaders } from './utils/headers';\n\nexport const modes = {\n domReady,\n lazy,\n manual,\n activate\n};\n\nconst frameport = () => {\n document\n .querySelectorAll('[data-frameport-iframe]')\n .forEach((iframe) => iframe.remove());\n\n const elsToBeTransformedTemplate =\n document.querySelectorAll('[data-frameport]');\n\n elsToBeTransformedTemplate.forEach((targetElement: HTMLElement) => {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports\n }\n } = targetElement;\n\n let html = targetElement.innerHTML;\n let templateElementToUse = targetElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports\n };\n\n dom(targetElement, options);\n });\n};\n\nexport default frameport;\n\nactivate(frameport);\n"],"names":["getSource","options","style","css","code","javascript","html","headers","window","location","protocol","host","trim","getCSS","getJavaScript","getCode","getStyle","join","getGeneratedPageURL","type","blob","Blob","URL","createObjectURL","getBlobURL","add","async","el","styles","Array","isArray","length","Object","keys","constructor","Promise","requestAnimationFrame","forEach","key","value","create","className","height","width","url","iframeElement","document","createElement","iframeStyle","src","setAttribute","classList","addStyles","HIDE_TEMPLATE_STYLE","clip","margin","overflow","position","DEFAULT_HEADERS","dom","targetElement","viewports","templateElement","target","screens","includes","split","push","viewPort","values","insertAdjacentElement","generateViewports","append","generate","getHeaders","rdeHeaders","map","h","domReady","frameport","readyState","addEventListener","lazy","frameportObserverTarget","IntersectionObserver","els","observer","intersectionRatio","dataset","frameportTemplate","templateSelector","frameportVh","frameportVw","frameportCss","frameportStyle","frameportCode","frameportJs","frameportClass","frameportHeaders","frameportViewports","innerHTML","templateElementToUse","querySelector","unobserve","querySelectorAll","observe","manual","activate","script","currentScript","frameportScriptSrc","getAttribute","hasAttribute","modes","iframe","remove"],"mappings":"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"}
1
+ {"version":3,"file":"frameport.esm.js","sources":["../src/utils/iframe.ts","../src/utils/source.ts","../src/utils/css.ts","../src/utils/js.ts","../src/utils/code.ts","../src/utils/style.ts","../src/utils/page.ts","../src/utils/blob.ts","../src/utils/styles.ts","../src/utils/wait.ts","../src/utils/create.ts","../src/constants/index.ts","../src/features/dom.ts","../src/config/generate-viewports.ts","../src/config/generate.ts","../src/utils/headers.ts","../src/config/browser.ts","../src/main.ts"],"sourcesContent":["/**\n * Create and return an iframe element.\n *\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const createIframe = (): HTMLIFrameElement =>\n document.createElement('iframe');\n","import { type FrameportOptionsInterface } from '../types';\n\nimport { getCode } from './code';\nimport { getCSS } from './css';\nimport { getJavaScript } from './js';\nimport { getStyle } from './style';\n\n/**\n * Generate the source code for an HTML page based on the provided options.\n *\n * @param {FrameportOptionsInterface} options - The options for generating the HTML page source.\n * @returns {string} - The generated HTML source code as a string.\n */\nexport const getSource = (options: FrameportOptionsInterface): string => {\n let { style, css, code, javascript } = options;\n\n const { html, headers = [] } = options;\n\n css = getCSS(css);\n javascript = getJavaScript(javascript);\n code = getCode(code);\n style = getStyle(style);\n\n return `<!DOCTYPE html>\n<html>\n<head>\n${headers.join('\\n')}\n${style}\n${css}\n</head>\n<body>\n${html || ''}\n${javascript}\n${code}\n</body>\n</html>`;\n};\n","/**\n * Generate a CSS link tag based on the provided URL.\n *\n * @param {string | undefined} css - The URL of the CSS file.\n * @returns {string} - A CSS link tag.\n */\nexport const getCSS = (css: string | undefined): string => {\n if (css && css !== '') {\n return `<link rel=\"stylesheet\" type=\"text/css\" href=\"${window.location.protocol}//${window.location.host}${css.trim()}\" />`;\n }\n\n return '';\n};\n","/**\n * Generate a script tag for the specified JavaScript file.\n *\n * @param {string | undefined} javascript - The path to the JavaScript file.\n * @returns {string} - The generated script tag or an empty string if no JavaScript path is provided.\n */\nexport const getJavaScript = (javascript: string | undefined): string => {\n if (javascript && javascript !== '') {\n return `<script src=\"${window.location.protocol}//${window.location.host}${javascript.trim()}\"></script>`;\n }\n\n return '';\n};\n","/**\n * Get a script element containing the provided code if available.\n *\n * @param {string | undefined} code - The code to include in the script element.\n * @returns {string} - The script element or an empty string if code is not available.\n */\nexport const getCode = (code: string | undefined): string => {\n if (code && code !== '') {\n return `<script>${code.trim()}</script>`;\n }\n\n return '';\n};\n","/**\n * Generate a style element based on the provided CSS styles.\n *\n * @param {string | undefined} style - The CSS styles to include in the style element.\n * @returns {string} - The style element as a string or an empty string if no styles are provided.\n */\nexport const getStyle = (style: string | undefined): string => {\n if (style && style !== '') {\n return `<style type=\"text/css\">${style}</style>`;\n }\n\n return '';\n};\n","import { getBlobURL } from './blob';\nimport { getSource } from './source';\n\n/**\n * Get the URL of a generated HTML page based on the provided options.\n *\n * @param {object} options - The options for generating the HTML page.\n * @returns {string} - The URL of the generated HTML page as a Blob URL.\n */\nexport const getGeneratedPageURL = (options) => {\n const source = getSource(options);\n\n return getBlobURL(source, 'text/html');\n};\n","/**\n * Generates a Blob URL from HTML content with the specified MIME type.\n *\n * @param {string} html - The HTML content to create a Blob from.\n * @param {string} type - The MIME type of the Blob (e.g., 'text/html', 'image/jpeg').\n * @returns {string} - The generated Blob URL.\n */\nexport const getBlobURL = (html: string, type: string): string => {\n const blob = new Blob([html], { type });\n\n return URL.createObjectURL(blob);\n};\n","/* eslint no-console:0 */\nimport { waitForFrame } from './wait';\n\n/**\n * Adds CSS styles to an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to apply styles to.\n * @param {object | Array<{ key: string; value: string }>} styles - An object or an array of objects containing CSS styles to apply.\n * @returns {Promise<void>} - A Promise that resolves after styles are applied.\n *\n * @example\n * ```ts\n * // Apply styles as an object\n * const element = document.getElementById('my-element');\n * await add(element, { color: 'red', fontSize: '16px' });\n *\n * // Apply styles as an array of objects\n * const styles = [\n * { key: 'color', value: 'blue' },\n * { key: 'backgroundColor', value: 'yellow' }\n * ];\n * await add(element, styles);\n * ```\n */\nexport const add = async (\n el: HTMLElement,\n styles: object | { key: string; value: string }[]\n): Promise<void> => {\n if (\n !el ||\n !styles ||\n typeof styles === 'string' ||\n typeof styles === 'number' ||\n typeof styles === 'boolean' ||\n (Array.isArray(styles) && styles.length === 0) ||\n (Object.keys(styles).length === 0 && styles.constructor === Object)\n ) {\n return;\n }\n\n await waitForFrame();\n\n if (Array.isArray(styles)) {\n styles.forEach(\n (style: { key: string; value: string }) =>\n (el.style[style.key] = style.value)\n );\n } else {\n Object.keys(styles).forEach((key) => (el.style[key] = styles[key]));\n }\n};\n\n/**\n * Gets the computed CSS styles of an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to get computed styles from.\n * @returns {Promise<CSSStyleDeclaration>} - A Promise that resolves with the computed CSS styles.\n *\n * @example\n * ```ts\n * // Get computed styles of an element\n * const element = document.getElementById('my-element');\n * const computedStyles = await get(element);\n * console.log(computedStyles.color); // Logs the color property value\n * ```\n */\nexport const get = async (el: HTMLElement): Promise<CSSStyleDeclaration> => {\n await waitForFrame();\n\n return getComputedStyle(el, null);\n};\n","/**\n * Waits for the next animation frame using requestAnimationFrame.\n *\n * @returns {Promise<number>} - A Promise that resolves with the timestamp of the next animation frame.\n *\n * @example\n * ```ts\n * // Wait for the next animation frame and get the rect\n * await waitForFrame();\n * const rect = el.getBoundingClientRect();\n * // Wait for the next animation frame and get the timestamp\n * const timestamp = await waitForFrame();\n * ```\n */\nexport const waitForFrame = (): Promise<number> =>\n new Promise<number>(requestAnimationFrame);\n","import { type FrameportOptionsInterface } from '../types';\nimport { createIframe } from '../utils/iframe';\nimport { getGeneratedPageURL } from '../utils/page';\nimport { add as addStyles } from '../utils/styles';\n\n/**\n * Create an iframe element with specified options and styles.\n *\n * @param {FrameportOptionsInterface} options - The options for creating the iframe.\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const create = (\n options: FrameportOptionsInterface\n): HTMLIFrameElement => {\n const { className, height, width } = options;\n const url = getGeneratedPageURL(options);\n const iframeElement = createIframe();\n const iframeStyle = {};\n\n iframeElement.src = url;\n iframeElement.setAttribute('data-rde-iframe', '');\n\n if (!className || className === '') {\n iframeStyle['border'] = 'none';\n } else {\n iframeElement.classList.add(className);\n }\n\n iframeStyle['width'] = `${width}px`;\n\n if (height) {\n iframeStyle['height'] = `${height}px`;\n }\n\n addStyles(iframeElement, iframeStyle);\n\n return iframeElement;\n};\n","/**\n * @constant\n * @description\n * Inline style used to visually hide an element from layout and screen readers,\n * often used to hide `<template>` elements or accessibility-hidden content.\n *\n * Mimics techniques commonly recommended for a11y-invisible content without removing from DOM.\n *\n * @type {{ clip: string, height: string, margin: string, overflow: string, position: string, width: string }}\n *\n * @example\n * ```ts\n * element.style = { ...HIDE_TEMPLATE_STYLE };\n * ```\n */\nexport const HIDE_TEMPLATE_STYLE: {\n clip: string;\n height: string;\n margin: string;\n overflow: string;\n position: string;\n width: string;\n} = {\n clip: 'rect(1px, 1px, 1px, 1px)',\n height: '1px',\n margin: '0',\n overflow: 'hidden',\n position: 'absolute',\n width: '1px'\n};\n\n/**\n * @constant\n * @description\n * Default `<meta>` tags to inject into a dynamically created HTML document.\n * Ensures consistent encoding, responsive layout, and no indexing by robots.\n *\n * Useful when rendering sandboxed `<iframe>` content or initializing virtual DOMs.\n *\n * @type {string[]}\n *\n * @example\n * ```ts\n * const headHtml = DEFAULT_HEADERS.join('\\n');\n * iframeDoc.head.innerHTML = headHtml;\n * ```\n */\nexport const DEFAULT_HEADERS: string[] = [\n '<meta charset=\"utf-8\" />',\n '<meta name=\"robots\" content=\"none\" />',\n '<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />'\n];\n","import { generate } from '../config/generate';\nimport { generateViewports } from '../config/generate-viewports';\nimport { HIDE_TEMPLATE_STYLE } from '../constants';\nimport { type FrameportOptionsInterface } from '../types';\nimport { add as addStyles } from '../utils/styles';\n\n/**\n * Generate iframes into the DOM, possibly generating viewports.\n *\n * @param {HTMLElement} targetElement - The target HTML element.\n * @param {FrameportOptionsInterface} options - The options for the iframe.\n * @returns {void}\n */\nconst dom = (\n targetElement: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n if (\n !targetElement ||\n !options ||\n (options && Object.keys(options).length === 0)\n )\n return;\n\n const { html, viewports, templateElement } = options;\n\n if (!html || html === '') return;\n\n addStyles(templateElement as HTMLElement, HIDE_TEMPLATE_STYLE);\n\n if (viewports) {\n generateViewports(targetElement, options);\n } else {\n generate(targetElement, options);\n }\n};\n\nexport default dom;\n","import { type FrameportOptionsInterface } from '../types';\nimport { create } from '../utils/create';\n\n/**\n * Generate multiple iframe elements for different viewports and append them to a target element.\n *\n * @param {HTMLElement} target - The target HTML element to insert iframes after.\n * @param {FrameportOptionsInterface} options - The options for generating the iframes.\n * @returns {void}\n */\nexport const generateViewports = (\n target: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n const { viewports } = options;\n\n if (!viewports || viewports === '') return;\n\n let screens: string[] = [];\n\n if (viewports.includes(',')) screens = [...screens, ...viewports.split(',')];\n else screens.push(viewports);\n\n for (const viewPort of screens) {\n const values = viewPort.split('x');\n const [width, height] = values;\n const iframeElement = create({ ...options, height, width });\n\n target.insertAdjacentElement('afterend', iframeElement);\n }\n};\n","import { type FrameportOptionsInterface } from '../types';\nimport { create } from '../utils/create';\n\n/**\n * Generate an iframe with the given options and append it to a target element.\n *\n * @param {HTMLElement} targetElement - The target HTML element to append the iframe to.\n * @param {FrameportOptionsInterface} options - The options for generating the iframe.\n * @returns {void}\n */\nexport const generate = (\n targetElement: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n const { width } = options;\n\n if (!width) return;\n\n const iframeElement = create(options);\n\n targetElement.append(iframeElement);\n};\n","import { DEFAULT_HEADERS } from '../constants';\n\n/**\n * Get headers for the iframe generated\n *\n * @param {string|string[]|null|undefined} rdeHeaders - The custom headers to include.\n * @returns {string[]} - An array of headers, including default and custom headers.\n */\nexport const getHeaders = (\n rdeHeaders: string | string[] | null | undefined\n): string[] => {\n let headers: string[] = [...DEFAULT_HEADERS];\n\n if (rdeHeaders) {\n if (Array.isArray(rdeHeaders)) {\n headers = [...headers, ...rdeHeaders].map((h) => h.trim());\n } else if (rdeHeaders.includes(',')) {\n headers = [...headers, ...rdeHeaders.split(',')].map((h) => h.trim());\n } else if (rdeHeaders !== '') {\n headers.push(rdeHeaders.trim());\n }\n }\n\n return headers;\n};\n","/* eslint no-console:0 */\nimport dom from '../features/dom';\nimport { type FrameportFunctionType } from '../types';\nimport { getHeaders } from '../utils/headers';\n\n/**\n * A function to initialize frameport when the DOM is ready.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // domReady(myRDE);\n * ```\n */\nexport const domReady = (frameport: FrameportFunctionType): void => {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n frameport();\n });\n } else {\n // `DOMContentLoaded` already fired\n frameport();\n }\n};\n\n/**\n * A function to initialize lazy frameport functionality.\n *\n * @example\n * ```ts\n * // Usage example:\n * // lazy();\n * ```\n */\nexport const lazy = (): void => {\n const frameportObserverTarget = new IntersectionObserver((els, observer) => {\n els.forEach((el: IntersectionObserverEntry) => {\n if (el.intersectionRatio > 0) {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports\n }\n } = el.target as HTMLElement;\n\n let html = el.target.innerHTML;\n let templateElementToUse = el.target as HTMLElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports\n };\n\n dom(el.target as HTMLElement, options);\n observer.unobserve(el.target);\n }\n });\n });\n\n document.querySelectorAll('[data-frameport]').forEach((el) => {\n frameportObserverTarget.observe(el);\n });\n};\n\n/**\n * A function to manually activate frameport.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // manual(myRDE);\n * ```\n */\nexport const manual = (frameport: FrameportFunctionType): void => {\n window.frameport = frameport;\n};\n\n/**\n * A function to activate frameport based on script attributes.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // activate(myRDE);\n * ```\n */\nexport const activate = (frameport: FrameportFunctionType): void => {\n const script = document.currentScript;\n\n if (script) {\n const frameportScriptSrc = script.getAttribute('src');\n\n if (frameportScriptSrc && frameportScriptSrc.includes('frameport.js')) {\n if (script.hasAttribute('data-manual')) {\n manual(frameport);\n } else if (script.hasAttribute('data-instant')) {\n frameport();\n } else if (script.hasAttribute('data-dom')) {\n domReady(frameport);\n } else if (script.hasAttribute('data-lazy')) {\n lazy();\n } else {\n domReady(frameport);\n }\n }\n }\n};\n","/* eslint-disable import/no-unused-modules */\nimport { domReady, lazy, manual, activate } from './config/browser';\nimport dom from './features/dom';\nimport { getHeaders } from './utils/headers';\n\n/**\n * Available initialization modes for frameport usage.\n * Can be triggered manually or via browser lifecycle hooks.\n */\nexport const modes = {\n domReady,\n lazy,\n manual,\n activate\n};\n\n/**\n * Transforms all DOM elements marked with `[data-frameport]` into embedded iframes\n * with sandboxed content based on HTML templates and associated metadata.\n *\n * Also removes any existing `[data-frameport-iframe]` elements from the document,\n * ensuring re-renders are clean.\n *\n * Reads attributes such as:\n * - `data-frameport-template`\n * - `data-frameport-css`\n * - `data-frameport-style`\n * - `data-frameport-code`\n * - `data-frameport-js`\n * - `data-frameport-class`\n * - `data-frameport-headers`\n * - `data-frameport-viewports`\n * - `data-frameport-vh`\n * - `data-frameport-vw`\n *\n * @example\n * ```html\n * <div\n * data-frameport\n * data-frameport-template=\"#my-template\"\n * data-frameport-vh=\"100\"\n * data-frameport-vw=\"100\"\n * data-frameport-css=\"styles.css\"\n * data-frameport-js=\"script.js\"\n * ></div>\n *\n * <template id=\"my-template\">\n * <h1>Hello, sandbox!</h1>\n * </template>\n * ```\n *\n * @function frameport\n * @returns void\n */\nconst frameport = () => {\n // Remove all generated iframes first\n document\n .querySelectorAll('[data-frameport-iframe]')\n .forEach((iframe) => iframe.remove());\n\n // Find all frameport targets\n const elsToBeTransformedTemplate =\n document.querySelectorAll('[data-frameport]');\n\n elsToBeTransformedTemplate.forEach((targetElement: HTMLElement) => {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports\n }\n } = targetElement;\n\n let html = targetElement.innerHTML;\n let templateElementToUse = targetElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports\n };\n\n dom(targetElement, options);\n });\n};\n\nexport default frameport;\n\n// Automatically activate frameport logic\nactivate(frameport);\n"],"names":["getSource","options","style","css","code","javascript","html","headers","window","location","protocol","host","trim","getCSS","getJavaScript","getCode","getStyle","join","getGeneratedPageURL","type","blob","Blob","URL","createObjectURL","getBlobURL","add","async","el","styles","Array","isArray","length","Object","keys","constructor","Promise","requestAnimationFrame","forEach","key","value","create","className","height","width","url","iframeElement","document","createElement","iframeStyle","src","setAttribute","classList","addStyles","HIDE_TEMPLATE_STYLE","clip","margin","overflow","position","DEFAULT_HEADERS","dom","targetElement","viewports","templateElement","target","screens","includes","split","push","viewPort","values","insertAdjacentElement","generateViewports","append","generate","getHeaders","rdeHeaders","map","h","domReady","frameport","readyState","addEventListener","lazy","frameportObserverTarget","IntersectionObserver","els","observer","intersectionRatio","dataset","frameportTemplate","templateSelector","frameportVh","frameportVw","frameportCss","frameportStyle","frameportCode","frameportJs","frameportClass","frameportHeaders","frameportViewports","innerHTML","templateElementToUse","querySelector","unobserve","querySelectorAll","observe","manual","activate","script","currentScript","frameportScriptSrc","getAttribute","hasAttribute","modes","iframe","remove"],"mappings":"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"}
package/dist/frameport.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * @phun-ky/frameport
3
- * Create responsive documentation examples on the fly
3
+ * A zero dependency package to effortlessly create responsive component previews in documentation using real media queries. Frameport dynamically generates iframes containing your HTML/CSS/JS, mimicking natural device viewports to test responsiveness, without any build steps or dependencies.
4
4
  * @author Alexander Vassbotn Røyne-Helgesen <alexander+frameport@phun-ky.net>
5
- * @version 2.0.20
5
+ * @version 2.0.22
6
6
  * @license
7
7
  * Copyright (c) 2023 Alexander Vassbotn Røyne-Helgesen
8
8
  *
@@ -1 +1 @@
1
- {"version":3,"file":"frameport.js","sources":["../src/utils/iframe.ts","../src/utils/source.ts","../src/utils/css.ts","../src/utils/js.ts","../src/utils/code.ts","../src/utils/style.ts","../src/utils/page.ts","../src/utils/blob.ts","../src/utils/styles.ts","../src/utils/wait.ts","../src/utils/create.ts","../src/constants/index.ts","../src/features/dom.ts","../src/config/generate-viewports.ts","../src/config/generate.ts","../src/utils/headers.ts","../src/config/browser.ts","../src/main.ts"],"sourcesContent":["/**\n * Create and return an iframe element.\n *\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const createIframe = (): HTMLIFrameElement =>\n document.createElement('iframe');\n","import { type FrameportOptionsInterface } from '../types';\n\nimport { getCode } from './code';\nimport { getCSS } from './css';\nimport { getJavaScript } from './js';\nimport { getStyle } from './style';\n\n/**\n * Generate the source code for an HTML page based on the provided options.\n *\n * @param {FrameportOptionsInterface} options - The options for generating the HTML page source.\n * @returns {string} - The generated HTML source code as a string.\n */\nexport const getSource = (options: FrameportOptionsInterface): string => {\n let { style, css, code, javascript } = options;\n\n const { html, headers = [] } = options;\n\n css = getCSS(css);\n javascript = getJavaScript(javascript);\n code = getCode(code);\n style = getStyle(style);\n\n return `<!DOCTYPE html>\n<html>\n<head>\n${headers.join('\\n')}\n${style}\n${css}\n</head>\n<body>\n${html || ''}\n${javascript}\n${code}\n</body>\n</html>`;\n};\n","/**\n * Generate a CSS link tag based on the provided URL.\n *\n * @param {string | undefined} css - The URL of the CSS file.\n * @returns {string} - A CSS link tag.\n */\nexport const getCSS = (css: string | undefined): string => {\n if (css && css !== '') {\n return `<link rel=\"stylesheet\" type=\"text/css\" href=\"${window.location.protocol}//${window.location.host}${css.trim()}\" />`;\n }\n\n return '';\n};\n","/**\n * Generate a script tag for the specified JavaScript file.\n *\n * @param {string | undefined} javascript - The path to the JavaScript file.\n * @returns {string} - The generated script tag or an empty string if no JavaScript path is provided.\n */\nexport const getJavaScript = (javascript: string | undefined): string => {\n if (javascript && javascript !== '') {\n return `<script src=\"${window.location.protocol}//${window.location.host}${javascript.trim()}\"></script>`;\n }\n\n return '';\n};\n","/**\n * Get a script element containing the provided code if available.\n *\n * @param {string | undefined} code - The code to include in the script element.\n * @returns {string} - The script element or an empty string if code is not available.\n */\nexport const getCode = (code: string | undefined): string => {\n if (code && code !== '') {\n return `<script>${code.trim()}</script>`;\n }\n\n return '';\n};\n","/**\n * Generate a style element based on the provided CSS styles.\n *\n * @param {string | undefined} style - The CSS styles to include in the style element.\n * @returns {string} - The style element as a string or an empty string if no styles are provided.\n */\nexport const getStyle = (style: string | undefined): string => {\n if (style && style !== '') {\n return `<style type=\"text/css\">${style}</style>`;\n }\n\n return '';\n};\n","import { getBlobURL } from './blob';\nimport { getSource } from './source';\n\n/**\n * Get the URL of a generated HTML page based on the provided options.\n *\n * @param {object} options - The options for generating the HTML page.\n * @returns {string} - The URL of the generated HTML page as a Blob URL.\n */\nexport const getGeneratedPageURL = (options) => {\n const source = getSource(options);\n\n return getBlobURL(source, 'text/html');\n};\n","/**\n * Generates a Blob URL from HTML content with the specified MIME type.\n *\n * @param {string} html - The HTML content to create a Blob from.\n * @param {string} type - The MIME type of the Blob (e.g., 'text/html', 'image/jpeg').\n * @returns {string} - The generated Blob URL.\n */\nexport const getBlobURL = (html: string, type: string): string => {\n const blob = new Blob([html], { type });\n\n return URL.createObjectURL(blob);\n};\n","/* eslint no-console:0 */\nimport { waitForFrame } from './wait';\n\n/**\n * Adds CSS styles to an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to apply styles to.\n * @param {object | Array<{ key: string; value: string }>} styles - An object or an array of objects containing CSS styles to apply.\n * @returns {Promise<void>} - A Promise that resolves after styles are applied.\n *\n * @example\n * ```ts\n * // Apply styles as an object\n * const element = document.getElementById('my-element');\n * await add(element, { color: 'red', fontSize: '16px' });\n *\n * // Apply styles as an array of objects\n * const styles = [\n * { key: 'color', value: 'blue' },\n * { key: 'backgroundColor', value: 'yellow' }\n * ];\n * await add(element, styles);\n * ```\n */\nexport const add = async (\n el: HTMLElement,\n styles: object | { key: string; value: string }[]\n): Promise<void> => {\n if (\n !el ||\n !styles ||\n typeof styles === 'string' ||\n typeof styles === 'number' ||\n typeof styles === 'boolean' ||\n (Array.isArray(styles) && styles.length === 0) ||\n (Object.keys(styles).length === 0 && styles.constructor === Object)\n ) {\n return;\n }\n\n await waitForFrame();\n\n if (Array.isArray(styles)) {\n styles.forEach(\n (style: { key: string; value: string }) =>\n (el.style[style.key] = style.value)\n );\n } else {\n Object.keys(styles).forEach((key) => (el.style[key] = styles[key]));\n }\n};\n\n/**\n * Gets the computed CSS styles of an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to get computed styles from.\n * @returns {Promise<CSSStyleDeclaration>} - A Promise that resolves with the computed CSS styles.\n *\n * @example\n * ```ts\n * // Get computed styles of an element\n * const element = document.getElementById('my-element');\n * const computedStyles = await get(element);\n * console.log(computedStyles.color); // Logs the color property value\n * ```\n */\nexport const get = async (el: HTMLElement): Promise<CSSStyleDeclaration> => {\n await waitForFrame();\n\n return getComputedStyle(el, null);\n};\n","/**\n * Waits for the next animation frame using requestAnimationFrame.\n *\n * @returns {Promise<number>} - A Promise that resolves with the timestamp of the next animation frame.\n *\n * @example\n * ```ts\n * // Wait for the next animation frame and get the rect\n * await waitForFrame();\n * const rect = el.getBoundingClientRect();\n * // Wait for the next animation frame and get the timestamp\n * const timestamp = await waitForFrame();\n * ```\n */\nexport const waitForFrame = (): Promise<number> =>\n new Promise<number>(requestAnimationFrame);\n","import { type FrameportOptionsInterface } from '../types';\nimport { createIframe } from '../utils/iframe';\nimport { getGeneratedPageURL } from '../utils/page';\nimport { add as addStyles } from '../utils/styles';\n\n/**\n * Create an iframe element with specified options and styles.\n *\n * @param {FrameportOptionsInterface} options - The options for creating the iframe.\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const create = (\n options: FrameportOptionsInterface\n): HTMLIFrameElement => {\n const { className, height, width } = options;\n const url = getGeneratedPageURL(options);\n const iframeElement = createIframe();\n const iframeStyle = {};\n\n iframeElement.src = url;\n iframeElement.setAttribute('data-rde-iframe', '');\n\n if (!className || className === '') {\n iframeStyle['border'] = 'none';\n } else {\n iframeElement.classList.add(className);\n }\n\n iframeStyle['width'] = `${width}px`;\n\n if (height) {\n iframeStyle['height'] = `${height}px`;\n }\n\n addStyles(iframeElement, iframeStyle);\n\n return iframeElement;\n};\n","/**\n * Style object for hiding an element in the HTML.\n *\n * @type {{ clip: string, height: string, margin: string, overflow: string, position: string, width: string }}\n */\nexport const HIDE_TEMPLATE_STYLE: {\n clip: string;\n height: string;\n margin: string;\n overflow: string;\n position: string;\n width: string;\n} = {\n clip: 'rect(1px, 1px, 1px, 1px)',\n height: '1px',\n margin: '0',\n overflow: 'hidden',\n position: 'absolute',\n width: '1px'\n};\n\n/**\n * Default meta headers for an HTML document.\n *\n * @type {string[]}\n */\nexport const DEFAULT_HEADERS: string[] = [\n '<meta charset=\"utf-8\" />',\n '<meta name=\"robots\" content=\"none\" />',\n '<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />'\n];\n","import { generate } from '../config/generate';\nimport { generateViewports } from '../config/generate-viewports';\nimport { HIDE_TEMPLATE_STYLE } from '../constants';\nimport { type FrameportOptionsInterface } from '../types';\nimport { add as addStyles } from '../utils/styles';\n\n/**\n * Generate iframes into the DOM, possibly generating viewports.\n *\n * @param {HTMLElement} targetElement - The target HTML element.\n * @param {FrameportOptionsInterface} options - The options for the iframe.\n * @returns {void}\n */\nconst dom = (\n targetElement: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n if (\n !targetElement ||\n !options ||\n (options && Object.keys(options).length === 0)\n )\n return;\n\n const { html, viewports, templateElement } = options;\n\n if (!html || html === '') return;\n\n addStyles(templateElement as HTMLElement, HIDE_TEMPLATE_STYLE);\n\n if (viewports) {\n generateViewports(targetElement, options);\n } else {\n generate(targetElement, options);\n }\n};\n\nexport default dom;\n","import { type FrameportOptionsInterface } from '../types';\nimport { create } from '../utils/create';\n\n/**\n * Generate multiple iframe elements for different viewports and append them to a target element.\n *\n * @param {HTMLElement} target - The target HTML element to insert iframes after.\n * @param {FrameportOptionsInterface} options - The options for generating the iframes.\n * @returns {void}\n */\nexport const generateViewports = (\n target: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n const { viewports } = options;\n\n if (!viewports || viewports === '') return;\n\n let screens: string[] = [];\n\n if (viewports.includes(',')) screens = [...screens, ...viewports.split(',')];\n else screens.push(viewports);\n\n for (const viewPort of screens) {\n const values = viewPort.split('x');\n const [width, height] = values;\n const iframeElement = create({ ...options, height, width });\n\n target.insertAdjacentElement('afterend', iframeElement);\n }\n};\n","import { type FrameportOptionsInterface } from '../types';\nimport { create } from '../utils/create';\n\n/**\n * Generate an iframe with the given options and append it to a target element.\n *\n * @param {HTMLElement} targetElement - The target HTML element to append the iframe to.\n * @param {FrameportOptionsInterface} options - The options for generating the iframe.\n * @returns {void}\n */\nexport const generate = (\n targetElement: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n const { width } = options;\n\n if (!width) return;\n\n const iframeElement = create(options);\n\n targetElement.append(iframeElement);\n};\n","import { DEFAULT_HEADERS } from '../constants';\n\n/**\n * Get headers for the iframe generated\n *\n * @param {string|string[]|null|undefined} rdeHeaders - The custom headers to include.\n * @returns {string[]} - An array of headers, including default and custom headers.\n */\nexport const getHeaders = (\n rdeHeaders: string | string[] | null | undefined\n): string[] => {\n let headers: string[] = [...DEFAULT_HEADERS];\n\n if (rdeHeaders) {\n if (Array.isArray(rdeHeaders)) {\n headers = [...headers, ...rdeHeaders].map((h) => h.trim());\n } else if (rdeHeaders.includes(',')) {\n headers = [...headers, ...rdeHeaders.split(',')].map((h) => h.trim());\n } else if (rdeHeaders !== '') {\n headers.push(rdeHeaders.trim());\n }\n }\n\n return headers;\n};\n","/* eslint no-console:0 */\nimport dom from '../features/dom';\nimport { type FrameportFunctionType } from '../types';\nimport { getHeaders } from '../utils/headers';\n\n/**\n * A function to initialize frameport when the DOM is ready.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // domReady(myRDE);\n * ```\n */\nexport const domReady = (frameport: FrameportFunctionType): void => {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n frameport();\n });\n } else {\n // `DOMContentLoaded` already fired\n frameport();\n }\n};\n\n/**\n * A function to initialize lazy frameport functionality.\n *\n * @example\n * ```ts\n * // Usage example:\n * // lazy();\n * ```\n */\nexport const lazy = (): void => {\n const frameportObserverTarget = new IntersectionObserver((els, observer) => {\n els.forEach((el: IntersectionObserverEntry) => {\n if (el.intersectionRatio > 0) {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports\n }\n } = el.target as HTMLElement;\n\n let html = el.target.innerHTML;\n let templateElementToUse = el.target as HTMLElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports\n };\n\n dom(el.target as HTMLElement, options);\n observer.unobserve(el.target);\n }\n });\n });\n\n document.querySelectorAll('[data-frameport]').forEach((el) => {\n frameportObserverTarget.observe(el);\n });\n};\n\n/**\n * A function to manually activate frameport.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // manual(myRDE);\n * ```\n */\nexport const manual = (frameport: FrameportFunctionType): void => {\n window.frameport = frameport;\n};\n\n/**\n * A function to activate frameport based on script attributes.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // activate(myRDE);\n * ```\n */\nexport const activate = (frameport: FrameportFunctionType): void => {\n const script = document.currentScript;\n\n if (script) {\n const frameportScriptSrc = script.getAttribute('src');\n\n if (frameportScriptSrc && frameportScriptSrc.includes('frameport.js')) {\n if (script.hasAttribute('data-manual')) {\n manual(frameport);\n } else if (script.hasAttribute('data-instant')) {\n frameport();\n } else if (script.hasAttribute('data-dom')) {\n domReady(frameport);\n } else if (script.hasAttribute('data-lazy')) {\n lazy();\n } else {\n domReady(frameport);\n }\n }\n }\n};\n","/* eslint-disable import/no-unused-modules */\nimport { domReady, lazy, manual, activate } from './config/browser';\nimport dom from './features/dom';\nimport { getHeaders } from './utils/headers';\n\nexport const modes = {\n domReady,\n lazy,\n manual,\n activate\n};\n\nconst frameport = () => {\n document\n .querySelectorAll('[data-frameport-iframe]')\n .forEach((iframe) => iframe.remove());\n\n const elsToBeTransformedTemplate =\n document.querySelectorAll('[data-frameport]');\n\n elsToBeTransformedTemplate.forEach((targetElement: HTMLElement) => {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports\n }\n } = targetElement;\n\n let html = targetElement.innerHTML;\n let templateElementToUse = targetElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports\n };\n\n dom(targetElement, options);\n });\n};\n\nexport default frameport;\n\nactivate(frameport);\n"],"names":["getSource","options","style","css","code","javascript","html","headers","window","location","protocol","host","trim","getCSS","getJavaScript","getCode","getStyle","join","getGeneratedPageURL","type","blob","Blob","URL","createObjectURL","getBlobURL","add","async","el","styles","Array","isArray","length","Object","keys","constructor","Promise","requestAnimationFrame","forEach","key","value","create","className","height","width","url","iframeElement","document","createElement","iframeStyle","src","setAttribute","classList","addStyles","HIDE_TEMPLATE_STYLE","clip","margin","overflow","position","DEFAULT_HEADERS","dom","targetElement","viewports","templateElement","target","screens","includes","split","push","viewPort","values","insertAdjacentElement","generateViewports","append","generate","getHeaders","rdeHeaders","map","h","domReady","frameport","readyState","addEventListener","lazy","frameportObserverTarget","IntersectionObserver","els","observer","intersectionRatio","dataset","frameportTemplate","templateSelector","frameportVh","frameportVw","frameportCss","frameportStyle","frameportCode","frameportJs","frameportClass","frameportHeaders","frameportViewports","innerHTML","templateElementToUse","querySelector","unobserve","querySelectorAll","observe","manual","activate","script","currentScript","frameportScriptSrc","getAttribute","hasAttribute","modes","iframe","remove"],"mappings":"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"}
1
+ {"version":3,"file":"frameport.js","sources":["../src/utils/iframe.ts","../src/utils/source.ts","../src/utils/css.ts","../src/utils/js.ts","../src/utils/code.ts","../src/utils/style.ts","../src/utils/page.ts","../src/utils/blob.ts","../src/utils/styles.ts","../src/utils/wait.ts","../src/utils/create.ts","../src/constants/index.ts","../src/features/dom.ts","../src/config/generate-viewports.ts","../src/config/generate.ts","../src/utils/headers.ts","../src/config/browser.ts","../src/main.ts"],"sourcesContent":["/**\n * Create and return an iframe element.\n *\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const createIframe = (): HTMLIFrameElement =>\n document.createElement('iframe');\n","import { type FrameportOptionsInterface } from '../types';\n\nimport { getCode } from './code';\nimport { getCSS } from './css';\nimport { getJavaScript } from './js';\nimport { getStyle } from './style';\n\n/**\n * Generate the source code for an HTML page based on the provided options.\n *\n * @param {FrameportOptionsInterface} options - The options for generating the HTML page source.\n * @returns {string} - The generated HTML source code as a string.\n */\nexport const getSource = (options: FrameportOptionsInterface): string => {\n let { style, css, code, javascript } = options;\n\n const { html, headers = [] } = options;\n\n css = getCSS(css);\n javascript = getJavaScript(javascript);\n code = getCode(code);\n style = getStyle(style);\n\n return `<!DOCTYPE html>\n<html>\n<head>\n${headers.join('\\n')}\n${style}\n${css}\n</head>\n<body>\n${html || ''}\n${javascript}\n${code}\n</body>\n</html>`;\n};\n","/**\n * Generate a CSS link tag based on the provided URL.\n *\n * @param {string | undefined} css - The URL of the CSS file.\n * @returns {string} - A CSS link tag.\n */\nexport const getCSS = (css: string | undefined): string => {\n if (css && css !== '') {\n return `<link rel=\"stylesheet\" type=\"text/css\" href=\"${window.location.protocol}//${window.location.host}${css.trim()}\" />`;\n }\n\n return '';\n};\n","/**\n * Generate a script tag for the specified JavaScript file.\n *\n * @param {string | undefined} javascript - The path to the JavaScript file.\n * @returns {string} - The generated script tag or an empty string if no JavaScript path is provided.\n */\nexport const getJavaScript = (javascript: string | undefined): string => {\n if (javascript && javascript !== '') {\n return `<script src=\"${window.location.protocol}//${window.location.host}${javascript.trim()}\"></script>`;\n }\n\n return '';\n};\n","/**\n * Get a script element containing the provided code if available.\n *\n * @param {string | undefined} code - The code to include in the script element.\n * @returns {string} - The script element or an empty string if code is not available.\n */\nexport const getCode = (code: string | undefined): string => {\n if (code && code !== '') {\n return `<script>${code.trim()}</script>`;\n }\n\n return '';\n};\n","/**\n * Generate a style element based on the provided CSS styles.\n *\n * @param {string | undefined} style - The CSS styles to include in the style element.\n * @returns {string} - The style element as a string or an empty string if no styles are provided.\n */\nexport const getStyle = (style: string | undefined): string => {\n if (style && style !== '') {\n return `<style type=\"text/css\">${style}</style>`;\n }\n\n return '';\n};\n","import { getBlobURL } from './blob';\nimport { getSource } from './source';\n\n/**\n * Get the URL of a generated HTML page based on the provided options.\n *\n * @param {object} options - The options for generating the HTML page.\n * @returns {string} - The URL of the generated HTML page as a Blob URL.\n */\nexport const getGeneratedPageURL = (options) => {\n const source = getSource(options);\n\n return getBlobURL(source, 'text/html');\n};\n","/**\n * Generates a Blob URL from HTML content with the specified MIME type.\n *\n * @param {string} html - The HTML content to create a Blob from.\n * @param {string} type - The MIME type of the Blob (e.g., 'text/html', 'image/jpeg').\n * @returns {string} - The generated Blob URL.\n */\nexport const getBlobURL = (html: string, type: string): string => {\n const blob = new Blob([html], { type });\n\n return URL.createObjectURL(blob);\n};\n","/* eslint no-console:0 */\nimport { waitForFrame } from './wait';\n\n/**\n * Adds CSS styles to an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to apply styles to.\n * @param {object | Array<{ key: string; value: string }>} styles - An object or an array of objects containing CSS styles to apply.\n * @returns {Promise<void>} - A Promise that resolves after styles are applied.\n *\n * @example\n * ```ts\n * // Apply styles as an object\n * const element = document.getElementById('my-element');\n * await add(element, { color: 'red', fontSize: '16px' });\n *\n * // Apply styles as an array of objects\n * const styles = [\n * { key: 'color', value: 'blue' },\n * { key: 'backgroundColor', value: 'yellow' }\n * ];\n * await add(element, styles);\n * ```\n */\nexport const add = async (\n el: HTMLElement,\n styles: object | { key: string; value: string }[]\n): Promise<void> => {\n if (\n !el ||\n !styles ||\n typeof styles === 'string' ||\n typeof styles === 'number' ||\n typeof styles === 'boolean' ||\n (Array.isArray(styles) && styles.length === 0) ||\n (Object.keys(styles).length === 0 && styles.constructor === Object)\n ) {\n return;\n }\n\n await waitForFrame();\n\n if (Array.isArray(styles)) {\n styles.forEach(\n (style: { key: string; value: string }) =>\n (el.style[style.key] = style.value)\n );\n } else {\n Object.keys(styles).forEach((key) => (el.style[key] = styles[key]));\n }\n};\n\n/**\n * Gets the computed CSS styles of an HTMLElement.\n *\n * @param {HTMLElement} el - The HTMLElement to get computed styles from.\n * @returns {Promise<CSSStyleDeclaration>} - A Promise that resolves with the computed CSS styles.\n *\n * @example\n * ```ts\n * // Get computed styles of an element\n * const element = document.getElementById('my-element');\n * const computedStyles = await get(element);\n * console.log(computedStyles.color); // Logs the color property value\n * ```\n */\nexport const get = async (el: HTMLElement): Promise<CSSStyleDeclaration> => {\n await waitForFrame();\n\n return getComputedStyle(el, null);\n};\n","/**\n * Waits for the next animation frame using requestAnimationFrame.\n *\n * @returns {Promise<number>} - A Promise that resolves with the timestamp of the next animation frame.\n *\n * @example\n * ```ts\n * // Wait for the next animation frame and get the rect\n * await waitForFrame();\n * const rect = el.getBoundingClientRect();\n * // Wait for the next animation frame and get the timestamp\n * const timestamp = await waitForFrame();\n * ```\n */\nexport const waitForFrame = (): Promise<number> =>\n new Promise<number>(requestAnimationFrame);\n","import { type FrameportOptionsInterface } from '../types';\nimport { createIframe } from '../utils/iframe';\nimport { getGeneratedPageURL } from '../utils/page';\nimport { add as addStyles } from '../utils/styles';\n\n/**\n * Create an iframe element with specified options and styles.\n *\n * @param {FrameportOptionsInterface} options - The options for creating the iframe.\n * @returns {HTMLIFrameElement} - The created iframe element.\n */\nexport const create = (\n options: FrameportOptionsInterface\n): HTMLIFrameElement => {\n const { className, height, width } = options;\n const url = getGeneratedPageURL(options);\n const iframeElement = createIframe();\n const iframeStyle = {};\n\n iframeElement.src = url;\n iframeElement.setAttribute('data-rde-iframe', '');\n\n if (!className || className === '') {\n iframeStyle['border'] = 'none';\n } else {\n iframeElement.classList.add(className);\n }\n\n iframeStyle['width'] = `${width}px`;\n\n if (height) {\n iframeStyle['height'] = `${height}px`;\n }\n\n addStyles(iframeElement, iframeStyle);\n\n return iframeElement;\n};\n","/**\n * @constant\n * @description\n * Inline style used to visually hide an element from layout and screen readers,\n * often used to hide `<template>` elements or accessibility-hidden content.\n *\n * Mimics techniques commonly recommended for a11y-invisible content without removing from DOM.\n *\n * @type {{ clip: string, height: string, margin: string, overflow: string, position: string, width: string }}\n *\n * @example\n * ```ts\n * element.style = { ...HIDE_TEMPLATE_STYLE };\n * ```\n */\nexport const HIDE_TEMPLATE_STYLE: {\n clip: string;\n height: string;\n margin: string;\n overflow: string;\n position: string;\n width: string;\n} = {\n clip: 'rect(1px, 1px, 1px, 1px)',\n height: '1px',\n margin: '0',\n overflow: 'hidden',\n position: 'absolute',\n width: '1px'\n};\n\n/**\n * @constant\n * @description\n * Default `<meta>` tags to inject into a dynamically created HTML document.\n * Ensures consistent encoding, responsive layout, and no indexing by robots.\n *\n * Useful when rendering sandboxed `<iframe>` content or initializing virtual DOMs.\n *\n * @type {string[]}\n *\n * @example\n * ```ts\n * const headHtml = DEFAULT_HEADERS.join('\\n');\n * iframeDoc.head.innerHTML = headHtml;\n * ```\n */\nexport const DEFAULT_HEADERS: string[] = [\n '<meta charset=\"utf-8\" />',\n '<meta name=\"robots\" content=\"none\" />',\n '<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\" />',\n '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />'\n];\n","import { generate } from '../config/generate';\nimport { generateViewports } from '../config/generate-viewports';\nimport { HIDE_TEMPLATE_STYLE } from '../constants';\nimport { type FrameportOptionsInterface } from '../types';\nimport { add as addStyles } from '../utils/styles';\n\n/**\n * Generate iframes into the DOM, possibly generating viewports.\n *\n * @param {HTMLElement} targetElement - The target HTML element.\n * @param {FrameportOptionsInterface} options - The options for the iframe.\n * @returns {void}\n */\nconst dom = (\n targetElement: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n if (\n !targetElement ||\n !options ||\n (options && Object.keys(options).length === 0)\n )\n return;\n\n const { html, viewports, templateElement } = options;\n\n if (!html || html === '') return;\n\n addStyles(templateElement as HTMLElement, HIDE_TEMPLATE_STYLE);\n\n if (viewports) {\n generateViewports(targetElement, options);\n } else {\n generate(targetElement, options);\n }\n};\n\nexport default dom;\n","import { type FrameportOptionsInterface } from '../types';\nimport { create } from '../utils/create';\n\n/**\n * Generate multiple iframe elements for different viewports and append them to a target element.\n *\n * @param {HTMLElement} target - The target HTML element to insert iframes after.\n * @param {FrameportOptionsInterface} options - The options for generating the iframes.\n * @returns {void}\n */\nexport const generateViewports = (\n target: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n const { viewports } = options;\n\n if (!viewports || viewports === '') return;\n\n let screens: string[] = [];\n\n if (viewports.includes(',')) screens = [...screens, ...viewports.split(',')];\n else screens.push(viewports);\n\n for (const viewPort of screens) {\n const values = viewPort.split('x');\n const [width, height] = values;\n const iframeElement = create({ ...options, height, width });\n\n target.insertAdjacentElement('afterend', iframeElement);\n }\n};\n","import { type FrameportOptionsInterface } from '../types';\nimport { create } from '../utils/create';\n\n/**\n * Generate an iframe with the given options and append it to a target element.\n *\n * @param {HTMLElement} targetElement - The target HTML element to append the iframe to.\n * @param {FrameportOptionsInterface} options - The options for generating the iframe.\n * @returns {void}\n */\nexport const generate = (\n targetElement: HTMLElement,\n options: FrameportOptionsInterface\n): void => {\n const { width } = options;\n\n if (!width) return;\n\n const iframeElement = create(options);\n\n targetElement.append(iframeElement);\n};\n","import { DEFAULT_HEADERS } from '../constants';\n\n/**\n * Get headers for the iframe generated\n *\n * @param {string|string[]|null|undefined} rdeHeaders - The custom headers to include.\n * @returns {string[]} - An array of headers, including default and custom headers.\n */\nexport const getHeaders = (\n rdeHeaders: string | string[] | null | undefined\n): string[] => {\n let headers: string[] = [...DEFAULT_HEADERS];\n\n if (rdeHeaders) {\n if (Array.isArray(rdeHeaders)) {\n headers = [...headers, ...rdeHeaders].map((h) => h.trim());\n } else if (rdeHeaders.includes(',')) {\n headers = [...headers, ...rdeHeaders.split(',')].map((h) => h.trim());\n } else if (rdeHeaders !== '') {\n headers.push(rdeHeaders.trim());\n }\n }\n\n return headers;\n};\n","/* eslint no-console:0 */\nimport dom from '../features/dom';\nimport { type FrameportFunctionType } from '../types';\nimport { getHeaders } from '../utils/headers';\n\n/**\n * A function to initialize frameport when the DOM is ready.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // domReady(myRDE);\n * ```\n */\nexport const domReady = (frameport: FrameportFunctionType): void => {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n frameport();\n });\n } else {\n // `DOMContentLoaded` already fired\n frameport();\n }\n};\n\n/**\n * A function to initialize lazy frameport functionality.\n *\n * @example\n * ```ts\n * // Usage example:\n * // lazy();\n * ```\n */\nexport const lazy = (): void => {\n const frameportObserverTarget = new IntersectionObserver((els, observer) => {\n els.forEach((el: IntersectionObserverEntry) => {\n if (el.intersectionRatio > 0) {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports\n }\n } = el.target as HTMLElement;\n\n let html = el.target.innerHTML;\n let templateElementToUse = el.target as HTMLElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports\n };\n\n dom(el.target as HTMLElement, options);\n observer.unobserve(el.target);\n }\n });\n });\n\n document.querySelectorAll('[data-frameport]').forEach((el) => {\n frameportObserverTarget.observe(el);\n });\n};\n\n/**\n * A function to manually activate frameport.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // manual(myRDE);\n * ```\n */\nexport const manual = (frameport: FrameportFunctionType): void => {\n window.frameport = frameport;\n};\n\n/**\n * A function to activate frameport based on script attributes.\n *\n * @param {FrameportFunctionType} frameport - The frameport function to execute.\n *\n * @example\n * ```ts\n * // Usage example:\n * // activate(myRDE);\n * ```\n */\nexport const activate = (frameport: FrameportFunctionType): void => {\n const script = document.currentScript;\n\n if (script) {\n const frameportScriptSrc = script.getAttribute('src');\n\n if (frameportScriptSrc && frameportScriptSrc.includes('frameport.js')) {\n if (script.hasAttribute('data-manual')) {\n manual(frameport);\n } else if (script.hasAttribute('data-instant')) {\n frameport();\n } else if (script.hasAttribute('data-dom')) {\n domReady(frameport);\n } else if (script.hasAttribute('data-lazy')) {\n lazy();\n } else {\n domReady(frameport);\n }\n }\n }\n};\n","/* eslint-disable import/no-unused-modules */\nimport { domReady, lazy, manual, activate } from './config/browser';\nimport dom from './features/dom';\nimport { getHeaders } from './utils/headers';\n\n/**\n * Available initialization modes for frameport usage.\n * Can be triggered manually or via browser lifecycle hooks.\n */\nexport const modes = {\n domReady,\n lazy,\n manual,\n activate\n};\n\n/**\n * Transforms all DOM elements marked with `[data-frameport]` into embedded iframes\n * with sandboxed content based on HTML templates and associated metadata.\n *\n * Also removes any existing `[data-frameport-iframe]` elements from the document,\n * ensuring re-renders are clean.\n *\n * Reads attributes such as:\n * - `data-frameport-template`\n * - `data-frameport-css`\n * - `data-frameport-style`\n * - `data-frameport-code`\n * - `data-frameport-js`\n * - `data-frameport-class`\n * - `data-frameport-headers`\n * - `data-frameport-viewports`\n * - `data-frameport-vh`\n * - `data-frameport-vw`\n *\n * @example\n * ```html\n * <div\n * data-frameport\n * data-frameport-template=\"#my-template\"\n * data-frameport-vh=\"100\"\n * data-frameport-vw=\"100\"\n * data-frameport-css=\"styles.css\"\n * data-frameport-js=\"script.js\"\n * ></div>\n *\n * <template id=\"my-template\">\n * <h1>Hello, sandbox!</h1>\n * </template>\n * ```\n *\n * @function frameport\n * @returns void\n */\nconst frameport = () => {\n // Remove all generated iframes first\n document\n .querySelectorAll('[data-frameport-iframe]')\n .forEach((iframe) => iframe.remove());\n\n // Find all frameport targets\n const elsToBeTransformedTemplate =\n document.querySelectorAll('[data-frameport]');\n\n elsToBeTransformedTemplate.forEach((targetElement: HTMLElement) => {\n const {\n dataset: {\n frameportTemplate: templateSelector,\n frameportVh: height,\n frameportVw: width,\n frameportCss: css,\n frameportStyle: style,\n frameportCode: code,\n frameportJs: javascript,\n frameportClass: className,\n frameportHeaders: headers,\n frameportViewports: viewports\n }\n } = targetElement;\n\n let html = targetElement.innerHTML;\n let templateElementToUse = targetElement;\n\n if (templateSelector) {\n const templateElement = document.querySelector(templateSelector);\n\n if (templateElement) {\n html = templateElement.innerHTML;\n templateElementToUse = templateElement as HTMLElement;\n }\n }\n\n const options = {\n templateSelector,\n templateElement: templateElementToUse,\n height,\n width,\n html,\n css,\n style,\n code,\n javascript,\n className,\n headers: getHeaders(headers),\n viewports\n };\n\n dom(targetElement, options);\n });\n};\n\nexport default frameport;\n\n// Automatically activate frameport logic\nactivate(frameport);\n"],"names":["getSource","options","style","css","code","javascript","html","headers","window","location","protocol","host","trim","getCSS","getJavaScript","getCode","getStyle","join","getGeneratedPageURL","type","blob","Blob","URL","createObjectURL","getBlobURL","add","async","el","styles","Array","isArray","length","Object","keys","constructor","Promise","requestAnimationFrame","forEach","key","value","create","className","height","width","url","iframeElement","document","createElement","iframeStyle","src","setAttribute","classList","addStyles","HIDE_TEMPLATE_STYLE","clip","margin","overflow","position","DEFAULT_HEADERS","dom","targetElement","viewports","templateElement","target","screens","includes","split","push","viewPort","values","insertAdjacentElement","generateViewports","append","generate","getHeaders","rdeHeaders","map","h","domReady","frameport","readyState","addEventListener","lazy","frameportObserverTarget","IntersectionObserver","els","observer","intersectionRatio","dataset","frameportTemplate","templateSelector","frameportVh","frameportVw","frameportCss","frameportStyle","frameportCode","frameportJs","frameportClass","frameportHeaders","frameportViewports","innerHTML","templateElementToUse","querySelector","unobserve","querySelectorAll","observe","manual","activate","script","currentScript","frameportScriptSrc","getAttribute","hasAttribute","modes","iframe","remove"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@phun-ky/frameport",
3
- "version": "2.0.20",
4
- "description": "Create responsive documentation examples on the fly",
3
+ "version": "2.0.22",
4
+ "description": "A zero dependency package to effortlessly create responsive component previews in documentation using real media queries. Frameport dynamically generates iframes containing your HTML/CSS/JS, mimicking natural device viewports to test responsiveness, without any build steps or dependencies.",
5
5
  "keywords": [
6
6
  "documentation",
7
7
  "style guide",
@@ -18,7 +18,25 @@
18
18
  "iframes",
19
19
  "iframe",
20
20
  "component",
21
- "frameport"
21
+ "frameport",
22
+ "component documentation",
23
+ "responsive design",
24
+ "responsive preview",
25
+ "breakpoints",
26
+ "screen sizes",
27
+ "live preview",
28
+ "component demo",
29
+ "web components",
30
+ "zero dependency",
31
+ "sandbox",
32
+ "playground",
33
+ "visual testing",
34
+ "devtools",
35
+ "framework agnostic",
36
+ "embed",
37
+ "browser preview",
38
+ "UI preview",
39
+ "storybook alternative"
22
40
  ],
23
41
  "homepage": "https://github.com/phun-ky/frameport#readme",
24
42
  "bugs": {