Skip to content
This repository has been archived by the owner on Dec 6, 2022. It is now read-only.

Commit

Permalink
first commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
jthoms1 committed May 16, 2018
1 parent 93aee0a commit 2df8119
Show file tree
Hide file tree
Showing 44 changed files with 8,620 additions and 3 deletions.
15 changes: 15 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# http://editorconfig.org

root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2018 Ionic
Copyright (c) 2017 Ionic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
98 changes: 96 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,96 @@
# stencil-state-tunnel
A tool for tunneling state/props down through a component stack.
![Built With Stencil](https://img.shields.io/badge/-Built%20With%20Stencil-16161d.svg?logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE5LjIuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9IkxheWVyXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IgoJIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA1MTIgNTEyOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI%2BCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI%2BCgkuc3Qwe2ZpbGw6I0ZGRkZGRjt9Cjwvc3R5bGU%2BCjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik00MjQuNywzNzMuOWMwLDM3LjYtNTUuMSw2OC42LTkyLjcsNjguNkgxODAuNGMtMzcuOSwwLTkyLjctMzAuNy05Mi43LTY4LjZ2LTMuNmgzMzYuOVYzNzMuOXoiLz4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTQyNC43LDI5Mi4xSDE4MC40Yy0zNy42LDAtOTIuNy0zMS05Mi43LTY4LjZ2LTMuNkgzMzJjMzcuNiwwLDkyLjcsMzEsOTIuNyw2OC42VjI5Mi4xeiIvPgo8cGF0aCBjbGFzcz0ic3QwIiBkPSJNNDI0LjcsMTQxLjdIODcuN3YtMy42YzAtMzcuNiw1NC44LTY4LjYsOTIuNy02OC42SDMzMmMzNy45LDAsOTIuNywzMC43LDkyLjcsNjguNlYxNDEuN3oiLz4KPC9zdmc%2BCg%3D%3D&colorA=16161d&style=flat-square)

# Stencil State Tunnel

This project was built to provide additional functionality to developers working with stencil
components and sharing state across components and through slots.

## Example Usage

1. First we will create a Tunnel.

`./data/message.ts`

```tsx
import { createProviderConsumer } from '@stencil/state-tunnel';

export interface State {
message: string,
increment?: () => void
}

export default createProviderConsumer<State>({
message: 'Hello!'
});
```

2. Create a tunnel entry point. Usually this will be at the top of your component tree.

`./components/my-app.tsx`
```tsx
import Tunnel from './data/message.ts';

@Component({
tag: 'my-app',
})
export class MyApp {

@Prop() intro: string = 'Hello!';
@State() message: string = '';

count: number = 0;

componentWillLoad() {
this.increment();
}

increment = () => {
this.count = this.count + 1;
this.message = `${this.intro} ${this.count}`;
}

render() {
const state = {
message: this.message,
increment: this.increment
};
return (
<div>
<header>
<h1>Stencil App Starter</h1>
</header>
<Tunnel.Provider state={state}>
<some-child-component/>
</Tunnel.Provider>
</div>
);
}
}
```

3. You can then create an exit point any where within your component tree that lives below the Tunnel.Provider.

`./components/way-down-child.tsx`
```tsx
import { Component } from '@stencil/core';
import Tunnel from './data/message.ts';

@Component({
tag: 'way-down-child',
})
export class WayDownChild {
render() {
return (
<Tunnel.Consumer>
{({ message, increment }) => (
<div class='app-profile'>
<button onClick={increment}>Increment Num</button>
<p>{message}</p>
</div>
)}
</Tunnel.Consumer>
);
}
}

```
41 changes: 41 additions & 0 deletions dist/collection/collection-manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"components": [
{
"tag": "context-consumer",
"dependencies": [],
"componentClass": "ContextConsumer",
"componentPath": "components/state-tunnel/state-tunnel.js",
"styles": {},
"props": [
{
"name": "context",
"attr": "context"
},
{
"name": "renderer",
"type": "Any",
"attr": "renderer"
},
{
"name": "subscribe",
"attr": "subscribe"
}
],
"states": [
{
"name": "unsubscribe"
}
],
"hostElement": {
"name": "el"
}
}
],
"collections": [],
"compiler": {
"name": "@stencil/core",
"version": "0.9.0",
"typescriptVersion": "2.8.3"
},
"bundles": []
}
102 changes: 102 additions & 0 deletions dist/collection/components/state-tunnel/state-tunnel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0)
t[p[i]] = s[p[i]];
return t;
};
export class ContextConsumer {
constructor() {
this.context = {};
this.renderer = (props) => {
props;
return null;
};
}
componentWillLoad() {
this.unsubscribe = this.subscribe(this.el, 'context');
}
componentDidUnload() {
this.unsubscribe();
}
render() {
return this.renderer(Object.assign({}, this.context));
}
static get is() { return "context-consumer"; }
static get properties() { return {
"context": {
"type": "Any",
"attr": "context"
},
"el": {
"elementRef": true
},
"renderer": {
"type": "Any",
"attr": "renderer"
},
"subscribe": {
"type": "Any",
"attr": "subscribe"
},
"unsubscribe": {
"state": true
}
}; }
}
export function createProviderConsumer(defaultState) {
let listeners = new Map();
let currentState = defaultState;
function notifyConsumers() {
listeners.forEach(updateListener);
}
function updateListener(fields, listener) {
if (Array.isArray(fields)) {
[...fields].forEach(fieldName => {
listener[fieldName] = currentState[fieldName];
});
}
else {
listener[fields] = Object.assign({}, currentState);
}
listener.forceUpdate();
}
function attachListener(propList) {
return (el) => {
if (listeners.has(el)) {
return;
}
listeners.set(el, propList);
updateListener(propList, el);
};
}
function subscribe(el, propList) {
attachListener(propList)(el);
return function () {
listeners.delete(el);
};
}
function Provider({ state, children }) {
currentState = state;
notifyConsumers();
return children;
}
function Consumer({ children }) {
return (h("context-consumer", { subscribe: subscribe, renderer: children[0] }));
}
function wrapConsumer(childComponent, fieldList) {
const Child = childComponent.is;
return (_a) => {
var { children } = _a, props = __rest(_a, ["children"]);
return (h(Child, Object.assign({ ref: attachListener(fieldList) }, props), children));
};
}
return {
Provider,
Consumer,
wrapConsumer,
subscribe
};
}
2 changes: 2 additions & 0 deletions dist/collection/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './components';
export * from './components/state-tunnel/state-tunnel';
Empty file added dist/collection/interface.js
Empty file.
2 changes: 2 additions & 0 deletions dist/esm/es5/grx7pc1a.js

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

