@ekzo-dev/bootstrap-addons 5.2.28 → 5.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.
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.28",
4
+ "version": "5.3.0",
5
5
  "homepage": "https://github.com/ekzo-dev/aurelia-components/tree/main/packages/bootstrap-addons",
6
6
  "repository": {
7
7
  "type": "git",
@@ -9,20 +9,20 @@
9
9
  },
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@ekzo-dev/bootstrap": "^5.2.20",
12
+ "@ekzo-dev/bootstrap": "^5.3.0",
13
13
  "@ekzo-dev/vanilla-jsoneditor": "^0.23.7",
14
14
  "@ekzo-dev/toolkit": "^1.2.4",
15
15
  "@fortawesome/free-solid-svg-icons": "^6.5.2",
16
16
  "@types/json-schema": "^7.0.14",
17
- "@formatjs/intl-durationformat": "^0.7.1",
17
+ "@js-temporal/polyfill": "^0.5.1",
18
18
  "ajv": "^8.17.1",
19
19
  "ajv-formats": "^3.0.1",
20
20
  "vanilla-jsoneditor": "~0.23.0",
21
21
  "immutable-json-patch": "^5.1.3"
22
22
  },
23
23
  "peerDependencies": {
24
- "aurelia": "^2.0.0-beta.8",
25
- "bootstrap": "^5.2.3",
24
+ "aurelia": "^2.0.0-beta.25",
25
+ "bootstrap": "~5.3.7",
26
26
  "@popperjs/core": "^2.11.8"
27
27
  },
28
28
  "main": "src/index.ts",
