From c0b53911f6017649186a23fa08aaf3e88dc1f31b Mon Sep 17 00:00:00 2001 From: Maxi Cespedes Date: Mon, 20 Dec 2021 22:13:33 +0100 Subject: [PATCH] fisis --- README.md | 18 +++++- cumbia.d.ts | 71 +++++++++++++-------- cumbia.js | 23 ++++++- example/counter/components/todo/messages.ts | 7 ++ example/counter/components/todo/todo.js | 11 ++++ example/counter/components/todo/todoList.js | 13 ++++ example/counter/index.html | 16 +++++ example/counter/index.js | 5 +- src/_version.ts | 2 +- src/actionParser/data-action.ts | 3 +- src/core/pubsub.ts | 6 +- src/cumbia.ts | 14 +++- src/utils/components/debug.ts | 46 +++++++++++++ src/utils/message.ts | 6 +- 14 files changed, 201 insertions(+), 40 deletions(-) create mode 100644 example/counter/components/todo/messages.ts create mode 100644 example/counter/components/todo/todo.js create mode 100644 example/counter/components/todo/todoList.js create mode 100644 src/utils/components/debug.ts diff --git a/README.md b/README.md index 548981e..ce80956 100644 --- a/README.md +++ b/README.md @@ -84,12 +84,28 @@ To let Cumbia know what to do with the HTML element we can pass an object with s - By default the event listener attached is based on `click` events. - For `input` elements the event listener attached is `change`. - - For `form` the name of the data-action MUST BE `submit` and it'll attach the event listener to the HTML form. + - For `form` the name of the data-action **MUST BE `submit`** and it'll attach the event listener to the HTML form. - `data-action-key` will attach `keyup` event listener to the action elements. When calling the action defined in your JS component, cumbia will give you the list of all the values parsed, including the elements. +### Global Initialisers +In case you need to interact with all data-components after initialising the process you can provide an argument to cumbia. This might be useful to log or check something in every component. +#### Debugger +```javascript +import cumbia, { debug } from 'cumbia'; + +// Define your component +const component = ({ el }) => { + +}; + +// Call the power of the Cumbia +cumbia([component], { + globalInitalisers: [debug] +}); +``` \ No newline at end of file diff --git a/cumbia.d.ts b/cumbia.d.ts index ce81613..7133124 100644 --- a/cumbia.d.ts +++ b/cumbia.d.ts @@ -1,15 +1,23 @@ -declare module "_version" { - export const version = "0.0.5"; +declare module "example/counter/components/todo/messages" { + export enum MESSAGES { + ADD_TODO = "ADD_TODO" + } + export type MESSAGES_TYPE = { + [MESSAGES.ADD_TODO]: string; + }; +} +declare module "src/_version" { + export const version = "0.0.6"; } -declare module "utils/message" { +declare module "src/utils/message" { const _default: { - error: (msg: string) => void; - warn: (msg: string) => void; - info: (msg: string) => void; + error: (msg: any) => void; + warn: (msg: any) => void; + info: (msg: any) => void; }; export default _default; } -declare module "types/cumbiaTypes" { +declare module "src/types/cumbiaTypes" { type Initialisers = (elements: Array) => void; type GlobalInitialisers = Array; export type CumbiaOptions = { @@ -40,59 +48,66 @@ declare module "types/cumbiaTypes" { }; export type ComponentFactory = (component: Component) => ComponentInstance; } -declare module "actionParser/utils/parseValues" { - import { BindedValues } from "types/cumbiaTypes"; +declare module "src/actionParser/utils/parseValues" { + import { BindedValues } from "src/types/cumbiaTypes"; const parseValues: (element: HTMLElement) => BindedValues; export default parseValues; } -declare module "actionParser/utils/caller" { - import { ComponentActions } from "types/cumbiaTypes"; +declare module "src/actionParser/utils/caller" { + import { ComponentActions } from "src/types/cumbiaTypes"; export type CallerValues = { prevent: boolean; }; const callFnWithValues: (element: HTMLElement, fnActions: ComponentActions, actionName: string, { prevent }: CallerValues) => (e: Event) => void; export default callFnWithValues; } -declare module "actionParser/data-action" { - import { ComponentActions } from "types/cumbiaTypes"; +declare module "src/actionParser/data-action" { + import { ComponentActions } from "src/types/cumbiaTypes"; const parseActions: (element: HTMLElement, fnActions: ComponentActions) => void; export default parseActions; } -declare module "actionParser/data-key" { - import { ComponentActions } from "types/cumbiaTypes"; +declare module "src/actionParser/data-key" { + import { ComponentActions } from "src/types/cumbiaTypes"; const parseKey: (element: HTMLElement, fnActions: ComponentActions) => void; export default parseKey; } -declare module "actionParser/lifecycle" { - import { ComponentInstance } from "types/cumbiaTypes"; +declare module "src/actionParser/lifecycle" { + import { ComponentInstance } from "src/types/cumbiaTypes"; const parseLifecycle: (instance: ComponentInstance, element: HTMLElement) => void; export default parseLifecycle; } -declare module "core/pubsub" { +declare module "src/core/pubsub" { export const on: (topic: string, fn: any) => void; - export const emit: (topic: string, message: any) => void; + type emitterType = (topic: string, message: T) => void; + export const emit: emitterType; const _default_1: { on: (topic: string, fn: any) => void; - emit: (topic: string, message: any) => void; + emit: emitterType; }; export default _default_1; } -declare module "core/componentExecutor" { - import { ComponentFactory } from "types/cumbiaTypes"; +declare module "src/core/componentExecutor" { + import { ComponentFactory } from "src/types/cumbiaTypes"; const componentExecutor: (element: HTMLElement, componentFactory: Map, name: string) => void; export default componentExecutor; } -declare module "core/createApp" { - import { ComponentFactory } from "types/cumbiaTypes"; - import { CumbiaOptions } from "types/cumbiaTypes"; +declare module "src/core/createApp" { + import { ComponentFactory } from "src/types/cumbiaTypes"; + import { CumbiaOptions } from "src/types/cumbiaTypes"; export const initialisedComponent: Map; export const componentFactory: Map; const createApp: (options: CumbiaOptions) => void; export default createApp; } -declare module "cumbia" { - import { ComponentFactory } from "types/cumbiaTypes"; - import { CumbiaOptions } from "types/cumbiaTypes"; +declare module "src/utils/components/debug" { + const debug: (components: Array) => void; + export default debug; +} +declare module "src/cumbia" { + import { ComponentFactory } from "src/types/cumbiaTypes"; + import { CumbiaOptions } from "src/types/cumbiaTypes"; + import debug from "src/utils/components/debug"; const addComponents: (components: Array, options: CumbiaOptions) => void; + export { debug }; export default addComponents; } diff --git a/cumbia.js b/cumbia.js index 24bc6af..d5382fe 100644 --- a/cumbia.js +++ b/cumbia.js @@ -1 +1,22 @@ -var y="0.0.5";var l="\u{1F3BC} Cumbia:",v=t=>console.error(`${l} ${t}`),x=t=>console.warn(`${l} ${t}`),E=t=>console.info(`${l} ${t}`),s={error:v,warn:x,info:E};var L=t=>{let o="data-value",e={};return t.querySelectorAll(`[${o}]`).forEach(r=>{let n=r.getAttribute(o)||"default_name",c=r.innerHTML;r.tagName==="INPUT"&&(c=r.value),e[n]={el:r,value:c}}),e},p=L;var M=(t,o,e,{prevent:a})=>r=>{let n=o[e];if(a&&r.preventDefault(),!n)return s.warn(`Action -->"${e}"<-- not defined in component.`);let c=p(t);n(c)},i=M;var V=(t,o)=>{let e="data-action";t.querySelectorAll(`[${e}]`).forEach(r=>{let n=r.getAttribute(e)||"default_action_name";if(n==="submit"){if(t.tagName!=="FORM")return s.error("Trying to handle submit handler outside of form");t.addEventListener("submit",i(t,o,n,{prevent:!0}));return}if(r.tagName==="INPUT"){r.addEventListener("change",i(t,o,n,{prevent:!1}));return}r.addEventListener("click",i(t,o,n,{prevent:!1}))})},g=V;var $=(t,o)=>{let e="data-action-key";t.querySelectorAll(`[${e}]`).forEach(r=>{let n=r.getAttribute(e)||"default_action_name";r.addEventListener("keyup",i(t,o,n,{prevent:!1}))})},b=$;var H=(t,o)=>{let e=p(o);t.init&&t.init(e)},C=H;var u=new Map,F=(t,o)=>{let e=u.get(t)||[];e.push(o),u.set(t,e)},w=(t,o)=>{(u.get(t)||[]).forEach(a=>{a?a(o):console.warn("Topic not found")})},f={on:F,emit:w};var I=(t,o,e)=>{let a=e.trim();if(!o.has(a))return s.warn(`Component -->"${a}"<-- was not found.`);let r=o.get(a);if(!r)return s.error("Undefined component");let n=r({el:t,on:f.on,emit:f.emit});C(n,t),(n==null?void 0:n.actions)&&(g(t,n.actions),b(t,n.actions))},T=I;var d=new Map,m=new Map,A="data-component",N=",",P=t=>{document.querySelectorAll(`[${A}]`).forEach(e=>{if(d.has(e))return;d.set(e,!0),(e.getAttribute(A)||"").split(N).forEach(n=>T(e,m,n))}),(t==null?void 0:t.globalInitialisers)&&t.globalInitialisers.length&&t.globalInitialisers.forEach(e=>{let a=[...d.keys()];e(a)})},h=P;var S=(t,o)=>{t.length||s.error("No components passed"),t.forEach(e=>{if(!e.name)return s.error("Component name not defined, please give a name to your component");m.has(e.name)&&s.warn(`Name collision detected. ${e.name} was previously defined`),m.set(e.name,e)}),h(o)};s.info(`Initializing ${y}`);var it=S;export{it as default}; +var y="0.0.6";var l="\u{1F3BC} Cumbia:",E=e=>console.error(`${l}`,e),A=e=>console.warn(`${l}`,e),L=e=>console.info(`${l}`,e),a={error:E,warn:A,info:L};var v=e=>{let o="data-value",t={};return e.querySelectorAll(`[${o}]`).forEach(n=>{let r=n.getAttribute(o)||"default_name",i=n.innerHTML;n.tagName==="INPUT"&&(i=n.value),t[r]={el:n,value:i}}),t},p=v;var M=(e,o,t,{prevent:s})=>n=>{let r=o[t];if(s&&n.preventDefault(),!r)return a.warn(`Action -->"${t}"<-- not defined in component.`);let i=p(e);r(i)},c=M;var H=(e,o)=>{let t="data-action";e.querySelectorAll(`[${t}]`).forEach(n=>{let r=n.getAttribute(t)||"default_action_name",i=n.getAttribute("type");if(r==="submit"||i==="submit"){if(e.tagName!=="FORM")return a.error("Trying to handle submit handler outside of form");e.addEventListener("submit",c(e,o,r,{prevent:!0}));return}if(n.tagName==="INPUT"){n.addEventListener("change",c(e,o,r,{prevent:!1}));return}n.addEventListener("click",c(e,o,r,{prevent:!1}))})},g=H;var V=(e,o)=>{let t="data-action-key";e.querySelectorAll(`[${t}]`).forEach(n=>{let r=n.getAttribute(t)||"default_action_name";n.addEventListener("keyup",c(e,o,r,{prevent:!1}))})},b=V;var w=(e,o)=>{let t=p(o);e.init&&e.init(t)},T=w;var u=new Map,F=(e,o)=>{let t=u.get(e)||[];t.push(o),u.set(e,t)},I=(e,o)=>{a.info({topic:e,message:o}),(u.get(e)||[]).forEach(s=>{s?s(o):console.warn("Topic not found")})},d={on:F,emit:I};var $=(e,o,t)=>{let s=t.trim();if(!o.has(s))return a.warn(`Component -->"${s}"<-- was not found.`);let n=o.get(s);if(!n)return a.error("Undefined component");let r=n({el:e,on:d.on,emit:d.emit});T(r,e),(r==null?void 0:r.actions)&&(g(e,r.actions),b(e,r.actions))},C=$;var f=new Map,m=new Map,h="data-component",k=",",N=e=>{document.querySelectorAll(`[${h}]`).forEach(t=>{if(f.has(t))return;f.set(t,!0),(t.getAttribute(h)||"").split(k).forEach(r=>C(t,m,r))}),(e==null?void 0:e.globalInitialisers)&&e.globalInitialisers.length&&e.globalInitialisers.forEach(t=>{let s=[...f.keys()];t(s)})},x=N;var S=` + * { + transition: outline 1s; + } + .debugIcon { + position: fixed; + top: 10px; + right: 10px; + height: 25px; + cursor: pointer; + background-image: url("https://github.com/neomaxzero/cumbia/blob/master/assets/logomin.png?raw=true"); + background-size: contain; + background-repeat: no-repeat; + padding-left: 25px; + padding-top: 2px; + color: #888; + } + + .signElement { + outline: 3px solid deeppink; + } +`,O=e=>{let o=document.createElement("style");o.innerHTML=S,document.head.appendChild(o);let t=document.createElement("div");t.classList.add("debugIcon"),t.innerHTML="DEBUG",document.body.appendChild(t),t.addEventListener("click",()=>{e.forEach(s=>{s.classList.add("signElement"),setTimeout(()=>{s.classList.remove("signElement")},3e3)})})},P=O;var _=(e,o)=>{e.length||a.error("No components passed"),e.forEach(t=>{if(!t.name)return a.error("Component name not defined, please give a name to your component");m.has(t.name)&&a.warn(`Name collision detected. ${t.name} was previously defined`),m.set(t.name,t)}),document.addEventListener("DOMContentLoaded",function(){x(o)})};a.info(`Initializing ${y}`);var de=_;export{P as debug,de as default}; diff --git a/example/counter/components/todo/messages.ts b/example/counter/components/todo/messages.ts new file mode 100644 index 0000000..f272b53 --- /dev/null +++ b/example/counter/components/todo/messages.ts @@ -0,0 +1,7 @@ +export enum MESSAGES { + ADD_TODO = "ADD_TODO", +} + +export type MESSAGES_TYPE = { + [MESSAGES.ADD_TODO]: string; +}; diff --git a/example/counter/components/todo/todo.js b/example/counter/components/todo/todo.js new file mode 100644 index 0000000..c907521 --- /dev/null +++ b/example/counter/components/todo/todo.js @@ -0,0 +1,11 @@ +import { MESSAGES_TYPE } from "./messages"; + +export const todo = ({ emit }) => { + const actions = { + add: ({ name }) => emit("ADD_TODO", name.value), + }; + + return { + actions, + }; +}; diff --git a/example/counter/components/todo/todoList.js b/example/counter/components/todo/todoList.js new file mode 100644 index 0000000..c8d3daf --- /dev/null +++ b/example/counter/components/todo/todoList.js @@ -0,0 +1,13 @@ +export const todoList = ({ on }) => { + const init = () => { + on() + } + const actions = { + add: ({ name }) => emit("ADD_TODO", name.value), + }; + + return { + actions, + }; + }; + \ No newline at end of file diff --git a/example/counter/index.html b/example/counter/index.html index f9793d1..689ddb3 100644 --- a/example/counter/index.html +++ b/example/counter/index.html @@ -41,6 +41,22 @@

