Skip to content

Commit

Permalink
tl-provider and tl-context components (v5.1.0, #63)
Browse files Browse the repository at this point in the history
  • Loading branch information
JRJurman authored Jan 1, 2024
1 parent 15b462c commit 5792eca
Show file tree
Hide file tree
Showing 13 changed files with 336 additions and 24 deletions.
1 change: 1 addition & 0 deletions build.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const classFiles = [
'src/processors/ControlledInput.js',
'src/processors/AttrBroadcaster.js',
'src/processors/EventRebroadcaster.js',
'src/processors/ContextConsumer.js',
'src/ComponentDefinition.js',
];
const loadedClassFiles = Object.fromEntries(
Expand Down
14 changes: 4 additions & 10 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
<a href="#tl-definition"><code>tl-definition</code></a>
<a href="#tl-controlled"><code>tl-controlled</code></a>
<a href="#tl-effect"><code>tl-effect</code></a>
<a href="#tl-context"><code>tl-context</code></a>
<a href="#tl-provider"><code>tl-provider</code></a>
<a href="#tl-broadcast"><code>tl-broadcast</code></a>
<a href="#tl-rebroadcast"><code>tl-rebroadcast</code></a>
</side-nav-section>
Expand All @@ -117,6 +119,8 @@
<page id="tl-rebroadcast"><html-import src="./pages/html-tl-rebroadcast.html"></html-import></page>
<page id="tl-controlled"><html-import src="./pages/html-tl-controlled.html"></html-import></page>
<page id="tl-effect"><html-import src="./pages/html-tl-effect.html"></html-import></page>
<page id="tl-context"><html-import src="./pages/html-tl-context.html"></html-import></page>
<page id="tl-provider"><html-import src="./pages/html-tl-provider.html"></html-import></page>
<page id="define"><html-import src="./pages/js-define.html"></html-import></page>
<page id="addAttributeListener"><html-import src="./pages/js-addAttributeListener.html"></html-import></page>
<page id="broadcastEvent"><html-import src="./pages/js-broadcastEvent.html"></html-import></page>
Expand All @@ -130,15 +134,5 @@
<page id="migration-guide"><html-import src="./pages/migration-guide.html"></html-import></page>
<page id="micro-guide"><html-import src="./pages/micro-guide.html"></html-import></page>
</main>

<script>
// because of a lack of :has pseudo-selector support, sometimes we can end up with the main page having no content!
// for now, we'll always redirect to the about page, but once we have that :has support, we can remove this
document.addEventListener('DOMContentLoaded', function (event) {
if (!window.location.hash) {
window.location.hash = 'about';
}
});
</script>
</body>
</html>
25 changes: 22 additions & 3 deletions docs/pages/about.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,34 @@ <h2>HTML API</h2>
<a href="#tl-effect"><code>tl-effect</code></a>
</dt>
<dd><p>Attribute for building attribute driven side-effects in web-components.</p></dd>
<dt>
<a href="#tl-rebroadcast"><code>tl-rebroadcast</code></a>
</dt>
<dd><p>Attribute for emitting events when another event is triggered on an element.</p></dd>
</dl>
<p>
Additionally, Tram-Lite also has a set of custom elements that can be used in web components to enhance their
behavior.
<dt>
<a href="#tl-broadcast"><code>tl-broadcast</code></a>
</dt>
<dd><p>Custom Element for emitting events when an attribute updates in a web-component.</p></dd>
<dt>
<a href="#tl-rebroadcast"><code>tl-rebroadcast</code></a>
<a href="#tl-context"><code>tl-context</code></a>
</dt>
<dd><p>Attribute for emitting events when another event is triggered on an element.</p></dd>
</dl>
<dd>
<p>Custom Element for pulling state down from a <tag-code tag="tl-provider"></tag-code>.</p>
</dd>
<dt>
<a href="#tl-provider"><code>tl-provider</code></a>
</dt>
<dd>
<p>
Custom Element (can live in the shadow or light DOM), that can provide state to web-components with a
<tag-code tag="tl-context"></tag-code> element.
</p>
</dd>
</p>

<h2>Javascript API</h2>
<dl>
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/html-tl-broadcast.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<h2><code>tl-broadcast</code></h2>
<section>
<p>
<code>tl-broadcast</code> is a custom element that lets you dispatch events up or down the tree when a
web-component's attributes update.
<tag-code tag="tl-broadcast"></tag-code> is a custom element that lets you dispatch events up or down the tree when
a web-component's attributes update.
</p>
<p>
<code-template-html>
Expand Down
117 changes: 117 additions & 0 deletions docs/pages/html-tl-context.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
<h2><code>tl-context</code></h2>
<section>
<p>
<tag-code tag="tl-context"></tag-code> is a custom element that pulls the attributes from a
<tag-code tag="tl-provider"></tag-code> parent, and maps it to attributes in your web-component. The main purpose is
to share state across multiple components without depending on prop-drilling or sending state via events.
</p>
<p>
<code-template-html>
<template>
<!-- component definition -->
<template tl-definition>
<text-preview>
<tl-context tl-name="font-size"></tl-context>
<div style="font-size: ${'size'}">
<slot></slot>
</div>
</text-preview>
</template>

<!-- main HTML -->
<tl-provider tl-name="font-size" size="1em">
<text-preview>This is some text content</text-preview>
</tl-provider>
</template>
</code-template-html>
</p>
</section>
<section>
<h2>Syntax</h2>
<p>
<code-template-html>
<template>
<tl-context tl-name="provider-name" tl-attrmap="provider-attribute:host-attribute"></tl-context>
</template>
</code-template-html>
</p>
<h3>Parameters</h3>
<dl>
<dt><code>tl-name</code></dt>
<dd>
<p>The name of the provider to pull context values from.</p>
</dd>
<dt><code>tl-attrmap</code> <optional-badge>optional</optional-badge></dt>
<dd>
<p>
Mapping of provider element's state (<code>provider-attribute</code>) to an attribute name that will be on the
host web-component (<code>host-attribute</code>), defaults to all the user-defined attributes on the provider
mapped to their same name. Can be multiple values (space delimited).
</p>
</dd>
</dl>
</section>
<section>
<h2>Custom Web Components</h2>
<p>
If you'd like to use this api with components that aren't defined in Tram-Lite, you can use the Javascript API to
apply it to a class using <code>TramLite.appendShadowRootProcessor</code>

<code-template-html>
<template>
<script src="https://unpkg.com/tram-lite@5"></script>
<script>
TramLite.appendShadowRootProcessor('tl-context', ContextConsumer, MyWebComponentClass);
</script>
</template>
</code-template-html>
</p>
</section>
<section>
<h2>Live Example</h2>
<div
class="codepen"
data-height="300"
data-theme-id="dark"
data-default-tab="html,result"
data-editable="true"
data-prefill="{}"
>
<pre data-lang="html">
&lt;script src="https://unpkg.com/tram-lite@5">&lt;/script>

&lt;!-- component definitions -->
&lt;template tl-definition>

&lt;!-- example component definition -->
&lt;font-toggle>
&lt;tl-context tl-name="font-size">&lt;/tl-context>
&lt;label>
Font Size
&lt;select tl-controlled tl-attrmap="value:size">
&lt;option value="0.8em">Small&lt;/option>
&lt;option value="1em">Medium&lt;/option>
&lt;option value="1.2em">Large&lt;/option>
&lt;/select>
&lt;/label>
&lt;/font-toggle>

&lt;text-preview>
&lt;tl-context tl-name="font-size">&lt;/tl-context>
&lt;div style="font-size: ${'size'}">
&lt;slot>&lt;/slot>
&lt;/div>
&lt;/text-preview>

&lt;/template>

&lt;!-- HTML Page -->
&lt;tl-provider tl-name="font-size" size="1em">
&lt;font-toggle>&lt;/font-toggle>
&lt;text-preview>This is a text preview&lt;/text-preview>
&lt;/tl-provider></pre
>
</div>

<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
</section>
8 changes: 4 additions & 4 deletions docs/pages/html-tl-controlled.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ <h2>Syntax</h2>
<p>
<code-template-html>
<template>
<input tl-controlled tl-attrmap="attribute:reference" tl-trigger="eventName" />
<input tl-controlled tl-attrmap="input-attribute:host-attribute" tl-trigger="eventName" />
</template>
</code-template-html>
</p>
Expand All @@ -31,9 +31,9 @@ <h3>Parameters</h3>
<dt><code>tl-attrmap</code> <optional-badge>optional</optional-badge></dt>
<dd>
<p>
Mapping of target element's state (<code>attribute</code>) to an attribute name that will be on the host
web-component (<code>reference</code>), defaults to <code>"value:value"</code>. Can be multiple values (space
delimited).
Mapping of input element's state (<code>input-attribute</code>) to an attribute name that will be on the host
web-component (<code>host-attribute</code>), defaults to <code>"value:value"</code>. Can be multiple values
(space delimited).
</p>
</dd>
<dt><code>tl-trigger</code> <optional-badge>optional</optional-badge></dt>
Expand Down
32 changes: 32 additions & 0 deletions docs/pages/html-tl-provider.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<h2><code>tl-provider</code></h2>
<section>
<p>
<tag-code tag="tl-provider"></tag-code> is a custom Element that can provide state to multiple
<tag-code tag="tl-context"></tag-code> elements. <tag-code tag="tl-provider"></tag-code> can live in the shadow or
light DOM.
</p>
</section>
<section>
<h2>Syntax</h2>
<p>
<code-template-html>
<template>
<tl-provider tl-name="provider-name" custom-attributes></tl-provider>
</template>
</code-template-html>
</p>
<h3>Parameters</h3>
<dl>
<dt><code>tl-name</code></dt>
<dd>
<p>Name to match with <tag-code tag="tl-context"></tag-code> tag.</p>
</dd>
<dt><code>custom-attributes</code> <optional-badge>optional</optional-badge></dt>
<dd>
<p>
User defined attributes to make available to components that use <tag-code tag="tl-context"></tag-code>. Can be
boolean or string values. No specific prefix is required.
</p>
</dd>
</dl>
</section>
33 changes: 33 additions & 0 deletions examples/inline/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,31 @@ <h1 style="font-size: 1em">Title: <slot></slot></h1>
}
</script>
</in-progressbar>

<in-start-color-setter>
<tl-context tl-name="color-theme" tl-attrmap="start-color:color"></tl-context>
<input type="color" tl-controlled tl-attrmap="value:color" tl-trigger="input" />
</in-start-color-setter>
<in-end-color-setter>
<tl-context tl-name="color-theme" tl-attrmap="end-color:color"></tl-context>
<input type="color" tl-controlled tl-attrmap="value:color" tl-trigger="input" />
</in-end-color-setter>
<in-color-preview>
<tl-context tl-name="color-theme"></tl-context>
<style>
div {
width: 120px;
height: 60px;
margin: 5px;
background: linear-gradient(${'degrees'}deg, ${'start-color'}, ${'end-color'});
}
</style>
<div></div>
</in-color-preview>
<in-direction-setter>
<tl-context tl-name="color-theme"></tl-context>
<input type="range" min="0" max="360" tl-controlled tl-attrmap="value:degrees" tl-trigger="input" />
</in-direction-setter>
</template>

<in-title>Tram-Lite Components!</in-title>
Expand All @@ -306,5 +331,13 @@ <h1 style="font-size: 1em">Title: <slot></slot></h1>
<in-container name="Progress Bar">
<in-progressbar></in-progressbar>
</in-container>
<in-container name="Gradient Builder">
<tl-provider tl-name="color-theme" start-color="#E66465" end-color="#9198E5" degrees="0">
<in-start-color-setter></in-start-color-setter>
<in-end-color-setter></in-end-color-setter>
<in-direction-setter></in-direction-setter>
<in-color-preview></in-color-preview>
</tl-provider>
</in-container>
</body>
</html>
20 changes: 20 additions & 0 deletions examples/inline/inline.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,25 @@ describe('Tram-Lite Example Components', () => {
cy.get('in-progressbar').should('have.attr', 'warning');
cy.get('in-progressbar').find('input#max').clear().type('15');
cy.get('in-progressbar').should('not.have.attr', 'warning');

/* verify that components pull initial state from providers */
cy.get('tl-provider[tl-name="color-theme"]').find('in-start-color-setter').should('have.attr', 'color', '#E66465');
cy.get('tl-provider[tl-name="color-theme"]').find('in-end-color-setter').should('have.attr', 'color', '#9198E5');
cy.get('tl-provider[tl-name="color-theme"]').find('in-direction-setter').should('have.attr', 'degrees', '0');
cy.get('tl-provider[tl-name="color-theme"]')
.find('in-color-preview')
.should('have.attr', 'start-color', '#E66465')
.should('have.attr', 'end-color', '#9198E5')
.should('have.attr', 'degrees', '0');

/* verify that components update when provider state updates */
cy.get('tl-provider[tl-name="color-theme"]').invoke('attr', 'degrees', '45');
cy.get('tl-provider[tl-name="color-theme"]').find('in-direction-setter').should('have.attr', 'degrees', '45');
cy.get('tl-provider[tl-name="color-theme"]').find('in-color-preview').should('have.attr', 'degrees', '45');

/* verify that provider updates when component (with context) updates */
cy.get('tl-provider[tl-name="color-theme"]').find('in-direction-setter').invoke('attr', 'degrees', '90');
cy.get('tl-provider[tl-name="color-theme"]').should('have.attr', 'degrees', '90');
cy.get('tl-provider[tl-name="color-theme"]').find('in-color-preview').should('have.attr', 'degrees', '90');
});
});
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.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "tram-lite",
"version": "5.0.0",
"version": "5.1.0",
"description": "💡 HTML library for building and enhancing web-components",
"homepage": "https://tram-one.io/tram-lite/",
"repository": "https://github.com/Tram-One/tram-lite",
Expand Down
4 changes: 2 additions & 2 deletions src/ComponentDefinition.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class ComponentDefinition {

/**
* function to test if node has an attribute value with a template variable
* e.g. <custom-element style="color: ${'color'}">
* e.g. \<custom-element style="color: ${'color'}"\>
*/
static nodeHasTramLiteAttr = (node) =>
[...node.attributes].some((attr) => attr.value.match(ComponentDefinition.templateVariableRegex))
Expand All @@ -19,7 +19,7 @@ class ComponentDefinition {

/**
* function to test if node has an TEXT node with a template variable
* e.g. <custom-element>Hello ${'name'}</custom-element>
* e.g. \<custom-element\>Hello ${'name'}\</custom-element\>
*/
static nodeHasTextElementWithTramLiteAttr = (node) =>
node.textContent.match(ComponentDefinition.templateVariableRegex)
Expand Down
Loading

0 comments on commit 5792eca

Please sign in to comment.