3 changes: 3 additions & 0 deletions dist/esm/es5/mycomponent.components.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// mycomponent: Host Data, ES Module/ES5 Target

export var ContextConsumer = ["context-consumer",function(){return(import("./grx7pc1a.js")).then(function(m){return m.ContextConsumer})},0,[["context",1],["el",7],["renderer",1,0,1,1],["subscribe",1],["unsubscribe",5]]];
5 changes: 5 additions & 0 deletions dist/esm/es5/mycomponent.core.js

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions dist/esm/es5/mycomponent.define.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// mycomponent: Custom Elements Define Library, ES Module/ES5 Target
import { defineCustomElement } from './mycomponent.core.js';
import {
ContextConsumer
} from './mycomponent.components.js';

export function defineCustomElements(window, opts) {
defineCustomElement(window, [
ContextConsumer
], opts);
}
3 changes: 3 additions & 0 deletions dist/esm/es5/mycomponent.global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/*! Built with http://stenciljs.com */
export default function appGlobal(namespace, Context, window, document, resourcesUrl, hydratedCssClass) {
}
12 changes: 12 additions & 0 deletions dist/esm/es5/polyfills/array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function applyPolyfill(window, document) {
/*!
Array.prototype.find
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
*/
Array.prototype.find||Object.defineProperty(Array.prototype,"find",{writable:!0,configurable:!0,value:function(c,e){if(null==this)throw new TypeError('"this" is null or not defined');var b=Object(this),f=b.length>>>0;if("function"!==typeof c)throw new TypeError("predicate must be a function");for(var a=0;a<f;){var d=b[a];if(c.call(e,d,a,b))return d;a++}}});
/*!
Array.prototype.includes
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
*/
Array.prototype.includes||Object.defineProperty(Array.prototype,"includes",{writable:!0,configurable:!0,value:function(r,e){if(null==this)throw new TypeError('"this" is null or not defined');var t=Object(this),n=t.length>>>0;if(0===n)return!1;var i,o,a=0|e,u=Math.max(0<=a?a:n-Math.abs(a),0);for(;u<n;){if((i=t[u])===(o=r)||"number"==typeof i&&"number"==typeof o&&isNaN(i)&&isNaN(o))return!0;u++}return!1}});
}
Loading

0 comments on commit 2df8119

Please sign in to comment.