diff --git a/.eslintrc.js b/.eslintrc.js
index 76f220db..deac7e89 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,6 +1,6 @@
module.exports = {
root: true,
- extends: 'airbnb-base',
+ extends: ['airbnb-base', 'prettier'],
env: {
browser: true,
},
@@ -11,11 +11,18 @@ module.exports = {
requireConfigFile: false,
},
rules: {
+ 'max-len': [2, 160, 2, { ignoreUrls: true }],
+ 'import/no-unresolved': [2, { commonjs: true }],
+ 'array-callback-return': 'off', // due to prettier
+ 'class-methods-use-this': 'off', // due to prettier
// allow reassigning param
'no-param-reassign': [2, { props: false }],
'linebreak-style': ['error', 'unix'],
- 'import/extensions': ['error', {
- js: 'always',
- }],
+ 'import/extensions': [
+ 'error',
+ {
+ js: 'always',
+ },
+ ],
},
};
diff --git a/blocks/button/button.css b/blocks/button/button.css
new file mode 100644
index 00000000..7358e7cb
--- /dev/null
+++ b/blocks/button/button.css
@@ -0,0 +1,32 @@
+raqn-button {
+ width: 100%;
+ display: grid;
+
+ & > div {
+ background-color: var(--scope-accent-background, #000);
+ color: var(--scope-accent-color, #fff);
+ text-transform: none;
+ border-radius: 20px;
+ border: 1px solid transparent;
+ overflow: hidden;
+
+ &:hover {
+ background-color: var(--scope-accent-background-hover, #fff);
+ color: var(--scope-accent-color-hover, #fff);
+ border-color: currentcolor;
+ }
+ }
+}
+
+raqn-button a {
+ color: currentcolor;
+ padding: 10px 20px;
+ text-decoration: none;
+}
+
+raqn-button a:hover,
+raqn-button a:visited,
+raqn-button a:active {
+ color: currentcolor;
+ text-decoration: none;
+}
diff --git a/blocks/button/button.js b/blocks/button/button.js
new file mode 100644
index 00000000..227717d3
--- /dev/null
+++ b/blocks/button/button.js
@@ -0,0 +1,8 @@
+import Column from '../column/column.js';
+
+export default class Button extends Column {
+ render() {
+ this.setAttribute('role', 'button');
+ this.setAttribute('tabindex', '0');
+ }
+}
diff --git a/blocks/card/card.css b/blocks/card/card.css
new file mode 100644
index 00000000..db0d2da7
--- /dev/null
+++ b/blocks/card/card.css
@@ -0,0 +1,10 @@
+raqn-card {
+ background-color: var(--scope-background, red);
+ display: grid;
+ grid-template-columns: var(--card-columns, 1fr);
+ gap: var(--scope-gap, 20px);
+}
+
+raqn-card > picture {
+ grid-column: span var(--card-columns, 1fr);
+}
\ No newline at end of file
diff --git a/blocks/card/card.js b/blocks/card/card.js
new file mode 100644
index 00000000..cd9b1026
--- /dev/null
+++ b/blocks/card/card.js
@@ -0,0 +1,42 @@
+import ComponentBase from '../../scripts/component-base.js';
+import { eagerImage } from '../../scripts/libs.js';
+
+export default class Card extends ComponentBase {
+ static get observedAttributes() {
+ return ['columns', 'ratio', 'eager'];
+ }
+
+ connected() {
+ this.eager = parseInt(this.getAttribute('eager') || 0, 10);
+ this.setupColumns(this.getAttribute('columns'));
+ if (this.eager) {
+ eagerImage(this, this.eager);
+ }
+ }
+
+ setupColumns(columns) {
+ if (!columns) {
+ return;
+ }
+ this.columns = parseInt(columns, 10);
+ this.area = Array.from(Array(parseInt(this.columns, 10)))
+ .map(() => '1fr')
+ .join(' ');
+ this.style.setProperty('--card-columns', this.area);
+ }
+
+ attributeChangedCallback(name, oldValue, newValue) {
+ if (oldValue !== newValue) {
+ switch (name) {
+ case 'columns':
+ this.setupColumns(newValue);
+ break;
+ case 'ratio':
+ this.style.setProperty('--card-ratio', newValue);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/blocks/cards/cards.css b/blocks/cards/cards.css
deleted file mode 100644
index a0315ede..00000000
--- a/blocks/cards/cards.css
+++ /dev/null
@@ -1,31 +0,0 @@
-.cards > ul {
- list-style: none;
- margin: 0;
- padding: 0;
- display: grid;
- grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
- grid-gap: 16px;
-}
-
-.cards > ul > li {
- border: 1px solid var(--highlight-background-color);
- background-color: var(--background-color)
-}
-
-.cards .cards-card-body {
- margin: 16px;
-}
-
-.cards .cards-card-image {
- line-height: 0;
-}
-
-.cards .cards-card-body > *:first-child {
- margin-top: 0;
-}
-
-.cards > ul > li img {
- width: 100%;
- aspect-ratio: 4 / 3;
- object-fit: cover;
-}
diff --git a/blocks/cards/cards.js b/blocks/cards/cards.js
deleted file mode 100644
index 717ec302..00000000
--- a/blocks/cards/cards.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import { createOptimizedPicture } from '../../scripts/lib-franklin.js';
-
-export default function decorate(block) {
- /* change to ul, li */
- const ul = document.createElement('ul');
- [...block.children].forEach((row) => {
- const li = document.createElement('li');
- while (row.firstElementChild) li.append(row.firstElementChild);
- [...li.children].forEach((div) => {
- if (div.children.length === 1 && div.querySelector('picture')) div.className = 'cards-card-image';
- else div.className = 'cards-card-body';
- });
- ul.append(li);
- });
- ul.querySelectorAll('img').forEach((img) => img.closest('picture').replaceWith(createOptimizedPicture(img.src, img.alt, false, [{ width: '750' }])));
- block.textContent = '';
- block.append(ul);
-}
diff --git a/blocks/column/column.css b/blocks/column/column.css
new file mode 100644
index 00000000..1879b40e
--- /dev/null
+++ b/blocks/column/column.css
@@ -0,0 +1,3 @@
+raqn-column {
+ margin: var(--scope-margin, 0);
+}
diff --git a/blocks/column/column.js b/blocks/column/column.js
new file mode 100644
index 00000000..71fe8f81
--- /dev/null
+++ b/blocks/column/column.js
@@ -0,0 +1,74 @@
+import ComponentBase from '../../scripts/component-base.js';
+
+export default class Column extends ComponentBase {
+ static observedAttributes() {
+ return ['position', 'size'];
+ }
+
+ connected() {
+ this.calculateGridTemplateColumns();
+ }
+
+ calculateGridTemplateColumns() {
+ this.position = parseInt(this.getAttribute('position'), 10);
+ this.size = this.getAttribute('size');
+ this.justify = this.getAttribute('justify') || 'stretch';
+ if (this.justify) {
+ this.style.justifyContent = this.justify;
+ }
+ if (this.position) {
+ const parent = this.parentElement;
+ const children = Array.from(parent.children);
+ this.parentElement.classList.add('raqn-grid');
+ let parentGridTemplateColumns = parent.style.getPropertyValue(
+ '--grid-template-columns',
+ );
+ if (!parentGridTemplateColumns) {
+ // we have no grid template columns yet
+ parentGridTemplateColumns = children
+ .map((child, index) => {
+ if (this.position === index + 1) {
+ return this.size || 'auto';
+ }
+ return 'auto';
+ })
+ .join(' ');
+ // set the new grid template columns
+ parent.style.setProperty(
+ '--grid-template-columns',
+ parentGridTemplateColumns,
+ );
+ } else {
+ const { position } = this;
+ const prio = children.indexOf(this) + 1;
+ parentGridTemplateColumns = parentGridTemplateColumns
+ .split(' ')
+ .map((size, i) => {
+ // we have a non standard value for this position
+ const hasValue = size !== 'auto';
+ // we are at the position
+ const isPosition = i + 1 === position;
+ // we are at a position before the prio
+ const isBeforePrio = i + 1 <= prio;
+ // we have a non standard value for this position and we are at the position
+ if (!hasValue && isPosition) {
+ return this.size || 'auto';
+ }
+ // we have a non standard value for this position and we are at a position before the prio
+ if (hasValue && isPosition && isBeforePrio) {
+ return this.size || size;
+ }
+ return size;
+ })
+ .join(' ');
+ // set the new grid template columns
+ parent.style.setProperty(
+ '--grid-template-columns',
+ parentGridTemplateColumns,
+ );
+ }
+ this.style.gridColumn = this.position;
+ this.style.gridRow = 1;
+ }
+ }
+}
diff --git a/blocks/columns/columns.css b/blocks/columns/columns.css
deleted file mode 100644
index 4b09aeea..00000000
--- a/blocks/columns/columns.css
+++ /dev/null
@@ -1,65 +0,0 @@
-.columns > div {
- display: flex;
- flex-direction: column;
-}
-
-.columns img {
- width: 100%;
-}
-
-@media (min-width: 900px) {
- .columns > div {
- align-items: center;
- flex-direction: unset;
- gap: var(--padding-vertical) var(--padding-horizontal);
- padding: var(--padding-vertical) var(--padding-horizontal);
- }
-
- .columns > div > div:nth-child(1) {
- flex: var(--column0-flex, 0);
- }
-
- .columns > div > div:nth-child(2) {
- flex: var(--column1-flex, 0);
- }
-
- .columns > div > div:nth-child(3) {
- flex: var(--column2-flex, 0);
- }
-
- .columns > div > div:nth-child(4) {
- flex: var(--column3-flex, 0);
- }
-
- .columns > div > div:nth-child(5) {
- flex: var(--column4-flex, 0);
- }
-
- .columns > div > div:nth-child(6) {
- flex: var(--column5-flex, 0);
- }
-
- .columns > div > div:nth-child(7) {
- flex: var(--column6-flex, 0);
- }
-
- .columns > div > div:nth-child(8) {
- flex: var(--column7-flex, 0);
- }
-
- .columns > div > div:nth-child(9) {
- flex: var(--column8-flex, 0);
- }
-
- .columns > div > div:nth-child(10) {
- flex: var(--column9-flex, 0);
- }
-
- .columns > div > div:nth-child(11) {
- flex: var(--column10-flex, 0);
- }
-
- .columns > div > div:nth-child(12) {
- flex: var(--column11-flex, 0);
- }
-}
diff --git a/blocks/columns/columns.js b/blocks/columns/columns.js
deleted file mode 100644
index 823c6c18..00000000
--- a/blocks/columns/columns.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import {
- addCssVariables,
-} from '../../scripts/lib-franklin.js';
-
-export default function decorate(block) {
- const columns = block.querySelectorAll(':scope > div > div');
- const columnCount = columns.length;
- // following line regex matches partition sizes separated by dashes like 1-2-3
- const columnPartionRegex = /^\d{1,}(?:-\d{1,})*$/;
- const columnPartions = [...block.classList].find((c) => columnPartionRegex.test(c))?.split('-') || [];
-
- const variables = {};
- for (let i = 0; i < columnCount; i += 1) {
- const partition = columnPartions.length > i ? columnPartions[i] : 1;
- variables[`column${i}-flex`] = partition;
- }
- addCssVariables(block, variables);
-}
diff --git a/blocks/footer/footer.css b/blocks/footer/footer.css
index 19fc5607..23d16ae2 100644
--- a/blocks/footer/footer.css
+++ b/blocks/footer/footer.css
@@ -11,4 +11,4 @@ footer .footer {
footer .footer p {
margin: 0;
-}
\ No newline at end of file
+}
diff --git a/blocks/footer/footer.js b/blocks/footer/footer.js
index ca8c7a68..c8ff6b12 100644
--- a/blocks/footer/footer.js
+++ b/blocks/footer/footer.js
@@ -1,25 +1,8 @@
-import { readBlockConfig, decorateIcons } from '../../scripts/lib-franklin.js';
+import ComponentBase from '../../scripts/component-base.js';
-/**
- * loads and decorates the footer
- * @param {Element} block The footer block element
- */
-export default async function decorate(block) {
- const cfg = readBlockConfig(block);
- block.textContent = '';
-
- // fetch footer content
- const footerPath = cfg.footer || '/footer';
- const resp = await fetch(`${footerPath}.plain.html`, window.location.pathname.endsWith('/footer') ? { cache: 'reload' } : {});
-
- if (resp.ok) {
- const html = await resp.text();
-
- // decorate footer DOM
- const footer = document.createElement('div');
- footer.innerHTML = html;
-
- decorateIcons(footer);
- block.append(footer);
+export default class Footer extends ComponentBase {
+ constructor() {
+ super();
+ this.external = '/footer.plain.html';
}
}
diff --git a/blocks/grid/grid.css b/blocks/grid/grid.css
deleted file mode 100644
index ba453ff5..00000000
--- a/blocks/grid/grid.css
+++ /dev/null
@@ -1,30 +0,0 @@
-.section.grid {
- display: grid;
- grid-template-columns: var(--grid-template-columns, unset);
- grid-template-rows: var(--grid-template-rows, unset);
-}
-
-.section.grid .element {
- grid-column: var(--grid-column-start-position, auto) / var(--grid-column-end-position, auto);
- grid-row: var(--grid-row-start-position, auto) / var(--grid-row-end-position, auto);
- width: 100%;
- max-width: unset;
- background-color: var(--background-color, transparent);
- color: var(--text-color);
- margin: auto;
-}
-
-.section.grid .element .image-wrapper {
- margin: 0;
- padding: 0;
-}
-
-.section.grid .element img {
- width: 100%;
- height: auto;
-}
-
-.section.grid .element p {
- margin: 0;
- padding: var(--padding-vertical) var(--padding-horizontal);
-}
diff --git a/blocks/grid/grid.js b/blocks/grid/grid.js
deleted file mode 100644
index 5a9fc3f8..00000000
--- a/blocks/grid/grid.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import {
- addCssVariables,
-} from '../../scripts/lib-franklin.js';
-
-export default function decorate(block) {
- const elements = [...block.querySelectorAll(':scope > div')];
-
- const columnTemplate = elements.find((e) => e.dataset.gridColumns)?.dataset.gridColumns;
- const rowTemplate = elements.find((e) => e.dataset.gridRows)?.dataset.gridRows;
- if (columnTemplate || rowTemplate) {
- addCssVariables(block, {
- 'grid-template-columns': columnTemplate,
- 'grid-template-rows': rowTemplate,
- });
- }
-
- elements.forEach((e) => {
- e.classList.add('element');
-
- const [[startColumnPosition, startRowPosition], [endColumnPosition, endRowPosition]] = e.dataset.gridPosition.split(/\s*\/\s*/).map((p) => p.split(/\s*-\s*/));
-
- addCssVariables(e, {
- 'grid-column-start-position': startColumnPosition,
- 'grid-row-start-position': startRowPosition,
- 'grid-column-end-position': endColumnPosition,
- 'grid-row-end-position': endRowPosition,
- });
- });
-}
diff --git a/blocks/header/header.css b/blocks/header/header.css
index 09581712..87526d55 100644
--- a/blocks/header/header.css
+++ b/blocks/header/header.css
@@ -1,19 +1,8 @@
-header a:any-link {
- color: inherit;
-}
-
-header p,
-header .section.grid .element p {
- margin: 0;
- padding: 0;
-}
-
-a.button:any-link {
- background-color: transparent;
- color: inherit;
- font-weight: normal;
-}
-
-a.button:any-link .icon {
- vertical-align: middle;
+raqn-header {
+ display: grid;
+ max-width: var(--scope-max-width, 90vw);
+ margin: 0 auto;
+ align-items: center;
+ border-block-end: var(--scope-border-color, #000) solid
+ var(--scope-border-width, 1px);
}
diff --git a/blocks/header/header.js b/blocks/header/header.js
index c8512c3f..5d373996 100644
--- a/blocks/header/header.js
+++ b/blocks/header/header.js
@@ -1,11 +1,11 @@
-import {
- loadBlocks,
-} from '../../scripts/lib-franklin.js';
-import {
- decorateMain,
-} from '../../scripts/scripts.js';
+import ComponentBase from '../../scripts/component-base.js';
+import { eagerImage } from '../../scripts/libs.js';
-export default async function decorate(block) {
- decorateMain(block);
- loadBlocks(block);
+export default class Header extends ComponentBase {
+ external = '/header.plain.html';
+
+ async processExternal(response) {
+ await super.processExternal(response);
+ eagerImage(this, 1);
+ }
}
diff --git a/blocks/hero/hero.css b/blocks/hero/hero.css
index cc5f4fa5..0483f623 100644
--- a/blocks/hero/hero.css
+++ b/blocks/hero/hero.css
@@ -1,39 +1,23 @@
/* block specific CSS goes here */
-main .hero-container > div {
- max-width: unset;
-}
-
-main .hero-container {
- padding: 0;
-}
-
-main .hero {
- position: relative;
- padding: 32px;
- min-height: 300px;
-}
+raqn-hero {
+ --raqn-background-color: var(--scope-background, transparent);
+ --raqn-color: var(--scope-color, transparent);
+ --raqn-grid-template-columns: 0.6fr 0.4fr;
-main .hero h1 {
- max-width: 1200px;
- margin-left: auto;
- margin-right: auto;
- color: white;
-}
+ background-color: var(--raqn-background-color);
+ color: var(--raqn-color);
+ align-items: center;
-main .hero picture {
- position: absolute;
- z-index: -1;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
- object-fit: cover;
- box-sizing: border-box;
-}
+ @media screen and (max-width: 768px) {
+ --raqn-grid-template-columns: 1fr;
+ }
+
+ grid-template-columns: var(--raqn-grid-template-columns, 1fr);
-main .hero img {
- object-fit: cover;
- width: 100%;
- height: 100%;
+ @media screen and (min-width: 768px) {
+ & > div:first-child {
+ max-width: 30vw;
+ }
+ }
}
diff --git a/blocks/hero/hero.js b/blocks/hero/hero.js
index e69de29b..67c2f5e6 100644
--- a/blocks/hero/hero.js
+++ b/blocks/hero/hero.js
@@ -0,0 +1,12 @@
+import ComponentBase from '../../scripts/component-base.js';
+
+export default class Hero extends ComponentBase {
+ connected() {
+ const child = this.children[0];
+ child.replaceWith(...child.children);
+ this.classList.add('full-width');
+ this.setAttribute('role', 'banner');
+ this.setAttribute('aria-label', 'hero');
+ this.style.setProperty('--hero-columns', this.getAttribute('height'));
+ }
+}
diff --git a/blocks/icon/icon.css b/blocks/icon/icon.css
new file mode 100644
index 00000000..bd707aa0
--- /dev/null
+++ b/blocks/icon/icon.css
@@ -0,0 +1,21 @@
+raqn-icon {
+ display: inline-flex;
+ font-size: 1em;
+ line-height: 1em;
+ min-width: var(--scope-icon-size, 1em);
+ min-height: var(--scope-icon-size, 1em);
+ text-align: center;
+ text-transform: none;
+ vertical-align: middle;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+raqn-icon svg {
+ display: inline-block;
+ max-height: 100%;
+ max-width: 100%;
+ fill: currentcolor;
+ overflow: hidden;
+ vertical-align: middle;
+}
diff --git a/blocks/icon/icon.js b/blocks/icon/icon.js
new file mode 100644
index 00000000..b1ab2434
--- /dev/null
+++ b/blocks/icon/icon.js
@@ -0,0 +1,104 @@
+import ComponentBase from '../../scripts/component-base.js';
+
+export default class Icon extends ComponentBase {
+ constructor() {
+ super();
+ this.setupSprite();
+ }
+
+ setupSprite() {
+ this.svgSprite = document.getElementById('franklin-svg-sprite');
+ if (!this.svgSprite) {
+ this.svgSprite = document.createElement('div');
+ this.svgSprite.id = 'franklin-svg-sprite';
+ document.body.append(this.svgSprite);
+ }
+ }
+
+ get iconUrl() {
+ return `assets/icons/${this.iconName}.svg`;
+ }
+
+ get cache() {
+ window.ICONS_CACHE = window.ICONS_CACHE || {};
+ return window.ICONS_CACHE;
+ }
+
+ async connected() {
+ this.iconName = this.getAttribute('icon');
+ if (!this.cache[this.iconName]) {
+ this.cache[this.iconName] = {
+ loading: new Promise((resolve) => {
+ resolve(this.load(this.iconUrl));
+ }),
+ };
+ } else {
+ await this.cache[this.iconName].loading;
+ this.innerHTML = this.template();
+ }
+ this.classList.add('loaded');
+ }
+
+ template() {
+ const { viewBox } = this.cache[this.iconName];
+ const attributes = Object.keys({ viewBox })
+ .map((k) => {
+ if (this.cache[this.iconName][k]) {
+ return `${k}="${this.cache[this.iconName][k]}"`;
+ }
+ return '';
+ })
+ .join(' ');
+ return ``;
+ }
+
+ iconTemplate(iconName, svg, viewBox, width, height) {
+ return `${svg.innerHTML}`;
+ }
+
+ async processExternal(response) {
+ if (response.ok) {
+ const { iconName } = this;
+ this.svg = await response.text();
+
+ if (this.svg.match(/(
diff --git a/icons/search.svg b/icons/search.svg
deleted file mode 100644
index 637c677b..00000000
--- a/icons/search.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-
diff --git a/package-lock.json b/package-lock.json
index c23bc9b6..2a33b8af 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,7 +20,9 @@
"chai": "4.3.7",
"eslint": "8.35.0",
"eslint-config-airbnb-base": "15.0.0",
+ "eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "2.27.5",
+ "prettier-eslint": "^16.2.0",
"semantic-release": "21.0.5",
"sinon": "15.0.1",
"stylelint": "15.2.0",
@@ -539,6 +541,18 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
+ "node_modules/@jest/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "dev": true,
+ "dependencies": {
+ "@sinclair/typebox": "^0.27.8"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
@@ -1623,6 +1637,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@sinclair/typebox": {
+ "version": "0.27.8",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "dev": true
+ },
"node_modules/@sinonjs/commons": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
@@ -1932,6 +1952,160 @@
"@types/node": "*"
}
},
+ "node_modules/@typescript-eslint/parser": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz",
+ "integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "6.16.0",
+ "@typescript-eslint/types": "6.16.0",
+ "@typescript-eslint/typescript-estree": "6.16.0",
+ "@typescript-eslint/visitor-keys": "6.16.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+ "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.16.0",
+ "@typescript-eslint/visitor-keys": "6.16.0"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+ "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
+ "dev": true,
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+ "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.16.0",
+ "@typescript-eslint/visitor-keys": "6.16.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "9.0.3",
+ "semver": "^7.5.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+ "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/types": "6.16.0",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^16.0.0 || >=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/@web/browser-logs": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@web/browser-logs/-/browser-logs-0.2.5.tgz",
@@ -3027,6 +3201,15 @@
"node": ">=8"
}
},
+ "node_modules/common-tags": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz",
+ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
"node_modules/compare-func": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz",
@@ -3574,6 +3757,12 @@
"node": ">=8"
}
},
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true
+ },
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -4016,6 +4205,18 @@
"eslint-plugin-import": "^2.25.2"
}
},
+ "node_modules/eslint-config-prettier": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
+ "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
+ "dev": true,
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
"node_modules/eslint-import-resolver-node": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz",
@@ -5057,6 +5258,27 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-ansi/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/has-bigints": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
@@ -6449,6 +6671,84 @@
"node": ">=8"
}
},
+ "node_modules/loglevel": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz",
+ "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ },
+ "funding": {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/loglevel"
+ }
+ },
+ "node_modules/loglevel-colored-level-prefix": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz",
+ "integrity": "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^1.1.3",
+ "loglevel": "^1.4.1"
+ }
+ },
+ "node_modules/loglevel-colored-level-prefix/node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/loglevel-colored-level-prefix/node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/loglevel-colored-level-prefix/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/loglevel-colored-level-prefix/node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/loglevel-colored-level-prefix/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/loupe": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.3.tgz",
@@ -10766,6 +11066,70 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
+ "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
+ "dev": true,
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-eslint": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-16.2.0.tgz",
+ "integrity": "sha512-GDTSKc62VaLceiaI/qMaKo2oco2CIWtbj4Zr6ckhbTgcBL/uR0d9jkMzh9OtBIT/Z7iBoCB4OHj/aJ5YuNgAuA==",
+ "dev": true,
+ "dependencies": {
+ "@typescript-eslint/parser": "^6.7.5",
+ "common-tags": "^1.4.0",
+ "dlv": "^1.1.0",
+ "eslint": "^8.7.0",
+ "indent-string": "^4.0.0",
+ "lodash.merge": "^4.6.0",
+ "loglevel-colored-level-prefix": "^1.0.0",
+ "prettier": "^3.0.1",
+ "pretty-format": "^29.7.0",
+ "require-relative": "^0.8.7",
+ "typescript": "^5.2.2",
+ "vue-eslint-parser": "^9.1.0"
+ },
+ "engines": {
+ "node": ">=16.10.0"
+ }
+ },
+ "node_modules/pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
+ "dependencies": {
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
+ },
+ "engines": {
+ "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/pretty-format/node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -10912,6 +11276,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "dev": true
+ },
"node_modules/read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@@ -11166,6 +11536,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/require-relative": {
+ "version": "0.8.7",
+ "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
+ "integrity": "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==",
+ "dev": true
+ },
"node_modules/resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@@ -12658,6 +13034,18 @@
"node": ">=8"
}
},
+ "node_modules/ts-api-utils": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
+ "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
+ "dev": true,
+ "engines": {
+ "node": ">=16.13.0"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.2.0"
+ }
+ },
"node_modules/tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -12751,6 +13139,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/typescript": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
+ "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/typical": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
@@ -12926,6 +13327,82 @@
"node": ">= 0.8"
}
},
+ "node_modules/vue-eslint-parser": {
+ "version": "9.3.2",
+ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz",
+ "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.3.4",
+ "eslint-scope": "^7.1.1",
+ "eslint-visitor-keys": "^3.3.0",
+ "espree": "^9.3.1",
+ "esquery": "^1.4.0",
+ "lodash": "^4.17.21",
+ "semver": "^7.3.6"
+ },
+ "engines": {
+ "node": "^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=6.0.0"
+ }
+ },
+ "node_modules/vue-eslint-parser/node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/vue-eslint-parser/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/vue-eslint-parser/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/vue-eslint-parser/node_modules/semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
@@ -13587,6 +14064,15 @@
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
"dev": true
},
+ "@jest/schemas": {
+ "version": "29.6.3",
+ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+ "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+ "dev": true,
+ "requires": {
+ "@sinclair/typebox": "^0.27.8"
+ }
+ },
"@jridgewell/gen-mapping": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
@@ -14341,6 +14827,12 @@
}
}
},
+ "@sinclair/typebox": {
+ "version": "0.27.8",
+ "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
+ "dev": true
+ },
"@sinonjs/commons": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz",
@@ -14650,6 +15142,98 @@
"@types/node": "*"
}
},
+ "@typescript-eslint/parser": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.16.0.tgz",
+ "integrity": "sha512-H2GM3eUo12HpKZU9njig3DF5zJ58ja6ahj1GoHEHOgQvYxzoFJJEvC1MQ7T2l9Ha+69ZSOn7RTxOdpC/y3ikMw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/scope-manager": "6.16.0",
+ "@typescript-eslint/types": "6.16.0",
+ "@typescript-eslint/typescript-estree": "6.16.0",
+ "@typescript-eslint/visitor-keys": "6.16.0",
+ "debug": "^4.3.4"
+ }
+ },
+ "@typescript-eslint/scope-manager": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz",
+ "integrity": "sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "6.16.0",
+ "@typescript-eslint/visitor-keys": "6.16.0"
+ }
+ },
+ "@typescript-eslint/types": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.16.0.tgz",
+ "integrity": "sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ==",
+ "dev": true
+ },
+ "@typescript-eslint/typescript-estree": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz",
+ "integrity": "sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "6.16.0",
+ "@typescript-eslint/visitor-keys": "6.16.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "9.0.3",
+ "semver": "^7.5.4",
+ "ts-api-utils": "^1.0.1"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ },
+ "semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
+ }
+ },
+ "@typescript-eslint/visitor-keys": {
+ "version": "6.16.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz",
+ "integrity": "sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/types": "6.16.0",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "dependencies": {
+ "eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true
+ }
+ }
+ },
"@web/browser-logs": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@web/browser-logs/-/browser-logs-0.2.5.tgz",
@@ -15441,6 +16025,12 @@
}
}
},
+ "common-tags": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz",
+ "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==",
+ "dev": true
+ },
"compare-func": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz",
@@ -15845,6 +16435,12 @@
"path-type": "^4.0.0"
}
},
+ "dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "dev": true
+ },
"doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -16279,6 +16875,13 @@
"semver": "^6.3.0"
}
},
+ "eslint-config-prettier": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz",
+ "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==",
+ "dev": true,
+ "requires": {}
+ },
"eslint-import-resolver-node": {
"version": "0.3.7",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz",
@@ -16985,6 +17588,23 @@
"function-bind": "^1.1.1"
}
},
+ "has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true
+ }
+ }
+ },
"has-bigints": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
@@ -18030,6 +18650,64 @@
}
}
},
+ "loglevel": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz",
+ "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==",
+ "dev": true
+ },
+ "loglevel-colored-level-prefix": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz",
+ "integrity": "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==",
+ "dev": true,
+ "requires": {
+ "chalk": "^1.1.3",
+ "loglevel": "^1.4.1"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true
+ },
+ "ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
+ "dev": true
+ },
+ "chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
+ "dev": true,
+ "requires": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
+ "dev": true
+ }
+ }
+ },
"loupe": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.3.tgz",
@@ -20970,6 +21648,51 @@
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
"dev": true
},
+ "prettier": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz",
+ "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==",
+ "dev": true
+ },
+ "prettier-eslint": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-16.2.0.tgz",
+ "integrity": "sha512-GDTSKc62VaLceiaI/qMaKo2oco2CIWtbj4Zr6ckhbTgcBL/uR0d9jkMzh9OtBIT/Z7iBoCB4OHj/aJ5YuNgAuA==",
+ "dev": true,
+ "requires": {
+ "@typescript-eslint/parser": "^6.7.5",
+ "common-tags": "^1.4.0",
+ "dlv": "^1.1.0",
+ "eslint": "^8.7.0",
+ "indent-string": "^4.0.0",
+ "lodash.merge": "^4.6.0",
+ "loglevel-colored-level-prefix": "^1.0.0",
+ "prettier": "^3.0.1",
+ "pretty-format": "^29.7.0",
+ "require-relative": "^0.8.7",
+ "typescript": "^5.2.2",
+ "vue-eslint-parser": "^9.1.0"
+ }
+ },
+ "pretty-format": {
+ "version": "29.7.0",
+ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
+ "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==",
+ "dev": true,
+ "requires": {
+ "@jest/schemas": "^29.6.3",
+ "ansi-styles": "^5.0.0",
+ "react-is": "^18.0.0"
+ },
+ "dependencies": {
+ "ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "dev": true
+ }
+ }
+ },
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -21080,6 +21803,12 @@
}
}
},
+ "react-is": {
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
+ "dev": true
+ },
"read-pkg": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
@@ -21269,6 +21998,12 @@
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true
},
+ "require-relative": {
+ "version": "0.8.7",
+ "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz",
+ "integrity": "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==",
+ "dev": true
+ },
"resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
@@ -22370,6 +23105,13 @@
"integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
"dev": true
},
+ "ts-api-utils": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz",
+ "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==",
+ "dev": true,
+ "requires": {}
+ },
"tsconfig-paths": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
@@ -22441,6 +23183,12 @@
"is-typed-array": "^1.1.9"
}
},
+ "typescript": {
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
+ "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==",
+ "dev": true
+ },
"typical": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz",
@@ -22567,6 +23315,54 @@
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
"dev": true
},
+ "vue-eslint-parser": {
+ "version": "9.3.2",
+ "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.2.tgz",
+ "integrity": "sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==",
+ "dev": true,
+ "requires": {
+ "debug": "^4.3.4",
+ "eslint-scope": "^7.1.1",
+ "eslint-visitor-keys": "^3.3.0",
+ "espree": "^9.3.1",
+ "esquery": "^1.4.0",
+ "lodash": "^4.17.21",
+ "semver": "^7.3.6"
+ },
+ "dependencies": {
+ "eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "requires": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ }
+ },
+ "eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true
+ },
+ "estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "dev": true
+ },
+ "semver": {
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
+ "dev": true,
+ "requires": {
+ "lru-cache": "^6.0.0"
+ }
+ }
+ }
+ },
"webidl-conversions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
diff --git a/package.json b/package.json
index 4587406e..6d846dd2 100644
--- a/package.json
+++ b/package.json
@@ -21,19 +21,21 @@
},
"homepage": "https://github.com/adobe/helix-project-boilerplate#readme",
"devDependencies": {
+ "@babel/core": "7.21.0",
+ "@babel/eslint-parser": "7.19.1",
+ "@esm-bundle/chai": "4.3.4-fix.0",
"@semantic-release/changelog": "6.0.3",
"@semantic-release/exec": "6.0.3",
"@semantic-release/git": "10.0.1",
- "semantic-release": "21.0.5",
- "@babel/core": "7.21.0",
- "@babel/eslint-parser": "7.19.1",
+ "@web/test-runner": "0.15.1",
+ "@web/test-runner-commands": "0.6.5",
"chai": "4.3.7",
"eslint": "8.35.0",
"eslint-config-airbnb-base": "15.0.0",
+ "eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "2.27.5",
- "@esm-bundle/chai": "4.3.4-fix.0",
- "@web/test-runner": "0.15.1",
- "@web/test-runner-commands": "0.6.5",
+ "prettier-eslint": "^16.2.0",
+ "semantic-release": "21.0.5",
"sinon": "15.0.1",
"stylelint": "15.2.0",
"stylelint-config-standard": "30.0.1"
diff --git a/scripts/component-base.js b/scripts/component-base.js
new file mode 100644
index 00000000..31e73567
--- /dev/null
+++ b/scripts/component-base.js
@@ -0,0 +1,49 @@
+import { init } from './init.js';
+
+export default class ComponentBase extends HTMLElement {
+ static get breakpoints() {
+ return {
+ S: 0,
+ M: 768,
+ L: 1024,
+ XL: 1280,
+ XXL: 1920,
+ };
+ }
+
+ constructor() {
+ super();
+ this.external = false;
+ this.uuid = `gen${crypto.randomUUID().split('-')[0]}`;
+ }
+
+ async connectedCallback() {
+ this.setAttribute('id', this.uuid);
+ if (this.external) {
+ await this.load(this.external);
+ }
+ this.connected();
+ this.render();
+ }
+
+ async load(block) {
+ const response = await fetch(
+ `${block}`,
+ window.location.pathname.endsWith(block) ? { cache: 'reload' } : {},
+ );
+ return this.processExternal(response);
+ }
+
+ async processExternal(response) {
+ if (response.ok) {
+ const html = await response.text();
+ this.innerHTML = html;
+ return init(this);
+ }
+ return response;
+ }
+
+ connected() {}
+
+ render() {}
+}
diff --git a/scripts/component-loader.js b/scripts/component-loader.js
new file mode 100644
index 00000000..22c40390
--- /dev/null
+++ b/scripts/component-loader.js
@@ -0,0 +1,143 @@
+import { config, getBreakPoint } from './libs.js';
+
+export default class ComponentLoader {
+ constructor(blockName, element) {
+ window.raqnComponents = window.raqnComponents || {};
+ this.blockName = blockName;
+ this.setBlockPaths();
+ this.block = element;
+ if (this.block) {
+ this.setParams();
+ this.content = this.block.children;
+ }
+ }
+
+ /**
+ * Loads a CSS file.
+ * @param {string} href URL to the CSS file
+ */
+ async loadCSS(href) {
+ return new Promise((resolve, reject) => {
+ if (!document.querySelector(`head > link[href="${href}"]`)) {
+ const link = document.createElement('link');
+ link.rel = 'stylesheet';
+ link.href = href;
+ link.onload = resolve;
+ link.onerror = reject;
+ document.head.append(link);
+ } else {
+ resolve();
+ }
+ });
+ }
+
+ /**
+ * Parse extra params from classList
+ */
+ setParams() {
+ const mediaParams = {};
+ this.params = {
+ ...Array.from(this.block.classList)
+ .filter((c) => c !== this.blockName && c !== 'block')
+ .reduce((acc, c) => {
+ const values = c.split('-');
+ let key = values.shift();
+ const breakpoint = getBreakPoint();
+ if (breakpoint === key) {
+ key = values.shift();
+ mediaParams[key] = values.join('-');
+ return acc;
+ }
+
+ if (config.breakpoints[key] !== undefined) {
+ return acc;
+ }
+
+ if (acc[key] && Array.isArray(acc[key])) {
+ acc[key].push(values.join('-'));
+ } else if (acc[key]) {
+ acc[key] = [acc[key], values.join('-')];
+ } else {
+ acc[key] = values.join('-');
+ }
+ return acc;
+ }, {}),
+ ...mediaParams,
+ };
+ }
+
+ /**
+ * Set the configuration for the given block, and also passes
+ * the config through all custom patching helpers added to the project.
+ *
+ * @param {Element} block The block element
+ * @returns {Object} The block config (blockName, cssPath and jsPath)
+ */
+ setBlockPaths() {
+ this.cssPath = `/blocks/${this.blockName}/${this.blockName}.css`;
+ this.jsPath = `/blocks/${this.blockName}/${this.blockName}.js`;
+ }
+
+ setupElement() {
+ const elementName = `raqn-${this.blockName.toLowerCase()}`;
+ const element = document.createElement(elementName);
+ element.append(...this.block.children);
+ Object.keys(this.params).forEach((key) => {
+ // @TODO sanitize
+ const value = Array.isArray(this.params[key])
+ ? this.params[key].join(' ')
+ : this.params[key];
+ element.setAttribute(key, value);
+ });
+ this.block.replaceWith(element);
+ }
+
+ async loadWebComponent() {
+ return new Promise((resolve, reject) => {
+ (async () => {
+ try {
+ const mod = await import(this.jsPath);
+ if (
+ mod.default &&
+ mod.default.name &&
+ mod.default.name !== 'decorate'
+ ) {
+ const { name } = mod.default;
+ const elementName = `raqn-${name.toLowerCase()}`;
+ // define the custom element if it doesn't exist
+ if (!window.raqnComponents[name]) {
+ const Contructor = mod.default;
+ customElements.define(elementName, Contructor);
+ window.raqnComponents[name] = Contructor;
+ }
+ if (this.block) {
+ this.setupElement();
+ }
+ } else if (mod.default) {
+ await mod.default(this.block);
+ }
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.log(`failed to load module for ${this.blockName}`, error);
+ return reject(error);
+ }
+ return resolve();
+ })();
+ });
+ }
+
+ async decorate() {
+ if (window.raqnComponents[this.blockName]) {
+ return this.setupElement();
+ }
+ try {
+ const cssLoaded = this.loadCSS(this.cssPath);
+ const decorationComplete = this.loadWebComponent();
+ return Promise.all([cssLoaded, decorationComplete]);
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.log(`failed to load module for ${this.blockName}`, error);
+ return Promise.resolve();
+ }
+ }
+}
diff --git a/scripts/delayed.js b/scripts/delayed.js
deleted file mode 100644
index 920b4ad8..00000000
--- a/scripts/delayed.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// eslint-disable-next-line import/no-cycle
-import { sampleRUM } from './lib-franklin.js';
-
-// Core Web Vitals RUM collection
-sampleRUM('cwv');
-
-// add more delayed functionality here
diff --git a/scripts/init.js b/scripts/init.js
new file mode 100644
index 00000000..ebc9b3d9
--- /dev/null
+++ b/scripts/init.js
@@ -0,0 +1,83 @@
+import ComponentLoader from './component-loader.js';
+import { config, debounce, eagerImage, getBreakPoint } from './libs.js';
+
+export function retriveDataFrom(blocks) {
+ return blocks.map((block) => {
+ let el = block;
+ const tagName = el.tagName.toLowerCase();
+ let name = tagName;
+ if (!config.elementBlocks.includes(tagName)) {
+ [name] = Array.from(el.classList);
+ } else {
+ el = document.createElement('div');
+ block.append(el);
+ }
+ return {
+ name,
+ el,
+ };
+ });
+}
+
+function lcpPriority() {
+ const eagerImages = document.querySelector('meta[name="lcp"]');
+ if (eagerImages) {
+ const length = parseInt(eagerImages.getAttribute('content'), 10);
+ eagerImage(document, length);
+ }
+
+ const lcp = document.querySelector('meta[name="lcp"]');
+ if (!lcp) {
+ return window.raqnLCP || [];
+ }
+ window.raqnLCP =
+ window.raqnLCP ||
+ lcp
+ .getAttribute('content')
+ .split(',')
+ .map((name) => ({ name }));
+ return window.raqnLCP;
+}
+
+export async function init(node = document) {
+ let blocks = Array.from(node.querySelectorAll('[class]:not([class^=style]'));
+
+ if (node === document) {
+ const header = node.querySelector('header');
+ const footer = node.querySelector('footer');
+ blocks = [header, ...blocks, footer];
+ }
+
+ const data = retriveDataFrom(blocks);
+ const lcp = window.raqnLCP;
+ const prio = data.slice(0, 2);
+ const rest = data.slice(2);
+ const start = ({ name, el }) => {
+ const loader = new ComponentLoader(name, el);
+ return loader.decorate();
+ };
+ Promise.all([
+ ...lcp.map(({ name, el }) => start({ name, el })),
+ ...prio.map(({ name, el }) => start({ name, el })),
+ ]);
+ setTimeout(() => {
+ Promise.all(
+ rest.map(({ name, el }) => setTimeout(() => start({ name, el }))),
+ );
+ });
+ // reload on breakpoint change
+ window.raqnBreakpoint = getBreakPoint();
+ window.addEventListener(
+ 'resize',
+ debounce(() => {
+ // only on width changes
+ if (window.raqnBreakpoint !== getBreakPoint()) {
+ window.location.reload();
+ }
+ }, 100),
+ );
+}
+// mechanism of retrieving lang to be used in the app
+document.documentElement.lang = document.documentElement.lang || 'en';
+lcpPriority();
+init();
diff --git a/scripts/lib-franklin.js b/scripts/lib-franklin.js
index 7b6cf0cf..d365f1bd 100644
--- a/scripts/lib-franklin.js
+++ b/scripts/lib-franklin.js
@@ -29,33 +29,52 @@ export function sampleRUM(checkpoint, data = {}) {
.forEach(({ fnname, args }) => sampleRUM[fnname](...args));
});
sampleRUM.always = sampleRUM.always || [];
- sampleRUM.always.on = (chkpnt, fn) => { sampleRUM.always[chkpnt] = fn; };
- sampleRUM.on = (chkpnt, fn) => { sampleRUM.cases[chkpnt] = fn; };
+ sampleRUM.always.on = (chkpnt, fn) => {
+ sampleRUM.always[chkpnt] = fn;
+ };
+ sampleRUM.on = (chkpnt, fn) => {
+ sampleRUM.cases[chkpnt] = fn;
+ };
defer('observe');
defer('cwv');
try {
window.hlx = window.hlx || {};
if (!window.hlx.rum) {
const usp = new URLSearchParams(window.location.search);
- const weight = (usp.get('rum') === 'on') ? 1 : 100; // with parameter, weight is 1. Defaults to 100.
+ const weight = usp.get('rum') === 'on' ? 1 : 100; // with parameter, weight is 1. Defaults to 100.
// eslint-disable-next-line no-bitwise
- const hashCode = (s) => s.split('').reduce((a, b) => (((a << 5) - a) + b.charCodeAt(0)) | 0, 0);
- const id = `${hashCode(window.location.href)}-${new Date().getTime()}-${Math.random().toString(16).substr(2, 14)}`;
+ const hashCode = (s) => s.split('').reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0);
+ const id = `${hashCode(
+ window.location.href,
+ )}-${new Date().getTime()}-${Math.random().toString(16).substr(2, 14)}`;
const random = Math.random();
- const isSelected = (random * weight < 1);
+ const isSelected = random * weight < 1;
const urlSanitizers = {
full: () => window.location.href,
origin: () => window.location.origin,
path: () => window.location.href.replace(/\?.*$/, ''),
};
// eslint-disable-next-line object-curly-newline, max-len
- window.hlx.rum = { weight, id, random, isSelected, sampleRUM, sanitizeURL: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'] };
+ window.hlx.rum = {
+ weight,
+ id,
+ random,
+ isSelected,
+ sampleRUM,
+ sanitizeURL: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'],
+ };
}
const { weight, id } = window.hlx.rum;
if (window.hlx && window.hlx.rum && window.hlx.rum.isSelected) {
const sendPing = (pdata = data) => {
// eslint-disable-next-line object-curly-newline, max-len, no-use-before-define
- const body = JSON.stringify({ weight, id, referer: window.hlx.rum.sanitizeURL(), checkpoint, ...data });
+ const body = JSON.stringify({
+ weight,
+ id,
+ referer: window.hlx.rum.sanitizeURL(),
+ checkpoint,
+ ...data,
+ });
const url = `https://rum.hlx.page/.rum/${weight}`;
// eslint-disable-next-line no-unused-expressions
navigator.sendBeacon(url, body);
@@ -73,9 +92,13 @@ export function sampleRUM(checkpoint, data = {}) {
},
};
sendPing(data);
- if (sampleRUM.cases[checkpoint]) { sampleRUM.cases[checkpoint](); }
+ if (sampleRUM.cases[checkpoint]) {
+ sampleRUM.cases[checkpoint]();
+ }
+ }
+ if (sampleRUM.always[checkpoint]) {
+ sampleRUM.always[checkpoint](data);
}
- if (sampleRUM.always[checkpoint]) { sampleRUM.always[checkpoint](data); }
} catch (error) {
// something went wrong
}
@@ -112,7 +135,7 @@ export async function loadScript(src, attrs) {
const script = document.createElement('script');
script.src = src;
if (attrs) {
- // eslint-disable-next-line no-restricted-syntax, guard-for-in
+ // eslint-disable-next-line no-restricted-syntax, guard-for-in
for (const attr in attrs) {
script.setAttribute(attr, attrs[attr]);
}
@@ -133,7 +156,9 @@ export async function loadScript(src, attrs) {
*/
export function getMetadata(name) {
const attr = name && name.includes(':') ? 'property' : 'name';
- const meta = [...document.head.querySelectorAll(`meta[${attr}="${name}"]`)].map((m) => m.content).join(', ');
+ const meta = [...document.head.querySelectorAll(`meta[${attr}="${name}"]`)]
+ .map((m) => m.content)
+ .join(', ');
return meta || '';
}
@@ -144,7 +169,11 @@ export function getMetadata(name) {
*/
export function toClassName(name) {
return typeof name === 'string'
- ? name.toLowerCase().replace(/[^0-9a-z]/gi, '-').replace(/-+/g, '-').replace(/^-|-$/g, '')
+ ? name
+ .toLowerCase()
+ .replace(/[^0-9a-z]/gi, '-')
+ .replace(/-+/g, '-')
+ .replace(/^-|-$/g, '')
: '';
}
@@ -174,47 +203,62 @@ export async function decorateIcons(element) {
// Download all new icons
const icons = [...element.querySelectorAll('span.icon')];
- await Promise.all(icons.map(async (span) => {
- const iconName = Array.from(span.classList).find((c) => c.startsWith('icon-')).substring(5);
- if (!ICONS_CACHE[iconName]) {
- ICONS_CACHE[iconName] = true;
- try {
- const response = await fetch(`${window.hlx.iconsPath}/${iconName}.svg`);
- if (!response.ok) {
+ await Promise.all(
+ icons.map(async (span) => {
+ const iconName = Array.from(span.classList)
+ .find((c) => c.startsWith('icon-'))
+ .substring(5);
+ if (!ICONS_CACHE[iconName]) {
+ ICONS_CACHE[iconName] = true;
+ try {
+ const response = await fetch(
+ `${window.hlx.iconsPath}/${iconName}.svg`,
+ );
+ if (!response.ok) {
+ ICONS_CACHE[iconName] = false;
+ return;
+ }
+ // Styled icons don't play nice with the sprite approach because of shadow dom isolation
+ // and same for internal references
+ const svg = await response.text();
+ if (svg.match(/(