@dile/ui 3.6.5 → 3.6.7

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.
@@ -29,4 +29,29 @@ describe('dile-confirm', () => {
29
29
 
30
30
  expect(accepted).toBe(true);
31
31
  });
32
+
33
+ it('handles dontCloseOnAccept and can be reset with resetProcessing()', async () => {
34
+ const el = await renderConfirm('<dile-confirm dontCloseOnAccept>Are you sure?</dile-confirm>');
35
+ let acceptCount = 0;
36
+ el.addEventListener('dile-confirm-accepted', () => { acceptCount++; });
37
+
38
+ el.shadowRoot.querySelector('.accept').click();
39
+ await el.updateComplete;
40
+ expect(acceptCount).toBe(1);
41
+ expect(el._isProcessing).toBe(true);
42
+ expect(el.shadowRoot.querySelector('.accept').classList.contains('disabled')).toBe(true);
43
+
44
+ // Clicking again while processing should not trigger accept
45
+ el.shadowRoot.querySelector('.accept').click();
46
+ expect(acceptCount).toBe(1);
47
+
48
+ // Calling resetProcessing should unlock the buttons
49
+ el.resetProcessing();
50
+ await el.updateComplete;
51
+ expect(el._isProcessing).toBe(false);
52
+ expect(el.shadowRoot.querySelector('.accept').classList.contains('disabled')).toBe(false);
53
+
54
+ el.shadowRoot.querySelector('.accept').click();
55
+ expect(acceptCount).toBe(2);
56
+ });
32
57
  });
@@ -52,6 +52,7 @@ export class DileConfirm extends LitElement {
52
52
  cancelLabel: { type: String },
53
53
  blocking: { type: Boolean },
54
54
  dontCloseOnAccept: { type: Boolean },
55
+ _isProcessing: { state: true },
55
56
  };
56
57
  }
57
58
 
@@ -61,6 +62,7 @@ export class DileConfirm extends LitElement {
61
62
  this.cancelLabel = "Cancell";
62
63
  this.opened = false;
63
64
  this.blocking = false;
65
+ this.dontCloseOnAccept = false;
64
66
  this._isProcessing = false;
65
67
  }
66
68
 
