@dile/ui 2.7.1 → 2.8.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.
@@ -0,0 +1,2 @@
1
+ export { DileNumberPickerElement } from './src/DileNumberPickerElement.js';
2
+ export { DileNumberPicker } from './src/DileNumberPicker.js';
@@ -0,0 +1,3 @@
1
+ import { DileNumberPickerElement } from './src/DileNumberPickerElement.js';
2
+
3
+ window.customElements.define('dile-number-picker-element', DileNumberPickerElement);
@@ -0,0 +1,3 @@
1
+ import { DileNumberPicker } from './src/DileNumberPicker.js';
2
+
3
+ customElements.define('dile-number-picker', DileNumberPicker);
@@ -0,0 +1,150 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import { DileEmmitChange } from '../../../mixins/form/index.js';
3
+ import '../number-picker-element.js';
4
+ import { messageStyles } from '../../input/src/message-styles.js';
5
+
6
+ export class DileNumberPicker extends DileEmmitChange(LitElement) {
7
+ static styles = [
8
+ messageStyles,
9
+ css`
10
+ :host {
11
+ display: block;
12
+ margin-bottom: 10px;
13
+ }
14
+ * {
15
+ box-sizing: border-box;
16
+ }
17
+ label {
18
+ display: block;
19
+ margin-bottom: var(--dile-input-label-margin-bottom, 4px);
20
+ font-size: var(--dile-input-label-font-size, 1em);
21
+ color: var(--dile-input-label-color, #59e);
22
+ font-weight: var(--dile-input-label-font-weight, normal);
23
+ }
24
+ `
25
+ ];
26
+
27
+ static get formAssociated() {
28
+ return true;
29
+ }
30
+
31
+ static get properties() {
32
+ return {
33
+ value: { type: String },
34
+ digits: { type: Number },
35
+ leadingZeros: { type: Boolean },
36
+ step: { type: Number },
37
+
38
+ /** Label to the element */
39
+ label: { type: String },
40
+
41
+ /** Disable the input field */
42
+ disabled: { type: Boolean },
43
+
44
+ /** Name for this input field */
45
+ name: { type: String },
46
+
47
+ /** Message Displayed */
48
+ message: { type: String },
49
+
50
+ /** Has error on this input field */
51
+ errored: { type: Boolean },
52
+
53
+ /** Hide errors on input */
54
+ hideErrorOnInput: { type: Boolean },
55
+
56
+ /** Set the application focus to this the input component after the initialization */
57
+ focusOnStart: { type: Boolean },
58
+
59
+ min: { type: String },
60
+ max: { type: String },
61
+ };
62
+ }
63
+
64
+ constructor() {
65
+ super();
66
+ this.value = "";
67
+ this.digits = 2;
68
+ this.leadingZeros = false;
69
+ this.step = 1;
70
+ this.internals = this.attachInternals();
71
+ }
72
+
73
+ render() {
74
+ return html`
75
+
76
+ <main>
77
+ ${this.label
78
+ ? html`<label for="textField">${this.label}</label>`
79
+ : ""}
80
+ <section class="for-input">
81
+ <dile-number-picker-element
82
+ value="${this.value}"
83
+ digits="${this.digits}"
84
+ ?leadingZeros="${this.leadingZeros}"
85
+ step="${this.step}"
86
+ @dile-number-picker-value-changed=${this.valueChanged}
87
+ ?focusOnStart=${this.focusOnStart}
88
+ ?errored=${this.errored}
89
+ min=${this._numericMin(this.min)}
90
+ max=${this._numericMax(this.max)}
91
+ ?disabled=${this.disabled}
92
+ ></dile-number-picker-element>
93
+ </section>
94
+ ${this.messageTemplate}
95
+ </main>
96
+ `;
97
+ }
98
+
99
+ get el() {
100
+ return this.shadowRoot.querySelector('dile-number-picker-element')
101
+ }
102
+
103
+ get messageTemplate() {
104
+ return html`
105
+ ${this.message
106
+ ? html`<div class="message ${this.errored ? 'errored-msg' : ''}"><span>${this.message}</span></div>`
107
+ : ''
108
+ }
109
+ `
110
+ }
111
+
112
+ _numericMin(min) {
113
+ return min !== undefined && min !== '' ? parseInt(min, 10) : undefined;
114
+ }
115
+
116
+ _numericMax(max) {
117
+ return max !== undefined && max !== '' ? parseInt(max, 10) : undefined;
118
+ }
119
+
120
+
121
+ clear() {
122
+ this.value = 0;
123
+ this.el.clear();
124
+ }
125
+
126
+
127
+ valueChanged(e) {
128
+ this.value = e.detail;
129
+ if (this.hideErrorOnInput && this.errored) {
130
+ this.clearError();
131
+ }
132
+ }
133
+
134
+ updated(changedProperties) {
135
+ if(changedProperties.has('value')) {
136
+ this.emmitChange();
137
+ this.internals.setFormValue(this.value);
138
+ }
139
+ }
140
+
141
+ focus() {
142
+ this.el.focus();
143
+ }
144
+
145
+ clearError() {
146
+ this.errored = false;
147
+ this.message = '';
148
+ }
149
+ }
150
+
@@ -0,0 +1,220 @@
1
+ import { html, css, LitElement } from "lit";
2
+ import { arrowDropUpLargeIcon, arrowDropDownLargeIcon } from '@dile/icons';
3
+ import '../../icon/icon.js'
4
+
5
+ export class DileNumberPickerElement extends LitElement {
6
+ static get styles() {
7
+ return css`
8
+ :host {
9
+ display: block;
10
+ --dile-icon-size: var(--dile-number-picker-icon-size, 16px);
11
+ --dile-icon-color: var(--dile-number-picker-icon-color, #888);
12
+ }
13
+ section {
14
+ display: flex;
15
+ align-items: stretch;
16
+ gap: 0.2rem;
17
+ }
18
+ input {
19
+ border-radius: var(--dile-input-border-radius, 5px);
20
+ padding: var(--dile-number-picker-padding, 0.15rem 0.25rem);
21
+ width: var(--dile-number-picker-width, 48px);
22
+ text-align: center;
23
+ box-sizing: border-box;
24
+ border-radius: var(--dile-input-border-radius, 5px);
25
+ border: var(--dile-input-border-width, 1px) solid var(--dile-input-border-color, #888);
26
+ font-size: var(--dile-input-font-size, 1em);
27
+ background-color: var(--dile-input-background-color, #fff);
28
+ color: var(--dile-input-color, #303030);
29
+ }
30
+ .controls {
31
+ display: flex;
32
+ flex-direction: column;
33
+ align-items: center;
34
+ gap: 0.3rem;
35
+ }
36
+ dile-icon {
37
+ cursor: pointer;
38
+ user-select: none;
39
+ }
40
+ :host([errored]) input {
41
+ border-color: var(--dile-input-error-border-color, #c00);
42
+ }
43
+
44
+ input:disabled {
45
+ background-color: #f5f5f5;
46
+ border-color: var(--dile-input-disabled-border-color, #eee);
47
+ }
48
+ `
49
+ }
50
+
51
+ static get properties() {
52
+ return {
53
+ value: { type: String },
54
+ digits: { type: Number },
55
+ leadingZeros: { type: Boolean },
56
+ step: { type: Number },
57
+ /** Set errored state */
58
+ errored: { type: Boolean },
59
+ /** Set the application focus to this the input component after the initialization */
60
+ focusOnStart: { type: Boolean },
61
+ min: {
62
+ type: String,
63
+ converter: {
64
+ fromAttribute: (value, type) => {
65
+ return value === undefined || value === "" ? undefined : parseInt(value);
66
+ },
67
+ toAttribute: (value, type) => {
68
+ return value;
69
+ }
70
+ }
71
+ },
72
+ max: {
73
+ type: String,
74
+ converter: {
75
+ fromAttribute: (value, type) => {
76
+ return value === undefined || value === "" ? undefined : parseInt(value);
77
+ },
78
+ toAttribute: (value, type) => {
79
+ return value;
80
+ }
81
+ }
82
+ },
83
+ disabled: { type: Boolean },
84
+ };
85
+ }
86
+
87
+ constructor() {
88
+ super();
89
+ this.value = "";
90
+ this.digits = 2;
91
+ this.leadingZeros = false;
92
+ this.step = 1;
93
+ this.disabled = false;
94
+ }
95
+
96
+ get elinput() {
97
+ return this.shadowRoot.getElementById('elinput');
98
+ }
99
+
100
+ firstUpdated() {
101
+ this._transformInput(this.value || "0");
102
+ if(this.focusOnStart) {
103
+ this.focus();
104
+ }
105
+ }
106
+
107
+ updated(changedProperties) {
108
+ if(changedProperties.has('value')) {
109
+ this._transformInput(this.value);
110
+ }
111
+ }
112
+
113
+ render() {
114
+ return html`
115
+ <section>
116
+ <input
117
+ type="text"
118
+ id="elinput"
119
+ @input=${this._onInput}
120
+ ?disabled=${this.disabled}
121
+ >
122
+ <div class="controls">
123
+ <dile-icon .icon=${arrowDropUpLargeIcon} @click=${this.increment}></dile-icon>
124
+ <dile-icon .icon=${arrowDropDownLargeIcon} @click=${this.decrement}></dile-icon>
125
+ </div>
126
+ </section>
127
+ `;
128
+ }
129
+
130
+ _onInput(e) {
131
+ this._transformInput(e.target.value);
132
+ }
133
+
134
+ _transformInput(value) {
135
+ const cleaned = this._clean(value);
136
+ const formatted = this._formatNumber(cleaned);
137
+ this.elinput.value = formatted;
138
+ this.value = formatted;
139
+ this.dispatchEvent(new CustomEvent('dile-number-picker-value-changed', {
140
+ bubbles: true,
141
+ composed: true,
142
+ detail: this.value,
143
+ }));
144
+ }
145
+
146
+ _clean(value) {
147
+ let cleaned = value.replace(/[^\d]/g, '');
148
+
149
+ if (this.leadingZeros && cleaned.length > 1 && cleaned.startsWith('0')) {
150
+ cleaned = cleaned.substring(1);
151
+ }
152
+
153
+ if (this.digits && cleaned.length > this.digits) {
154
+ cleaned = cleaned.substring(0, this.digits);
155
+ }
156
+
157
+ let num = parseInt(cleaned || "0", 10);
158
+
159
+ const maxByDigits = Math.pow(10, this.digits) - 1;
160
+ if (num > maxByDigits) {
161
+ num = maxByDigits;
162
+ }
163
+
164
+ if (typeof this.min === 'number' && num < this.min) {
165
+ num = this.min;
166
+ }
167
+ if (typeof this.max === 'number' && num > this.max) {
168
+ num = this.max;
169
+ }
170
+
171
+ if (!this.leadingZeros) {
172
+ return num;
173
+ }
174
+
175
+ return num.toString();
176
+ }
177
+
178
+ _formatNumber(value) {
179
+ let val = value.toString();
180
+ if (this.leadingZeros) {
181
+ val = val.padStart(this.digits, '0');
182
+ }
183
+ return val;
184
+ }
185
+
186
+ increment() {
187
+ if(!this.disabled) {
188
+ let current = parseInt(this._clean(this.elinput.value), 10) || 0;
189
+ let next = current + this.step;
190
+ let asString = next.toString();
191
+
192
+ // Si el resultado excede digits, no hacemos nada
193
+ if (asString.length > this.digits) {
194
+ return;
195
+ }
196
+
197
+ this._transformInput(asString);
198
+ }
199
+ }
200
+
201
+ decrement() {
202
+ if(!this.disabled) {
203
+ let current = parseInt(this._clean(this.elinput.value), 10) || 0;
204
+ let next = Math.max(0, current - this.step);
205
+ let asString = next.toString();
206
+
207
+ this._transformInput(asString);
208
+ }
209
+ }
210
+
211
+ focus() {
212
+ console.log(this.elinput);
213
+ this.elinput.focus();
214
+ }
215
+
216
+ clear() {
217
+ this.value = 0;
218
+ this.elinput.value = 0;
219
+ }
220
+ }
@@ -0,0 +1,172 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import { DileEmmitChange } from '../../../mixins/form/index.js';
3
+ import '../../number-picker/number-picker-element.js';
4
+ import { messageStyles } from '../../input/src/message-styles.js';
5
+
6
+ export class DileTimePicker extends DileEmmitChange(LitElement) {
7
+ static styles = [
8
+ messageStyles,
9
+ css`
10
+ :host {
11
+ display: block;
12
+ margin-bottom: 10px;
13
+ }
14
+ label {
15
+ display: block;
16
+ margin-bottom: var(--dile-input-label-margin-bottom, 4px);
17
+ font-size: var(--dile-input-label-font-size, 1em);
18
+ color: var(--dile-input-label-color, #59e);
19
+ font-weight: var(--dile-input-label-font-weight, normal);
20
+ }
21
+ section {
22
+ display: flex;
23
+ gap: 0.5rem;
24
+ }
25
+ `
26
+ ];
27
+
28
+ static get formAssociated() {
29
+ return true;
30
+ }
31
+
32
+ static get properties() {
33
+ return {
34
+ value: { type: String },
35
+ _hours: { type: String, state: true },
36
+ _minutes: { type: String, state: true },
37
+ _seconds: { type: String, state: true },
38
+
39
+ label: { type: String },
40
+ disabled: { type: Boolean },
41
+ message: { type: String },
42
+ errored: { type: Boolean },
43
+ hideErrorOnInput: { type: Boolean },
44
+ focusOnStart: { type: Boolean },
45
+ name: { type: String },
46
+ };
47
+ }
48
+
49
+ constructor() {
50
+ super();
51
+ this.value = "00:00:00";
52
+ this._setFromValue(this.value);
53
+ this.internals = this.attachInternals();
54
+ }
55
+
56
+ render() {
57
+ return html`
58
+ <main>
59
+ ${this.label ? html`<label>${this.label}</label>` : ''}
60
+ <section class="for-input">
61
+ <dile-number-picker-element
62
+ min="0"
63
+ max="23"
64
+ step="1"
65
+ digits="2"
66
+ leadingZeros
67
+ .value=${this._hours}
68
+ ?disabled=${this.disabled}
69
+ ?errored=${this.errored}
70
+ ?focusOnStart=${this.focusOnStart}
71
+ @dile-number-picker-value-changed=${this._changeHours}
72
+ ></dile-number-picker-element>
73
+ <dile-number-picker-element
74
+ min="0"
75
+ max="59"
76
+ step="5"
77
+ digits="2"
78
+ leadingZeros
79
+ .value=${this._minutes}
80
+ ?disabled=${this.disabled}
81
+ ?errored=${this.errored}
82
+ @dile-number-picker-value-changed=${this._changeMinutes}
83
+ ></dile-number-picker-element>
84
+ <dile-number-picker-element
85
+ min="0"
86
+ max="59"
87
+ step="5"
88
+ digits="2"
89
+ leadingZeros
90
+ .value=${this._seconds}
91
+ ?disabled=${this.disabled}
92
+ ?errored=${this.errored}
93
+ @dile-number-picker-value-changed=${this._changeSeconds}
94
+ ></dile-number-picker-element>
95
+ </section>
96
+ ${this.messageTemplate}
97
+ </main>
98
+ `;
99
+ }
100
+
101
+ get messageTemplate() {
102
+ return html`
103
+ ${this.message
104
+ ? html`<div class="message ${this.errored ? 'errored-msg' : ''}"><span>${this.message}</span></div>`
105
+ : ''
106
+ }
107
+ `
108
+ }
109
+
110
+ get hoursEl() {
111
+ return this.shadowRoot.querySelectorAll('dile-number-picker-element')[0];
112
+ }
113
+
114
+ willUpdate(changedProperties) {
115
+ if (changedProperties.has('value')) {
116
+ this._setFromValue(this.value);
117
+ }
118
+ }
119
+
120
+ updated(changedProperties) {
121
+ if(changedProperties.has('value')) {
122
+ this.emmitChange();
123
+ this.internals.setFormValue(this.value);
124
+ }
125
+ }
126
+
127
+ _changeHours(e) {
128
+ this._hours = this._normalize(e.detail);
129
+ this._updateValue();
130
+ if (this.hideErrorOnInput && this.errored) this.clearError();
131
+ }
132
+
133
+ _changeMinutes(e) {
134
+ this._minutes = this._normalize(e.detail);
135
+ this._updateValue();
136
+ if (this.hideErrorOnInput && this.errored) this.clearError();
137
+ }
138
+
139
+ _changeSeconds(e) {
140
+ this._seconds = this._normalize(e.detail);
141
+ this._updateValue();
142
+ if (this.hideErrorOnInput && this.errored) this.clearError();
143
+ }
144
+
145
+ _normalize(value) {
146
+ const num = parseInt(value, 10);
147
+ return isNaN(num) ? '00' : num.toString().padStart(2, '0');
148
+ }
149
+
150
+ _setFromValue(value) {
151
+ const parts = (value || '00:00:00').split(':');
152
+ this._hours = this._normalize(parts[0]);
153
+ this._minutes = this._normalize(parts[1]);
154
+ this._seconds = this._normalize(parts[2]);
155
+ }
156
+
157
+ _updateValue() {
158
+ const newValue = `${this._hours}:${this._minutes}:${this._seconds}`;
159
+ if (this.value !== newValue) {
160
+ this.value = newValue;
161
+ }
162
+ }
163
+
164
+ focus() {
165
+ this.hoursEl.focus();
166
+ }
167
+
168
+ clearError() {
169
+ this.errored = false;
170
+ this.message = '';
171
+ }
172
+ }
@@ -0,0 +1,2 @@
1
+ import { DileTimePicker } from "./src/DileTimePicker";
2
+ customElements.define('dile-time-picker', DileTimePicker);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dile/ui",
3
- "version": "2.7.1",
3
+ "version": "2.8.0",
4
4
  "description": "UI Core components from dile-components.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -20,11 +20,11 @@
20
20
  },
21
21
  "homepage": "https://dile-components.com/",
22
22
  "dependencies": {
23
- "@dile/icons": "^2.2.0",
23
+ "@dile/icons": "^2.3.0",
24
24
  "lit": "^2.7.0 || ^3.0.0"
25
25
  },
26
26
  "publishConfig": {
27
27
  "access": "public"
28
28
  },
29
- "gitHead": "260fc2605a66bdb10796e07242fa396081659c2c"
29
+ "gitHead": "23cccd2c6346a026fe4dae9374520e604c620085"
30
30
  }