Value: 5

+

Todo

+
+ + + +
+
    + +
+ + + diff --git a/example/counter/index.js b/example/counter/index.js index 120d5ac..c0f6219 100644 --- a/example/counter/index.js +++ b/example/counter/index.js @@ -1,4 +1,5 @@ -import cumbia from '../../dist-lib/cumbia.js'; +import cumbia from '../../cumbia.js'; +import debug from '../../src/utils/components/debug'; const counter = ({ el }) => { const init = (values) => { @@ -34,4 +35,4 @@ const form = () => { }; }; -cumbia([form, counter]); +cumbia([form, counter], { globalInitialisers: [debug]}); diff --git a/src/_version.ts b/src/_version.ts index 328834a..09a5339 100644 --- a/src/_version.ts +++ b/src/_version.ts @@ -1 +1 @@ -export const version = '0.0.5'; \ No newline at end of file +export const version = '0.0.6'; \ No newline at end of file diff --git a/src/actionParser/data-action.ts b/src/actionParser/data-action.ts index d7545dc..58d640a 100644 --- a/src/actionParser/data-action.ts +++ b/src/actionParser/data-action.ts @@ -10,8 +10,9 @@ const parseActions = (element: HTMLElement, fnActions: ComponentActions) => { actions.forEach((actionElement: HTMLElement) => { const actionName = actionElement.getAttribute(dataActionAttr) || 'default_action_name'; + const actionType = actionElement.getAttribute('type'); - if (actionName === 'submit') { + if (actionName === 'submit' || actionType === 'submit') { if (element.tagName !== 'FORM') { return message.error('Trying to handle submit handler outside of form'); } diff --git a/src/core/pubsub.ts b/src/core/pubsub.ts index 7a6f02b..c820fcc 100644 --- a/src/core/pubsub.ts +++ b/src/core/pubsub.ts @@ -1,3 +1,4 @@ +import msg from "../utils/message"; const subscriptions = new Map void>>(); export const on = (topic: string, fn: any) => { @@ -6,7 +7,10 @@ export const on = (topic: string, fn: any) => { subscriptions.set(topic, currentSubscriptions); }; -export const emit = (topic: string, message: any) => { +type emitterType = (topic: string, message: T) => void; + +export const emit: emitterType = (topic, message) => { + msg.info({ topic, message }); const fns = subscriptions.get(topic) || []; fns.forEach((fn) => { diff --git a/src/cumbia.ts b/src/cumbia.ts index 3cdd5d0..5dfc289 100644 --- a/src/cumbia.ts +++ b/src/cumbia.ts @@ -4,8 +4,12 @@ import message from "./utils/message"; import { ComponentFactory } from "types/cumbiaTypes"; import createApp, { componentFactory } from "./core/createApp"; import { CumbiaOptions } from "types/cumbiaTypes"; +import debug from "./utils/components/debug"; -const addComponents = (components: Array, options: CumbiaOptions) => { +const addComponents = ( + components: Array, + options: CumbiaOptions +) => { if (!components.length) { message.error("No components passed"); } @@ -25,9 +29,15 @@ const addComponents = (components: Array, options: CumbiaOptio componentFactory.set(component.name, component); }); - createApp(options); + document.addEventListener("DOMContentLoaded", function() { + createApp(options); + }); }; message.info(`Initializing ${version}`); +export { debug }; + + + export default addComponents; diff --git a/src/utils/components/debug.ts b/src/utils/components/debug.ts new file mode 100644 index 0000000..9ce991f --- /dev/null +++ b/src/utils/components/debug.ts @@ -0,0 +1,46 @@ +const globalCSS = ` + * { + transition: outline 1s; + } + .debugIcon { + position: fixed; + top: 10px; + right: 10px; + height: 25px; + cursor: pointer; + background-image: url("https://github.com/neomaxzero/cumbia/blob/master/assets/logomin.png?raw=true"); + background-size: contain; + background-repeat: no-repeat; + padding-left: 25px; + padding-top: 2px; + color: #888; + } + + .signElement { + outline: 3px solid deeppink; + } +`; + +const debug = (components: Array) => { + const css = document.createElement("style"); + css.innerHTML = globalCSS; + document.head.appendChild(css); + + const debugIcon = document.createElement("div"); + debugIcon.classList.add("debugIcon"); + + debugIcon.innerHTML = 'DEBUG'; + document.body.appendChild(debugIcon); + + debugIcon.addEventListener("click", () => { + components.forEach((comp) => { + comp.classList.add('signElement'); + + setTimeout(() => { + comp.classList.remove('signElement'); + }, 3000); + }); + }); +}; + +export default debug; diff --git a/src/utils/message.ts b/src/utils/message.ts index 72e9d8f..667d61d 100644 --- a/src/utils/message.ts +++ b/src/utils/message.ts @@ -1,6 +1,6 @@ const logPrefix = '🎼 Cumbia:'; -const error = (msg: string) => console.error(`${logPrefix} ${msg}`); -const warn = (msg: string) => console.warn(`${logPrefix} ${msg}`); -const info = (msg: string) => console.info(`${logPrefix} ${msg}`); +const error = (msg: any) => console.error(`${logPrefix}`,msg); +const warn = (msg: any) => console.warn(`${logPrefix}`, msg); +const info = (msg: any) => console.info(`${logPrefix}`, msg); export default { error, warn, info };