@@ -100,6 +102,7 @@ export class DileConfirm extends LitElement {
100
102
 
101
103
  open() {
102
104
  this.modal.open();
105
+ this._isProcessing = false;
103
106
  }
104
107
 
105
108
  close() {
@@ -107,6 +110,10 @@ export class DileConfirm extends LitElement {
107
110
  this._isProcessing = false;
108
111
  }
109
112
 
113
+ resetProcessing() {
114
+ this._isProcessing = false;
115
+ }
116
+
110
117
  firstUpdated() {
111
118
  this.modal = this.shadowRoot.getElementById("modal");
112
119
  }
@@ -19,22 +19,52 @@ export class DileInputSearch extends LitElement {
19
19
  }
20
20
  div:focus-within {
21
21
  border-color: var(--dile-input-focus-border-color, var(--dile-link-color, #6af));
22
+ /* Outline adicional para mayor visibilidad */
23
+ outline: 2px solid var(--dile-input-focus-border-color, var(--dile-link-color, #6af));
24
+ outline-offset: 2px;
22
25
  }
23
26
  input {
24
27
  flex-grow: 1;
25
28
  border: none;
26
- outline: none;
27
29
  color: var(--dile-input-color, #303030);
28
30
  font-size: var(--dile-input-font-size, 1em);
29
31
  line-height: var(--dile-input-line-height, 1.5em);
30
32
  background-color: var(--dile-input-background-color, #fff);
33
+ padding: 2px 4px;
34
+ }
35
+ input:focus {
36
+ outline: none;
31
37
  }
32
38
  input::placeholder {
33
- color: var(--dile-input-placeholder-color, #ccc);
39
+ /* WCAG AA contrast: #666 sobre #fff = 7.5:1 */
40
+ color: var(--dile-input-placeholder-color, #666);
34
41
  }
35
- dile-icon {
42
+ .icon-button {
43
+ background: none;
44
+ border: none;
45
+ cursor: pointer;
46
+ padding: 4px;
36
47
  margin-left: 1px;
37
48
  display: flex;
49
+ align-items: center;
50
+ justify-content: center;
51
+ border-radius: 3px;
52
+ color: var(--dile-input-color, #303030);
53
+ font-size: 1em;
54
+ }
55
+ .icon-button:focus {
56
+ outline: 2px solid var(--dile-input-focus-border-color, var(--dile-link-color, #6af));
57
+ outline-offset: 1px;
58
+ }
59
+ .icon-button:hover:not(:disabled) {
60
+ background-color: var(--dile-input-hover-background, rgba(0,0,0,0.05));
61
+ }
62
+ .icon-button:disabled {
63
+ cursor: not-allowed;
64
+ opacity: 0.5;
65
+ }
66
+ dile-icon {
67
+ display: flex;
38
68
  }
39
69
  :host([disabled]) {
40
70
  opacity: 0.5;
@@ -42,6 +72,12 @@ export class DileInputSearch extends LitElement {
42
72
  .errored {
43
73
  border-color: var(--dile-input-error-border-color, #c00);
44
74
  }
75
+ .error-message {
76
+ color: var(--dile-input-error-border-color, #c00);
77
+ font-size: 0.875em;
78
+ margin-top: 4px;
79
+ padding: 4px 0;
80
+ }
45
81
  `
46
82
  ];
47
83
 
@@ -72,6 +108,10 @@ export class DileInputSearch extends LitElement {
72
108
  }
73
109
 
74
110
  render() {
111
+ const iconLabel = this.value.length
112
+ ? 'Limpiar búsqueda'
113
+ : 'Buscar';
114
+
75
115
  return html`
76
116
  <div class="${this.errored ? "errored" : ""}">
77
117
  <input
@@ -83,12 +123,29 @@ export class DileInputSearch extends LitElement {
83
123
  .value="${this.value}"
84
124
  ?disabled="${this.disabled}"
85
125
  ?readonly="${this.readOnly}"
126
+ aria-label="${this.name || 'Búsqueda'}"
127
+ ?aria-invalid="${this.errored}"
128
+ aria-describedby="${this.errored ? 'error-msg' : null}"
86
129
  >
87
- <dile-icon
130
+ <button
88
131
  @click=${this.iconClick}
89
- .icon="${this.value.length ? clearIcon : searchIcon}"
90
- ></dile-icon>
132
+ @keydown=${this.iconKeydown}
133
+ class="icon-button"
134
+ aria-label="${iconLabel}"
135
+ type="button"
136
+ ?disabled="${this.disabled}"
137
+ >
138
+ <dile-icon
139
+ .icon="${this.value.length ? clearIcon : searchIcon}"
140
+ aria-hidden="true"
141
+ ></dile-icon>
142
+ </button>
91
143
  </div>
144
+ ${this.errored ? html`
145
+ <div id="error-msg" class="error-message" role="alert">
146
+ <slot name="error"></slot>
147
+ </div>
148
+ ` : ''}
92
149
  `;
93
150
  }
94
151
 
@@ -107,6 +164,15 @@ export class DileInputSearch extends LitElement {
107
164
  this.input.focus();
108
165
  }
109
166
 
167
+ iconKeydown(e) {
168
+ // Permitir Space y Enter para activar el icono
169
+ if (e.key === ' ' || e.key === 'Enter') {
170
+ e.preventDefault();
171
+ this.clear();
172
+ this.input.focus();
173
+ }
174
+ }
175
+
110
176
  dispatchSearch(key) {
111
177
  this.dispatchEvent(new CustomEvent('dile-input-search', {
112
178
  bubbles: true,
@@ -137,6 +137,17 @@ export const DileForm = (superclass) => class extends superclass {
137
137
  }
138
138
  }
139
139
 
140
+ clearField(name) {
141
+ const node = this.getNodeElement(name);
142
+ if (node) {
143
+ if (typeof node.clear === "function") {
144
+ node.clear();
145
+ } else {
146
+ node.value = '';
147
+ }
148
+ }
149
+ }
150
+
140
151
  showError(name, error) {
141
152
  const parts = name.split('.');
142
153
 
@@ -82,10 +82,6 @@ export const DileOverlay = function(superClass) {
82
82
  * closes the overlay
83
83
  */
84
84
  close() {
85
- this.dispatchEvent(new CustomEvent('overlay-closed', {
86
- bubbles: true,
87
- composed: true,
88
- }));
89
85
  if(!this._opening && this._overlayClass=='opened') {
90
86
  this._overlayClass = '';
91
87
  this._removePositionListeners();
@@ -93,6 +89,10 @@ export const DileOverlay = function(superClass) {
93
89
  this.delayId = setTimeout(() => {
94
90
  this.overlay.style.display = 'none'
95
91
  }, 500);
92
+ this.dispatchEvent(new CustomEvent('overlay-closed', {
93
+ bubbles: true,
94
+ composed: true,
95
+ }));
96
96
  }
97
97
  }
98
98
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dile/ui",
3
- "version": "3.6.5",
3
+ "version": "3.6.7",
4
4
  "description": "UI Core components from dile-components.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -28,5 +28,5 @@
28
28
  "publishConfig": {
29
29
  "access": "public"
30
30
  },
31
- "gitHead": "ee029c01956874746ff8c78f02f4868ef4ce4875"
31
+ "gitHead": "d62c55983a8fcdf7b1a4cb2b6da64d4d1e30b9c6"
32
32
  }