@dogiloki/artha-js 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- artha-message{width:100%;padding:10px;text-align:left;font-size:1em;cursor:default}artha-message[type=error]{background-color:#f2dede;color:#b94a48}artha-message[type=success]{background-color:#dff0d8;color:#468847}artha-message[type=warning]{background-color:#fcf8e3;color:#c09853}artha-message[type=info]{background-color:#d9edf7;color:#3a87ad}artha-loader{display:inline-flex;flex-direction:column;align-items:center}artha-loader .loader-content{display:flex;justify-content:center;align-items:center;gap:10px}artha-loader[type=dots] .loader-content>div{width:10px;height:10px;background-color:#3b82f6;border-radius:50%;animation:dot 1.2s infinite ease-in-out}artha-loader[type=dots] .loader-content>div:nth-of-type(1){animation-delay:0s}artha-loader[type=dots] .loader-content>div:nth-of-type(2){animation-delay:.2s}artha-loader[type=dots] .loader-content>div:nth-of-type(3){animation-delay:.4s}artha-loader[type=ring] .loader-content>div{width:32px;height:32px;border:3px solid #93c5fd;border-top-color:#3b82f6;border-radius:50%;animation:ring .8s linear infinite}artha-loader span{font-size:1rem;color:#5b6e8c}@keyframes dot{0%,100%{transform:scale(0.8);opacity:.4}50%{transform:scale(1.2);opacity:1}}@keyframes ring{to{transform:rotate(360deg)}}/*# sourceMappingURL=artha.min.css.map */
1
+ .icon{width:1.2rem;height:1.2rem;display:inline-block;vertical-align:middle;background-color:#000;mask-repeat:no-repeat;mask-position:center;mask-size:contain;-webkit-mask-repeat:no-repeat;-webkit-mask-position:center;-webkit-mask-size:contain}.icon.search{mask-image:url("./assets/icons/search.svg");-webkit-mask-image:url("./assets/icons/search.svg")}artha-message{width:100%;padding:10px;text-align:left;font-size:1em;cursor:default}artha-message[type=error]{background-color:#f2dede;color:#b94a48}artha-message[type=success]{background-color:#dff0d8;color:#468847}artha-message[type=warning]{background-color:#fcf8e3;color:#c09853}artha-message[type=info]{background-color:#d9edf7;color:#3a87ad}artha-loader{display:inline-flex;flex-direction:column;align-items:center}artha-loader .loader-content{display:flex;justify-content:center;align-items:center;gap:10px}artha-loader[type=dots] .loader-content>div{width:10px;height:10px;background-color:#3b82f6;border-radius:50%;animation:dot 1.2s infinite ease-in-out}artha-loader[type=dots] .loader-content>div:nth-of-type(1){animation-delay:0s}artha-loader[type=dots] .loader-content>div:nth-of-type(2){animation-delay:.2s}artha-loader[type=dots] .loader-content>div:nth-of-type(3){animation-delay:.4s}artha-loader[type=ring] .loader-content>div{width:32px;height:32px;border:3px solid #93c5fd;border-top-color:#3b82f6;border-radius:50%;animation:ring .8s linear infinite}artha-loader span{font-size:1rem;color:#5b6e8c}@keyframes dot{0%,100%{transform:scale(0.8);opacity:.4}50%{transform:scale(1.2);opacity:1}}@keyframes ring{to{transform:rotate(360deg)}}/*# sourceMappingURL=artha.min.css.map */
@@ -1 +1 @@
1
- {"version":3,"sourceRoot":"","sources":["../src/scss/message.scss","../src/scss/colors.scss","../src/scss/loader.scss"],"names":[],"mappings":"AAEA,cACI,WACA,aACA,gBACA,cACA,eAEA,0BACI,iBCLqB,QDMrB,MCVe,QDYnB,4BACI,iBCRuB,QDSvB,MCbiB,QDerB,4BACI,iBCXuB,QDYvB,MChBiB,QDkBrB,yBACI,iBCdoB,QDepB,MCnBc,QCFtB,aACI,oBACA,sBACA,mBAEA,6BACI,aACA,uBACA,mBACA,SAKI,4CACI,WACA,YACA,iBDTO,QCUP,kBACA,wCAEA,2DACI,mBAEJ,2DACI,oBAEJ,2DACI,oBAQR,4CACI,WACA,YACA,yBACA,iBDhCO,QCiCP,kBACA,mCAIZ,kBACI,eACA,MDtCa,QC0CrB,eACI,QACI,qBACA,WAEJ,IACI,qBACA,WAIR,gBACI,GACI","file":"artha.min.css"}
1
+ {"version":3,"sourceRoot":"","sources":["../src/scss/icons.scss","../src/scss/colors.scss","../src/scss/message.scss","../src/scss/loader.scss"],"names":[],"mappings":"AAEA,MACI,aACA,cACA,qBACA,sBACA,iBCFK,KDGL,sBACA,qBACA,kBACA,8BACA,6BACA,0BAEA,aACI,4CACA,oDEfR,cACI,WACA,aACA,gBACA,cACA,eAEA,0BACI,iBDcqB,QCbrB,MDSe,QCPnB,4BACI,iBDWuB,QCVvB,MDMiB,QCJrB,4BACI,iBDQuB,QCPvB,MDGiB,QCDrB,yBACI,iBDKoB,QCJpB,cCrBR,aACI,oBACA,sBACA,mBAEA,6BACI,aACA,uBACA,mBACA,SAKI,4CACI,WACA,YACA,iBFWO,QEVP,kBACA,wCAEA,2DACI,mBAEJ,2DACI,oBAEJ,2DACI,oBAQR,4CACI,WACA,YACA,yBACA,iBFZO,QEaP,kBACA,mCAIZ,kBACI,eACA,MFlBa,QEsBrB,eACI,QACI,qBACA,WAEJ,IACI,qBACA,WAIR,gBACI,GACI","file":"artha.min.css"}
package/dist/artha.min.js CHANGED
@@ -6,6 +6,7 @@ import ArthaMessage from '../src/components/artha-message.js';
6
6
  import ArthaLoader from '../src/components/artha-loader.js';
7
7
  import ArthaContainer from '../src/components/artha-container.js';
8
8
  import ArthaForm from '../src/components/artha-form.js';
9
+ import InputSearch from '../src/components/input-search.js';
9
10
 
10
11
  export {
11
12
  Util,
@@ -15,7 +16,8 @@ export {
15
16
  ArthaMessage,
16
17
  ArthaLoader,
17
18
  ArthaContainer,
18
- ArthaForm
19
+ ArthaForm,
20
+ InputSearch
19
21
  };
20
22
 
21
23
  Promise.resolve().then(()=>{
@@ -37,4 +39,7 @@ function registerComponents(){
37
39
  if(!customElements.get('artha-loader')){
38
40
  customElements.define('artha-loader',ArthaLoader);
39
41
  }
42
+ if(!customElements.get('input-search')){
43
+ customElements.define('input-search',InputSearch);
44
+ }
40
45
  }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M482-160q-134 0-228-93t-94-227v-7l-64 64-56-56 160-160 160 160-56 56-64-64v7q0 100 70.5 170T482-240q26 0 51-6t49-18l60 60q-38 22-78 33t-82 11Zm278-161L600-481l56-56 64 64v-7q0-100-70.5-170T478-720q-26 0-51 6t-49 18l-60-60q38-22 78-33t82-11q134 0 228 93t94 227v7l64-64 56 56-160 160Z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"/></svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dogiloki/artha-js",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "",
5
5
  "main": "dist/artha.min.js",
6
6
  "type": "module",
@@ -16,12 +16,15 @@ export default class BaseComponent extends HTMLElement{
16
16
  this._updating=false;
17
17
  // Mapeo de atributos
18
18
  this._props=[];
19
+ // Mapeo de propiedade no reflejadas como atributos
20
+ this._memory={};
19
21
  // Mapeo para indicar comportamiento especiales en el mapeo de atributos
20
22
  this._special_props={
21
23
  booleans:[], // Propiedades booleanas
22
24
  element_refs:[], // Propiedades de referencian elementos por ID
23
25
  defaults:{}, // Propiedades con valor por defecto
24
- resolvers:{} // Propiedades con un callback
26
+ resolvers:{}, // Propiedades con un callback
27
+ reflect:{} // Guardar en memoria y no llamar a setAttribute y getAttribute
25
28
  };
26
29
  this.configureProperties(props,options);
27
30
  }
@@ -43,12 +46,13 @@ export default class BaseComponent extends HTMLElement{
43
46
 
44
47
  attributeChangedCallback(name,old_value,new_value){
45
48
  if(old_value===new_value) return;
46
- if(this._props.includes(name)){
47
- this._triggerUpdate(name,this._getPropertyValue(name));
49
+ const attr=this._valueToAttr(name);
50
+ if(this._props.includes(attr)){
51
+ this._triggerUpdate(attr,this._getPropertyValue(attr));
48
52
  }
49
- this.onAttributeChanged(name,old_value,new_value);
53
+ this.onAttributeChanged(attr,old_value,new_value);
50
54
  }
51
- onAttributeChanged(name,old_value,new_value){}
55
+ onAttributeChanged(prop,old_value,new_value){}
52
56
 
53
57
  configureProperties(props,options={}){
54
58
  if(props==null) return;
@@ -57,11 +61,40 @@ export default class BaseComponent extends HTMLElement{
57
61
  booleans:options.booleans||[],
58
62
  element_refs:options.element_refs||[],
59
63
  defaults:options.defaults||{},
60
- resolvers:options.resolvers||{}
64
+ resolvers:options.resolvers||{},
65
+ reflect:options.reflect||{}
61
66
  };
62
67
  this._setupProperties();
63
68
  }
64
69
 
70
+ _isReflected(prop){
71
+ return this._special_props.reflect[prop]!==false;
72
+ }
73
+
74
+ _getAttribute(attr){
75
+ return this.getAttribute(this._valueToAttr(attr));
76
+ }
77
+
78
+ _setAttribute(attr,value){
79
+ return this.setAttribute(this._valueToAttr(attr),value);
80
+ }
81
+
82
+ _removeAttribute(attr){
83
+ return this.removeAttribute(this._valueToAttr(attr));
84
+ }
85
+
86
+ _hasAttribute(attr){
87
+ return this.hasAttribute(this._valueToAttr(attr));
88
+ }
89
+
90
+ _valueToAttr(value){
91
+ return value.replace(/_/g,'-');
92
+ }
93
+
94
+ _attrToValue(value){
95
+ return value.replace(/-/g,'_');
96
+ }
97
+
65
98
  _setupProperties(){
66
99
  this._props.forEach((prop)=>{
67
100
  Object.defineProperty(this,prop,{
@@ -76,10 +109,22 @@ export default class BaseComponent extends HTMLElement{
76
109
  }
77
110
 
78
111
  _getPropertyValue(prop){
112
+ // Propiedades que son se refleja como atributos
113
+ if(!this._isReflected(prop)){
114
+ if(prop in this._memory){
115
+ return this._memory[prop];
116
+ }
117
+ if(this._special_props.defaults[prop]!==undefined){
118
+ return this._special_props.defaults[prop];
119
+ }
120
+ return null;
121
+ }
79
122
  // Propiedade que referencia un elemento por ID
80
123
  if(this._special_props.element_refs.includes(prop)){
81
- const element_id=this.getAttribute(prop);
82
- if(!element_id) return null;
124
+ const element_id=this._getAttribute(prop);
125
+ if(!element_id){
126
+ return this._elements[prop]??null;
127
+ }
83
128
  // Cache para evitar múltiples búsquedas en el DOM
84
129
  if(!this._elements[prop] || this._elements[prop].id!==element_id){
85
130
  this._elements[prop]=document.getElementById(element_id);
@@ -88,15 +133,15 @@ export default class BaseComponent extends HTMLElement{
88
133
  }
89
134
  // Propiedades con callback
90
135
  if(this._special_props.resolvers[prop]){
91
- const raw_value=this.getAttribute(prop);
136
+ const raw_value=this._getAttribute(prop);
92
137
  return this._special_props.resolvers[prop].get(raw_value,this);
93
138
  }
94
139
  // Propiedad booleana
95
140
  if(this._special_props.booleans.includes(prop)){
96
- return this.hasAttribute(prop) && this.getAttribute(prop)!=='false';
141
+ return this._hasAttribute(prop) && this._getAttribute(prop)!=='false';
97
142
  }
98
143
  // Propiedad con valor por defecto
99
- const value=this.getAttribute(prop);
144
+ const value=this._getAttribute(prop);
100
145
  if(value===null && this._special_props.defaults[prop]!==undefined){
101
146
  return this._special_props.defaults[prop];
102
147
  }
@@ -105,7 +150,13 @@ export default class BaseComponent extends HTMLElement{
105
150
 
106
151
  _setPropertyValue(prop,value){
107
152
  if(this._updating) return;
108
- const current_value=this.getAttribute(prop);
153
+ // Propiedades que son se refleja como atributos
154
+ if(this._isReflected(prop)===false){
155
+ this._memory[prop]=value;
156
+ this._triggerUpdate(prop,value);
157
+ return;
158
+ }
159
+ const current_value=this._getAttribute(prop);
109
160
  let new_value=value;
110
161
  // Convertir a string para atributos
111
162
  if(value===null || value===undefined){
@@ -126,9 +177,9 @@ export default class BaseComponent extends HTMLElement{
126
177
  // Solo actualizar si cambió
127
178
  if(current_value!==new_value){
128
179
  if(new_value===null){
129
- this.removeAttribute(prop);
180
+ this._removeAttribute(prop);
130
181
  }else{
131
- this.setAttribute(prop,new_value);
182
+ this._setAttribute(prop,new_value);
132
183
  }
133
184
  this._triggerUpdate(prop,value);
134
185
  }
@@ -136,7 +187,13 @@ export default class BaseComponent extends HTMLElement{
136
187
 
137
188
  _initializeProperties(){
138
189
  this._props.forEach((prop)=>{
139
- const attrib_value=this.getAttribute(prop);
190
+ if(this._isReflected(prop)===false){
191
+ if(this._special_props.defaults[prop]!==undefined){
192
+ this._memory[prop]=this._special_props.defaults[prop];
193
+ }
194
+ return;
195
+ }
196
+ const attrib_value=this._getAttribute(prop);
140
197
  if(attrib_value!==null){
141
198
  this[prop]=this._getPropertyValue(prop);
142
199
  }else if(this._special_props.defaults[prop]!==undefined){
@@ -3,20 +3,29 @@ import Util from '../core/Util.js';
3
3
  import EventBus from '../core/EventBus.js';
4
4
  import XHR from '../core/XHR.js';
5
5
  import TaskQueue from '../core/TaskQueue.js';
6
- import ArthaMessage from './artha-message.js';
7
6
 
8
7
  export default class ArthaContainer extends BaseComponent{
9
8
 
9
+ static defaults={
10
+ method:'GET',
11
+ pagination:10,
12
+ page:1,
13
+ response_type:'json'
14
+ };
15
+
10
16
  constructor(){
11
17
  super(
12
- ["template","action","action_router","method",
13
- "pagination","message","searcher","selectable","multiple"],
18
+ ["template","action","action_router","method","page","search",
19
+ "pagination","message","searcher","selectable","multiple","response_type"],
14
20
  {
15
21
  booleans:['searcher','selectable','multiple'],
16
- element_refs:['template','mesage'],
22
+ element_refs:['template','message'],
17
23
  defaults:{
18
- method:'GET',
19
- pagination:10
24
+ response_type:ArthaContainer.defaults.response_type
25
+ },
26
+ reflect:{
27
+ search:false,
28
+ response_type:false
20
29
  }
21
30
  }
22
31
  );
@@ -26,26 +35,40 @@ export default class ArthaContainer extends BaseComponent{
26
35
  this.onRenderItemIter=(element,data,iter_element,iter_data)=>{};
27
36
 
28
37
  this.task_queue=TaskQueue.singleton();
38
+ this._current_xhr=null;
29
39
  this.items={};
30
40
  this.selection_store=new SelectionStore();
31
- this.response_type='json';
32
41
  this.message??=this.querySelector('artha-message')??this.querySelector(this.getAttribute('message-target'))??null;
33
42
  this.id=this.getAttribute('id')??'container-'+BaseComponent.counter;
43
+ if(this.hasPagination()){
44
+ this.pagination=this.pagination||ArthaContainer.defaults.pagination;
45
+ this.page=this.page||ArthaContainer.defaults.page;
46
+ }
47
+ if(this.hasAction()){
48
+ this.method=this.method||ArthaContainer.defaults.method;
49
+ }
34
50
 
35
51
  // Loader
36
52
  this.loader_container=this._createLoader();
37
53
 
54
+ // Input de búsqueda
55
+ if(this.searcher){
56
+ this.searcher_input=Util.createElement('input-search');
57
+ this.appendChild(this.searcher_input);
58
+ this.searcher_input.addEventListener('search',(evt)=>this._handleSearch(evt));
59
+ this.searcher_input.addEventListener('cancel-search',(evt)=>this._cancelSearch(evt));
60
+ }
61
+
38
62
  // Contenido
39
63
  this.content=this.querySelector(':scope > dynamic-content') || this.appendChild(document.createElement('dynamic-content'));
40
64
  this._content=this.content.children[0];
41
65
 
42
- // Input de búsqueda
43
- this.input_search=this.querySelector("input-search");
44
- if(this.input_search){
45
- this.input_search.addEventListener('search',(evt)=>this._handleSearch(evt));
46
- this.refresh(this.input_search.value);
47
- }else{
48
- this.refresh();
66
+ if(this.hasAction()){
67
+ if(this.searcher){
68
+ this.refresh(this.searcher_input.value);
69
+ }else{
70
+ this.refresh();
71
+ }
49
72
  }
50
73
  }
51
74
 
@@ -54,16 +77,23 @@ export default class ArthaContainer extends BaseComponent{
54
77
  }
55
78
 
56
79
  _handleSearch(evt){
80
+ this.page=1;
57
81
  if(this.action){
58
- this.refresh(evt.detail.query);
82
+ this.search=evt.detail.query;
83
+ return this.refresh();
59
84
  }else{
60
85
  const search=evt.detail.query?.toLowerCase()??'';
61
- for(const item of this.items??[]){
86
+ for(const item of this.items){
62
87
  Util.modal(item,item.textContent.toLowerCase().includes(search));
63
88
  }
64
89
  }
65
90
  }
66
91
 
92
+ _cancelSearch(evt){
93
+ this._current_xhr?.abort();
94
+ this._current_xhr=null;
95
+ }
96
+
67
97
  // value - getter/setter
68
98
  get value(){
69
99
  if(!this.selectable) return null;
@@ -105,10 +135,20 @@ export default class ArthaContainer extends BaseComponent{
105
135
  }
106
136
 
107
137
  getData(search=null){
138
+ search??=this.search;
108
139
  if(!this.action) return;
109
- const query=search?{search}:{};
110
- this.task_queue.loadTask(`container-${this.id}`,null,(task)=>{
111
- XHR.request({
140
+ let query={};
141
+ if(this.hasPagination()){
142
+ query={
143
+ pagination:this.pagination,
144
+ page:this.page
145
+ };
146
+ }
147
+ if(search){
148
+ query['search']=search;
149
+ }
150
+ return this.task_queue.loadTask(`container-${this.id}`,null,(task)=>{
151
+ this._current_xhr=XHR.request({
112
152
  url:this.action,
113
153
  method:this.method,
114
154
  headers:{
@@ -120,6 +160,7 @@ export default class ArthaContainer extends BaseComponent{
120
160
  this.dispatchEvent(new CustomEvent('load',{detail:xhr}));
121
161
  },
122
162
  onData:(xhr,json)=>{
163
+ this._current_xhr=null;
123
164
  // Respuesta procesada en en formato json
124
165
  task.resolve(xhr,()=>{
125
166
  this.dispatchEvent(new CustomEvent('resolve',{detail:json}));
@@ -132,6 +173,11 @@ export default class ArthaContainer extends BaseComponent{
132
173
  onError:(err)=>{
133
174
  this.message?.error(err??"Error de conexión");
134
175
  task.onFinalize();
176
+ this._cancelSearch();
177
+ },
178
+ onAbort:(err)=>{
179
+ task.onFinalize();
180
+ this._cancelSearch();
135
181
  }
136
182
  });
137
183
  },{
@@ -139,14 +185,49 @@ export default class ArthaContainer extends BaseComponent{
139
185
  });
140
186
  }
141
187
 
188
+ hasAction(){
189
+ return this.hasAttribute('action');
190
+ }
191
+
192
+ hasPagination(){
193
+ return this.hasAttribute('pagination');
194
+ }
195
+
196
+ nextPage(){
197
+ if(!this.hasPagination()) return;
198
+ this.page+=1;
199
+ return this.refresh(this.search);
200
+ }
201
+
202
+ prevPage(){
203
+ if(!this.hasPagination()) return;
204
+ if(this.page>1){
205
+ this.page-=1;
206
+ }
207
+ return this.refresh(this.search);
208
+ }
209
+
210
+ goToPage(page){
211
+ page=Number(page);
212
+ if(!this.hasPagination() || !Number.isInteger(page) || page<1) return;
213
+ this.page=page;
214
+ return this.refresh(this.search);
215
+ }
216
+
217
+ resetPagination(refresh=false){
218
+ this.page=1;
219
+ if(refresh) return this.refresh(this.search);
220
+ }
221
+
142
222
  refresh(search=null){
223
+ search??=this.search;
143
224
  this.loader_container.remove();
144
225
  if(this.template){
145
226
  this.content.innerHTML="";
146
227
  if(this._content) this.content.appendChild(this._content);
147
228
  this.content.appendChild(this.loader_container);
148
229
  }
149
- this.getData(search);
230
+ return this.getData(search);
150
231
  }
151
232
 
152
233
  refreshWithData(data){
@@ -2,15 +2,26 @@ import BaseComponent from '../abstract/BaseComponent.js';
2
2
  import Util from '../core/Util.js';
3
3
  import XHR from '../core/XHR.js';
4
4
  import TaskQueue from '../core/TaskQueue.js';
5
- import ArthaMessage from './artha-message.js';
6
5
 
7
6
  export default class ArthaForm extends BaseComponent{
8
7
 
8
+ static defaults={
9
+ response_type:'json'
10
+ };
11
+
9
12
  constructor(){
10
- super();
13
+ super([
14
+ 'action','method','response_type','disable_submit'
15
+ ],{
16
+ booleans:['disable_submit'],
17
+ defaults:{
18
+ 'response_type':ArthaForm.defaults.response_type
19
+ },
20
+ reflect:{
21
+ response_type:false
22
+ }
23
+ });
11
24
  this.task_queue=TaskQueue.singleton();
12
- this.response_type=this.getAttribute('response-type')??'json';
13
- this.disable_submit=this.hasAttribute('disable-submit');
14
25
  this.message=this.querySelector('artha-message')??this.querySelector(this.getAttribute('message-target'))??null;
15
26
  if(!this.message){
16
27
  this.message=Util.createElement('artha-message');
@@ -112,13 +123,11 @@ export default class ArthaForm extends BaseComponent{
112
123
  this.element_inputs.forEach((element)=>{
113
124
  form_data[element.name]=element.type==='checkbox'?(element.checked?1:0):element.value;
114
125
  });
115
- const action=this.getAttribute('action')??'';
116
- const method=this.getAttribute('method')??'GET';
117
126
  const id=this.getAttribute('id');
118
127
  this.task_queue.loadTask(`form-${id}`,null,(task)=>{
119
128
  XHR.request({
120
- url:action,
121
- method:method,
129
+ url:this.action,
130
+ method:this.method,
122
131
  data:form_data,
123
132
  response_type:this.response_type,
124
133
  onLoad:(xhr)=>{
@@ -0,0 +1,104 @@
1
+ import BaseComponent from '../abstract/BaseComponent.js';
2
+ import Util from "../core/Util.js";
3
+
4
+ export default class InputSearch extends BaseComponent{
5
+
6
+ static defaults={
7
+ delay:300,
8
+ text:'Búscar',
9
+ icon:'../dist/assets/icons/search.svg'
10
+ }
11
+
12
+ constructor(){
13
+ super([
14
+ 'delay','text','value','input','button'
15
+ ],{
16
+ element_refs:['input','button'],
17
+ resolvers:{
18
+ 'value':{
19
+ set:(raw)=>{
20
+ return this.input.value=raw;
21
+ },
22
+ get:(raw)=>{
23
+ return this.input?.value??null;
24
+ }
25
+ }
26
+ },
27
+ defaults:{
28
+ delay:InputSearch.defaults.delay,
29
+ text:InputSearch.defaults.text
30
+ },
31
+ reflect:{
32
+ text:false
33
+ }
34
+ });
35
+ this._search_timer=null;
36
+ this._ensureStructure();
37
+ }
38
+
39
+ _ensureStructure(){
40
+ this.icon=InputSearch.defaults.icon;
41
+ this.style.display="flex";
42
+ this.input=this.appendChild(Util.createElement('input',(input)=>{
43
+ input.classList.add('input-field');
44
+ input.type="search";
45
+ input.placeholder=this.text;
46
+ }));
47
+ this.button=this.appendChild(Util.createElement('button',async(button)=>{
48
+ button.classList.add('button-search');
49
+ button.appendChild(Util.createElement('span',(span)=>{
50
+ span.classList.add('icon','search');
51
+ }));
52
+ }));
53
+ this._bindEvents();
54
+ }
55
+
56
+ _bindEvents(){
57
+ this.input.addEventListener('input',(evt)=>{
58
+ this._queueSearch();
59
+ });
60
+ this.input.addEventListener('keydown',(evt)=>{
61
+ if(evt.key==='Enter'){
62
+ evt.preventDefault();
63
+ this._cancelQueuedSearch();
64
+ this.search();
65
+ }
66
+ });
67
+ this.button.addEventListener('click',(evt)=>{
68
+ evt.preventDefault();
69
+ this._cancelQueuedSearch();
70
+ this.search();
71
+ });
72
+ }
73
+
74
+ _queueSearch(){
75
+ this._cancelQueuedSearch();
76
+ this._search_timer=setTimeout(()=>{
77
+ this.search();
78
+ this._search_timer=null;
79
+ },Number(this.delay));
80
+ }
81
+
82
+ _cancelQueuedSearch(){
83
+ this.dispatchEvent(new CustomEvent('cancel-search',{
84
+ detail:{
85
+ query:this.value
86
+ },
87
+ bubbles:true
88
+ }));
89
+ if(this._search_timer){
90
+ clearTimeout(this._search_timer);
91
+ this._search_timer=null;
92
+ }
93
+ }
94
+
95
+ search(){
96
+ this.dispatchEvent(new CustomEvent('search',{
97
+ detail:{
98
+ query:this.value
99
+ },
100
+ bubbles:true
101
+ }));
102
+ }
103
+
104
+ }
@@ -153,11 +153,6 @@ class TaskQueueItem{
153
153
  this.onFinalize();
154
154
  }
155
155
 
156
- // Cancelar si usa XHR
157
- cancel(){
158
- if(this.xhr) this.xhr.abort();
159
- }
160
-
161
156
  // Resolver manualmente
162
157
  resolve(data,callback){
163
158
  this.resolve_callback=callback;
@@ -1,3 +1,22 @@
1
+ // Colores generales
2
+ $primary-color: #06c;
3
+ $secondary-color: #2c3e50;
4
+ $primary-color-hover: #007bff;
5
+ $secondary-color-hover: #2c3e50;
6
+ $black1: #000000;
7
+ $black2: #202020;
8
+ $black3: #404040;
9
+ $black4: #808080;
10
+ $black: $black1;
11
+ $white1: #ffffff;
12
+ $white2: #f5f5f5;
13
+ $white3: #e0e0e0;
14
+ $white4: #bfbfbf;
15
+ $white: $white1;
16
+ $valid-color: #008000;
17
+ $invalid-color: #FF0000;
18
+ $neutral-color: #353535;
19
+
1
20
  // Colores de ventanas de mensajes
2
21
  $msg-text-error-color: #b94a48;
3
22
  $msg-text-success-color: #468847;
@@ -8,6 +27,16 @@ $msg-background-success-color: #dff0d8;
8
27
  $msg-background-warning-color: #fcf8e3;
9
28
  $msg-background-info-color: #d9edf7;
10
29
 
30
+ // Colores para carga
11
31
  $loader-primary-color: #3b82f6;
12
32
  $loader-secondary-color: #93c5fd;
13
- $loader-muted-color: #5b6e8c;
33
+ $loader-muted-color: #5b6e8c;
34
+
35
+ // Colores para botones
36
+ $add-button-background: #006400;
37
+ $add-button-background-hover: #004b00;
38
+ $edit-button-background: #004080;
39
+ $edit-button-background-hover: #003060;
40
+ $delete-button-background: #8b0000;
41
+ $delete-button-background-hover: #6b0000;
42
+ $disabled-button-background: #dddddd;
@@ -0,0 +1,20 @@
1
+ @use './colors.scss' as *;
2
+
3
+ .icon{
4
+ width: 1.2rem;
5
+ height: 1.2rem;
6
+ display: inline-block;
7
+ vertical-align: middle;
8
+ background-color: $black;
9
+ mask-repeat: no-repeat;
10
+ mask-position: center;
11
+ mask-size: contain;
12
+ -webkit-mask-repeat: no-repeat;
13
+ -webkit-mask-position: center;
14
+ -webkit-mask-size: contain;
15
+
16
+ &.search{
17
+ mask-image: url("./assets/icons/search.svg");
18
+ -webkit-mask-image: url("./assets/icons/search.svg");
19
+ }
20
+ }
@@ -1,2 +1,3 @@
1
+ @use './icons.scss' as *;
1
2
  @use './message.scss' as *;
2
3
  @use './loader.scss' as *;