@ekzo-dev/bootstrap-addons 5.3.11 → 5.3.13

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.3.11",
4
+ "version": "5.3.13",
5
5
  "homepage": "https://github.com/ekzo-dev/aurelia-components/tree/main/packages/bootstrap-addons",
6
6
  "repository": {
7
7
  "type": "git",
@@ -9,21 +9,21 @@
9
9
  },
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@ekzo-dev/bootstrap": "~5.3.0",
13
- "@ekzo-dev/vanilla-jsoneditor": "^3.10.0",
12
+ "@ekzo-dev/bootstrap": "~5.3.3",
13
+ "@ekzo-dev/vanilla-jsoneditor": "~3.11.0",
14
14
  "@ekzo-dev/toolkit": "^1.2.4",
15
- "@fortawesome/free-solid-svg-icons": "^6.5.2",
15
+ "@fortawesome/free-solid-svg-icons": "^7.0.1",
16
16
  "@types/json-schema": "^7.0.14",
17
17
  "@js-temporal/polyfill": "^0.5.1",
18
18
  "ajv": "^8.17.1",
19
19
  "ajv-formats": "^3.0.1",
20
- "json-schema-library": "^10.5.1"
20
+ "json-schema-library": "^10.5.2"
21
21
  },
22
22
  "peerDependencies": {
23
23
  "aurelia": "^2.0.0-rc.0",
24
24
  "bootstrap": "~5.3.7",
25
25
  "@popperjs/core": "^2.11.8",
26
- "vanilla-jsoneditor": "~3.7.0",
26
+ "vanilla-jsoneditor": "~3.11.0",
27
27
  "immutable-json-patch": "^6.0.1"
28
28
  },
29
29
  "main": "src/index.ts",
@@ -1,9 +1,9 @@
1
1
  <template class="${floatingLabel ? 'form-floating' : ''}">
2
- <label for="${id}" if.bind="label && !floatingLabel" class="form-label">${label}</label>
2
+ <label for.one-time="id" if.bind="label && !floatingLabel" class="form-label">${label}</label>
3
3
  <fieldset class="${classes}" disabled.bind="disabled">
4
4
  <input
5
5
  type="text"
6
- id="${id}"
6
+ id.one-time="id"
7
7
  required.bind="required"
8
8
  value.bind="value"
9
9
  form.bind="form & attr"
@@ -22,7 +22,7 @@
22
22
  <input type="number" min="0" value.bind="duration.seconds" placeholder="--" />
23
23
  <span>${labels.seconds}</span>
24
24
  </fieldset>
25
- <label for="${id}" if.bind="label && floatingLabel"><span>${label}</span></label>
25
+ <label for.one-time="id" if.bind="label && floatingLabel"><span>${label}</span></label>
26
26
  <div class="invalid-feedback" if.bind="invalidFeedback">${invalidFeedback}</div>
27
27
  <div class="valid-feedback" if.bind="validFeedback">${validFeedback}</div>
28
28
  </template>
@@ -17,16 +17,17 @@ import type {
17
17
  Validator,
18
18
  } from 'vanilla-jsoneditor';
19
19
 
20
+ import { ProxyObservable } from '@aurelia/runtime';
20
21
  import { coerceBoolean } from '@ekzo-dev/toolkit';
21
22
  import { JsonEditor } from '@ekzo-dev/vanilla-jsoneditor';
22
23
  import { faUpRightAndDownLeftFromCenter } from '@fortawesome/free-solid-svg-icons/faUpRightAndDownLeftFromCenter';
23
- import Ajv, { ErrorObject, Options, ValidateFunction } from 'ajv';
24
+ import Ajv, { ErrorObject, Options } from 'ajv';
24
25
  import Ajv2019 from 'ajv/dist/2019';
25
26
  import Ajv2020 from 'ajv/dist/2020';
26
27
  import addFormats from 'ajv-formats';
27
28
  import { bindable, BindingMode, customElement } from 'aurelia';
28
29
  import { parsePath } from 'immutable-json-patch';
29
- import { compileSchema, JsonError, JsonSchema, SchemaNode } from 'json-schema-library';
30
+ import { CompileOptions, compileSchema, JsonError, SchemaNode } from 'json-schema-library';
30
31
 
