chore: format code
This commit is contained in:
parent
ae2df5096d
commit
833e835f65
51 changed files with 3547 additions and 1684 deletions
6
.github/workflows/eslint.yml
vendored
6
.github/workflows/eslint.yml
vendored
|
@ -2,12 +2,12 @@ name: ESLint
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: ["main"]
|
branches: ['main']
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: ["main"]
|
branches: ['main']
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "36 3 * * 2"
|
- cron: '36 3 * * 2'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
eslint:
|
eslint:
|
||||||
|
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"js/ts.implicitProjectConfig.checkJs": true,
|
"js/ts.implicitProjectConfig.checkJs": true,
|
||||||
"editor.formatOnSave": true
|
"editor.formatOnSave": true
|
||||||
}
|
}
|
||||||
|
|
182
README.md
182
README.md
|
@ -14,36 +14,39 @@ When you extend the `WebComponent` class for your component, you only have to de
|
||||||
The result is a reactive UI on property changes.
|
The result is a reactive UI on property changes.
|
||||||
|
|
||||||
Links:
|
Links:
|
||||||
|
|
||||||
- [Read a blog explaining the reactivity](https://ayos.blog/reactive-custom-elements-with-html-dataset/)
|
- [Read a blog explaining the reactivity](https://ayos.blog/reactive-custom-elements-with-html-dataset/)
|
||||||
- [View demo on CodePen](https://codepen.io/ayoayco-the-styleful/pen/ZEwoNOz?editors=1010)
|
- [View demo on CodePen](https://codepen.io/ayoayco-the-styleful/pen/ZEwoNOz?editors=1010)
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
1. [Project Status](#project-status)
|
1. [Project Status](#project-status)
|
||||||
1. [Installation](#installation)
|
1. [Installation](#installation)
|
||||||
1. [Import via CDN](#import-via-cdn)
|
1. [Import via CDN](#import-via-cdn)
|
||||||
1. [Installation via npm](#installation-via-npm)
|
1. [Installation via npm](#installation-via-npm)
|
||||||
1. [Exports](#exports)
|
1. [Exports](#exports)
|
||||||
1. [Main Exports](#main-exports)
|
1. [Main Exports](#main-exports)
|
||||||
1. [Utilities](#utilities)
|
1. [Utilities](#utilities)
|
||||||
1. [Usage](#usage)
|
1. [Usage](#usage)
|
||||||
1. [Examples](#Examples)
|
1. [Examples](#Examples)
|
||||||
1. [To-Do App](#1-to-do-app)
|
1. [To-Do App](#1-to-do-app)
|
||||||
1. [Single HTML file](#2-single-html-file-example)
|
1. [Single HTML file](#2-single-html-file-example)
|
||||||
1. [Feature Demos](#3-feature-demos)
|
1. [Feature Demos](#3-feature-demos)
|
||||||
1. [`template` vs `render()`](#template-vs-render)
|
1. [`template` vs `render()`](#template-vs-render)
|
||||||
1. [Prop access](#prop-access)
|
1. [Prop access](#prop-access)
|
||||||
1. [Alternatives](#alternatives)
|
1. [Alternatives](#alternatives)
|
||||||
1. [Styling](#styling)
|
1. [Styling](#styling)
|
||||||
1. [Shadow DOM Opt-In](#shadow-dom-opt-in)
|
1. [Shadow DOM Opt-In](#shadow-dom-opt-in)
|
||||||
1. [Just the Templating](#just-the-templating)
|
1. [Just the Templating](#just-the-templating)
|
||||||
1. [Life-Cycle Hooks](#life-cycle-hooks)
|
1. [Life-Cycle Hooks](#life-cycle-hooks)
|
||||||
1. [`onInit`](#oninit) - the component is connected to the DOM, before view is initialized
|
1. [`onInit`](#oninit) - the component is connected to the DOM, before view is initialized
|
||||||
1. [`afterViewInit`](#afterviewinit) - after the view is first initialized
|
1. [`afterViewInit`](#afterviewinit) - after the view is first initialized
|
||||||
1. [`onDestroy`](#ondestroy) - the component is disconnected from the DOM
|
1. [`onDestroy`](#ondestroy) - the component is disconnected from the DOM
|
||||||
1. [`onChanges`](#onchanges) - every time an attribute value changes
|
1. [`onChanges`](#onchanges) - every time an attribute value changes
|
||||||
1. [Library Size](#library-size)
|
1. [Library Size](#library-size)
|
||||||
|
|
||||||
## Project Status
|
## Project Status
|
||||||
|
|
||||||
It is ready for many cases we see people use custom elements for. If you have a cool project built on **WebComponent.io** we'd love to know! :)
|
It is ready for many cases we see people use custom elements for. If you have a cool project built on **WebComponent.io** we'd love to know! :)
|
||||||
|
|
||||||
For building some advanced interactions, we have a few issues that are still open: [#24 smart diffing](https://github.com/ayoayco/web-component-base/issues/24) & [#4 attachEffect improvements](https://github.com/ayoayco/web-component-base/issues/4)
|
For building some advanced interactions, we have a few issues that are still open: [#24 smart diffing](https://github.com/ayoayco/web-component-base/issues/24) & [#4 attachEffect improvements](https://github.com/ayoayco/web-component-base/issues/4)
|
||||||
|
@ -53,6 +56,7 @@ In the mean time, if you have some complex needs, we recommend using the `WebCom
|
||||||
...or you can even [use just parts](#just-the-templating) of it for your own base class.
|
...or you can even [use just parts](#just-the-templating) of it for your own base class.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
The library is distributed as complete ECMAScript Modules (ESM) and published on [NPM](https://ayco.io/n/web-component-base). Please file an issue in our [issue tracker](https://ayco.io/gh/web-component-base/issues) for problems or requests regarding our distribution.
|
The library is distributed as complete ECMAScript Modules (ESM) and published on [NPM](https://ayco.io/n/web-component-base). Please file an issue in our [issue tracker](https://ayco.io/gh/web-component-base/issues) for problems or requests regarding our distribution.
|
||||||
|
|
||||||
### Import via CDN
|
### Import via CDN
|
||||||
|
@ -62,10 +66,11 @@ It is possible to import directly using a CDN like [esm.sh](https://esm.sh/web-c
|
||||||
Additionally, we use `@latest` in the rest of our [usage examples](#usage) here for simplicity, but take note that this incurs additional resolution steps for CDNs to find the actual latest published version. You may replace the `@latest` in the URL with specific versions as shown in our CodePen examples, and this will typically be better for performance.
|
Additionally, we use `@latest` in the rest of our [usage examples](#usage) here for simplicity, but take note that this incurs additional resolution steps for CDNs to find the actual latest published version. You may replace the `@latest` in the URL with specific versions as shown in our CodePen examples, and this will typically be better for performance.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { WebComponent } from "https://unpkg.com/web-component-base@latest/index.js"
|
import { WebComponent } from 'https://unpkg.com/web-component-base@latest/index.js'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Installation via npm
|
### Installation via npm
|
||||||
|
|
||||||
Usable for projects with bundlers or using import maps pointing to the specific files downloaded in `node_modules/web-component-base`.
|
Usable for projects with bundlers or using import maps pointing to the specific files downloaded in `node_modules/web-component-base`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
@ -81,31 +86,37 @@ You can import everything separately, or in a single file each for the main expo
|
||||||
```js
|
```js
|
||||||
// all in a single file
|
// all in a single file
|
||||||
|
|
||||||
import { WebComponent, html, attachEffect } from "web-component-base";
|
import { WebComponent, html, attachEffect } from 'web-component-base'
|
||||||
|
|
||||||
// in separate files
|
// in separate files
|
||||||
|
|
||||||
import { WebComponent } from "web-component-base/WebComponent.js";
|
import { WebComponent } from 'web-component-base/WebComponent.js'
|
||||||
|
|
||||||
import { html } from "web-component-base/html.js";
|
import { html } from 'web-component-base/html.js'
|
||||||
|
|
||||||
import { attachEffect } from "web-component-base/attach-effect.js";
|
import { attachEffect } from 'web-component-base/attach-effect.js'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Utilities
|
### Utilities
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// in a single file
|
// in a single file
|
||||||
|
|
||||||
import { serialize, deserialize, getCamelCase, getKebabCase, createElement } from "web-component-base/utils";
|
import {
|
||||||
|
serialize,
|
||||||
|
deserialize,
|
||||||
|
getCamelCase,
|
||||||
|
getKebabCase,
|
||||||
|
createElement,
|
||||||
|
} from 'web-component-base/utils'
|
||||||
|
|
||||||
// or separate files
|
// or separate files
|
||||||
|
|
||||||
import { serialize } from "web-component-base/utils/serialize.js";
|
import { serialize } from 'web-component-base/utils/serialize.js'
|
||||||
|
|
||||||
import { createElement } from "web-component-base/utils/create-element.js";
|
import { createElement } from 'web-component-base/utils/create-element.js'
|
||||||
|
|
||||||
// etc...
|
// etc...
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
@ -114,21 +125,21 @@ In your component class:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// HelloWorld.mjs
|
// HelloWorld.mjs
|
||||||
import { WebComponent } from "https://unpkg.com/web-component-base@latest/index.js";
|
import { WebComponent } from 'https://unpkg.com/web-component-base@latest/index.js'
|
||||||
|
|
||||||
class HelloWorld extends WebComponent {
|
class HelloWorld extends WebComponent {
|
||||||
static props ={
|
static props = {
|
||||||
myName: 'World',
|
myName: 'World',
|
||||||
emotion: 'sad'
|
emotion: 'sad',
|
||||||
}
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return `
|
return `
|
||||||
<h1>Hello ${this.props.myName}${this.props.emotion === "sad" ? ". 😭" : "! 🙌"}</h1>
|
<h1>Hello ${this.props.myName}${this.props.emotion === 'sad' ? '. 😭' : '! 🙌'}</h1>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('hello-world', HelloWorld);
|
customElements.define('hello-world', HelloWorld)
|
||||||
```
|
```
|
||||||
|
|
||||||
In your HTML page:
|
In your HTML page:
|
||||||
|
@ -163,40 +174,42 @@ A simple app that allows adding / completing tasks:
|
||||||
Here is an example of using a custom element in a single .html file.
|
Here is an example of using a custom element in a single .html file.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>WC Base Test</title>
|
<title>WC Base Test</title>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { WebComponent } from "https://unpkg.com/web-component-base@latest/index.js";
|
import { WebComponent } from 'https://unpkg.com/web-component-base@latest/index.js'
|
||||||
|
|
||||||
class HelloWorld extends WebComponent {
|
class HelloWorld extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
myName: 'World'
|
myName: 'World',
|
||||||
}
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return `<h1>Hello ${this.props.myName}!</h1>`;
|
return `<h1>Hello ${this.props.myName}!</h1>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("hello-world", HelloWorld);
|
customElements.define('hello-world', HelloWorld)
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<hello-world my-name="Ayo"></hello-world>
|
<hello-world my-name="Ayo"></hello-world>
|
||||||
<script>
|
<script>
|
||||||
const helloWorld = document.querySelector('hello-world');
|
const helloWorld = document.querySelector('hello-world')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
helloWorld.props.myName = 'Ayo zzzZzzz';
|
helloWorld.props.myName = 'Ayo zzzZzzz'
|
||||||
}, 2500);
|
}, 2500)
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Feature Demos
|
### 3. Feature Demos
|
||||||
|
|
||||||
Some feature-specific demos:
|
Some feature-specific demos:
|
||||||
1. [Context-Aware Post-Apocalyptic Human](https://codepen.io/ayoayco-the-styleful/pen/WNqJMNG?editors=1010)
|
|
||||||
|
1. [Context-Aware Post-Apocalyptic Human](https://codepen.io/ayoayco-the-styleful/pen/WNqJMNG?editors=1010)
|
||||||
1. [Simple reactive property](https://codepen.io/ayoayco-the-styleful/pen/ZEwoNOz?editors=1010)
|
1. [Simple reactive property](https://codepen.io/ayoayco-the-styleful/pen/ZEwoNOz?editors=1010)
|
||||||
1. [Counter & Toggle](https://codepen.io/ayoayco-the-styleful/pen/PoVegBK?editors=1010)
|
1. [Counter & Toggle](https://codepen.io/ayoayco-the-styleful/pen/PoVegBK?editors=1010)
|
||||||
1. [Using custom templating (lit-html)](https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010)
|
1. [Using custom templating (lit-html)](https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010)
|
||||||
|
@ -209,25 +222,23 @@ Some feature-specific demos:
|
||||||
|
|
||||||
This mental model attempts to reduce the cognitive complexity of authoring components:
|
This mental model attempts to reduce the cognitive complexity of authoring components:
|
||||||
|
|
||||||
1. The `template` is a read-only property (initialized with a `get` keyword) that represents *how* the component view is rendered.
|
1. The `template` is a read-only property (initialized with a `get` keyword) that represents _how_ the component view is rendered.
|
||||||
1. There is a `render()` method that triggers a view render.
|
1. There is a `render()` method that triggers a view render.
|
||||||
1. This `render()` method is *automatically* called under the hood every time an attribute value changed.
|
1. This `render()` method is _automatically_ called under the hood every time an attribute value changed.
|
||||||
1. You can *optionally* call this `render()` method at any point to trigger a render if you need (eg, if you have private unobserved properties that need to manually trigger a render)
|
1. You can _optionally_ call this `render()` method at any point to trigger a render if you need (eg, if you have private unobserved properties that need to manually trigger a render)
|
||||||
1. Overriding the `render()` function for handling a custom `template` is also possible. Here's an example of using `lit-html`: [View on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010)
|
1. Overriding the `render()` function for handling a custom `template` is also possible. Here's an example of using `lit-html`: [View on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010)
|
||||||
|
|
||||||
## Prop Access
|
## Prop Access
|
||||||
|
|
||||||
The `props` property of the `WebComponent` interface is provided for easy read/write access to a camelCase counterpart of *any* observed attribute.
|
The `props` property of the `WebComponent` interface is provided for easy read/write access to a camelCase counterpart of _any_ observed attribute.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
class HelloWorld extends WebComponent {
|
class HelloWorld extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
myProp: 'World'
|
myProp: 'World',
|
||||||
}
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html` <h1>Hello ${this.props.myProp}</h1> `
|
||||||
<h1>Hello ${this.props.myProp}</h1>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -235,11 +246,13 @@ class HelloWorld extends WebComponent {
|
||||||
Assigning a value to the `props.camelCase` counterpart of an observed attribute will trigger an "attribute change" hook.
|
Assigning a value to the `props.camelCase` counterpart of an observed attribute will trigger an "attribute change" hook.
|
||||||
|
|
||||||
For example, assigning a value like so:
|
For example, assigning a value like so:
|
||||||
|
|
||||||
```
|
```
|
||||||
this.props.myName = 'hello'
|
this.props.myName = 'hello'
|
||||||
```
|
```
|
||||||
|
|
||||||
...is like calling the following:
|
...is like calling the following:
|
||||||
|
|
||||||
```
|
```
|
||||||
this.setAttribute('my-name','hello');
|
this.setAttribute('my-name','hello');
|
||||||
```
|
```
|
||||||
|
@ -253,6 +266,7 @@ Therefore, this will tell the browser that the UI needs a render if the attribut
|
||||||
### Alternatives
|
### Alternatives
|
||||||
|
|
||||||
The current alternatives are using what `HTMLElement` provides out-of-the-box, which are:
|
The current alternatives are using what `HTMLElement` provides out-of-the-box, which are:
|
||||||
|
|
||||||
1. `HTMLElement.dataset` for attributes prefixed with `data-*`. Read more about this [on MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset).
|
1. `HTMLElement.dataset` for attributes prefixed with `data-*`. Read more about this [on MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset).
|
||||||
1. Methods for reading/writing attribute values: `setAttribute(...)` and `getAttribute(...)`; note that managing the attribute names as strings can be difficult as the code grows.
|
1. Methods for reading/writing attribute values: `setAttribute(...)` and `getAttribute(...)`; note that managing the attribute names as strings can be difficult as the code grows.
|
||||||
|
|
||||||
|
@ -261,56 +275,58 @@ The current alternatives are using what `HTMLElement` provides out-of-the-box, w
|
||||||
When using the built-in `html` function for tagged templates, a style object of type `Partial<CSSStyleDeclaration>` can be passed to any element's `style` attribute. This allows for calculated and conditional styles. Read more on style objects [on MDN](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration).
|
When using the built-in `html` function for tagged templates, a style object of type `Partial<CSSStyleDeclaration>` can be passed to any element's `style` attribute. This allows for calculated and conditional styles. Read more on style objects [on MDN](https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration).
|
||||||
|
|
||||||
Try it now with this [example on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/bGzXjwQ?editors=1010)
|
Try it now with this [example on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/bGzXjwQ?editors=1010)
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { WebComponent } from "https://unpkg.com/web-component-base@latest/index.js";
|
import { WebComponent } from 'https://unpkg.com/web-component-base@latest/index.js'
|
||||||
|
|
||||||
class StyledElements extends WebComponent {
|
class StyledElements extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
emphasize: false,
|
emphasize: false,
|
||||||
type: "warn",
|
type: 'warn',
|
||||||
};
|
}
|
||||||
|
|
||||||
#typeStyles = {
|
#typeStyles = {
|
||||||
warn: {
|
warn: {
|
||||||
backgroundColor: "yellow",
|
backgroundColor: 'yellow',
|
||||||
border: "1px solid orange",
|
border: '1px solid orange',
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
backgroundColor: "orange",
|
backgroundColor: 'orange',
|
||||||
border: "1px solid red",
|
border: '1px solid red',
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
style=${{
|
style=${{
|
||||||
...this.#typeStyles[this.props.type],
|
...this.#typeStyles[this.props.type],
|
||||||
padding: "1em",
|
padding: '1em',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p style=${{ fontStyle: this.props.emphasize && "italic" }}>Wow!</p>
|
<p style=${{ fontStyle: this.props.emphasize && 'italic' }}>Wow!</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("styled-elements", StyledElements);
|
customElements.define('styled-elements', StyledElements)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Shadow DOM Opt-In
|
## Shadow DOM Opt-In
|
||||||
|
|
||||||
Add a static property `shadowRootInit` with object value of type `ShadowRootInit` (see [options on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#options)) to opt-in to using shadow dom for the whole component.
|
Add a static property `shadowRootInit` with object value of type `ShadowRootInit` (see [options on MDN](https://developer.mozilla.org/en-US/docs/Web/API/Element/attachShadow#options)) to opt-in to using shadow dom for the whole component.
|
||||||
|
|
||||||
Try it now [on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/VwRYVPv?editors=1010)
|
Try it now [on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/VwRYVPv?editors=1010)
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
static shadowRootInit = {
|
static shadowRootInit = {
|
||||||
mode: "closed",
|
mode: "closed",
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Just the Templating
|
## Just the Templating
|
||||||
|
|
||||||
You don't have to extend the whole base class just to use some features. All internals are exposed and usable separately so you can practically build the behavior on your own classes.
|
You don't have to extend the whole base class just to use some features. All internals are exposed and usable separately so you can practically build the behavior on your own classes.
|
||||||
|
@ -318,110 +334,112 @@ You don't have to extend the whole base class just to use some features. All int
|
||||||
Here's an example of using the `html` tag template on a class that extends from vanilla `HTMLElement`... also [View on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/bGzJQJg?editors=1010).
|
Here's an example of using the `html` tag template on a class that extends from vanilla `HTMLElement`... also [View on CodePen ↗](https://codepen.io/ayoayco-the-styleful/pen/bGzJQJg?editors=1010).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import {html} from 'https://unpkg.com/web-component-base/html'
|
import { html } from 'https://unpkg.com/web-component-base/html'
|
||||||
import {createElement} from 'https://unpkg.com/web-component-base/utils'
|
import { createElement } from 'https://unpkg.com/web-component-base/utils'
|
||||||
|
|
||||||
class MyQuote extends HTMLElement {
|
class MyQuote extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
const el = createElement(html`
|
const el = createElement(
|
||||||
<button onClick=${() => alert('hey')}>
|
html` <button onClick=${() => alert('hey')}>hey</button>`
|
||||||
hey
|
)
|
||||||
</button>`);
|
|
||||||
this.appendChild(el)
|
this.appendChild(el)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('my-quote', MyQuote)
|
customElements.define('my-quote', MyQuote)
|
||||||
```
|
```
|
||||||
|
|
||||||
## Life-Cycle Hooks
|
## Life-Cycle Hooks
|
||||||
|
|
||||||
Define behavior when certain events in the component's life cycle is triggered by providing hook methods
|
Define behavior when certain events in the component's life cycle is triggered by providing hook methods
|
||||||
|
|
||||||
### onInit()
|
### onInit()
|
||||||
|
|
||||||
- Triggered when the component is connected to the DOM
|
- Triggered when the component is connected to the DOM
|
||||||
- Best for setting up the component
|
- Best for setting up the component
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { WebComponent } from "https://unpkg.com/web-component-base@latest/index.js";
|
import { WebComponent } from 'https://unpkg.com/web-component-base@latest/index.js'
|
||||||
|
|
||||||
class ClickableText extends WebComponent {
|
class ClickableText extends WebComponent {
|
||||||
// gets called when the component is used in an HTML document
|
// gets called when the component is used in an HTML document
|
||||||
onInit() {
|
onInit() {
|
||||||
this.onclick = () => console.log(">>> click!");
|
this.onclick = () => console.log('>>> click!')
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return `<span style="cursor:pointer">Click me!</span>`;
|
return `<span style="cursor:pointer">Click me!</span>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### afterViewInit()
|
### afterViewInit()
|
||||||
- Triggered after the view is first initialized
|
|
||||||
|
|
||||||
|
- Triggered after the view is first initialized
|
||||||
|
|
||||||
```js
|
```js
|
||||||
class ClickableText extends WebComponent {
|
class ClickableText extends WebComponent {
|
||||||
// gets called when the component's innerHTML is first filled
|
// gets called when the component's innerHTML is first filled
|
||||||
afterViewInit() {
|
afterViewInit() {
|
||||||
const footer = this.querySelector('footer');
|
const footer = this.querySelector('footer')
|
||||||
// do stuff to footer after view is initialized
|
// do stuff to footer after view is initialized
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return `<footer>Awesome site © 2023</footer>`;
|
return `<footer>Awesome site © 2023</footer>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### onDestroy()
|
### onDestroy()
|
||||||
|
|
||||||
- Triggered when the component is disconnected from the DOM
|
- Triggered when the component is disconnected from the DOM
|
||||||
- best for undoing any setup done in `onInit()`
|
- best for undoing any setup done in `onInit()`
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { WebComponent } from "https://unpkg.com/web-component-base@latest/index.js";
|
import { WebComponent } from 'https://unpkg.com/web-component-base@latest/index.js'
|
||||||
|
|
||||||
class ClickableText extends WebComponent {
|
class ClickableText extends WebComponent {
|
||||||
|
|
||||||
clickCallback() {
|
clickCallback() {
|
||||||
console.log(">>> click!");
|
console.log('>>> click!')
|
||||||
}
|
}
|
||||||
|
|
||||||
onInit() {
|
onInit() {
|
||||||
this.onclick = this.clickCallback;
|
this.onclick = this.clickCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
console.log(">>> removing event listener");
|
console.log('>>> removing event listener')
|
||||||
this.removeEventListener("click", this.clickCallback);
|
this.removeEventListener('click', this.clickCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return `<span style="cursor:pointer">Click me!</span>`;
|
return `<span style="cursor:pointer">Click me!</span>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### onChanges()
|
### onChanges()
|
||||||
|
|
||||||
- Triggered when an attribute value changed
|
- Triggered when an attribute value changed
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import { WebComponent } from "https://unpkg.com/web-component-base@latest/index.js";
|
import { WebComponent } from 'https://unpkg.com/web-component-base@latest/index.js'
|
||||||
|
|
||||||
class ClickableText extends WebComponent {
|
class ClickableText extends WebComponent {
|
||||||
// gets called when an attribute value changes
|
// gets called when an attribute value changes
|
||||||
onChanges(changes) {
|
onChanges(changes) {
|
||||||
const {property, previousValue, currentValue} = changes;
|
const { property, previousValue, currentValue } = changes
|
||||||
console.log('>>> ', {property, previousValue, currentValue})
|
console.log('>>> ', { property, previousValue, currentValue })
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return `<span style="cursor:pointer">Click me!</span>`;
|
return `<span style="cursor:pointer">Click me!</span>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Library Size
|
## Library Size
|
||||||
|
|
||||||
All the functions and the base class in the library are minimalist by design and only contains what is needed for their purpose.
|
All the functions and the base class in the library are minimalist by design and only contains what is needed for their purpose.
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import globals from "globals";
|
import globals from 'globals'
|
||||||
import pluginJs from "@eslint/js";
|
import pluginJs from '@eslint/js'
|
||||||
|
|
||||||
/** @type {import('eslint').Linter.Config[]} */
|
/** @type {import('eslint').Linter.Config[]} */
|
||||||
export default [
|
export default [
|
||||||
|
@ -7,10 +7,10 @@ export default [
|
||||||
pluginJs.configs.recommended,
|
pluginJs.configs.recommended,
|
||||||
{
|
{
|
||||||
rules: {
|
rules: {
|
||||||
"no-unused-vars": "warn",
|
'no-unused-vars': 'warn',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ignores: ["site/*"],
|
ignores: ['site/*'],
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
|
@ -1,21 +1,23 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { WebComponent, attachEffect, html } from "../../src/index.js";
|
import { WebComponent, attachEffect, html } from '../../src/index.js'
|
||||||
export class Counter extends WebComponent {
|
export class Counter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 0,
|
count: 0,
|
||||||
};
|
}
|
||||||
|
|
||||||
onInit() {
|
onInit() {
|
||||||
attachEffect(this.props.count, (count) => console.log(count));
|
attachEffect(this.props.count, (count) => console.log(count))
|
||||||
}
|
}
|
||||||
|
|
||||||
afterViewInit() {
|
afterViewInit() {
|
||||||
attachEffect(this.props.count, (count) => console.log(count + 100));
|
attachEffect(this.props.count, (count) => console.log(count + 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`<button onclick=${() => ++this.props.count} id="btn">${this.props.count}</button>`;
|
return html`<button onclick=${() => ++this.props.count} id="btn">
|
||||||
|
${this.props.count}
|
||||||
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-counter", Counter);
|
customElements.define('my-counter', Counter)
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { WebComponent, attachEffect, html } from "../../src/index.js";
|
import { WebComponent, attachEffect, html } from '../../src/index.js'
|
||||||
|
|
||||||
export class Decrease extends WebComponent {
|
export class Decrease extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 999,
|
count: 999,
|
||||||
};
|
}
|
||||||
|
|
||||||
onInit() {
|
onInit() {
|
||||||
attachEffect(this.props.count, (count) => console.log(count));
|
attachEffect(this.props.count, (count) => console.log(count))
|
||||||
}
|
}
|
||||||
|
|
||||||
afterViewInit() {
|
afterViewInit() {
|
||||||
attachEffect(this.props.count, (count) => console.log(count + 100));
|
attachEffect(this.props.count, (count) => console.log(count + 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`<button onclick=${() => --this.props.count} id="btn">${this.props.count}</button>`;
|
return html`<button onclick=${() => --this.props.count} id="btn">
|
||||||
|
${this.props.count}
|
||||||
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-decrement", Decrease);
|
customElements.define('my-decrement', Decrease)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
export class BooleanPropTest extends WebComponent {
|
export class BooleanPropTest extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
isInline: false,
|
isInline: false,
|
||||||
anotherone: false,
|
anotherone: false,
|
||||||
};
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html`
|
||||||
<p>is-inline: ${this.props.isInline}</p><p>another-one: ${this.props.anotherone}</p>
|
<p>is-inline: ${this.props.isInline}</p>
|
||||||
`;
|
<p>another-one: ${this.props.anotherone}</p>
|
||||||
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("boolean-prop-test", BooleanPropTest);
|
customElements.define('boolean-prop-test', BooleanPropTest)
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { WebComponent, html } from "../../src/index.js";
|
import { WebComponent, html } from '../../src/index.js'
|
||||||
|
|
||||||
export class Counter extends WebComponent {
|
export class Counter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 0,
|
count: 0,
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html`
|
||||||
<button onClick=${() => ++this.props.count} id="btn">
|
<button onClick=${() => ++this.props.count} id="btn">
|
||||||
${this.props.count}
|
${this.props.count}
|
||||||
</button>
|
</button>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-counter", Counter);
|
customElements.define('my-counter', Counter)
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
export class HelloWorld extends WebComponent {
|
export class HelloWorld extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 0,
|
count: 0,
|
||||||
emotion: "sad",
|
emotion: 'sad',
|
||||||
};
|
}
|
||||||
|
|
||||||
onInit() {
|
onInit() {
|
||||||
this.props.count = 0;
|
this.props.count = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
const label = this.props.count ? `Clicked ${this.props.count}` : "World";
|
const label = this.props.count ? `Clicked ${this.props.count}` : 'World'
|
||||||
const emote = this.props.emotion === "sad" ? ". 😭" : "! 🙌";
|
const emote = this.props.emotion === 'sad' ? '. 😭' : '! 🙌'
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<button onclick=${() => ++this.props.count}>Hello ${label}${emote}</button>
|
<button onclick=${() => ++this.props.count}>
|
||||||
|
Hello ${label}${emote}
|
||||||
|
</button>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("hello-world", HelloWorld);
|
customElements.define('hello-world', HelloWorld)
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
class SimpleText extends WebComponent {
|
class SimpleText extends WebComponent {
|
||||||
clickCallback() {
|
clickCallback() {
|
||||||
console.log(">>> click!");
|
console.log('>>> click!')
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
console.log(">>> removing event listener");
|
console.log('>>> removing event listener')
|
||||||
this.removeEventListener("click", this.clickCallback);
|
this.removeEventListener('click', this.clickCallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`<span onclick=${this.clickCallback} style="cursor:pointer">Click me!</span>`;
|
return html`<span onclick=${this.clickCallback} style="cursor:pointer"
|
||||||
|
>Click me!</span
|
||||||
|
>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("simple-text", SimpleText);
|
customElements.define('simple-text', SimpleText)
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import { WebComponent, html } from "../../src/index.js";
|
import { WebComponent, html } from '../../src/index.js'
|
||||||
|
|
||||||
class Toggle extends WebComponent {
|
class Toggle extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
toggle: false,
|
toggle: false,
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html`
|
||||||
<button onClick=${() => (this.props.toggle = !this.props.toggle)}>
|
<button onClick=${() => (this.props.toggle = !this.props.toggle)}>
|
||||||
${this.props.toggle}
|
${this.props.toggle}
|
||||||
</button>
|
</button>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-toggle", Toggle);
|
customElements.define('my-toggle', Toggle)
|
||||||
|
|
|
@ -24,10 +24,10 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
const helloWorld = document.querySelector("hello-world");
|
const helloWorld = document.querySelector('hello-world')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
helloWorld.props.emotion = "excited";
|
helloWorld.props.emotion = 'excited'
|
||||||
}, 2500);
|
}, 2500)
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -13,33 +13,35 @@
|
||||||
import {
|
import {
|
||||||
WebComponent,
|
WebComponent,
|
||||||
html,
|
html,
|
||||||
} from "https://esm.sh/web-component-base@latest";
|
} from 'https://esm.sh/web-component-base@latest'
|
||||||
|
|
||||||
export class Counter extends WebComponent {
|
export class Counter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 0,
|
count: 0,
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`<button onClick=${() => ++this.props.count}>
|
return html`<button onClick=${() => ++this.props.count}>
|
||||||
${this.props.count}
|
${this.props.count}
|
||||||
</button>`;
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Toggle extends WebComponent {
|
class Toggle extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
toggle: false,
|
toggle: false,
|
||||||
};
|
}
|
||||||
|
|
||||||
clickFn = () => (this.props.toggle = !this.props.toggle);
|
clickFn = () => (this.props.toggle = !this.props.toggle)
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`<button onclick=${this.clickFn}>${this.props.toggle ? "On" : "Off"}</button>`;
|
return html`<button onclick=${this.clickFn}>
|
||||||
|
${this.props.toggle ? 'On' : 'Off'}
|
||||||
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-counter", Counter);
|
customElements.define('my-counter', Counter)
|
||||||
customElements.define("my-toggle", Toggle);
|
customElements.define('my-toggle', Toggle)
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
export class HelloWorld extends WebComponent {
|
export class HelloWorld extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
myName: "World",
|
myName: 'World',
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`<p>Hello ${this.props.myName}</p>`;
|
return html`<p>Hello ${this.props.myName}</p>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("hello-world", HelloWorld);
|
customElements.define('hello-world', HelloWorld)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
export class Counter extends WebComponent {
|
export class Counter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 123,
|
count: 123,
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`<button onclick=${() => ++this.props.count} id="btn">${this.props.count}</button>`;
|
return html`<button onclick=${() => ++this.props.count} id="btn">
|
||||||
|
${this.props.count}
|
||||||
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-counter", Counter);
|
customElements.define('my-counter', Counter)
|
||||||
|
|
|
@ -1,39 +1,39 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { WebComponent, html } from "../../src/index.js";
|
import { WebComponent, html } from '../../src/index.js'
|
||||||
|
|
||||||
class StyledElements extends WebComponent {
|
class StyledElements extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
condition: false,
|
condition: false,
|
||||||
type: "info",
|
type: 'info',
|
||||||
};
|
}
|
||||||
|
|
||||||
#typeStyles = {
|
#typeStyles = {
|
||||||
info: {
|
info: {
|
||||||
backgroundColor: "blue",
|
backgroundColor: 'blue',
|
||||||
border: "1px solid green",
|
border: '1px solid green',
|
||||||
},
|
},
|
||||||
warn: {
|
warn: {
|
||||||
backgroundColor: "yellow",
|
backgroundColor: 'yellow',
|
||||||
border: "1px solid orange",
|
border: '1px solid orange',
|
||||||
},
|
},
|
||||||
error: {
|
error: {
|
||||||
backgroundColor: "orange",
|
backgroundColor: 'orange',
|
||||||
border: "1px solid red",
|
border: '1px solid red',
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
style=${{
|
style=${{
|
||||||
...this.#typeStyles[this.props.type],
|
...this.#typeStyles[this.props.type],
|
||||||
padding: "1em",
|
padding: '1em',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p style=${{ fontStyle: this.props.condition && "italic" }}>Wow!</p>
|
<p style=${{ fontStyle: this.props.condition && 'italic' }}>Wow!</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("styled-elements", StyledElements);
|
customElements.define('styled-elements', StyledElements)
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { WebComponent, html } from "../../src/index.js";
|
import { WebComponent, html } from '../../src/index.js'
|
||||||
|
|
||||||
export class Counter extends WebComponent {
|
export class Counter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 123,
|
count: 123,
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
const list = ["a", "b", "c", "what"];
|
const list = ['a', 'b', 'c', 'what']
|
||||||
const links = [
|
const links = [
|
||||||
{
|
{
|
||||||
url: "https://ayco.io",
|
url: 'https://ayco.io',
|
||||||
text: "Ayo Ayco",
|
text: 'Ayo Ayco',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: "https://ayco.io/gh/McFly",
|
url: 'https://ayco.io/gh/McFly',
|
||||||
text: "McFly",
|
text: 'McFly',
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<button
|
<button
|
||||||
|
@ -39,11 +39,11 @@ export class Counter extends WebComponent {
|
||||||
<ul>
|
<ul>
|
||||||
${links.map(
|
${links.map(
|
||||||
(link) =>
|
(link) =>
|
||||||
html`<li><a href=${link.url} target="_blank">${link.text}</a></li>`,
|
html`<li><a href=${link.url} target="_blank">${link.text}</a></li>`
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-counter", Counter);
|
customElements.define('my-counter', Counter)
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import { WebComponent } from "../../src/index.js";
|
import { WebComponent } from '../../src/index.js'
|
||||||
import {
|
import {
|
||||||
html,
|
html,
|
||||||
render as lit,
|
render as lit,
|
||||||
} from "https://unpkg.com/lit-html@3.1.0/lit-html.js";
|
} from 'https://unpkg.com/lit-html@3.1.0/lit-html.js'
|
||||||
|
|
||||||
export class LitCounter extends WebComponent {
|
export class LitCounter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 123,
|
count: 123,
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
const list = ["a", "b", "c", "what"];
|
const list = ['a', 'b', 'c', 'what']
|
||||||
const links = [
|
const links = [
|
||||||
{
|
{
|
||||||
url: "https://ayco.io",
|
url: 'https://ayco.io',
|
||||||
text: "Ayo Ayco",
|
text: 'Ayo Ayco',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: "https://ayco.io/gh/McFly",
|
url: 'https://ayco.io/gh/McFly',
|
||||||
text: "McFly",
|
text: 'McFly',
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<button
|
<button
|
||||||
|
@ -42,14 +42,14 @@ export class LitCounter extends WebComponent {
|
||||||
<ul>
|
<ul>
|
||||||
${links.map(
|
${links.map(
|
||||||
(link) =>
|
(link) =>
|
||||||
html`<li><a href=${link.url} target="_blank">${link.text}</a></li>`,
|
html`<li><a href=${link.url} target="_blank">${link.text}</a></li>`
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
lit(this.template, this);
|
lit(this.template, this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("lit-counter", LitCounter);
|
customElements.define('lit-counter', LitCounter)
|
||||||
|
|
|
@ -1,13 +1,15 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
export class Counter extends WebComponent {
|
export class Counter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 1,
|
count: 1,
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`<button onclick=${() => ++this.props.count}>${this.props.count}</button>`;
|
return html`<button onclick=${() => ++this.props.count}>
|
||||||
|
${this.props.count}
|
||||||
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-counter", Counter);
|
customElements.define('my-counter', Counter)
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
export class HelloWorld extends WebComponent {
|
export class HelloWorld extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
name: "a",
|
name: 'a',
|
||||||
};
|
}
|
||||||
addA = () => (this.props.name += "a");
|
addA = () => (this.props.name += 'a')
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
return html`<button onclick=${this.addA}>W${this.props.name}h!</button>`;
|
return html`<button onclick=${this.addA}>W${this.props.name}h!</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-hello-world", HelloWorld);
|
customElements.define('my-hello-world', HelloWorld)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO: rendering currently wipes all children so focus gets removed on fields
|
* TODO: rendering currently wipes all children so focus gets removed on fields
|
||||||
|
@ -6,45 +6,43 @@ import { html, WebComponent } from "../../src/index.js";
|
||||||
export class ObjectText extends WebComponent {
|
export class ObjectText extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
object: {
|
object: {
|
||||||
hello: "worldzz",
|
hello: 'worldzz',
|
||||||
age: 2,
|
age: 2,
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
onChanges() {
|
onChanges() {
|
||||||
console.log(">>> object", this.props.object);
|
console.log('>>> object', this.props.object)
|
||||||
}
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html`
|
||||||
<form>
|
<form>
|
||||||
<label for="greeting-field">Hello</label>
|
<label for="greeting-field">Hello</label>
|
||||||
<textarea
|
<textarea
|
||||||
onkeyup=${
|
onkeyup=${(event) => {
|
||||||
(event) => {
|
this.props.object = {
|
||||||
this.props.object = {
|
...this.props.object,
|
||||||
...this.props.object,
|
hello: event.target.value,
|
||||||
hello: event.target.value,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
id="greeting-field">
|
id="greeting-field"
|
||||||
|
>
|
||||||
${this.props.object.hello}
|
${this.props.object.hello}
|
||||||
</textarea>
|
</textarea
|
||||||
|
>
|
||||||
<label for="age-field">Age</label>
|
<label for="age-field">Age</label>
|
||||||
<input
|
<input
|
||||||
onkeyup=${
|
onkeyup=${(event) => {
|
||||||
(event) => {
|
this.props.object = {
|
||||||
this.props.object = {
|
...this.props.object,
|
||||||
...this.props.object,
|
age: event.target.value,
|
||||||
age: event.target.value,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
id="age-field" value=${this.props.object.age} />
|
id="age-field"
|
||||||
|
value=${this.props.object.age}
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-object", ObjectText);
|
customElements.define('my-object', ObjectText)
|
||||||
|
|
|
@ -1,18 +1,20 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { html, WebComponent } from "../../src/index.js";
|
import { html, WebComponent } from '../../src/index.js'
|
||||||
|
|
||||||
export class Toggle extends WebComponent {
|
export class Toggle extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
toggle: false,
|
toggle: false,
|
||||||
};
|
}
|
||||||
handleToggle() {
|
handleToggle() {
|
||||||
this.props.toggle = !this.props.toggle;
|
this.props.toggle = !this.props.toggle
|
||||||
}
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`
|
return html`
|
||||||
<button onclick=${() => this.handleToggle()} id="toggle">${this.props.toggle ? "On" : "Off"}</button>
|
<button onclick=${() => this.handleToggle()} id="toggle">
|
||||||
`;
|
${this.props.toggle ? 'On' : 'Off'}
|
||||||
|
</button>
|
||||||
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-toggle", Toggle);
|
customElements.define('my-toggle', Toggle)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
@ -10,33 +10,27 @@
|
||||||
<script type="module" src="./Object.mjs"></script>
|
<script type="module" src="./Object.mjs"></script>
|
||||||
<style>
|
<style>
|
||||||
* {
|
* {
|
||||||
font-size: larger
|
font-size: larger;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div>
|
<div>Counter: <my-counter></my-counter></div>
|
||||||
Counter: <my-counter></my-counter>
|
<div>Toggle: <my-toggle></my-toggle></div>
|
||||||
</div>
|
<div>String: <my-hello-world></my-hello-world></div>
|
||||||
<div>
|
|
||||||
Toggle: <my-toggle></my-toggle>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
String: <my-hello-world></my-hello-world>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<my-object></my-object>
|
<my-object></my-object>
|
||||||
<p id="display-panel"></p>
|
<p id="display-panel"></p>
|
||||||
</div>
|
</div>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { attachEffect } from "../../src/index.js";
|
import { attachEffect } from '../../src/index.js'
|
||||||
const myObjectEl = document.querySelector('my-object');
|
const myObjectEl = document.querySelector('my-object')
|
||||||
const objectProp = myObjectEl.props.object;
|
const objectProp = myObjectEl.props.object
|
||||||
const displayPanelEl = document.querySelector('#display-panel');
|
const displayPanelEl = document.querySelector('#display-panel')
|
||||||
displayPanelEl.textContent = JSON.stringify(objectProp);
|
displayPanelEl.textContent = JSON.stringify(objectProp)
|
||||||
attachEffect(objectProp, (object) => {
|
attachEffect(objectProp, (object) => {
|
||||||
displayPanelEl.textContent = JSON.stringify(object);
|
displayPanelEl.textContent = JSON.stringify(object)
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,33 +1,33 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
import { WebComponent, html } from "../../src/index.js";
|
import { WebComponent, html } from '../../src/index.js'
|
||||||
|
|
||||||
export class Counter extends WebComponent {
|
export class Counter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 123,
|
count: 123,
|
||||||
};
|
}
|
||||||
static shadowRootInit = {
|
static shadowRootInit = {
|
||||||
mode: "open",
|
mode: 'open',
|
||||||
};
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
const list = ["a", "b", "c", "what"];
|
const list = ['a', 'b', 'c', 'what']
|
||||||
const links = [
|
const links = [
|
||||||
{
|
{
|
||||||
url: "https://ayco.io",
|
url: 'https://ayco.io',
|
||||||
text: "Ayo Ayco",
|
text: 'Ayo Ayco',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
url: "https://ayco.io/gh/McFly",
|
url: 'https://ayco.io/gh/McFly',
|
||||||
text: "McFly",
|
text: 'McFly',
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<button
|
<button
|
||||||
class="hey"
|
class="hey"
|
||||||
id="btn"
|
id="btn"
|
||||||
onClick=${() => ++this.props.count}
|
onClick=${() => ++this.props.count}
|
||||||
style=${{ backgroundColor: "green", color: "white" }}
|
style=${{ backgroundColor: 'green', color: 'white' }}
|
||||||
about="Elephant"
|
about="Elephant"
|
||||||
data-name="thing"
|
data-name="thing"
|
||||||
aria-name="thingz"
|
aria-name="thingz"
|
||||||
|
@ -48,8 +48,8 @@ export class Counter extends WebComponent {
|
||||||
</li>`
|
</li>`
|
||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("my-counter", Counter);
|
customElements.define('my-counter', Counter)
|
||||||
|
|
3566
pnpm-lock.yaml
3566
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -1,3 +1,3 @@
|
||||||
packages:
|
packages:
|
||||||
# include packages in subfolders (e.g. apps/ and packages/)
|
# include packages in subfolders (e.g. apps/ and packages/)
|
||||||
- "site/**"
|
- 'site/**'
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# McFly Starter Project
|
# McFly Starter Project
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Background
|
## Background
|
||||||
|
|
||||||
This project was generated from the basic template for **McFly** -- a no-framework framework that assists in leveraging the web platform.
|
This project was generated from the basic template for **McFly** -- a no-framework framework that assists in leveraging the web platform.
|
||||||
|
|
||||||

|

|
||||||
|
@ -10,6 +9,7 @@ This project was generated from the basic template for **McFly** -- a no-framewo
|
||||||
It contains example files to get you started using vanilla web technologies in a modern way. See the [Special Directories](#special-directories) section for more information.
|
It contains example files to get you started using vanilla web technologies in a modern way. See the [Special Directories](#special-directories) section for more information.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
The time has come for vanilla Web tech. 🎉
|
The time has come for vanilla Web tech. 🎉
|
||||||
|
|
||||||
✅ Create web apps with vanilla custom elements<br>
|
✅ Create web apps with vanilla custom elements<br>
|
||||||
|
@ -19,17 +19,21 @@ The time has come for vanilla Web tech. 🎉
|
||||||
✅ Deploy anywhere<br>
|
✅ Deploy anywhere<br>
|
||||||
|
|
||||||
## Special directories
|
## Special directories
|
||||||
|
|
||||||
**1. `./src/pages/`**
|
**1. `./src/pages/`**
|
||||||
|
|
||||||
- file-based routing for `.html` files
|
- file-based routing for `.html` files
|
||||||
- directly use custom elements & static fragments (no imports or registry maintenance needed)
|
- directly use custom elements & static fragments (no imports or registry maintenance needed)
|
||||||
- use `<script server:setup>` to define logic that runs on the server, which then gets stripped away
|
- use `<script server:setup>` to define logic that runs on the server, which then gets stripped away
|
||||||
|
|
||||||
**2. `./src/components/`**
|
**2. `./src/components/`**
|
||||||
|
|
||||||
- custom element constructor files (only `.js` files for now)
|
- custom element constructor files (only `.js` files for now)
|
||||||
- all components are automatically registered using their file names; a `hello-world.js` component can be used as `<hello-world>`
|
- all components are automatically registered using their file names; a `hello-world.js` component can be used as `<hello-world>`
|
||||||
- static `.html` fragments; a `my-header.html` fragment can be directly used as `<my-header>`
|
- static `.html` fragments; a `my-header.html` fragment can be directly used as `<my-header>`
|
||||||
|
|
||||||
**3. `./routes/api/`**
|
**3. `./routes/api/`**
|
||||||
|
|
||||||
- file-based routing for REST API endpoints
|
- file-based routing for REST API endpoints
|
||||||
- e.g., `./routes/api/users.ts` can be accessed via `http://<domain>/api/users`
|
- e.g., `./routes/api/users.ts` can be accessed via `http://<domain>/api/users`
|
||||||
- TypeScript or JavaScript welcome!
|
- TypeScript or JavaScript welcome!
|
||||||
|
@ -39,25 +43,25 @@ The time has come for vanilla Web tech. 🎉
|
||||||
To tell McFly you want to use components, pass the mode (only `"js"` for now) to the `components` prop mcfly.config.ts
|
To tell McFly you want to use components, pass the mode (only `"js"` for now) to the `components` prop mcfly.config.ts
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import defineConfig from "./packages/define-config";
|
import defineConfig from './packages/define-config'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
components: "js",
|
components: 'js',
|
||||||
});
|
})
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
The following commands are available to you on this project. Add more, or modify them as needed in your `./package.json` file.
|
The following commands are available to you on this project. Add more, or modify them as needed in your `./package.json` file.
|
||||||
|
|
||||||
| Command | Action |
|
| Command | Action |
|
||||||
| --- | --- |
|
| --------------- | ---------------------------------------------------- |
|
||||||
| npm start | Start the development server |
|
| npm start | Start the development server |
|
||||||
| npm run prepare | Prepare the workspace |
|
| npm run prepare | Prepare the workspace |
|
||||||
| npm run build | Locally generate the app's build files to `./output` |
|
| npm run build | Locally generate the app's build files to `./output` |
|
||||||
| npm run preview | Preview the built app locally |
|
| npm run preview | Preview the built app locally |
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
*Just keep building*<br />
|
|
||||||
*A project by [Ayo Ayco](https://ayco.io)*
|
_Just keep building_<br />
|
||||||
|
_A project by [Ayo Ayco](https://ayco.io)_
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineMcFlyConfig } from "#imports";
|
import { defineMcFlyConfig } from '#imports'
|
||||||
export default defineMcFlyConfig({
|
export default defineMcFlyConfig({
|
||||||
components: "js",
|
components: 'js',
|
||||||
});
|
})
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
export default defineNitroConfig({ extends: "@mcflyjs/config" });
|
export default defineNitroConfig({ extends: '@mcflyjs/config' })
|
||||||
|
|
|
@ -1,3 +1,118 @@
|
||||||
/* PrismJS 1.29.0
|
/* PrismJS 1.29.0
|
||||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||||
code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}
|
code[class*='language-'],
|
||||||
|
pre[class*='language-'] {
|
||||||
|
color: #000;
|
||||||
|
background: 0 0;
|
||||||
|
text-shadow: 0 1px #fff;
|
||||||
|
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
|
||||||
|
font-size: 1em;
|
||||||
|
text-align: left;
|
||||||
|
white-space: pre;
|
||||||
|
word-spacing: normal;
|
||||||
|
word-break: normal;
|
||||||
|
word-wrap: normal;
|
||||||
|
line-height: 1.5;
|
||||||
|
-moz-tab-size: 4;
|
||||||
|
-o-tab-size: 4;
|
||||||
|
tab-size: 4;
|
||||||
|
-webkit-hyphens: none;
|
||||||
|
-moz-hyphens: none;
|
||||||
|
-ms-hyphens: none;
|
||||||
|
hyphens: none;
|
||||||
|
}
|
||||||
|
code[class*='language-'] ::-moz-selection,
|
||||||
|
code[class*='language-']::-moz-selection,
|
||||||
|
pre[class*='language-'] ::-moz-selection,
|
||||||
|
pre[class*='language-']::-moz-selection {
|
||||||
|
text-shadow: none;
|
||||||
|
background: #b3d4fc;
|
||||||
|
}
|
||||||
|
code[class*='language-'] ::selection,
|
||||||
|
code[class*='language-']::selection,
|
||||||
|
pre[class*='language-'] ::selection,
|
||||||
|
pre[class*='language-']::selection {
|
||||||
|
text-shadow: none;
|
||||||
|
background: #b3d4fc;
|
||||||
|
}
|
||||||
|
@media print {
|
||||||
|
code[class*='language-'],
|
||||||
|
pre[class*='language-'] {
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pre[class*='language-'] {
|
||||||
|
padding: 1em;
|
||||||
|
margin: 0.5em 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
:not(pre) > code[class*='language-'],
|
||||||
|
pre[class*='language-'] {
|
||||||
|
background: #f5f2f0;
|
||||||
|
}
|
||||||
|
:not(pre) > code[class*='language-'] {
|
||||||
|
padding: 0.1em;
|
||||||
|
border-radius: 0.3em;
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
.token.cdata,
|
||||||
|
.token.comment,
|
||||||
|
.token.doctype,
|
||||||
|
.token.prolog {
|
||||||
|
color: #708090;
|
||||||
|
}
|
||||||
|
.token.punctuation {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.token.namespace {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
.token.boolean,
|
||||||
|
.token.constant,
|
||||||
|
.token.deleted,
|
||||||
|
.token.number,
|
||||||
|
.token.property,
|
||||||
|
.token.symbol,
|
||||||
|
.token.tag {
|
||||||
|
color: #905;
|
||||||
|
}
|
||||||
|
.token.attr-name,
|
||||||
|
.token.builtin,
|
||||||
|
.token.char,
|
||||||
|
.token.inserted,
|
||||||
|
.token.selector,
|
||||||
|
.token.string {
|
||||||
|
color: #690;
|
||||||
|
}
|
||||||
|
.language-css .token.string,
|
||||||
|
.style .token.string,
|
||||||
|
.token.entity,
|
||||||
|
.token.operator,
|
||||||
|
.token.url {
|
||||||
|
color: #9a6e3a;
|
||||||
|
background: hsla(0, 0%, 100%, 0.5);
|
||||||
|
}
|
||||||
|
.token.atrule,
|
||||||
|
.token.attr-value,
|
||||||
|
.token.keyword {
|
||||||
|
color: #07a;
|
||||||
|
}
|
||||||
|
.token.class-name,
|
||||||
|
.token.function {
|
||||||
|
color: #dd4a68;
|
||||||
|
}
|
||||||
|
.token.important,
|
||||||
|
.token.regex,
|
||||||
|
.token.variable {
|
||||||
|
color: #e90;
|
||||||
|
}
|
||||||
|
.token.bold,
|
||||||
|
.token.important {
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
.token.italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.token.entity {
|
||||||
|
cursor: help;
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/* PrismJS 1.29.0
|
/* PrismJS 1.29.0
|
||||||
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
|
||||||
var _self =
|
var _self =
|
||||||
"undefined" != typeof window
|
'undefined' != typeof window
|
||||||
? window
|
? window
|
||||||
: "undefined" != typeof WorkerGlobalScope &&
|
: 'undefined' != typeof WorkerGlobalScope &&
|
||||||
self instanceof WorkerGlobalScope
|
self instanceof WorkerGlobalScope
|
||||||
? self
|
? self
|
||||||
: {},
|
: {},
|
||||||
|
@ -22,27 +22,27 @@ var _self =
|
||||||
: Array.isArray(n)
|
: Array.isArray(n)
|
||||||
? n.map(e)
|
? n.map(e)
|
||||||
: n
|
: n
|
||||||
.replace(/&/g, "&")
|
.replace(/&/g, '&')
|
||||||
.replace(/</g, "<")
|
.replace(/</g, '<')
|
||||||
.replace(/\u00a0/g, " ");
|
.replace(/\u00a0/g, ' ')
|
||||||
},
|
},
|
||||||
type: function (e) {
|
type: function (e) {
|
||||||
return Object.prototype.toString.call(e).slice(8, -1);
|
return Object.prototype.toString.call(e).slice(8, -1)
|
||||||
},
|
},
|
||||||
objId: function (e) {
|
objId: function (e) {
|
||||||
return (
|
return (
|
||||||
e.__id || Object.defineProperty(e, "__id", { value: ++t }), e.__id
|
e.__id || Object.defineProperty(e, '__id', { value: ++t }), e.__id
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
clone: function e(n, t) {
|
clone: function e(n, t) {
|
||||||
var r, i;
|
var r, i
|
||||||
switch (((t = t || {}), a.util.type(n))) {
|
switch (((t = t || {}), a.util.type(n))) {
|
||||||
case "Object":
|
case 'Object':
|
||||||
if (((i = a.util.objId(n)), t[i])) return t[i];
|
if (((i = a.util.objId(n)), t[i])) return t[i]
|
||||||
for (var l in ((r = {}), (t[i] = r), n))
|
for (var l in ((r = {}), (t[i] = r), n))
|
||||||
n.hasOwnProperty(l) && (r[l] = e(n[l], t));
|
n.hasOwnProperty(l) && (r[l] = e(n[l], t))
|
||||||
return r;
|
return r
|
||||||
case "Array":
|
case 'Array':
|
||||||
return (
|
return (
|
||||||
(i = a.util.objId(n)),
|
(i = a.util.objId(n)),
|
||||||
t[i]
|
t[i]
|
||||||
|
@ -50,49 +50,49 @@ var _self =
|
||||||
: ((r = []),
|
: ((r = []),
|
||||||
(t[i] = r),
|
(t[i] = r),
|
||||||
n.forEach(function (n, a) {
|
n.forEach(function (n, a) {
|
||||||
r[a] = e(n, t);
|
r[a] = e(n, t)
|
||||||
}),
|
}),
|
||||||
r)
|
r)
|
||||||
);
|
)
|
||||||
default:
|
default:
|
||||||
return n;
|
return n
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getLanguage: function (e) {
|
getLanguage: function (e) {
|
||||||
for (; e; ) {
|
for (; e; ) {
|
||||||
var t = n.exec(e.className);
|
var t = n.exec(e.className)
|
||||||
if (t) return t[1].toLowerCase();
|
if (t) return t[1].toLowerCase()
|
||||||
e = e.parentElement;
|
e = e.parentElement
|
||||||
}
|
}
|
||||||
return "none";
|
return 'none'
|
||||||
},
|
},
|
||||||
setLanguage: function (e, t) {
|
setLanguage: function (e, t) {
|
||||||
(e.className = e.className.replace(RegExp(n, "gi"), "")),
|
;(e.className = e.className.replace(RegExp(n, 'gi'), '')),
|
||||||
e.classList.add("language-" + t);
|
e.classList.add('language-' + t)
|
||||||
},
|
},
|
||||||
currentScript: function () {
|
currentScript: function () {
|
||||||
if ("undefined" == typeof document) return null;
|
if ('undefined' == typeof document) return null
|
||||||
if ("currentScript" in document) return document.currentScript;
|
if ('currentScript' in document) return document.currentScript
|
||||||
try {
|
try {
|
||||||
throw new Error();
|
throw new Error()
|
||||||
} catch (r) {
|
} catch (r) {
|
||||||
var e = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(r.stack) ||
|
var e = (/at [^(\r\n]*\((.*):[^:]+:[^:]+\)$/i.exec(r.stack) ||
|
||||||
[])[1];
|
[])[1]
|
||||||
if (e) {
|
if (e) {
|
||||||
var n = document.getElementsByTagName("script");
|
var n = document.getElementsByTagName('script')
|
||||||
for (var t in n) if (n[t].src == e) return n[t];
|
for (var t in n) if (n[t].src == e) return n[t]
|
||||||
}
|
}
|
||||||
return null;
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isActive: function (e, n, t) {
|
isActive: function (e, n, t) {
|
||||||
for (var r = "no-" + n; e; ) {
|
for (var r = 'no-' + n; e; ) {
|
||||||
var a = e.classList;
|
var a = e.classList
|
||||||
if (a.contains(n)) return !0;
|
if (a.contains(n)) return !0
|
||||||
if (a.contains(r)) return !1;
|
if (a.contains(r)) return !1
|
||||||
e = e.parentElement;
|
e = e.parentElement
|
||||||
}
|
}
|
||||||
return !!t;
|
return !!t
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
languages: {
|
languages: {
|
||||||
|
@ -101,45 +101,45 @@ var _self =
|
||||||
text: r,
|
text: r,
|
||||||
txt: r,
|
txt: r,
|
||||||
extend: function (e, n) {
|
extend: function (e, n) {
|
||||||
var t = a.util.clone(a.languages[e]);
|
var t = a.util.clone(a.languages[e])
|
||||||
for (var r in n) t[r] = n[r];
|
for (var r in n) t[r] = n[r]
|
||||||
return t;
|
return t
|
||||||
},
|
},
|
||||||
insertBefore: function (e, n, t, r) {
|
insertBefore: function (e, n, t, r) {
|
||||||
var i = (r = r || a.languages)[e],
|
var i = (r = r || a.languages)[e],
|
||||||
l = {};
|
l = {}
|
||||||
for (var o in i)
|
for (var o in i)
|
||||||
if (i.hasOwnProperty(o)) {
|
if (i.hasOwnProperty(o)) {
|
||||||
if (o == n)
|
if (o == n)
|
||||||
for (var s in t) t.hasOwnProperty(s) && (l[s] = t[s]);
|
for (var s in t) t.hasOwnProperty(s) && (l[s] = t[s])
|
||||||
t.hasOwnProperty(o) || (l[o] = i[o]);
|
t.hasOwnProperty(o) || (l[o] = i[o])
|
||||||
}
|
}
|
||||||
var u = r[e];
|
var u = r[e]
|
||||||
return (
|
return (
|
||||||
(r[e] = l),
|
(r[e] = l),
|
||||||
a.languages.DFS(a.languages, function (n, t) {
|
a.languages.DFS(a.languages, function (n, t) {
|
||||||
t === u && n != e && (this[n] = l);
|
t === u && n != e && (this[n] = l)
|
||||||
}),
|
}),
|
||||||
l
|
l
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
DFS: function e(n, t, r, i) {
|
DFS: function e(n, t, r, i) {
|
||||||
i = i || {};
|
i = i || {}
|
||||||
var l = a.util.objId;
|
var l = a.util.objId
|
||||||
for (var o in n)
|
for (var o in n)
|
||||||
if (n.hasOwnProperty(o)) {
|
if (n.hasOwnProperty(o)) {
|
||||||
t.call(n, o, n[o], r || o);
|
t.call(n, o, n[o], r || o)
|
||||||
var s = n[o],
|
var s = n[o],
|
||||||
u = a.util.type(s);
|
u = a.util.type(s)
|
||||||
"Object" !== u || i[l(s)]
|
'Object' !== u || i[l(s)]
|
||||||
? "Array" !== u || i[l(s)] || ((i[l(s)] = !0), e(s, t, o, i))
|
? 'Array' !== u || i[l(s)] || ((i[l(s)] = !0), e(s, t, o, i))
|
||||||
: ((i[l(s)] = !0), e(s, t, null, i));
|
: ((i[l(s)] = !0), e(s, t, null, i))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: {},
|
plugins: {},
|
||||||
highlightAll: function (e, n) {
|
highlightAll: function (e, n) {
|
||||||
a.highlightAllUnder(document, e, n);
|
a.highlightAllUnder(document, e, n)
|
||||||
},
|
},
|
||||||
highlightAllUnder: function (e, n, t) {
|
highlightAllUnder: function (e, n, t) {
|
||||||
var r = {
|
var r = {
|
||||||
|
@ -147,162 +147,160 @@ var _self =
|
||||||
container: e,
|
container: e,
|
||||||
selector:
|
selector:
|
||||||
'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code',
|
'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code',
|
||||||
};
|
}
|
||||||
a.hooks.run("before-highlightall", r),
|
a.hooks.run('before-highlightall', r),
|
||||||
(r.elements = Array.prototype.slice.apply(
|
(r.elements = Array.prototype.slice.apply(
|
||||||
r.container.querySelectorAll(r.selector),
|
r.container.querySelectorAll(r.selector)
|
||||||
)),
|
)),
|
||||||
a.hooks.run("before-all-elements-highlight", r);
|
a.hooks.run('before-all-elements-highlight', r)
|
||||||
for (var i, l = 0; (i = r.elements[l++]); )
|
for (var i, l = 0; (i = r.elements[l++]); )
|
||||||
a.highlightElement(i, !0 === n, r.callback);
|
a.highlightElement(i, !0 === n, r.callback)
|
||||||
},
|
},
|
||||||
highlightElement: function (n, t, r) {
|
highlightElement: function (n, t, r) {
|
||||||
var i = a.util.getLanguage(n),
|
var i = a.util.getLanguage(n),
|
||||||
l = a.languages[i];
|
l = a.languages[i]
|
||||||
a.util.setLanguage(n, i);
|
a.util.setLanguage(n, i)
|
||||||
var o = n.parentElement;
|
var o = n.parentElement
|
||||||
o && "pre" === o.nodeName.toLowerCase() && a.util.setLanguage(o, i);
|
o && 'pre' === o.nodeName.toLowerCase() && a.util.setLanguage(o, i)
|
||||||
var s = { element: n, language: i, grammar: l, code: n.textContent };
|
var s = { element: n, language: i, grammar: l, code: n.textContent }
|
||||||
function u(e) {
|
function u(e) {
|
||||||
(s.highlightedCode = e),
|
;(s.highlightedCode = e),
|
||||||
a.hooks.run("before-insert", s),
|
a.hooks.run('before-insert', s),
|
||||||
(s.element.innerHTML = s.highlightedCode),
|
(s.element.innerHTML = s.highlightedCode),
|
||||||
a.hooks.run("after-highlight", s),
|
a.hooks.run('after-highlight', s),
|
||||||
a.hooks.run("complete", s),
|
a.hooks.run('complete', s),
|
||||||
r && r.call(s.element);
|
r && r.call(s.element)
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(a.hooks.run("before-sanity-check", s),
|
(a.hooks.run('before-sanity-check', s),
|
||||||
(o = s.element.parentElement) &&
|
(o = s.element.parentElement) &&
|
||||||
"pre" === o.nodeName.toLowerCase() &&
|
'pre' === o.nodeName.toLowerCase() &&
|
||||||
!o.hasAttribute("tabindex") &&
|
!o.hasAttribute('tabindex') &&
|
||||||
o.setAttribute("tabindex", "0"),
|
o.setAttribute('tabindex', '0'),
|
||||||
!s.code)
|
!s.code)
|
||||||
)
|
)
|
||||||
return a.hooks.run("complete", s), void (r && r.call(s.element));
|
return a.hooks.run('complete', s), void (r && r.call(s.element))
|
||||||
if ((a.hooks.run("before-highlight", s), s.grammar))
|
if ((a.hooks.run('before-highlight', s), s.grammar))
|
||||||
if (t && e.Worker) {
|
if (t && e.Worker) {
|
||||||
var c = new Worker(a.filename);
|
var c = new Worker(a.filename)
|
||||||
(c.onmessage = function (e) {
|
;(c.onmessage = function (e) {
|
||||||
u(e.data);
|
u(e.data)
|
||||||
}),
|
}),
|
||||||
c.postMessage(
|
c.postMessage(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
language: s.language,
|
language: s.language,
|
||||||
code: s.code,
|
code: s.code,
|
||||||
immediateClose: !0,
|
immediateClose: !0,
|
||||||
}),
|
})
|
||||||
);
|
)
|
||||||
} else u(a.highlight(s.code, s.grammar, s.language));
|
} else u(a.highlight(s.code, s.grammar, s.language))
|
||||||
else u(a.util.encode(s.code));
|
else u(a.util.encode(s.code))
|
||||||
},
|
},
|
||||||
highlight: function (e, n, t) {
|
highlight: function (e, n, t) {
|
||||||
var r = { code: e, grammar: n, language: t };
|
var r = { code: e, grammar: n, language: t }
|
||||||
if ((a.hooks.run("before-tokenize", r), !r.grammar))
|
if ((a.hooks.run('before-tokenize', r), !r.grammar))
|
||||||
throw new Error(
|
throw new Error('The language "' + r.language + '" has no grammar.')
|
||||||
'The language "' + r.language + '" has no grammar.',
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
(r.tokens = a.tokenize(r.code, r.grammar)),
|
(r.tokens = a.tokenize(r.code, r.grammar)),
|
||||||
a.hooks.run("after-tokenize", r),
|
a.hooks.run('after-tokenize', r),
|
||||||
i.stringify(a.util.encode(r.tokens), r.language)
|
i.stringify(a.util.encode(r.tokens), r.language)
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
tokenize: function (e, n) {
|
tokenize: function (e, n) {
|
||||||
var t = n.rest;
|
var t = n.rest
|
||||||
if (t) {
|
if (t) {
|
||||||
for (var r in t) n[r] = t[r];
|
for (var r in t) n[r] = t[r]
|
||||||
delete n.rest;
|
delete n.rest
|
||||||
}
|
}
|
||||||
var a = new s();
|
var a = new s()
|
||||||
return (
|
return (
|
||||||
u(a, a.head, e),
|
u(a, a.head, e),
|
||||||
o(e, a, n, a.head, 0),
|
o(e, a, n, a.head, 0),
|
||||||
(function (e) {
|
(function (e) {
|
||||||
for (var n = [], t = e.head.next; t !== e.tail; )
|
for (var n = [], t = e.head.next; t !== e.tail; )
|
||||||
n.push(t.value), (t = t.next);
|
n.push(t.value), (t = t.next)
|
||||||
return n;
|
return n
|
||||||
})(a)
|
})(a)
|
||||||
);
|
)
|
||||||
},
|
},
|
||||||
hooks: {
|
hooks: {
|
||||||
all: {},
|
all: {},
|
||||||
add: function (e, n) {
|
add: function (e, n) {
|
||||||
var t = a.hooks.all;
|
var t = a.hooks.all
|
||||||
(t[e] = t[e] || []), t[e].push(n);
|
;(t[e] = t[e] || []), t[e].push(n)
|
||||||
},
|
},
|
||||||
run: function (e, n) {
|
run: function (e, n) {
|
||||||
var t = a.hooks.all[e];
|
var t = a.hooks.all[e]
|
||||||
if (t && t.length) for (var r, i = 0; (r = t[i++]); ) r(n);
|
if (t && t.length) for (var r, i = 0; (r = t[i++]); ) r(n)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Token: i,
|
Token: i,
|
||||||
};
|
}
|
||||||
function i(e, n, t, r) {
|
function i(e, n, t, r) {
|
||||||
(this.type = e),
|
;(this.type = e),
|
||||||
(this.content = n),
|
(this.content = n),
|
||||||
(this.alias = t),
|
(this.alias = t),
|
||||||
(this.length = 0 | (r || "").length);
|
(this.length = 0 | (r || '').length)
|
||||||
}
|
}
|
||||||
function l(e, n, t, r) {
|
function l(e, n, t, r) {
|
||||||
e.lastIndex = n;
|
e.lastIndex = n
|
||||||
var a = e.exec(t);
|
var a = e.exec(t)
|
||||||
if (a && r && a[1]) {
|
if (a && r && a[1]) {
|
||||||
var i = a[1].length;
|
var i = a[1].length
|
||||||
(a.index += i), (a[0] = a[0].slice(i));
|
;(a.index += i), (a[0] = a[0].slice(i))
|
||||||
}
|
}
|
||||||
return a;
|
return a
|
||||||
}
|
}
|
||||||
function o(e, n, t, r, s, g) {
|
function o(e, n, t, r, s, g) {
|
||||||
for (var f in t)
|
for (var f in t)
|
||||||
if (t.hasOwnProperty(f) && t[f]) {
|
if (t.hasOwnProperty(f) && t[f]) {
|
||||||
var h = t[f];
|
var h = t[f]
|
||||||
h = Array.isArray(h) ? h : [h];
|
h = Array.isArray(h) ? h : [h]
|
||||||
for (var d = 0; d < h.length; ++d) {
|
for (var d = 0; d < h.length; ++d) {
|
||||||
if (g && g.cause == f + "," + d) return;
|
if (g && g.cause == f + ',' + d) return
|
||||||
var v = h[d],
|
var v = h[d],
|
||||||
p = v.inside,
|
p = v.inside,
|
||||||
m = !!v.lookbehind,
|
m = !!v.lookbehind,
|
||||||
y = !!v.greedy,
|
y = !!v.greedy,
|
||||||
k = v.alias;
|
k = v.alias
|
||||||
if (y && !v.pattern.global) {
|
if (y && !v.pattern.global) {
|
||||||
var x = v.pattern.toString().match(/[imsuy]*$/)[0];
|
var x = v.pattern.toString().match(/[imsuy]*$/)[0]
|
||||||
v.pattern = RegExp(v.pattern.source, x + "g");
|
v.pattern = RegExp(v.pattern.source, x + 'g')
|
||||||
}
|
}
|
||||||
for (
|
for (
|
||||||
var b = v.pattern || v, w = r.next, A = s;
|
var b = v.pattern || v, w = r.next, A = s;
|
||||||
w !== n.tail && !(g && A >= g.reach);
|
w !== n.tail && !(g && A >= g.reach);
|
||||||
A += w.value.length, w = w.next
|
A += w.value.length, w = w.next
|
||||||
) {
|
) {
|
||||||
var E = w.value;
|
var E = w.value
|
||||||
if (n.length > e.length) return;
|
if (n.length > e.length) return
|
||||||
if (!(E instanceof i)) {
|
if (!(E instanceof i)) {
|
||||||
var P,
|
var P,
|
||||||
L = 1;
|
L = 1
|
||||||
if (y) {
|
if (y) {
|
||||||
if (!(P = l(b, A, e, m)) || P.index >= e.length) break;
|
if (!(P = l(b, A, e, m)) || P.index >= e.length) break
|
||||||
var S = P.index,
|
var S = P.index,
|
||||||
O = P.index + P[0].length,
|
O = P.index + P[0].length,
|
||||||
j = A;
|
j = A
|
||||||
for (j += w.value.length; S >= j; )
|
for (j += w.value.length; S >= j; )
|
||||||
j += (w = w.next).value.length;
|
j += (w = w.next).value.length
|
||||||
if (((A = j -= w.value.length), w.value instanceof i))
|
if (((A = j -= w.value.length), w.value instanceof i))
|
||||||
continue;
|
continue
|
||||||
for (
|
for (
|
||||||
var C = w;
|
var C = w;
|
||||||
C !== n.tail && (j < O || "string" == typeof C.value);
|
C !== n.tail && (j < O || 'string' == typeof C.value);
|
||||||
C = C.next
|
C = C.next
|
||||||
)
|
)
|
||||||
L++, (j += C.value.length);
|
L++, (j += C.value.length)
|
||||||
L--, (E = e.slice(A, j)), (P.index -= A);
|
L--, (E = e.slice(A, j)), (P.index -= A)
|
||||||
} else if (!(P = l(b, 0, E, m))) continue;
|
} else if (!(P = l(b, 0, E, m))) continue
|
||||||
S = P.index;
|
S = P.index
|
||||||
var N = P[0],
|
var N = P[0],
|
||||||
_ = E.slice(0, S),
|
_ = E.slice(0, S),
|
||||||
M = E.slice(S + N.length),
|
M = E.slice(S + N.length),
|
||||||
W = A + E.length;
|
W = A + E.length
|
||||||
g && W > g.reach && (g.reach = W);
|
g && W > g.reach && (g.reach = W)
|
||||||
var z = w.prev;
|
var z = w.prev
|
||||||
if (
|
if (
|
||||||
(_ && ((z = u(n, z, _)), (A += _.length)),
|
(_ && ((z = u(n, z, _)), (A += _.length)),
|
||||||
c(n, z, L),
|
c(n, z, L),
|
||||||
|
@ -310,9 +308,9 @@ var _self =
|
||||||
M && u(n, w, M),
|
M && u(n, w, M),
|
||||||
L > 1)
|
L > 1)
|
||||||
) {
|
) {
|
||||||
var I = { cause: f + "," + d, reach: W };
|
var I = { cause: f + ',' + d, reach: W }
|
||||||
o(e, n, t, w.prev, A, I),
|
o(e, n, t, w.prev, A, I),
|
||||||
g && I.reach > g.reach && (g.reach = I.reach);
|
g && I.reach > g.reach && (g.reach = I.reach)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,107 +319,106 @@ var _self =
|
||||||
}
|
}
|
||||||
function s() {
|
function s() {
|
||||||
var e = { value: null, prev: null, next: null },
|
var e = { value: null, prev: null, next: null },
|
||||||
n = { value: null, prev: e, next: null };
|
n = { value: null, prev: e, next: null }
|
||||||
(e.next = n), (this.head = e), (this.tail = n), (this.length = 0);
|
;(e.next = n), (this.head = e), (this.tail = n), (this.length = 0)
|
||||||
}
|
}
|
||||||
function u(e, n, t) {
|
function u(e, n, t) {
|
||||||
var r = n.next,
|
var r = n.next,
|
||||||
a = { value: t, prev: n, next: r };
|
a = { value: t, prev: n, next: r }
|
||||||
return (n.next = a), (r.prev = a), e.length++, a;
|
return (n.next = a), (r.prev = a), e.length++, a
|
||||||
}
|
}
|
||||||
function c(e, n, t) {
|
function c(e, n, t) {
|
||||||
for (var r = n.next, a = 0; a < t && r !== e.tail; a++) r = r.next;
|
for (var r = n.next, a = 0; a < t && r !== e.tail; a++) r = r.next
|
||||||
(n.next = r), (r.prev = n), (e.length -= a);
|
;(n.next = r), (r.prev = n), (e.length -= a)
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
((e.Prism = a),
|
((e.Prism = a),
|
||||||
(i.stringify = function e(n, t) {
|
(i.stringify = function e(n, t) {
|
||||||
if ("string" == typeof n) return n;
|
if ('string' == typeof n) return n
|
||||||
if (Array.isArray(n)) {
|
if (Array.isArray(n)) {
|
||||||
var r = "";
|
var r = ''
|
||||||
return (
|
return (
|
||||||
n.forEach(function (n) {
|
n.forEach(function (n) {
|
||||||
r += e(n, t);
|
r += e(n, t)
|
||||||
}),
|
}),
|
||||||
r
|
r
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
var i = {
|
var i = {
|
||||||
type: n.type,
|
type: n.type,
|
||||||
content: e(n.content, t),
|
content: e(n.content, t),
|
||||||
tag: "span",
|
tag: 'span',
|
||||||
classes: ["token", n.type],
|
classes: ['token', n.type],
|
||||||
attributes: {},
|
attributes: {},
|
||||||
language: t,
|
language: t,
|
||||||
},
|
},
|
||||||
l = n.alias;
|
l = n.alias
|
||||||
l &&
|
l &&
|
||||||
(Array.isArray(l)
|
(Array.isArray(l)
|
||||||
? Array.prototype.push.apply(i.classes, l)
|
? Array.prototype.push.apply(i.classes, l)
|
||||||
: i.classes.push(l)),
|
: i.classes.push(l)),
|
||||||
a.hooks.run("wrap", i);
|
a.hooks.run('wrap', i)
|
||||||
var o = "";
|
var o = ''
|
||||||
for (var s in i.attributes)
|
for (var s in i.attributes)
|
||||||
o +=
|
o +=
|
||||||
" " +
|
' ' +
|
||||||
s +
|
s +
|
||||||
'="' +
|
'="' +
|
||||||
(i.attributes[s] || "").replace(/"/g, """) +
|
(i.attributes[s] || '').replace(/"/g, '"') +
|
||||||
'"';
|
'"'
|
||||||
return (
|
return (
|
||||||
"<" +
|
'<' +
|
||||||
i.tag +
|
i.tag +
|
||||||
' class="' +
|
' class="' +
|
||||||
i.classes.join(" ") +
|
i.classes.join(' ') +
|
||||||
'"' +
|
'"' +
|
||||||
o +
|
o +
|
||||||
">" +
|
'>' +
|
||||||
i.content +
|
i.content +
|
||||||
"</" +
|
'</' +
|
||||||
i.tag +
|
i.tag +
|
||||||
">"
|
'>'
|
||||||
);
|
)
|
||||||
}),
|
}),
|
||||||
!e.document)
|
!e.document)
|
||||||
)
|
)
|
||||||
return e.addEventListener
|
return e.addEventListener
|
||||||
? (a.disableWorkerMessageHandler ||
|
? (a.disableWorkerMessageHandler ||
|
||||||
e.addEventListener(
|
e.addEventListener(
|
||||||
"message",
|
'message',
|
||||||
function (n) {
|
function (n) {
|
||||||
var t = JSON.parse(n.data),
|
var t = JSON.parse(n.data),
|
||||||
r = t.language,
|
r = t.language,
|
||||||
i = t.code,
|
i = t.code,
|
||||||
l = t.immediateClose;
|
l = t.immediateClose
|
||||||
e.postMessage(a.highlight(i, a.languages[r], r)),
|
e.postMessage(a.highlight(i, a.languages[r], r)), l && e.close()
|
||||||
l && e.close();
|
|
||||||
},
|
},
|
||||||
!1,
|
!1
|
||||||
),
|
),
|
||||||
a)
|
a)
|
||||||
: a;
|
: a
|
||||||
var g = a.util.currentScript();
|
var g = a.util.currentScript()
|
||||||
function f() {
|
function f() {
|
||||||
a.manual || a.highlightAll();
|
a.manual || a.highlightAll()
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(g &&
|
(g &&
|
||||||
((a.filename = g.src),
|
((a.filename = g.src),
|
||||||
g.hasAttribute("data-manual") && (a.manual = !0)),
|
g.hasAttribute('data-manual') && (a.manual = !0)),
|
||||||
!a.manual)
|
!a.manual)
|
||||||
) {
|
) {
|
||||||
var h = document.readyState;
|
var h = document.readyState
|
||||||
"loading" === h || ("interactive" === h && g && g.defer)
|
'loading' === h || ('interactive' === h && g && g.defer)
|
||||||
? document.addEventListener("DOMContentLoaded", f)
|
? document.addEventListener('DOMContentLoaded', f)
|
||||||
: window.requestAnimationFrame
|
: window.requestAnimationFrame
|
||||||
? window.requestAnimationFrame(f)
|
? window.requestAnimationFrame(f)
|
||||||
: window.setTimeout(f, 16);
|
: window.setTimeout(f, 16)
|
||||||
}
|
}
|
||||||
return a;
|
return a
|
||||||
})(_self);
|
})(_self)
|
||||||
"undefined" != typeof module && module.exports && (module.exports = Prism),
|
'undefined' != typeof module && module.exports && (module.exports = Prism),
|
||||||
"undefined" != typeof global && (global.Prism = Prism);
|
'undefined' != typeof global && (global.Prism = Prism)
|
||||||
(Prism.languages.markup = {
|
;(Prism.languages.markup = {
|
||||||
comment: { pattern: /<!--(?:(?!<!--)[\s\S])*?-->/, greedy: !0 },
|
comment: { pattern: /<!--(?:(?!<!--)[\s\S])*?-->/, greedy: !0 },
|
||||||
prolog: { pattern: /<\?[\s\S]+?\?>/, greedy: !0 },
|
prolog: { pattern: /<\?[\s\S]+?\?>/, greedy: !0 },
|
||||||
doctype: {
|
doctype: {
|
||||||
|
@ -429,7 +426,7 @@ var _self =
|
||||||
/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,
|
/<!DOCTYPE(?:[^>"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\]\s*)?>/i,
|
||||||
greedy: !0,
|
greedy: !0,
|
||||||
inside: {
|
inside: {
|
||||||
"internal-subset": {
|
'internal-subset': {
|
||||||
pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/,
|
pattern: /(^[^\[]*\[)[\s\S]+(?=\]>$)/,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
greedy: !0,
|
greedy: !0,
|
||||||
|
@ -437,7 +434,7 @@ var _self =
|
||||||
},
|
},
|
||||||
string: { pattern: /"[^"]*"|'[^']*'/, greedy: !0 },
|
string: { pattern: /"[^"]*"|'[^']*'/, greedy: !0 },
|
||||||
punctuation: /^<!|>$|[[\]]/,
|
punctuation: /^<!|>$|[[\]]/,
|
||||||
"doctype-tag": /^DOCTYPE/i,
|
'doctype-tag': /^DOCTYPE/i,
|
||||||
name: /[^\s<>'"]+/,
|
name: /[^\s<>'"]+/,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -451,120 +448,118 @@ var _self =
|
||||||
pattern: /^<\/?[^\s>\/]+/,
|
pattern: /^<\/?[^\s>\/]+/,
|
||||||
inside: { punctuation: /^<\/?/, namespace: /^[^\s>\/:]+:/ },
|
inside: { punctuation: /^<\/?/, namespace: /^[^\s>\/:]+:/ },
|
||||||
},
|
},
|
||||||
"special-attr": [],
|
'special-attr': [],
|
||||||
"attr-value": {
|
'attr-value': {
|
||||||
pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
|
pattern: /=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,
|
||||||
inside: {
|
inside: {
|
||||||
punctuation: [
|
punctuation: [
|
||||||
{ pattern: /^=/, alias: "attr-equals" },
|
{ pattern: /^=/, alias: 'attr-equals' },
|
||||||
{ pattern: /^(\s*)["']|["']$/, lookbehind: !0 },
|
{ pattern: /^(\s*)["']|["']$/, lookbehind: !0 },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
punctuation: /\/?>/,
|
punctuation: /\/?>/,
|
||||||
"attr-name": {
|
'attr-name': {
|
||||||
pattern: /[^\s>\/]+/,
|
pattern: /[^\s>\/]+/,
|
||||||
inside: { namespace: /^[^\s>\/:]+:/ },
|
inside: { namespace: /^[^\s>\/:]+:/ },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
entity: [
|
entity: [
|
||||||
{ pattern: /&[\da-z]{1,8};/i, alias: "named-entity" },
|
{ pattern: /&[\da-z]{1,8};/i, alias: 'named-entity' },
|
||||||
/&#x?[\da-f]{1,8};/i,
|
/&#x?[\da-f]{1,8};/i,
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
(Prism.languages.markup.tag.inside["attr-value"].inside.entity =
|
(Prism.languages.markup.tag.inside['attr-value'].inside.entity =
|
||||||
Prism.languages.markup.entity),
|
Prism.languages.markup.entity),
|
||||||
(Prism.languages.markup.doctype.inside["internal-subset"].inside =
|
(Prism.languages.markup.doctype.inside['internal-subset'].inside =
|
||||||
Prism.languages.markup),
|
Prism.languages.markup),
|
||||||
Prism.hooks.add("wrap", function (a) {
|
Prism.hooks.add('wrap', function (a) {
|
||||||
"entity" === a.type &&
|
'entity' === a.type &&
|
||||||
(a.attributes.title = a.content.replace(/&/, "&"));
|
(a.attributes.title = a.content.replace(/&/, '&'))
|
||||||
}),
|
}),
|
||||||
Object.defineProperty(Prism.languages.markup.tag, "addInlined", {
|
Object.defineProperty(Prism.languages.markup.tag, 'addInlined', {
|
||||||
value: function (a, e) {
|
value: function (a, e) {
|
||||||
var s = {};
|
var s = {}
|
||||||
(s["language-" + e] = {
|
;(s['language-' + e] = {
|
||||||
pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,
|
pattern: /(^<!\[CDATA\[)[\s\S]+?(?=\]\]>$)/i,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
inside: Prism.languages[e],
|
inside: Prism.languages[e],
|
||||||
}),
|
}),
|
||||||
(s.cdata = /^<!\[CDATA\[|\]\]>$/i);
|
(s.cdata = /^<!\[CDATA\[|\]\]>$/i)
|
||||||
var t = {
|
var t = {
|
||||||
"included-cdata": { pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, inside: s },
|
'included-cdata': { pattern: /<!\[CDATA\[[\s\S]*?\]\]>/i, inside: s },
|
||||||
};
|
}
|
||||||
t["language-" + e] = { pattern: /[\s\S]+/, inside: Prism.languages[e] };
|
t['language-' + e] = { pattern: /[\s\S]+/, inside: Prism.languages[e] }
|
||||||
var n = {};
|
var n = {}
|
||||||
(n[a] = {
|
;(n[a] = {
|
||||||
pattern: RegExp(
|
pattern: RegExp(
|
||||||
"(<__[^>]*>)(?:<!\\[CDATA\\[(?:[^\\]]|\\](?!\\]>))*\\]\\]>|(?!<!\\[CDATA\\[)[^])*?(?=</__>)".replace(
|
'(<__[^>]*>)(?:<!\\[CDATA\\[(?:[^\\]]|\\](?!\\]>))*\\]\\]>|(?!<!\\[CDATA\\[)[^])*?(?=</__>)'.replace(
|
||||||
/__/g,
|
/__/g,
|
||||||
function () {
|
function () {
|
||||||
return a;
|
return a
|
||||||
},
|
}
|
||||||
),
|
),
|
||||||
"i",
|
'i'
|
||||||
),
|
),
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
greedy: !0,
|
greedy: !0,
|
||||||
inside: t,
|
inside: t,
|
||||||
}),
|
}),
|
||||||
Prism.languages.insertBefore("markup", "cdata", n);
|
Prism.languages.insertBefore('markup', 'cdata', n)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Object.defineProperty(Prism.languages.markup.tag, "addAttribute", {
|
Object.defineProperty(Prism.languages.markup.tag, 'addAttribute', {
|
||||||
value: function (a, e) {
|
value: function (a, e) {
|
||||||
Prism.languages.markup.tag.inside["special-attr"].push({
|
Prism.languages.markup.tag.inside['special-attr'].push({
|
||||||
pattern: RegExp(
|
pattern: RegExp(
|
||||||
"(^|[\"'\\s])(?:" +
|
'(^|["\'\\s])(?:' +
|
||||||
a +
|
a +
|
||||||
")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))",
|
')\\s*=\\s*(?:"[^"]*"|\'[^\']*\'|[^\\s\'">=]+(?=[\\s>]))',
|
||||||
"i",
|
'i'
|
||||||
),
|
),
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
inside: {
|
inside: {
|
||||||
"attr-name": /^[^\s=]+/,
|
'attr-name': /^[^\s=]+/,
|
||||||
"attr-value": {
|
'attr-value': {
|
||||||
pattern: /=[\s\S]+/,
|
pattern: /=[\s\S]+/,
|
||||||
inside: {
|
inside: {
|
||||||
value: {
|
value: {
|
||||||
pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
|
pattern: /(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
alias: [e, "language-" + e],
|
alias: [e, 'language-' + e],
|
||||||
inside: Prism.languages[e],
|
inside: Prism.languages[e],
|
||||||
},
|
},
|
||||||
punctuation: [{ pattern: /^=/, alias: "attr-equals" }, /"|'/],
|
punctuation: [{ pattern: /^=/, alias: 'attr-equals' }, /"|'/],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
(Prism.languages.html = Prism.languages.markup),
|
(Prism.languages.html = Prism.languages.markup),
|
||||||
(Prism.languages.mathml = Prism.languages.markup),
|
(Prism.languages.mathml = Prism.languages.markup),
|
||||||
(Prism.languages.svg = Prism.languages.markup),
|
(Prism.languages.svg = Prism.languages.markup),
|
||||||
(Prism.languages.xml = Prism.languages.extend("markup", {})),
|
(Prism.languages.xml = Prism.languages.extend('markup', {})),
|
||||||
(Prism.languages.ssml = Prism.languages.xml),
|
(Prism.languages.ssml = Prism.languages.xml),
|
||||||
(Prism.languages.atom = Prism.languages.xml),
|
(Prism.languages.atom = Prism.languages.xml),
|
||||||
(Prism.languages.rss = Prism.languages.xml);
|
(Prism.languages.rss = Prism.languages.xml)
|
||||||
!(function (s) {
|
!(function (s) {
|
||||||
var e =
|
var e =
|
||||||
/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;
|
/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/
|
||||||
(s.languages.css = {
|
;(s.languages.css = {
|
||||||
comment: /\/\*[\s\S]*?\*\//,
|
comment: /\/\*[\s\S]*?\*\//,
|
||||||
atrule: {
|
atrule: {
|
||||||
pattern: RegExp(
|
pattern: RegExp(
|
||||||
"@[\\w-](?:[^;{\\s\"']|\\s+(?!\\s)|" +
|
'@[\\w-](?:[^;{\\s"\']|\\s+(?!\\s)|' + e.source + ')*?(?:;|(?=\\s*\\{))'
|
||||||
e.source +
|
|
||||||
")*?(?:;|(?=\\s*\\{))",
|
|
||||||
),
|
),
|
||||||
inside: {
|
inside: {
|
||||||
rule: /^@[\w-]+/,
|
rule: /^@[\w-]+/,
|
||||||
"selector-function-argument": {
|
'selector-function-argument': {
|
||||||
pattern:
|
pattern:
|
||||||
/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
|
/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
alias: "selector",
|
alias: 'selector',
|
||||||
},
|
},
|
||||||
keyword: {
|
keyword: {
|
||||||
pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/,
|
pattern: /(^|[^\w-])(?:and|not|only|or)(?![\w-])/,
|
||||||
|
@ -574,21 +569,21 @@ var _self =
|
||||||
},
|
},
|
||||||
url: {
|
url: {
|
||||||
pattern: RegExp(
|
pattern: RegExp(
|
||||||
"\\burl\\((?:" + e.source + "|(?:[^\\\\\r\n()\"']|\\\\[^])*)\\)",
|
'\\burl\\((?:' + e.source + '|(?:[^\\\\\r\n()"\']|\\\\[^])*)\\)',
|
||||||
"i",
|
'i'
|
||||||
),
|
),
|
||||||
greedy: !0,
|
greedy: !0,
|
||||||
inside: {
|
inside: {
|
||||||
function: /^url/i,
|
function: /^url/i,
|
||||||
punctuation: /^\(|\)$/,
|
punctuation: /^\(|\)$/,
|
||||||
string: { pattern: RegExp("^" + e.source + "$"), alias: "url" },
|
string: { pattern: RegExp('^' + e.source + '$'), alias: 'url' },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
selector: {
|
selector: {
|
||||||
pattern: RegExp(
|
pattern: RegExp(
|
||||||
"(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|" +
|
'(^|[{}\\s])[^{}\\s](?:[^{};"\'\\s]|\\s+(?![\\s{])|' +
|
||||||
e.source +
|
e.source +
|
||||||
")*(?=\\s*\\{)",
|
')*(?=\\s*\\{)'
|
||||||
),
|
),
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
},
|
},
|
||||||
|
@ -602,10 +597,10 @@ var _self =
|
||||||
function: { pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, lookbehind: !0 },
|
function: { pattern: /(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i, lookbehind: !0 },
|
||||||
punctuation: /[(){};:,]/,
|
punctuation: /[(){};:,]/,
|
||||||
}),
|
}),
|
||||||
(s.languages.css.atrule.inside.rest = s.languages.css);
|
(s.languages.css.atrule.inside.rest = s.languages.css)
|
||||||
var t = s.languages.markup;
|
var t = s.languages.markup
|
||||||
t && (t.tag.addInlined("style", "css"), t.tag.addAttribute("style", "css"));
|
t && (t.tag.addInlined('style', 'css'), t.tag.addAttribute('style', 'css'))
|
||||||
})(Prism);
|
})(Prism)
|
||||||
Prism.languages.clike = {
|
Prism.languages.clike = {
|
||||||
comment: [
|
comment: [
|
||||||
{ pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, lookbehind: !0, greedy: !0 },
|
{ pattern: /(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/, lookbehind: !0, greedy: !0 },
|
||||||
|
@ -615,7 +610,7 @@ Prism.languages.clike = {
|
||||||
pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
|
pattern: /(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
|
||||||
greedy: !0,
|
greedy: !0,
|
||||||
},
|
},
|
||||||
"class-name": {
|
'class-name': {
|
||||||
pattern:
|
pattern:
|
||||||
/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,
|
/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
|
@ -628,10 +623,10 @@ Prism.languages.clike = {
|
||||||
number: /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
|
number: /\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,
|
||||||
operator: /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
|
operator: /[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,
|
||||||
punctuation: /[{}[\];(),.:]/,
|
punctuation: /[{}[\];(),.:]/,
|
||||||
};
|
}
|
||||||
(Prism.languages.javascript = Prism.languages.extend("clike", {
|
;(Prism.languages.javascript = Prism.languages.extend('clike', {
|
||||||
"class-name": [
|
'class-name': [
|
||||||
Prism.languages.clike["class-name"],
|
Prism.languages.clike['class-name'],
|
||||||
{
|
{
|
||||||
pattern:
|
pattern:
|
||||||
/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,
|
/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,
|
||||||
|
@ -650,37 +645,37 @@ Prism.languages.clike = {
|
||||||
/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
|
/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,
|
||||||
number: {
|
number: {
|
||||||
pattern: RegExp(
|
pattern: RegExp(
|
||||||
"(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])",
|
'(^|[^\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\dA-Fa-f]+(?:_[\\dA-Fa-f]+)*n?|\\d+(?:_\\d+)*n|(?:\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\.\\d+(?:_\\d+)*)(?:[Ee][+-]?\\d+(?:_\\d+)*)?)(?![\\w$])'
|
||||||
),
|
),
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
},
|
},
|
||||||
operator:
|
operator:
|
||||||
/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/,
|
/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/,
|
||||||
})),
|
})),
|
||||||
(Prism.languages.javascript["class-name"][0].pattern =
|
(Prism.languages.javascript['class-name'][0].pattern =
|
||||||
/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/),
|
/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/),
|
||||||
Prism.languages.insertBefore("javascript", "keyword", {
|
Prism.languages.insertBefore('javascript', 'keyword', {
|
||||||
regex: {
|
regex: {
|
||||||
pattern: RegExp(
|
pattern: RegExp(
|
||||||
"((?:^|[^$\\w\\xA0-\\uFFFF.\"'\\])\\s]|\\b(?:return|yield))\\s*)/(?:(?:\\[(?:[^\\]\\\\\r\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|/\\*(?:[^*]|\\*(?!/))*\\*/)*(?:$|[\r\n,.;:})\\]]|//))",
|
'((?:^|[^$\\w\\xA0-\\uFFFF."\'\\])\\s]|\\b(?:return|yield))\\s*)/(?:(?:\\[(?:[^\\]\\\\\r\n]|\\\\.)*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}|(?:\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.|\\[(?:[^[\\]\\\\\r\n]|\\\\.)*\\])*\\])*\\]|\\\\.|[^/\\\\\\[\r\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\s|/\\*(?:[^*]|\\*(?!/))*\\*/)*(?:$|[\r\n,.;:})\\]]|//))'
|
||||||
),
|
),
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
greedy: !0,
|
greedy: !0,
|
||||||
inside: {
|
inside: {
|
||||||
"regex-source": {
|
'regex-source': {
|
||||||
pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/,
|
pattern: /^(\/)[\s\S]+(?=\/[a-z]*$)/,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
alias: "language-regex",
|
alias: 'language-regex',
|
||||||
inside: Prism.languages.regex,
|
inside: Prism.languages.regex,
|
||||||
},
|
},
|
||||||
"regex-delimiter": /^\/|\/$/,
|
'regex-delimiter': /^\/|\/$/,
|
||||||
"regex-flags": /^[a-z]+$/,
|
'regex-flags': /^[a-z]+$/,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"function-variable": {
|
'function-variable': {
|
||||||
pattern:
|
pattern:
|
||||||
/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,
|
/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,
|
||||||
alias: "function",
|
alias: 'function',
|
||||||
},
|
},
|
||||||
parameter: [
|
parameter: [
|
||||||
{
|
{
|
||||||
|
@ -710,22 +705,22 @@ Prism.languages.clike = {
|
||||||
],
|
],
|
||||||
constant: /\b[A-Z](?:[A-Z_]|\dx?)*\b/,
|
constant: /\b[A-Z](?:[A-Z_]|\dx?)*\b/,
|
||||||
}),
|
}),
|
||||||
Prism.languages.insertBefore("javascript", "string", {
|
Prism.languages.insertBefore('javascript', 'string', {
|
||||||
hashbang: { pattern: /^#!.*/, greedy: !0, alias: "comment" },
|
hashbang: { pattern: /^#!.*/, greedy: !0, alias: 'comment' },
|
||||||
"template-string": {
|
'template-string': {
|
||||||
pattern:
|
pattern:
|
||||||
/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,
|
/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,
|
||||||
greedy: !0,
|
greedy: !0,
|
||||||
inside: {
|
inside: {
|
||||||
"template-punctuation": { pattern: /^`|`$/, alias: "string" },
|
'template-punctuation': { pattern: /^`|`$/, alias: 'string' },
|
||||||
interpolation: {
|
interpolation: {
|
||||||
pattern:
|
pattern:
|
||||||
/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,
|
/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
inside: {
|
inside: {
|
||||||
"interpolation-punctuation": {
|
'interpolation-punctuation': {
|
||||||
pattern: /^\$\{|\}$/,
|
pattern: /^\$\{|\}$/,
|
||||||
alias: "punctuation",
|
alias: 'punctuation',
|
||||||
},
|
},
|
||||||
rest: Prism.languages.javascript,
|
rest: Prism.languages.javascript,
|
||||||
},
|
},
|
||||||
|
@ -733,26 +728,26 @@ Prism.languages.clike = {
|
||||||
string: /[\s\S]+/,
|
string: /[\s\S]+/,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"string-property": {
|
'string-property': {
|
||||||
pattern:
|
pattern:
|
||||||
/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,
|
/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
greedy: !0,
|
greedy: !0,
|
||||||
alias: "property",
|
alias: 'property',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Prism.languages.insertBefore("javascript", "operator", {
|
Prism.languages.insertBefore('javascript', 'operator', {
|
||||||
"literal-property": {
|
'literal-property': {
|
||||||
pattern:
|
pattern:
|
||||||
/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,
|
/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,
|
||||||
lookbehind: !0,
|
lookbehind: !0,
|
||||||
alias: "property",
|
alias: 'property',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
Prism.languages.markup &&
|
Prism.languages.markup &&
|
||||||
(Prism.languages.markup.tag.addInlined("script", "javascript"),
|
(Prism.languages.markup.tag.addInlined('script', 'javascript'),
|
||||||
Prism.languages.markup.tag.addAttribute(
|
Prism.languages.markup.tag.addAttribute(
|
||||||
"on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)",
|
'on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)',
|
||||||
"javascript",
|
'javascript'
|
||||||
)),
|
)),
|
||||||
(Prism.languages.js = Prism.languages.javascript);
|
(Prism.languages.js = Prism.languages.javascript)
|
||||||
|
|
|
@ -5,5 +5,5 @@
|
||||||
* ...reusable code are in ./src/components
|
* ...reusable code are in ./src/components
|
||||||
* @see https://ayco.io/gh/McFly#special-directories
|
* @see https://ayco.io/gh/McFly#special-directories
|
||||||
*/
|
*/
|
||||||
import config from "../mcfly.config.mjs";
|
import config from '../mcfly.config.mjs'
|
||||||
export default useMcFlyRoute({ config, storage: useStorage() });
|
export default useMcFlyRoute({ config, storage: useStorage() })
|
||||||
|
|
|
@ -1,41 +1,41 @@
|
||||||
class CodeBlockComponent extends HTMLElement {
|
class CodeBlockComponent extends HTMLElement {
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
const trimmed = this.innerHTML.trim();
|
const trimmed = this.innerHTML.trim()
|
||||||
const lang = this.getAttribute("language");
|
const lang = this.getAttribute('language')
|
||||||
const inline = this.getAttribute("inline") !== null;
|
const inline = this.getAttribute('inline') !== null
|
||||||
|
|
||||||
this.innerHTML = `
|
this.innerHTML = `
|
||||||
<pre><code id="code">${trimmed}</code></pre>
|
<pre><code id="code">${trimmed}</code></pre>
|
||||||
`;
|
`
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {HTMLPreElement}
|
* @type {HTMLPreElement}
|
||||||
*/
|
*/
|
||||||
const pre = this.querySelector("pre");
|
const pre = this.querySelector('pre')
|
||||||
|
|
||||||
if (lang) {
|
if (lang) {
|
||||||
pre.className = `language-${lang}`;
|
pre.className = `language-${lang}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Partial<CSSStyleDeclaration>}
|
* @type {Partial<CSSStyleDeclaration>}
|
||||||
*/
|
*/
|
||||||
const style = {
|
const style = {
|
||||||
background: "#f5f2f0",
|
background: '#f5f2f0',
|
||||||
padding: "1em",
|
padding: '1em',
|
||||||
margin: "1em 0",
|
margin: '1em 0',
|
||||||
fontSize: "large",
|
fontSize: 'large',
|
||||||
overflow: "auto",
|
overflow: 'auto',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
};
|
}
|
||||||
|
|
||||||
if (inline) {
|
if (inline) {
|
||||||
style.display = "inline";
|
style.display = 'inline'
|
||||||
style.padding = "0.25em 0.3em";
|
style.padding = '0.25em 0.3em'
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.keys(style).forEach((rule) => {
|
Object.keys(style).forEach((rule) => {
|
||||||
pre.style[rule] = style[rule];
|
pre.style[rule] = style[rule]
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,44 +1,44 @@
|
||||||
class FeatureSet extends WebComponent {
|
class FeatureSet extends WebComponent {
|
||||||
#features = [
|
#features = [
|
||||||
{
|
{
|
||||||
icon: "️🔄",
|
icon: '️🔄',
|
||||||
title: "Reactive.",
|
title: 'Reactive.',
|
||||||
description:
|
description:
|
||||||
"A robust API for synchronizing your component's UI and properties",
|
"A robust API for synchronizing your component's UI and properties",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "️🤏",
|
icon: '️🤏',
|
||||||
title: "Tiny.",
|
title: 'Tiny.',
|
||||||
description:
|
description:
|
||||||
"~1 kB base class (minified, compressed) with versatile utilities",
|
'~1 kB base class (minified, compressed) with versatile utilities',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "😌",
|
icon: '😌',
|
||||||
title: "Easy.",
|
title: 'Easy.',
|
||||||
description: "Sensible life-cycle hooks that you understand and remember",
|
description: 'Sensible life-cycle hooks that you understand and remember',
|
||||||
url: "",
|
url: '',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "️💡",
|
icon: '️💡',
|
||||||
title: "Familiar.",
|
title: 'Familiar.',
|
||||||
description:
|
description:
|
||||||
"Use the built-in JSX-like syntax or bring your own custom templating",
|
'Use the built-in JSX-like syntax or bring your own custom templating',
|
||||||
url: "https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010",
|
url: 'https://codepen.io/ayoayco-the-styleful/pen/ZEwNJBR?editors=1010',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: "️🛜",
|
icon: '️🛜',
|
||||||
title: "Powerful.",
|
title: 'Powerful.',
|
||||||
description:
|
description:
|
||||||
"Attach 'side effects' that gets triggered on property value changes",
|
"Attach 'side effects' that gets triggered on property value changes",
|
||||||
url: "",
|
url: '',
|
||||||
},
|
},
|
||||||
];
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Array<HTMLArticleElement>}
|
* @type {Array<HTMLArticleElement>}
|
||||||
*/
|
*/
|
||||||
get articleEl() {
|
get articleEl() {
|
||||||
return this.querySelectorAll("article");
|
return this.querySelectorAll('article')
|
||||||
}
|
}
|
||||||
|
|
||||||
afterViewInit() {
|
afterViewInit() {
|
||||||
|
@ -46,29 +46,29 @@ class FeatureSet extends WebComponent {
|
||||||
* @type {Partial<CSSStyleDeclaration>}
|
* @type {Partial<CSSStyleDeclaration>}
|
||||||
*/
|
*/
|
||||||
const articleStyles = {
|
const articleStyles = {
|
||||||
border: "1px solid #ccc",
|
border: '1px solid #ccc',
|
||||||
borderRadius: "5px",
|
borderRadius: '5px',
|
||||||
padding: "30px",
|
padding: '30px',
|
||||||
margin: "0 auto 1em",
|
margin: '0 auto 1em',
|
||||||
boxShadow: "5px 25px 10px -25px rgba(34, 34, 34, 0.15)",
|
boxShadow: '5px 25px 10px -25px rgba(34, 34, 34, 0.15)',
|
||||||
};
|
}
|
||||||
Object.keys(articleStyles).forEach((rule) =>
|
Object.keys(articleStyles).forEach((rule) =>
|
||||||
this.articleEl.forEach((el) => (el.style[rule] = articleStyles[rule])),
|
this.articleEl.forEach((el) => (el.style[rule] = articleStyles[rule]))
|
||||||
);
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {Partial<CSSStyleDeclaration>}
|
* @type {Partial<CSSStyleDeclaration>}
|
||||||
*/
|
*/
|
||||||
const ftrStyles = {
|
const ftrStyles = {
|
||||||
maxWidth: "800px",
|
maxWidth: '800px',
|
||||||
margin: "0 auto",
|
margin: '0 auto',
|
||||||
padding: "30px",
|
padding: '30px',
|
||||||
gap: "1em",
|
gap: '1em',
|
||||||
};
|
}
|
||||||
const featureWrapper = this.querySelector(".feature-wrapper");
|
const featureWrapper = this.querySelector('.feature-wrapper')
|
||||||
Object.keys(ftrStyles).forEach(
|
Object.keys(ftrStyles).forEach(
|
||||||
(rule) => (featureWrapper.style[rule] = ftrStyles[rule]),
|
(rule) => (featureWrapper.style[rule] = ftrStyles[rule])
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
get template() {
|
get template() {
|
||||||
|
@ -84,9 +84,9 @@ class FeatureSet extends WebComponent {
|
||||||
${feature.description}
|
${feature.description}
|
||||||
</p>
|
</p>
|
||||||
</article>
|
</article>
|
||||||
`,
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
class Counter extends WebComponent {
|
class Counter extends WebComponent {
|
||||||
static props = {
|
static props = {
|
||||||
count: 0,
|
count: 0,
|
||||||
};
|
}
|
||||||
get template() {
|
get template() {
|
||||||
return html`<button onClick=${() => ++this.props.count}>
|
return html`<button onClick=${() => ++this.props.count}>
|
||||||
${this.props.count}
|
${this.props.count}
|
||||||
</button>`;
|
</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
--color-fade: #416fff;
|
--color-fade: #416fff;
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
class HelloWorld extends HTMLElement {
|
class HelloWorld extends HTMLElement {
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
return ["my-name"];
|
return ['my-name']
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
let count = 0;
|
let count = 0
|
||||||
const currentName = this.getAttribute("my-name");
|
const currentName = this.getAttribute('my-name')
|
||||||
|
|
||||||
if (!currentName) {
|
if (!currentName) {
|
||||||
this.setAttribute("my-name", "World");
|
this.setAttribute('my-name', 'World')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.onclick = () => this.setAttribute("my-name", `Clicked ${++count}x`);
|
this.onclick = () => this.setAttribute('my-name', `Clicked ${++count}x`)
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(property, previousValue, currentValue) {
|
attributeChangedCallback(property, previousValue, currentValue) {
|
||||||
if (property === "my-name" && previousValue !== currentValue) {
|
if (property === 'my-name' && previousValue !== currentValue) {
|
||||||
this.innerHTML = `<button style="cursor:pointer">Hello ${currentValue}!</button>`;
|
this.innerHTML = `<button style="cursor:pointer">Hello ${currentValue}!</button>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,20 +10,20 @@
|
||||||
<script src="prism.js" defer></script>
|
<script src="prism.js" defer></script>
|
||||||
<script server:setup>
|
<script server:setup>
|
||||||
const project = {
|
const project = {
|
||||||
name: "WebComponent.io",
|
name: 'WebComponent.io',
|
||||||
description: "A simple reactivity system for web components",
|
description: 'A simple reactivity system for web components',
|
||||||
};
|
}
|
||||||
const author = {
|
const author = {
|
||||||
name: "Ayo Ayco",
|
name: 'Ayo Ayco',
|
||||||
url: "https://ayco.io",
|
url: 'https://ayco.io',
|
||||||
year: "2023",
|
year: '2023',
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@counter-style publish-icons {
|
@counter-style publish-icons {
|
||||||
system: cyclic;
|
system: cyclic;
|
||||||
symbols: "️✅";
|
symbols: '️✅';
|
||||||
suffix: " ";
|
suffix: ' ';
|
||||||
}
|
}
|
||||||
main {
|
main {
|
||||||
font-size: large;
|
font-size: large;
|
||||||
|
|
|
@ -9,31 +9,31 @@ import {
|
||||||
getCamelCase,
|
getCamelCase,
|
||||||
serialize,
|
serialize,
|
||||||
deserialize,
|
deserialize,
|
||||||
} from "./utils/index.js";
|
} from './utils/index.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A minimal base class to reduce the complexity of creating reactive custom elements
|
* A minimal base class to reduce the complexity of creating reactive custom elements
|
||||||
* @see https://WebComponent.io
|
* @see https://WebComponent.io
|
||||||
*/
|
*/
|
||||||
export class WebComponent extends HTMLElement {
|
export class WebComponent extends HTMLElement {
|
||||||
#host;
|
#host
|
||||||
#prevDOM;
|
#prevDOM
|
||||||
#props;
|
#props
|
||||||
#typeMap = {};
|
#typeMap = {}
|
||||||
#effectsMap = {};
|
#effectsMap = {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array of strings that tells the browsers which attributes will cause a render
|
* Array of strings that tells the browsers which attributes will cause a render
|
||||||
* @type {Array<string>}
|
* @type {Array<string>}
|
||||||
*/
|
*/
|
||||||
static properties = [];
|
static properties = []
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blueprint for the Proxy props
|
* Blueprint for the Proxy props
|
||||||
* @typedef {{[name: string]: any}} PropStringMap
|
* @typedef {{[name: string]: any}} PropStringMap
|
||||||
* @type {PropStringMap}
|
* @type {PropStringMap}
|
||||||
*/
|
*/
|
||||||
static props;
|
static props
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read-only string property that represents how the component will be rendered
|
* Read-only string property that represents how the component will be rendered
|
||||||
|
@ -41,14 +41,14 @@ export class WebComponent extends HTMLElement {
|
||||||
* @see https://www.npmjs.com/package/web-component-base#template-vs-render
|
* @see https://www.npmjs.com/package/web-component-base#template-vs-render
|
||||||
*/
|
*/
|
||||||
get template() {
|
get template() {
|
||||||
return "";
|
return ''
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shadow root initialization options
|
* Shadow root initialization options
|
||||||
* @type {ShadowRootInit}
|
* @type {ShadowRootInit}
|
||||||
*/
|
*/
|
||||||
static shadowRootInit;
|
static shadowRootInit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read-only property containing camelCase counterparts of observed attributes.
|
* Read-only property containing camelCase counterparts of observed attributes.
|
||||||
|
@ -57,7 +57,7 @@ export class WebComponent extends HTMLElement {
|
||||||
* @type {PropStringMap}
|
* @type {PropStringMap}
|
||||||
*/
|
*/
|
||||||
get props() {
|
get props() {
|
||||||
return this.#props;
|
return this.#props
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -87,126 +87,126 @@ export class WebComponent extends HTMLElement {
|
||||||
onChanges(changes) {}
|
onChanges(changes) {}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.#initializeProps();
|
this.#initializeProps()
|
||||||
this.#initializeHost();
|
this.#initializeHost()
|
||||||
}
|
}
|
||||||
|
|
||||||
static get observedAttributes() {
|
static get observedAttributes() {
|
||||||
const propKeys = this.props
|
const propKeys = this.props
|
||||||
? Object.keys(this.props).map((camelCase) => getKebabCase(camelCase))
|
? Object.keys(this.props).map((camelCase) => getKebabCase(camelCase))
|
||||||
: [];
|
: []
|
||||||
|
|
||||||
return [...new Set([...this.properties, ...propKeys])];
|
return [...new Set([...this.properties, ...propKeys])]
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
this.onInit();
|
this.onInit()
|
||||||
this.render();
|
this.render()
|
||||||
this.afterViewInit();
|
this.afterViewInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
this.onDestroy();
|
this.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeChangedCallback(property, previousValue, currentValue) {
|
attributeChangedCallback(property, previousValue, currentValue) {
|
||||||
const camelCaps = getCamelCase(property);
|
const camelCaps = getCamelCase(property)
|
||||||
|
|
||||||
if (previousValue !== currentValue) {
|
if (previousValue !== currentValue) {
|
||||||
this[property] = currentValue === "" || currentValue;
|
this[property] = currentValue === '' || currentValue
|
||||||
this[camelCaps] = this[property];
|
this[camelCaps] = this[property]
|
||||||
|
|
||||||
this.#handleUpdateProp(camelCaps, this[property]);
|
this.#handleUpdateProp(camelCaps, this[property])
|
||||||
|
|
||||||
this.render();
|
this.render()
|
||||||
this.onChanges({ property, previousValue, currentValue });
|
this.onChanges({ property, previousValue, currentValue })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#handleUpdateProp(key, stringifiedValue) {
|
#handleUpdateProp(key, stringifiedValue) {
|
||||||
const restored = deserialize(stringifiedValue, this.#typeMap[key]);
|
const restored = deserialize(stringifiedValue, this.#typeMap[key])
|
||||||
if (restored !== this.props[key]) this.props[key] = restored;
|
if (restored !== this.props[key]) this.props[key] = restored
|
||||||
}
|
}
|
||||||
|
|
||||||
#handler(setter, meta) {
|
#handler(setter, meta) {
|
||||||
const effectsMap = meta.#effectsMap;
|
const effectsMap = meta.#effectsMap
|
||||||
const typeMap = meta.#typeMap;
|
const typeMap = meta.#typeMap
|
||||||
|
|
||||||
return {
|
return {
|
||||||
set(obj, prop, value) {
|
set(obj, prop, value) {
|
||||||
const oldValue = obj[prop];
|
const oldValue = obj[prop]
|
||||||
|
|
||||||
if (!(prop in typeMap)) {
|
if (!(prop in typeMap)) {
|
||||||
typeMap[prop] = typeof value;
|
typeMap[prop] = typeof value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.attach === "effect") {
|
if (value.attach === 'effect') {
|
||||||
if (!effectsMap[prop]) {
|
if (!effectsMap[prop]) {
|
||||||
effectsMap[prop] = [];
|
effectsMap[prop] = []
|
||||||
}
|
}
|
||||||
effectsMap[prop].push(value.callback);
|
effectsMap[prop].push(value.callback)
|
||||||
} else if (typeMap[prop] !== typeof value) {
|
} else if (typeMap[prop] !== typeof value) {
|
||||||
throw TypeError(
|
throw TypeError(
|
||||||
`Cannot assign ${typeof value} to ${
|
`Cannot assign ${typeof value} to ${
|
||||||
typeMap[prop]
|
typeMap[prop]
|
||||||
} property (setting '${prop}' of ${meta.constructor.name})`
|
} property (setting '${prop}' of ${meta.constructor.name})`
|
||||||
);
|
)
|
||||||
} else if (oldValue !== value) {
|
} else if (oldValue !== value) {
|
||||||
obj[prop] = value;
|
obj[prop] = value
|
||||||
effectsMap[prop]?.forEach((f) => f(value));
|
effectsMap[prop]?.forEach((f) => f(value))
|
||||||
const kebab = getKebabCase(prop);
|
const kebab = getKebabCase(prop)
|
||||||
setter(kebab, serialize(value));
|
setter(kebab, serialize(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true
|
||||||
},
|
},
|
||||||
get(obj, prop) {
|
get(obj, prop) {
|
||||||
// TODO: handle non-objects
|
// TODO: handle non-objects
|
||||||
if (obj[prop] !== null && obj[prop] !== undefined) {
|
if (obj[prop] !== null && obj[prop] !== undefined) {
|
||||||
Object.getPrototypeOf(obj[prop]).proxy = meta.#props;
|
Object.getPrototypeOf(obj[prop]).proxy = meta.#props
|
||||||
Object.getPrototypeOf(obj[prop]).prop = prop;
|
Object.getPrototypeOf(obj[prop]).prop = prop
|
||||||
}
|
}
|
||||||
return obj[prop];
|
return obj[prop]
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#initializeProps() {
|
#initializeProps() {
|
||||||
let initialProps = structuredClone(this.constructor.props) ?? {};
|
let initialProps = structuredClone(this.constructor.props) ?? {}
|
||||||
Object.keys(initialProps).forEach((camelCase) => {
|
Object.keys(initialProps).forEach((camelCase) => {
|
||||||
const value = initialProps[camelCase];
|
const value = initialProps[camelCase]
|
||||||
this.#typeMap[camelCase] = typeof value;
|
this.#typeMap[camelCase] = typeof value
|
||||||
this.setAttribute(getKebabCase(camelCase), serialize(value));
|
this.setAttribute(getKebabCase(camelCase), serialize(value))
|
||||||
});
|
})
|
||||||
if (!this.#props) {
|
if (!this.#props) {
|
||||||
this.#props = new Proxy(
|
this.#props = new Proxy(
|
||||||
initialProps,
|
initialProps,
|
||||||
this.#handler((key, value) => this.setAttribute(key, value), this)
|
this.#handler((key, value) => this.setAttribute(key, value), this)
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#initializeHost() {
|
#initializeHost() {
|
||||||
this.#host = this;
|
this.#host = this
|
||||||
if (this.constructor.shadowRootInit) {
|
if (this.constructor.shadowRootInit) {
|
||||||
this.#host = this.attachShadow(this.constructor.shadowRootInit);
|
this.#host = this.attachShadow(this.constructor.shadowRootInit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (typeof this.template === "string") {
|
if (typeof this.template === 'string') {
|
||||||
this.innerHTML = this.template;
|
this.innerHTML = this.template
|
||||||
} else if (typeof this.template === "object") {
|
} else if (typeof this.template === 'object') {
|
||||||
const tree = this.template;
|
const tree = this.template
|
||||||
|
|
||||||
// TODO: smart diffing
|
// TODO: smart diffing
|
||||||
if (JSON.stringify(this.#prevDOM) !== JSON.stringify(tree)) {
|
if (JSON.stringify(this.#prevDOM) !== JSON.stringify(tree)) {
|
||||||
const el = createElement(tree);
|
const el = createElement(tree)
|
||||||
if (el) {
|
if (el) {
|
||||||
if (Array.isArray(el)) this.#host.replaceChildren(...el);
|
if (Array.isArray(el)) this.#host.replaceChildren(...el)
|
||||||
else this.#host.replaceChildren(el);
|
else this.#host.replaceChildren(el)
|
||||||
}
|
}
|
||||||
this.#prevDOM = tree;
|
this.#prevDOM = tree
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,10 @@
|
||||||
* @param {(newValue: any) => void} callback
|
* @param {(newValue: any) => void} callback
|
||||||
*/
|
*/
|
||||||
export function attachEffect(obj, callback) {
|
export function attachEffect(obj, callback) {
|
||||||
const { proxy, prop } = Object.getPrototypeOf(obj);
|
const { proxy, prop } = Object.getPrototypeOf(obj)
|
||||||
|
|
||||||
proxy[prop] = {
|
proxy[prop] = {
|
||||||
attach: "effect",
|
attach: 'effect',
|
||||||
callback,
|
callback,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
42
src/html.js
42
src/html.js
|
@ -6,15 +6,15 @@ const htm =
|
||||||
l,
|
l,
|
||||||
s = arguments,
|
s = arguments,
|
||||||
t = 1,
|
t = 1,
|
||||||
u = "",
|
u = '',
|
||||||
r = "",
|
r = '',
|
||||||
o = [0],
|
o = [0],
|
||||||
f = function (n) {
|
f = function (n) {
|
||||||
1 === t && (n || (u = u.replace(/^\s*\n\s*|\s*\n\s*$/g, "")))
|
1 === t && (n || (u = u.replace(/^\s*\n\s*|\s*\n\s*$/g, '')))
|
||||||
? o.push(n ? s[n] : u)
|
? o.push(n ? s[n] : u)
|
||||||
: 3 === t && (n || u)
|
: 3 === t && (n || u)
|
||||||
? ((o[1] = n ? s[n] : u), (t = 2))
|
? ((o[1] = n ? s[n] : u), (t = 2))
|
||||||
: 2 === t && "..." === u && n
|
: 2 === t && '...' === u && n
|
||||||
? (o[2] = Object.assign(o[2] || {}, s[n]))
|
? (o[2] = Object.assign(o[2] || {}, s[n]))
|
||||||
: 2 === t && u && !n
|
: 2 === t && u && !n
|
||||||
? ((o[2] = o[2] || {})[u] = !0)
|
? ((o[2] = o[2] || {})[u] = !0)
|
||||||
|
@ -27,50 +27,50 @@ const htm =
|
||||||
: u),
|
: u),
|
||||||
(t = 6))
|
(t = 6))
|
||||||
: (n || u) && (o[2][l] += n ? u + s[n] : u)),
|
: (n || u) && (o[2][l] += n ? u + s[n] : u)),
|
||||||
(u = "");
|
(u = '')
|
||||||
},
|
},
|
||||||
i = 0;
|
i = 0;
|
||||||
i < n.length;
|
i < n.length;
|
||||||
i++
|
i++
|
||||||
) {
|
) {
|
||||||
i && (1 === t && f(), f(i));
|
i && (1 === t && f(), f(i))
|
||||||
for (var p = 0; p < n[i].length; p++)
|
for (var p = 0; p < n[i].length; p++)
|
||||||
(e = n[i][p]),
|
(e = n[i][p]),
|
||||||
1 === t
|
1 === t
|
||||||
? "<" === e
|
? '<' === e
|
||||||
? (f(), (o = [o, "", null]), (t = 3))
|
? (f(), (o = [o, '', null]), (t = 3))
|
||||||
: (u += e)
|
: (u += e)
|
||||||
: 4 === t
|
: 4 === t
|
||||||
? "--" === u && ">" === e
|
? '--' === u && '>' === e
|
||||||
? ((t = 1), (u = ""))
|
? ((t = 1), (u = ''))
|
||||||
: (u = e + u[0])
|
: (u = e + u[0])
|
||||||
: r
|
: r
|
||||||
? e === r
|
? e === r
|
||||||
? (r = "")
|
? (r = '')
|
||||||
: (u += e)
|
: (u += e)
|
||||||
: '"' === e || "'" === e
|
: '"' === e || "'" === e
|
||||||
? (r = e)
|
? (r = e)
|
||||||
: ">" === e
|
: '>' === e
|
||||||
? (f(), (t = 1))
|
? (f(), (t = 1))
|
||||||
: t &&
|
: t &&
|
||||||
("=" === e
|
('=' === e
|
||||||
? ((t = 5), (l = u), (u = ""))
|
? ((t = 5), (l = u), (u = ''))
|
||||||
: "/" === e && (t < 5 || ">" === n[i][p + 1])
|
: '/' === e && (t < 5 || '>' === n[i][p + 1])
|
||||||
? (f(),
|
? (f(),
|
||||||
3 === t && (o = o[0]),
|
3 === t && (o = o[0]),
|
||||||
(t = o),
|
(t = o),
|
||||||
(o = o[0]).push(this.apply(null, t.slice(1))),
|
(o = o[0]).push(this.apply(null, t.slice(1))),
|
||||||
(t = 0))
|
(t = 0))
|
||||||
: " " === e || "\t" === e || "\n" === e || "\r" === e
|
: ' ' === e || '\t' === e || '\n' === e || '\r' === e
|
||||||
? (f(), (t = 2))
|
? (f(), (t = 2))
|
||||||
: (u += e)),
|
: (u += e)),
|
||||||
3 === t && "!--" === u && ((t = 4), (o = o[0]));
|
3 === t && '!--' === u && ((t = 4), (o = o[0]))
|
||||||
}
|
}
|
||||||
return f(), o.length > 2 ? o.slice(1) : o[1];
|
return f(), o.length > 2 ? o.slice(1) : o[1]
|
||||||
});
|
})
|
||||||
|
|
||||||
function h(type, props, ...children) {
|
function h(type, props, ...children) {
|
||||||
return { type, props, children };
|
return { type, props, children }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,4 +78,4 @@ function h(type, props, ...children) {
|
||||||
* @license Apache <https://www.apache.org/licenses/LICENSE-2.0>
|
* @license Apache <https://www.apache.org/licenses/LICENSE-2.0>
|
||||||
* @author Jason Miller <jason@developit.ca>
|
* @author Jason Miller <jason@developit.ca>
|
||||||
*/
|
*/
|
||||||
export const html = htm.bind(h);
|
export const html = htm.bind(h)
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export { attachEffect } from "./attach-effect.js";
|
export { attachEffect } from './attach-effect.js'
|
||||||
export { WebComponent } from "./WebComponent.js";
|
export { WebComponent } from './WebComponent.js'
|
||||||
export { html } from "./html.js";
|
export { html } from './html.js'
|
||||||
|
|
|
@ -1,46 +1,46 @@
|
||||||
import { serialize } from "./serialize.mjs";
|
import { serialize } from './serialize.mjs'
|
||||||
export function createElement(tree) {
|
export function createElement(tree) {
|
||||||
if (!tree.type) {
|
if (!tree.type) {
|
||||||
if (Array.isArray(tree)) {
|
if (Array.isArray(tree)) {
|
||||||
const frag = document.createDocumentFragment();
|
const frag = document.createDocumentFragment()
|
||||||
frag.replaceChildren(...tree.map((leaf) => createElement(leaf)));
|
frag.replaceChildren(...tree.map((leaf) => createElement(leaf)))
|
||||||
return frag;
|
return frag
|
||||||
}
|
}
|
||||||
return document.createTextNode(tree);
|
return document.createTextNode(tree)
|
||||||
} else {
|
} else {
|
||||||
const el = document.createElement(tree.type);
|
const el = document.createElement(tree.type)
|
||||||
/**
|
/**
|
||||||
* handle props
|
* handle props
|
||||||
*/
|
*/
|
||||||
if (tree.props) {
|
if (tree.props) {
|
||||||
Object.entries(tree.props).forEach(([prop, value]) => {
|
Object.entries(tree.props).forEach(([prop, value]) => {
|
||||||
const domProp = prop.toLowerCase();
|
const domProp = prop.toLowerCase()
|
||||||
if (domProp === "style" && typeof value === "object" && !!value) {
|
if (domProp === 'style' && typeof value === 'object' && !!value) {
|
||||||
applyStyles(el, value);
|
applyStyles(el, value)
|
||||||
} else if (prop in el) {
|
} else if (prop in el) {
|
||||||
el[prop] = value;
|
el[prop] = value
|
||||||
} else if (domProp in el) {
|
} else if (domProp in el) {
|
||||||
el[domProp] = value;
|
el[domProp] = value
|
||||||
} else {
|
} else {
|
||||||
el.setAttribute(prop, serialize(value));
|
el.setAttribute(prop, serialize(value))
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* handle children
|
* handle children
|
||||||
*/
|
*/
|
||||||
tree.children?.forEach((child) => {
|
tree.children?.forEach((child) => {
|
||||||
const childEl = createElement(child);
|
const childEl = createElement(child)
|
||||||
if (childEl instanceof Node) {
|
if (childEl instanceof Node) {
|
||||||
el.appendChild(childEl);
|
el.appendChild(childEl)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
return el;
|
return el
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyStyles(el, styleObj) {
|
function applyStyles(el, styleObj) {
|
||||||
Object.entries(styleObj).forEach(([rule, value]) => {
|
Object.entries(styleObj).forEach(([rule, value]) => {
|
||||||
if (rule in el.style && value) el.style[rule] = value;
|
if (rule in el.style && value) el.style[rule] = value
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
export function deserialize(value, type) {
|
export function deserialize(value, type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "number":
|
case 'number':
|
||||||
case "boolean":
|
case 'boolean':
|
||||||
case "object":
|
case 'object':
|
||||||
case "undefined":
|
case 'undefined':
|
||||||
return JSON.parse(value);
|
return JSON.parse(value)
|
||||||
default:
|
default:
|
||||||
return value;
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
export function getCamelCase(kebab) {
|
export function getCamelCase(kebab) {
|
||||||
return kebab.replace(/-./g, (x) => x[1].toUpperCase());
|
return kebab.replace(/-./g, (x) => x[1].toUpperCase())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export function getKebabCase(str) {
|
export function getKebabCase(str) {
|
||||||
return str.replace(
|
return str.replace(
|
||||||
/[A-Z]+(?![a-z])|[A-Z]/g,
|
/[A-Z]+(?![a-z])|[A-Z]/g,
|
||||||
($, ofs) => (ofs ? "-" : "") + $.toLowerCase(),
|
($, ofs) => (ofs ? '-' : '') + $.toLowerCase()
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
export { serialize } from "./serialize.mjs";
|
export { serialize } from './serialize.mjs'
|
||||||
export { deserialize } from "./deserialize.mjs";
|
export { deserialize } from './deserialize.mjs'
|
||||||
export { getCamelCase } from "./get-camel-case.mjs";
|
export { getCamelCase } from './get-camel-case.mjs'
|
||||||
export { getKebabCase } from "./get-kebab-case.mjs";
|
export { getKebabCase } from './get-kebab-case.mjs'
|
||||||
export { createElement } from "./create-element.mjs";
|
export { createElement } from './create-element.mjs'
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
export function serialize(value) {
|
export function serialize(value) {
|
||||||
switch (typeof value) {
|
switch (typeof value) {
|
||||||
case "number":
|
case 'number':
|
||||||
case "boolean":
|
case 'boolean':
|
||||||
case "object":
|
case 'object':
|
||||||
return JSON.stringify(value);
|
return JSON.stringify(value)
|
||||||
default:
|
default:
|
||||||
return value;
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,27 @@
|
||||||
import { describe, expect, test } from "vitest";
|
import { describe, expect, test } from 'vitest'
|
||||||
import { serialize } from "../src/utils/serialize.mjs";
|
import { serialize } from '../src/utils/serialize.mjs'
|
||||||
|
|
||||||
describe("serialize", () => {
|
describe('serialize', () => {
|
||||||
test("should stringify number", () => {
|
test('should stringify number', () => {
|
||||||
const result = serialize(3);
|
const result = serialize(3)
|
||||||
expect(result).toBeTypeOf("string");
|
expect(result).toBeTypeOf('string')
|
||||||
expect(result).toEqual("3");
|
expect(result).toEqual('3')
|
||||||
});
|
})
|
||||||
|
|
||||||
test("should stringify boolean", () => {
|
test('should stringify boolean', () => {
|
||||||
const result = serialize(false);
|
const result = serialize(false)
|
||||||
expect(result).toBeTypeOf("string");
|
expect(result).toBeTypeOf('string')
|
||||||
expect(result).toEqual("false");
|
expect(result).toEqual('false')
|
||||||
});
|
})
|
||||||
|
|
||||||
test("should stringify object", () => {
|
test('should stringify object', () => {
|
||||||
const result = serialize({ hello: "world" });
|
const result = serialize({ hello: 'world' })
|
||||||
expect(result).toBeTypeOf("string");
|
expect(result).toBeTypeOf('string')
|
||||||
expect(result).toEqual('{"hello":"world"}');
|
expect(result).toEqual('{"hello":"world"}')
|
||||||
});
|
})
|
||||||
|
|
||||||
test("should return undefined", () => {
|
test('should return undefined', () => {
|
||||||
const result = serialize(undefined);
|
const result = serialize(undefined)
|
||||||
expect(result).toBeUndefined();
|
expect(result).toBeUndefined()
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
Loading…
Reference in a new issue