@ekzo-dev/bootstrap-addons 5.2.18 → 5.2.20

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ekzo-dev/bootstrap-addons",
3
3
  "description": "Aurelia Bootstrap additional component",
4
- "version": "5.2.18",
4
+ "version": "5.2.20",
5
5
  "homepage": "https://github.com/ekzo-dev/aurelia-components/tree/main/packages/bootstrap-addons",
6
6
  "repository": {
7
7
  "type": "git",
@@ -1,19 +1,26 @@
1
1
  <template class="${floatingLabel ? 'form-floating' : ''}">
2
2
  <label for="${id}" if.bind="label && !floatingLabel" class="form-label">${label}</label>
3
- <fieldset class="${classes}" id="${id}" disabled.bind="disabled">
4
- <input type="number" min="0" value.bind="duration.years" disabled.bind="disabled" placeholder="--" />
5
- ${labels.years}
6
- <input type="number" min="0" value.bind="duration.months" disabled.bind="disabled" placeholder="--" />
7
- ${labels.months}
8
- <input type="number" min="0" value.bind="duration.days" disabled.bind="disabled" placeholder="--" />
9
- ${labels.days}
10
- <input type="number" min="0" value.bind="duration.hours" disabled.bind="disabled" placeholder="--" />
11
- ${labels.hours}
12
- <input type="number" min="0" value.bind="duration.minutes" disabled.bind="disabled" placeholder="--" />
13
- ${labels.minutes}
14
- <input type="number" min="0" value.bind="duration.seconds" disabled.bind="disabled" placeholder="--" />
15
- ${labels.seconds}
16
- <input if.bind="required" required value.bind="value" />
3
+ <fieldset class="${classes}" disabled.bind="disabled">
4
+ <input
5
+ type="text"
6
+ id="${id}"
7
+ required.bind="required"
8
+ value.bind="value"
9
+ form.bind="form & attr"
10
+ focus.trigger="focus()"
11
+ />
12
+ <input type="number" min="0" value.bind="duration.years" placeholder="--" />
13
+ <span>${labels.years}</span>
14
+ <input type="number" min="0" value.bind="duration.months" placeholder="--" />
15
+ <span>${labels.months}</span>
16
+ <input type="number" min="0" value.bind="duration.days" placeholder="--" />
17
+ <span>${labels.days}</span>
18
+ <input type="number" min="0" value.bind="duration.hours" placeholder="--" />
19
+ <span>${labels.hours}</span>
20
+ <input type="number" min="0" value.bind="duration.minutes" placeholder="--" />
21
+ <span>${labels.minutes}</span>
22
+ <input type="number" min="0" value.bind="duration.seconds" placeholder="--" />
23
+ <span>${labels.seconds}</span>
17
24
  </fieldset>
18
25
  <label for="${id}" if.bind="label && floatingLabel"><span>${label}</span></label>
19
26
  <div class="invalid-feedback" if.bind="invalidFeedback">${invalidFeedback}</div>
@@ -9,6 +9,25 @@ bs-duration-input {
9
9
 
10
10
  fieldset {
11
11
  position: relative;
12
+
13
+ // Customize the `:focus` state to imitate native WebKit styles.
14
+ &:focus-within {
15
+ color: $input-focus-color;
16
+ background-color: $input-focus-bg;
17
+ border-color: $input-focus-border-color;
18
+ outline: 0;
19
+
20
+ @if $enable-shadows {
21
+ @include box-shadow($input-box-shadow, $input-focus-box-shadow);
22
+ } @else {
23
+ // Avoid using mixin so we can pass custom focus shadow properly
24
+ box-shadow: $input-focus-box-shadow;
25
+ }
26
+ }
27
+
28
+ span {
29
+ user-select: none;
30
+ }
12
31
  }
13
32
 
14
33
  input[type='number'] {
@@ -18,6 +37,7 @@ bs-duration-input {
18
37
  outline: 0;
19
38
  text-align: right;
20
39
  field-sizing: content;
40
+ background: transparent;
21
41
 
22
42
  &::-webkit-outer-spin-button,
23
43
  &::-webkit-inner-spin-button {
@@ -26,7 +46,7 @@ bs-duration-input {
26
46
  }
27
47
  }
28
48
 
29
- input[required] {
49
+ input[type='text'] {
30
50
  position: absolute;
31
51
  height: 100%;
32
52
  width: 100%;
@@ -37,6 +57,18 @@ bs-duration-input {
37
57
  }
38
58
  }
39
59
 
60
+ .was-validated bs-duration-input {
61
+ .form-control:invalid:focus-within,
62
+ .form-control.is-invalid:focus-within {
63
+ box-shadow: 0 0 0 0.25rem rgb(220 53 69 / 25%);
64
+ }
65
+
66
+ .form-control:valid:focus-within,
67
+ .form-control.is-valid:focus-within {
68
+ box-shadow: 0 0 0 0.25rem rgb(25 135 84 / 25%);
69
+ }
70
+ }
71
+
40
72
  @supports not (field-sizing: content) {
41
73
  bs-duration-input {
42
74
  input[type='number'] {
@@ -33,7 +33,6 @@ const Validation: Story = (args): StoryFnAureliaReturnType => ({
33
33
 
34
34
  Validation.args = {
35
35
  required: true,
36
- floatingLabel: true,
37
36
  };
38
37
 
39
38
  // eslint-disable-next-line
@@ -6,7 +6,7 @@ import '@formatjs/intl-durationformat/polyfill';
6
6
 
7
7
  import { BaseField, Size } from '@ekzo-dev/bootstrap';
8
8
  import { coerceBoolean } from '@ekzo-dev/toolkit';
9
- import { bindable, BindingMode, customElement } from 'aurelia';
9
+ import { bindable, BindingMode, customElement, resolve } from 'aurelia';
10
10
 
11
11
  interface IDuration {
12
12
  years?: string;
@@ -21,7 +21,7 @@ interface IDuration {
21
21
  name: 'bs-duration-input',
22
22
  template,
23
23
  })
24
- export class BsDurationInput extends BaseField {
24
+ export class BsDurationInput extends BaseField implements EventListenerObject {
25
25
  @bindable({ mode: BindingMode.twoWay })
26
26
  get value(): string {
27
27
  const { years, months, days, hours, minutes, seconds } = this.duration;
@@ -32,20 +32,7 @@ export class BsDurationInput extends BaseField {
32
32
  return date || time ? `P${date}${time ? 'T' + time : ''}` : '';
33
33
  }
34
34
  set value(value: string | null | undefined) {
35
- const match = value?.match(/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/);
36
-
37
- if (match) {
38
- this.duration = {
39
- years: match[1],
40
- months: match[2],
41
- days: match[3],
42
- hours: match[4],
43
- minutes: match[5],
44
- seconds: match[6],
45
- };
46
- } else {
47
- this.duration = {};
48
- }
35
+ this.parseDuration(value);
49
36
  }
50
37
 
51
38
  @bindable()
@@ -54,10 +41,14 @@ export class BsDurationInput extends BaseField {
54
41
  @bindable(coerceBoolean)
55
42
  floatingLabel: boolean = false;
56
43
 
44
+ readonly host = resolve(HTMLElement);
45
+
57
46
  duration: IDuration = {};
58
47
 
59
48
  labels: IDuration = this.#getLabels();
60
49
 
50
+ controls!: NodeListOf<HTMLInputElement>;
51
+
61
52
  get classes(): string {
62
53
  return [
63
54
  'form-control',
@@ -69,6 +60,56 @@ export class BsDurationInput extends BaseField {
69
60
  .join(' ');
70
61
  }
71
62
 
63
+ attaching() {
64
+ this.controls = this.host.querySelectorAll('input[type=number]');
65
+ this.controls.forEach((control) => {
66
+ control.addEventListener('keypress', this);
67
+ control.addEventListener('paste', this);
68
+ });
69
+ }
70
+
71
+ detached() {
72
+ this.controls.forEach((control) => {
73
+ control.removeEventListener('keypress', this);
74
+ control.removeEventListener('paste', this);
75
+ });
76
+ }
77
+
78
+ handleEvent(event: KeyboardEvent | ClipboardEvent): void {
79
+ const data = event instanceof KeyboardEvent ? event.key : event.clipboardData.getData('text');
80
+
81
+ // don't allow non-numeric values
82
+ if (!/^\d+$/.test(data)) {
83
+ event.preventDefault();
84
+ }
85
+
86
+ // allow pasting full duration value, e.g. P2YT2H
87
+ if (event instanceof ClipboardEvent && data.startsWith('P')) {
88
+ this.parseDuration(data);
89
+ }
90
+ }
91
+
92
+ focus() {
93
+ this.controls.item(0).focus();
94
+ }
95
+
96
+ private parseDuration(value: string) {
97
+ const match = value?.match(/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/);
98
+
99
+ if (match) {
100
+ this.duration = {
101
+ years: match[1],
102
+ months: match[2],
103
+ days: match[3],
104
+ hours: match[4],
105
+ minutes: match[5],
106
+ seconds: match[6],
107
+ };
108
+ } else {
109
+ this.duration = {};
110
+ }
111
+ }
112
+
72
113
  #getLabels(): IDuration {
73
114
  const str: string = new Intl['DurationFormat'](navigator.language, { style: 'narrow' }).format({
74
115
  years: 1,