31
32
  const patternMap: Record<string, string> = {
32
33
  '^[A-Za-z_][-A-Za-z0-9._]*$': '^[A-Za-z_][\\-A-Za-z0-9._]*$',
@@ -48,11 +49,11 @@ export class BsJsonInput {
48
49
  @bindable(coerceBoolean)
49
50
  disabled: boolean = false;
50
51
 
51
- @bindable({ set: (v) => (v === '' || v === true || v === 'true' ? true : v) })
52
- jsonSchema?: JSONSchema | boolean;
52
+ @bindable({ set: (v: BsJsonInput['jsonSchema'] | string) => (v === '' || v === true || v === 'true' ? true : v) })
53
+ jsonSchema?: JSONSchema | SchemaNode | boolean;
53
54
 
54
55
  @bindable()
55
- ajvOptions: Options = {};
56
+ validatorOptions?: CompileOptions;
56
57
 
57
58
  @bindable()
58
59
  jsonEditorOptions: JSONEditorPropsOptional = {};
@@ -148,52 +149,24 @@ export class BsJsonInput {
148
149
  }
149
150
 
150
151
  get validator(): Validator | undefined {
151
- const { schemaVersion, disabled, ajvOptions, jsonSchema } = this;
152
- // use raw object because proxies don't work with private properties
153
- const rawThis = this['__raw__'] as BsJsonInput;
154
- // use jsonSchema from raw object to pass original (non-proxied) object to AJV
155
- const { jsonSchema: rawJsonSchema } = rawThis;
152
+ const { schemaVersion, disabled, jsonSchema } = this;
153
+ const rawThis = ProxyObservable.getRaw<BsJsonInput>(this);
156
154
 
157
- if (jsonSchema && typeof jsonSchema === 'object' && !disabled) {
158
- const ajv = rawThis.#initAjv(jsonSchema.$schema as string, ajvOptions);
155
+ if (disabled) return;
159
156
 
160
- addFormats(ajv);
161
- let validate: ValidateFunction;
162
- let schema: SchemaNode;
163
-
164
- try {
165
- schema = compileSchema(rawJsonSchema as JsonSchema);
166
- } catch (e) {
167
- console.error('json-schema-library validator compilation error', e);
168
- }
169
-
170
- try {
171
- validate = ajv.compile(rawJsonSchema);
172
- } catch (e) {
173
- console.error('AJV validator compilation error', e);
174
- }
157
+ if (jsonSchema && typeof jsonSchema === 'object') {
158
+ const schema = rawThis.#initJsonSchemaLibrary();
175
159
 
176
160
  return (json: unknown): ValidationError[] => {
177
161
  // do not validate empty documents
178
- if (json === undefined) return [];
162
+ if (json === undefined || !schema) return [];
179
163
 
180
- let allErrors: ValidationError[] = [];
181
-
182
- if (schema) {
183
- const { errors } = schema.validate(json);
184
-
185
- allErrors = rawThis.#processErrors(errors, json);
186
- }
164
+ const { errors } = schema.validate(json);
187
165
 
188
- if (validate) {
189
- validate(json);
190
- allErrors = allErrors.concat(rawThis.#processErrorsAjv(validate.errors, json));
191
- }
192
-
193
- return allErrors;
166
+ return rawThis.#processErrors(errors, json);
194
167
  };
195
- } else if (schemaVersion != null && !disabled) {
196
- const ajv = rawThis.#initAjv(schemaVersion, ajvOptions);
168
+ } else if (schemaVersion != null) {
169
+ const ajv = rawThis.#initAjv(schemaVersion);
197
170
 
198
171
  return (json: unknown): ValidationError[] => {
199
172
  // do not validate empty documents
@@ -216,7 +189,7 @@ export class BsJsonInput {
216
189
  }
217
190
  }
218
191
 
219
- #initAjv($schema: string, ajvOptions: Options): Ajv {
192
+ #initAjv($schema: string): Ajv {
220
193
  // some regexp's in 2019-09/2020-12 meta-schemas are not compatible with 'v' flag, so update them
221
194
  const regExp = (pattern: string) => new RegExp(patternMap[pattern] ?? pattern, 'v');
222
195
 
@@ -228,7 +201,7 @@ export class BsJsonInput {
228
201
  code: {
229
202
  regExp,
230
203
  },
231
- ...ajvOptions,
204
+ allErrors: true,
232
205
  };
233
206
  let ajv: Ajv;
234
207
 
@@ -245,9 +218,28 @@ export class BsJsonInput {
245
218
  ajv = new Ajv(options);
246
219
  }
247
220
 
221
+ addFormats(ajv);
222
+
248
223
  return ajv;
249
224
  }
250
225
 
226
+ #initJsonSchemaLibrary(): SchemaNode | undefined {
227
+ const { jsonSchema } = this;
228
+
229
+ // already a SchemaNode
230
+ if ((jsonSchema as SchemaNode).evaluationPath) {
231
+ return jsonSchema as SchemaNode;
232
+ }
233
+
234
+ try {
235
+ return compileSchema(jsonSchema as JSONSchema, this.validatorOptions);
236
+ } catch (e) {
237
+ console.error('json-schema-library validator compilation error', e);
238
+
239
+ return;
240
+ }
241
+ }
242
+
251
243
  #getSchemaDefinitions(schema: JSONSchema): JSONSchemaDefinitions {
252
244
  return (schema.$defs ?? schema.definitions) as JSONSchemaDefinitions;
253
245
  }
@@ -272,7 +264,7 @@ export class BsJsonInput {
272
264
  return (errors || []).map((error) => ({
273
265
  path: parsePath(json, error.data.pointer),
274
266
  message: error.message || 'Unknown error',
275
- severity: 'error' as ValidationSeverity,
267
+ severity: 'warning' as ValidationSeverity,
276
268
  }));
277
269
  }
278
270
  }
@@ -1,16 +1,11 @@
1
1
  <template class="addon ${floatingLabel ? 'form-floating' : ''}" bs-dropdown>
2
- <label for="${id}" if.bind="label && !floatingLabel" class="form-label">${label}</label>
2
+ <label for.one-time="id" if.bind="label && !floatingLabel" class="form-label">${label}</label>
3
3
  <input
4
- id="${id}"
4
+ id.one-time="id"
5
5
  class="form-select ${bsSize ? `form-select-${bsSize}` : ''} ${valid ? 'is-valid' : valid === false ? 'is-invalid' : ''}"
6
6
  bs-dropdown-toggle="arrow.bind: false"
7
7
  value="${valueText}"
8
8
  placeholder="${emptyOption?.text ?? ''}"
9
- disabled.bind="disabled"
10
- required.bind="required"
11
- form.bind="form & attr"
12
- name.bind="name & attr"
13
- title.bind="title & attr"
14
9
  autocomplete="off"
15
10
  keydown.trigger="$event.preventDefault()"
16
11
  ref="control"
@@ -33,12 +28,12 @@
33
28
  class="form-check-input"
34
29
  type="checkbox"
35
30
  checked.bind="value"
36
- model.bind="option.value"
37
- disabled.bind="option.disabled"
38
31
  matcher.bind="matcher"
39
- id="${optionId($index)}"
32
+ model.one-time="option.value"
33
+ disabled.one-time="option.disabled"
34
+ id.one-time="optionId($index)"
40
35
  />
41
- <label class="form-check-label" for="${optionId($index)}">${option.text || '&nbsp;'}</label>
36
+ <label class="form-check-label" for.one-time="optionId($index)">${option.text || '&nbsp;'}</label>
42
37
  </div>
43
38
  </div>
44
39
  <template repeat.for="[k, v] of groupedOptions | filter:filter">
@@ -49,12 +44,14 @@
49
44
  class="form-check-input"
50
45
  type="checkbox"
51
46
  checked.bind="value"
52
- model.bind="option.value"
53
- disabled.bind="option.disabled"
54
47
  matcher.bind="matcher"
55
- id="${optionId($index, $parent.$index)}"
48
+ model.one-time="option.value"
49
+ disabled.one-time="option.disabled"
50
+ id.one-time="optionId($index, $parent.$index)"
56
51
  />
57
- <label class="form-check-label" for="${optionId($index, $parent.$index)}">${option.text || '&nbsp;'}</label>
52
+ <label class="form-check-label" for.one-time="optionId($index, $parent.$index)"
53
+ >${option.text || '&nbsp;'}</label
54
+ >
58
55
  </div>
59
56
  </div>
60
57
  </template>
@@ -64,7 +61,7 @@
64
61
  type="button"
65
62
  repeat.for="option of ungroupedOptions | filter:filter:emptyOption"
66
63
  class="dropdown-item ${option.value === selectedOption?.value ? 'active' : ''}"
67
- disabled.bind="option.disabled"
64
+ disabled.one-time="option.disabled"
68
65
  click.trigger="selectOption(option)"
69
66
  >
70
67
  ${option.text || '&nbsp;'}
@@ -75,7 +72,7 @@
75
72
  type="button"
76
73
  repeat.for="option of v"
77
74
  class="ps-4 dropdown-item ${option.value === selectedOption?.value ? 'active' : ''}"
78
- disabled.bind="option.disabled"
75
+ disabled.one-time="option.disabled"
79
76
  click.trigger="selectOption(option)"
80
77
  >
81
78
  ${option.text || '&nbsp;'}
@@ -83,7 +80,7 @@
83
80
  </template>
84
81
  </template>
85
82
  </bs-dropdown-menu>
86
- <label for="${id}" if.bind="label && floatingLabel"><span>${label}</span></label>
83
+ <label for.one-time="id" if.bind="label && floatingLabel"><span>${label}</span></label>
87
84
  <div class="invalid-feedback" if.bind="invalidFeedback">${invalidFeedback}</div>
88
85
  <div class="valid-feedback" if.bind="validFeedback">${validFeedback}</div>
89
86
  </template>
@@ -29,8 +29,6 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
29
29
 
30
30
  host = resolve(HTMLElement);
31
31
 
32
- control!: HTMLFieldSetElement;
33
-
34
32
  filter: string = '';
35
33
 
36
34
  emptyOption?: ISelectOption;
@@ -97,8 +95,6 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
97
95
  }
98
96
 
99
97
  get showClear(): boolean {
100
- console.warn(`BsSelect #${this.id}: get showClear`);
101
-
102
98
  return (
103
99
  !this.disabled &&
104
100
  ((this.emptyOption && this.selectedOption?.value !== this.emptyOption.value) ||
@@ -126,7 +122,6 @@ export class BsSelect extends BaseBsSelect implements ICustomElementViewModel {
126
122
  }
127
123
 
128
124
  get selectedOption(): ISelectOption | undefined {
129
- console.warn(`BsSelect #${this.id}: get selectedOption`);
130
125
  if (this.multiple) return;
131
126
 
132
127
  const { value, emptyValue, matcher } = this;