Skip to content

Commit

Permalink
[update]
Browse files Browse the repository at this point in the history
  • Loading branch information
木瓜丸 committed Dec 20, 2020
1 parent 6bb9a7e commit 7126542
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 112 deletions.
33 changes: 12 additions & 21 deletions examples/src/main.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
import {Component, ProviderComponent, Dispatcher, html} from '../../main.js';
import styles from './style.css';

class MainDispatcher extends Dispatcher {
class MainComponent extends ProviderComponent {
static get styles() {
return [styles];
}
get providerId() {
return 'main';
}
init() {
return {
select: 0,
sounds: new Array(16).fill(0),
name: 'label'
}
}
async select(state, i) {
async select({state}, i) {
return new Promise((resolve, reject) => {
setTimeout(_ => {
state.select = i;
Expand All @@ -18,16 +24,7 @@ class MainDispatcher extends Dispatcher {
}, i*1000);
});
}
}

class MainComponent extends ProviderComponent {
static get dispatcher() {
return MainDispatcher;
}
static get styles() {
return [styles];
}
render(state, dispatch){
render({state, dispatch}){
return html`
<div id="title">
</div>
Expand All @@ -46,22 +43,16 @@ class MainComponent extends ProviderComponent {
}
}

class SubDispatcher extends Dispatcher {
class SubComponent extends Component {
init() {
return {
status: 0
};
}
}

class SubComponent extends Component {
static get dispatcher() {
return SubDispatcher;
}
render(state) {
render({state, $ctx}) {
return html`
<style> :host([selected]) { color: tomato; } </style>
<div>${state.$context.sounds[this.dataset.id]}</div>
<div>${$ctx('main').state.sounds[this.dataset.id]}</div>
`;
}
}
Expand Down
111 changes: 42 additions & 69 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,105 +28,70 @@ export function html(strings, ...values){
return new RawHTMLTagFuncOutput(strings, values)
}

export class Dispatcher extends Function {
constructor(element, store) {
super();
this.element = element;
this.store = store;
return new Proxy(this, {
apply(target, thisArg, args) {
return target.dispatch(...args);
}
});
}
async dispatch(action, ...args) {
this.store.update(await this[action](this.store.proxy(), ...args));
}
init(){
return {}
}
updatecontext(state){
return {...state}
}
prop(key, default_value){
return this.element[key] ? this.element[key] : default_value;
}
attr(key, default_value){
return this.element.hasAttribute(key) ? this.element.getAttribute(key) : default_value;
}
proxy() {
return new Proxy(this, {
get: (target, prop, receiver) => {
if(prop == '$context'){
return this.element.context ? this.element.context.dispatcher.proxy() : null;
}
return Reflect.get(target, prop, receiver);
}
});
}
}

export class Store{
constructor(element, state = {}) {
this.context = null;
this.state = state;
this.element = element;
}
setContext(store) {
this.context = store;
}
update(state) {
this.state = state;
this.element.update();
}
proxy() {
return new Proxy(this.state, {
get: (target, prop, receiver) => {
if(prop == '$context'){
return this.element.context ? this.element.context.store.proxy() : null;
}
return Reflect.get(target, prop, receiver);
}
});
}
}

export class Component extends HTMLElement{
static get dispatcher() { return Dispatcher; }
constructor() {
super();
this.store = new Store(this);
this.dispatcher = new this.constructor.dispatcher(this, this.store);
this.context = {};
this.attachShadow({mode: 'open'});
}
static get styles() {
return [];
}
async connectedCallback(){
await this.dispatcher('init');
await this.dispatch('init');
if(this.afterFirstUpdate) this.afterFirstUpdate();
}
updatecontext(state){
return {...state}
}
$ctx(contextId) {
return this.context[contextId];
}
setContext(template) {
const walker = document.createTreeWalker(template);
while(walker.nextNode()){
walker.currentNode.context = this.context;
if(walker.currentNode.childNodes.length > 0){
this.setContext(walker.currentNode);
}
if(walker.currentNode instanceof Component) {
for(const k of Object.keys(this.context)){
walker.currentNode.context[k] = this.context[k];
}
walker.currentNode.setContext(walker.currentNode.shadowRoot);
}
if(walker.currentNode.childNodes.length > 0){
this.setContext(walker.currentNode);
}
}
}
get $contextStore() {
return this.context.store.proxy();
get state() {
return this.store.state;
}
get $contextDispatch() {
return this.context.dispatch.proxy();
async dispatch(action, ...args) {
this.store.update(await this[action]({
...this,
state: this.state,
$ctx: contextId => this.context[contextId],
dispatch: (..._args) => Reflect.apply(this.dispatch, this, args)
}, ...args));
}
render(){ return html``; }
async update(){
const {strings, values} = this.render(this.store.proxy(), this.dispatcher.proxy());
const {strings, values} = this.render({
...this,
state: this.state,
$ctx: contextId => this.context[contextId],
dispatch: (...args) => Reflect.apply(this.dispatch, this, args)
})
if(this.template == null) {
this.template = new Template(strings);
this.shadowRoot.appendChild(this.template.fragment);
Expand All @@ -150,16 +115,24 @@ export class Component extends HTMLElement{
}

export class ProviderComponent extends Component {
get providerId() {
return this.hasAttribute('provider-id')
? this.getAttribute('provider-id')
: undefined;
}
set providerId(value) {
this.setAttribute('provider-id', value);
}
setContext(template) {
const walker = document.createTreeWalker(template);
while(walker.nextNode()){
walker.currentNode.context = this;
if(walker.currentNode.childNodes.length > 0){
this.setContext(walker.currentNode);
}
if(walker.currentNode instanceof Component) {
walker.currentNode.context[this.providerId] = this;
walker.currentNode.setContext(walker.currentNode.shadowRoot);
}
if(walker.currentNode.childNodes.length > 0){
this.setContext(walker.currentNode);
}
}
}
}
Expand Down Expand Up @@ -286,7 +259,7 @@ class ValueArray {
const walker = document.createTreeWalker(tmp.fragment);
while(walker.nextNode()) {
if(walker.currentNode instanceof Component) {
walker.currentNode.dispatcher('updatecontext');
walker.currentNode.dispatch('updatecontext');
}
}
}
Expand Down
33 changes: 11 additions & 22 deletions omusubi.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,47 +9,36 @@ declare module 'omusubi-js' {
export function defineComponent(tagname: string, options?: ElementDefinitionOptions): (wrapped: typeof Component) => void;

export function html(strings: string[], values: string[]): new () => RawHTMLTagFuncOutput;

export class Dispatcher extends Function {
constructor(element: unknown, store: unknown);

dispatch(action: string, ...args: string[]): Promise<void>;

init(): void;

prop(key: string, default_value: string): string;

attr(key: string, default_value: string): string;

updatecontext(state: unknown): object;

proxy(): object;
}

export class Store<T extends object> {
constructor(element: unknown, state?: T);

setContext(store: unknown): void;

update(state: T): void;

proxy(): object;
}

export class Component extends HTMLElement {
static dispatcher: typeof Dispatcher;
static styles: unknown[];

state: object;

dispatch(action: string, ...args: unknown[]): Promise<void>;

connectedCallback(): Promise<void>;

$ctx(contextId: string): ProviderComponent;

updatecontext(state: object): object;

setContext(template: Template): void;

render(state: object, dispatch: unknown): new () => RawHTMLTagFuncOutput;
render(props: object): new () => RawHTMLTagFuncOutput;

update(): Promise<void>;
}

export class ProviderComponent extends Component {
providerId: string;

setContext(template: Template): void;
}

Expand Down

0 comments on commit 7126542

Please sign in to comment.