@@ -9,7 +9,7 @@ const meta: Meta = {
9
9
  title: 'Ekzo / Bootstrap Addons / Forms / Duration input',
10
10
  component: BsDurationInput,
11
11
  args: {
12
- value: 'P5DT1H',
12
+ value: 'P5DT1Hasds',
13
13
  label: 'Duration',
14
14
  },
15
15
  argTypes: {
@@ -27,7 +27,7 @@ const Validation: Story = (args): StoryFnAureliaReturnType => ({
27
27
  props: args,
28
28
  template: `<form class='was-validated'>${createComponentTemplate(
29
29
  BsDurationInput
30
- )}<br><button bs-button>Validate</button></form>`,
30
+ )}<br>\${value} <button bs-button>Validate</button></form>`,
31
31
  components: [BsButton],
32
32
  });
33
33
 
@@ -2,20 +2,15 @@ import template from './duration-input.html';
2
2
 
3
3
  import './duration-input.scss';
4
4
 
5
- import '@formatjs/intl-durationformat/polyfill';
6
-
7
5
  import { BaseField, Size } from '@ekzo-dev/bootstrap';
8
6
  import { coerceBoolean } from '@ekzo-dev/toolkit';
7
+ import { Temporal } from '@js-temporal/polyfill';
9
8
  import { bindable, BindingMode, customElement, resolve } from 'aurelia';
10
9
 
11
- interface IDuration {
12
- years?: string;
13
- months?: string;
14
- days?: string;
15
- hours?: string;
16
- minutes?: string;
17
- seconds?: string;
18
- }
10
+ type Duration = Partial<Pick<Temporal.Duration, 'years' | 'months' | 'days' | 'hours' | 'minutes' | 'seconds'>>;
11
+ type DurationLabels = {
12
+ [K in keyof Duration]: string;
13
+ };
19
14
 
20
15
  /**
21
16
  * https://github.com/whatwg/html/issues/5488
@@ -30,13 +25,18 @@ export class BsDurationInput extends BaseField implements EventListenerObject {
30
25
  get value(): string {
31
26
  const { years, months, days, hours, minutes, seconds } = this.duration;
32
27
 
33
- const date = `${years ? years + 'Y' : ''}${months ? months + 'M' : ''}${days ? days + 'D' : ''}`;
34
- const time = `${hours ? hours + 'H' : ''}${minutes ? minutes + 'M' : ''}${seconds ? seconds + 'S' : ''}`;
35
-
36
- return date || time ? `P${date}${time ? 'T' + time : ''}` : '';
28
+ return Temporal.Duration.from({
29
+ // at least one field must be present for correct formatting
30
+ years: years ?? 0,
31
+ months,
32
+ days,
33
+ hours,
34
+ minutes,
35
+ seconds,
36
+ }).toString();
37
37
  }
38
38
  set value(value: string | null | undefined) {
39
- this.parseDuration(value);
39
+ this._parseDuration(value);
40
40
  }
41
41
 
42
42
  @bindable()
@@ -47,9 +47,9 @@ export class BsDurationInput extends BaseField implements EventListenerObject {
47
47
 
48
48
  readonly host = resolve(HTMLElement);
49
49
 
50
- duration: IDuration = {};
50
+ duration!: Duration;
51
51
 
52
- labels: IDuration = this.#getLabels();
52
+ labels: DurationLabels = this.#getLabels();
53
53
 
54
54
  controls!: NodeListOf<HTMLInputElement>;
55
55
 
@@ -89,7 +89,7 @@ export class BsDurationInput extends BaseField implements EventListenerObject {
89
89
 
90
90
  // allow pasting full duration value, e.g. P2YT2H
91
91
  if (event instanceof ClipboardEvent && data.startsWith('P')) {
92
- this.parseDuration(data);
92
+ this._parseDuration(data);
93
93
  }
94
94
  }
95
95
 
@@ -97,24 +97,29 @@ export class BsDurationInput extends BaseField implements EventListenerObject {
97
97
  this.controls.item(0).focus();
98
98
  }
99
99
 
100
- private parseDuration(value: string) {
101
- const match = value?.match(/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?)?$/);
100
+ private _parseDuration(value: string) {
101
+ try {
102
+ const duration = Temporal.Duration.from(value);
102
103
 
103
- if (match) {
104
104
  this.duration = {
105
- years: match[1],
106
- months: match[2],
107
- days: match[3],
108
- hours: match[4],
109
- minutes: match[5],
110
- seconds: match[6],
105
+ years: duration.years,
106
+ months: duration.months,
107
+ days: duration.days,
108
+ hours: duration.hours,
109
+ minutes: duration.minutes,
110
+ seconds: duration.seconds,
111
111
  };
112
- } else {
113
- this.duration = {};
112
+ } catch (error) {
113
+ if (error instanceof RangeError) {
114
+ console.warn(`[bs-duration-input] ${error.message}`);
115
+ this.duration = {};
116
+ } else {
117
+ throw error;
118
+ }
114
119
  }
115
120
  }
116
121
 
117
- #getLabels(): IDuration {
122
+ #getLabels(): DurationLabels {
118
123
  const str: string = new Intl['DurationFormat'](navigator.language, { style: 'narrow' }).format({
119
124
  years: 1,
120
125
  months: 1,
@@ -84,9 +84,13 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
84
84
  }
85
85
 
86
86
  get valueText(): string {
87
- // if (this.multiple) {
88
- //
89
- // }
87
+ if (this.multiple) {
88
+ const { options, value } = this;
89
+
90
+ return (value as [])
91
+ .map((val) => (options as ISelectOption[]).find((option) => option.value === val).text)
92
+ .join(', ');
93
+ }
90
94
 
91
95
  const { selectedOption, emptyOption } = this;
92
96
 
@@ -134,19 +138,20 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
134
138
 
135
139
  const isEntries = Array.isArray(options[0]);
136
140
  let option = (options as Array<ISelectOption | readonly [unknown, string]>).find((option) => {
137
- const currentValue: unknown = isEntries ? option[0] : (option as ISelectOption).value;
141
+ const optionValue: unknown = isEntries ? option[0] : (option as ISelectOption).value;
138
142
 
139
- if (currentValue == emptyValue) {
143
+ if (optionValue == emptyValue) {
140
144
  emptyOption = {
141
- value: currentValue,
142
- text: isEntries ? option[1] : (option as ISelectOption).text,
145
+ value: optionValue,
146
+ text: isEntries ? (option[1] as string) : (option as ISelectOption).text,
143
147
  } as ISelectOption;
144
148
  }
145
149
 
146
- return matcher ? matcher(value, currentValue) : value === currentValue;
150
+ return matcher ? matcher(value, optionValue) : value === optionValue;
147
151
  });
148
152
 
149
- option = isEntries && option !== undefined ? { value: option[0], text: option[1] } : (option as ISelectOption);
153
+ option =
154
+ isEntries && option !== undefined ? { value: option[0], text: option[1] as string } : (option as ISelectOption);
150
155
 
151
156
  // update value next tick
152
157
  const foundValue = option?.value;