Skip to content

Commit

Permalink
update exported test and README examples (v6.1.2)
Browse files Browse the repository at this point in the history
  • Loading branch information
JRJurman committed Jan 19, 2025
1 parent 7fac6f1 commit fb3a1df
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 135 deletions.
61 changes: 38 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,44 +23,64 @@ Components, without the addition of APIs that don't already exist.
<script src="https://unpkg.com/tram-deco@6"></script>

<!-- define some web components -->
<template id="componentDefinitions">
<!-- definition for a custom-title tag! -->
<custom-title>
<template id="definitions">
<!-- definition for a custom header tag -->
<header-anchor>
<!-- declarative shadow dom for the insides -->
<template shadowrootmode="open">
<!-- styles, for just this element -->
<style>
h1 {
color: blue;
a {
color: inherit;
}
::slotted(*)::before {
content: '# ';
opacity: 0.3;
}
::slotted(*:hover)::before {
opacity: 0.7;
}
a:not(:hover) {
text-decoration: none;
}
</style>

<!-- dom, to show on the page -->
<h1>
<slot>Hello World</slot>
</h1>
<hr />
<a><slot></slot></a>
</template>

<!-- scripts, that let you define lifecycle methods -->
<script td-method="connectedCallback">
this.shadowRoot.querySelector('slot').addEventListener('slotchange', () => {
document.title = this.textContent || 'Hello World';
});
<!-- scripts, that let you define lifecycle and custom methods -->
<script td-method="constructor">
new MutationObserver(() => {
this.decorateHeader();
}).observe(this, { childList: true });
</script>
</custom-title>
<script td-method="decorateHeader">
this.id = this.textContent.trim().toLowerCase().replace(/\s+/g, '-');
const link = this.shadowRoot.querySelector('a');
link.href = `#${this.id}`;
</script>
</header-anchor>
</template>

<!-- process the template to generate new definitions -->
<script>
TramDeco.processTemplate(componentDefinitions);
TramDeco.processTemplate(definitions);
</script>

<!-- use our new element! -->
<custom-title>Tram-Deco is Cool!</custom-title>
<header-anchor>
<h1>Introduction</h1>
</header-anchor>
This is some introductory content
<header-anchor>
<h2>More Details</h2>
</header-anchor>
If you want to read more, checkout the README.
```

[Live on Codepen](https://codepen.io/JRJurman/pen/mdYbxgw)
[Live on Codepen](https://codepen.io/JRJurman/pen/RwXPqEe)

## How to use

Expand Down Expand Up @@ -92,11 +112,6 @@ Create a template tag with your component definitions, and then use Tram-Deco to

### Export JS Definition

> [!important]
>
> Tram-Deco import depends on `setHTMLUnsafe`, which is a recently released feature. Check
> [caniuse.com](https://caniuse.com/?search=setHTMLUnsafe) to understand browser support and coverage here.
If you want to export your component definition, to be used in other projects, or to organize the components in
different files, you can do the following:

Expand Down
12 changes: 6 additions & 6 deletions example/example.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@ test.describe('Tram-Deco Example Components', () => {
await expect(counterB).toHaveAttribute('count', '12');
await expect(counterB.locator('button')).toHaveText('Counter: 12');

// validate that exported components are rendered as expected
const spoilerTag = page.locator('spoiler-tag');
await expect(spoilerTag.locator('[aria-hidden="true"]')).toBeVisible();
await spoilerTag.click();
await expect(spoilerTag.locator('[aria-hidden="false"]')).toBeVisible();

// validate that button that implements a shadow DOM from a parent with none works as expected
const removableButton = page.locator('red-removable-button#r');
await expect(removableButton).toBeVisible();
Expand All @@ -72,5 +66,11 @@ test.describe('Tram-Deco Example Components', () => {
await expect(decrementingCounter).toHaveAttribute('count', '5');
await decrementingCounter.click();
await expect(decrementingCounter).toHaveAttribute('count', '4');

// validate that exported components work as expected
const introAnchor = page.locator('header-anchor#introduction');
await expect(introAnchor.locator('a')).toHaveAttribute('href', '#introduction');
const detailsAnchor = page.locator('header-anchor#more-details');
await expect(detailsAnchor.locator('a')).toHaveAttribute('href', '#more-details');
});
});
33 changes: 33 additions & 0 deletions example/header-anchor.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<header-anchor>
<template shadowrootmode="open">
<style>
a {
color: inherit;
}
::slotted(*)::before {
content: '# ';
opacity: 0.3;
}
::slotted(*:hover)::before {
opacity: 0.7;
}
a:not(:hover) {
text-decoration: none;
}
</style>

<a><slot></slot></a>
</template>

<script td-method="constructor">
new MutationObserver(() => {
this.decorateHeader();
}).observe(this, { childList: true });
</script>
<script td-method="decorateHeader">
this.id = this.textContent.trim().toLowerCase().replace(/\s+/g, '-');

const link = this.shadowRoot.querySelector('a');
link.href = `#${this.id}`;
</script>
</header-anchor>
66 changes: 22 additions & 44 deletions example/spoiler-tag.js → example/header-anchor.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,39 @@
class TramDeco{static processTemplate(e){[...e.content.children].forEach(e=>{TramDeco.define(e)})}static define(templateElement){const tagName=templateElement.tagName.toLowerCase();class BaseTDElement extends HTMLElement{constructor(e){var t;super(),e&&(this.attachShadow(e),(t=document.createRange()).selectNodeContents(e),this.shadowRoot.append(t.cloneContents()))}}const parentClassName=templateElement.getAttribute("td-extends"),parentClass=customElements.get(parentClassName)||BaseTDElement,modifiedConstructor=templateElement.querySelector('script[td-method="constructor"]');class TDElement extends parentClass{constructor(overrideShadowRoot){super(overrideShadowRoot||templateElement.shadowRoot),eval(modifiedConstructor?.textContent||"")}}templateElement.querySelectorAll("script[td-method]").forEach(lifecycleScript=>{const methodName=lifecycleScript.getAttribute("td-method");TDElement.prototype[methodName]=function(){eval(lifecycleScript.textContent)}}),templateElement.querySelectorAll("script[td-property]").forEach(propertyScript=>{const propertyName=propertyScript.getAttribute("td-property");Object.defineProperty(TDElement,propertyName,{get:function(){return eval(propertyScript.textContent)}})}),customElements.define(tagName,TDElement)}}

const importTemplate = document.createElement('template')
importTemplate.setHTMLUnsafe(`<spoiler-tag>
<template shadowrootmode="open" delegatesfocus>
importTemplate.setHTMLUnsafe(`<header-anchor>
<template shadowrootmode="open">
<style>
span[aria-expanded='false'] {
display: inline-block;
position: relative;
&::after {
background: black;
border-radius: 0.5em;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
content: '';
}
}
span[aria-expanded='true'] {
a {
color: inherit;
background: inherit;
cursor: inherit;
}
::slotted(*)::before {
content: '# ';
opacity: 0.3;
}
::slotted(*:hover)::before {
opacity: 0.7;
}
a:not(:hover) {
text-decoration: none;
}
</style>
<span part="control" role="button" aria-label="Spoiler" tabindex="0" aria-expanded="false">
<span part="content" role="presentation" aria-hidden="true">
<slot></slot>
</span>
</span>
<a><slot></slot></a>
</template>
<script td-method="constructor">
this.control = this.shadowRoot.querySelector('[part="control"]');
this.content = this.shadowRoot.querySelector('[part="content"]');
this.reveal = () => {
this.control.ariaLabel = null;
this.control.role = 'presentation';
this.control.tabIndex = -1;
this.content.ariaHidden = 'false';
this.control.ariaExpanded = 'true';
};
new MutationObserver(() => {
this.decorateHeader();
}).observe(this, { childList: true });
</script>
<script td-method="decorateHeader">
this.id = this.textContent.trim().toLowerCase().replace(/\\s+/g, '-');
<script td-method="connectedCallback">
this.control.addEventListener('click', this.reveal, { once: true });
this.control.addEventListener('keydown', (event) => {
if (event.key === ' ' || event.key === 'Enter') {
this.reveal();
}
});
const link = this.shadowRoot.querySelector('a');
link.href = \`#\${this.id}\`;
</script>
</spoiler-tag>
</header-anchor>
`)

TramDeco.processTemplate(importTemplate);
Expand Down
14 changes: 11 additions & 3 deletions example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,8 @@ <h1>
</script>

<!-- import definition from external file -->
<!-- this definition must be built using `npx tram-deco export-components ./spoiler-tag.html` -->
<script src="./spoiler-tag.js"></script>
<!-- this definition must be built using `npx tram-deco export-components ./header-anchor.html` -->
<script src="./header-anchor.js"></script>

<!-- include the defined components in the main HTML body -->
<custom-title>Tram-Deco is Cool!</custom-title>
Expand All @@ -184,4 +184,12 @@ <h1>
<span slot="title">Import Alert</span>
<span>The following spoiler only works on browsers that support <code>setHTMLUnsafe</code></span>
</callout-alert>
This is some <spoiler-tag>mystery</spoiler-tag> content.

<header-anchor>
<h1>Introduction</h1>
</header-anchor>
This is some introductory content
<header-anchor>
<h2>More Details</h2>
</header-anchor>
If you want to read more, checkout the README.
55 changes: 0 additions & 55 deletions example/spoiler-tag.html

This file was deleted.

4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tram-deco",
"version": "6.1.1",
"version": "6.1.2",
"description": "Declarative Custom Elements using native Web Component APIs and specs",
"main": "tram-deco.js",
"files": [
Expand All @@ -15,7 +15,7 @@
"start": "serve . -p 3000",
"prepublishOnly": "npm run build",
"build": "uglifyjs tram-deco.js -o tram-deco.min.js -c -m",
"test-export": "node scripts/export-components.js example/spoiler-tag.html -o example/spoiler-tag.js",
"test-export": "node scripts/export-components.js example/header-anchor.html -o example/header-anchor.js",
"pretest": "npm run build && npm run test-export",
"test": "playwright test --ui",
"test:ci": "playwright test"
Expand Down

0 comments on commit fb3a1df

Please sign in to comment.