@lion/ui 0.5.6 → 0.5.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.
Files changed (66) hide show
  1. package/components/form-core/src/FormControlMixin.js +1 -1
  2. package/components/form-core/src/validate/ValidateMixin.js +8 -2
  3. package/components/form-core/src/validate/Validator.js +17 -3
  4. package/components/form-core/test/validate/Validator.test.js +8 -0
  5. package/components/input-file/src/LionInputFile.js +30 -12
  6. package/components/input-file/test/lion-input-file.test.js +37 -3
  7. package/custom-elements.json +1129 -676
  8. package/dist-types/components/form-core/src/validate/ValidateMixin.d.ts.map +1 -1
  9. package/dist-types/components/form-core/src/validate/Validator.d.ts +16 -6
  10. package/dist-types/components/form-core/src/validate/Validator.d.ts.map +1 -1
  11. package/dist-types/components/input-file/src/LionInputFile.d.ts +5 -0
  12. package/dist-types/components/input-file/src/LionInputFile.d.ts.map +1 -1
  13. package/dist-types/tsconfig.tsbuildinfo +1 -1
  14. package/docs/components/checkbox-group/overview.md +2 -2
  15. package/docs/components/collapsible/overview.md +1 -1
  16. package/docs/components/combobox/overview.md +1 -1
  17. package/docs/components/combobox/use-cases.md +1 -1
  18. package/docs/components/dialog/overview.md +1 -1
  19. package/docs/components/fieldset/overview.md +5 -5
  20. package/docs/components/form/overview.md +3 -3
  21. package/docs/components/icon/use-cases.md +1 -1
  22. package/docs/components/input/overview.md +1 -1
  23. package/docs/components/input-amount/overview.md +3 -3
  24. package/docs/components/input-date/overview.md +3 -3
  25. package/docs/components/input-datepicker/overview.md +5 -5
  26. package/docs/components/input-email/overview.md +2 -2
  27. package/docs/components/input-file/overview.md +1 -1
  28. package/docs/components/input-iban/overview.md +2 -2
  29. package/docs/components/input-range/overview.md +2 -2
  30. package/docs/components/input-stepper/overview.md +1 -1
  31. package/docs/components/input-tel/overview.md +1 -1
  32. package/docs/components/input-tel/use-cases.md +6 -6
  33. package/docs/components/input-tel-dropdown/overview.md +1 -1
  34. package/docs/components/listbox/use-cases.md +1 -1
  35. package/docs/components/radio-group/overview.md +3 -3
  36. package/docs/components/select/use-cases.md +1 -1
  37. package/docs/components/select-rich/use-cases.md +1 -1
  38. package/docs/components/tabs/examples.md +1 -1
  39. package/docs/fundamentals/index.md +4 -4
  40. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  41. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  42. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  43. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  44. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  45. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  46. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  47. package/docs/fundamentals/rationales/accessibility.md +1 -1
  48. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  49. package/docs/fundamentals/systems/core/overview.md +1 -1
  50. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  51. package/docs/fundamentals/systems/form/model-value.md +1 -1
  52. package/docs/fundamentals/systems/form/overview.md +28 -28
  53. package/docs/fundamentals/systems/form/validate.md +2 -2
  54. package/docs/fundamentals/systems/localize/overview.md +4 -4
  55. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  56. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  57. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  58. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  59. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  60. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  61. package/docs/guides/how-to/create-a-form.md +4 -4
  62. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  63. package/docs/guides/index.md +8 -8
  64. package/docs/guides/principles/index.md +5 -5
  65. package/docs/guides/principles/styling.md +1 -1
  66. package/package.json +1 -1
@@ -277,7 +277,7 @@ const FormControlMixinImplementation = superclass =>
277
277
  super.updated(changedProperties);
278
278
 
279
279
  if (changedProperties.has('disabled')) {
280
- this._inputNode?.setAttribute('aria-disabled', this.disabled.toString());
280
+ this._inputNode?.setAttribute('aria-disabled', `${Boolean(this.disabled)}`);
281
281
  }
282
282
 
283
283
  if (changedProperties.has('_ariaLabelledNodes')) {
@@ -10,6 +10,7 @@ import { SyncUpdatableMixin } from '../utils/SyncUpdatableMixin.js';
10
10
  import { LionValidationFeedback } from './LionValidationFeedback.js';
11
11
  import { ResultValidator as MetaValidator } from './ResultValidator.js';
12
12
  import { Unparseable } from './Unparseable.js';
13
+ // eslint-disable-next-line no-unused-vars
13
14
  import { Validator } from './Validator.js';
14
15
  import { Required } from './validators/Required.js';
15
16
  import { FormControlMixin } from '../FormControlMixin.js';
@@ -460,7 +461,9 @@ export const ValidateMixinImplementation = superclass =>
460
461
 
461
462
  if (isEmpty) {
462
463
  const hasSingleValue = !(/** @type {* & ValidateHost} */ (this)._isFormOrFieldset);
463
- const requiredValidator = this._allValidators.find(v => v instanceof Required);
464
+ const requiredValidator = this._allValidators.find(
465
+ v => /** @type {typeof Validator} */ (v.constructor)?.validatorName === 'Required',
466
+ );
464
467
  if (requiredValidator) {
465
468
  this.__syncValidationResult = [{ validator: requiredValidator, outcome: true }];
466
469
  }
@@ -685,7 +688,10 @@ export const ValidateMixinImplementation = superclass =>
685
688
  }
686
689
 
687
690
  for (const validatorToSetup of this._allValidators) {
688
- if (!(validatorToSetup instanceof Validator)) {
691
+ // disable dot notation to avoid the renaming for the prop during build/minification
692
+ const validatorCtor = /** @type {typeof Validator} */ (validatorToSetup.constructor);
693
+ // eslint-disable-next-line dot-notation
694
+ if (validatorCtor['_$isValidator$'] === undefined) {
689
695
  // throws in constructor are not visible to end user so we do both
690
696
  const errorType = Array.isArray(validatorToSetup) ? 'array' : typeof validatorToSetup;
691
697
  const errorMessage = `Validators array only accepts class instances of Validator. Type "${errorType}" found. This may be caused by having multiple installations of "@lion/ui/form-core.js".`;
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * @typedef {import('../../types/validate/index.js').FeedbackMessageData} FeedbackMessageData
3
- * @typedef {import('../../types/validate/index.js').ValidatorParam} ValidatorParam
4
- * @typedef {import('../../types/validate/index.js').ValidatorConfig} ValidatorConfig
5
3
  * @typedef {import('../../types/validate/index.js').ValidatorOutcome} ValidatorOutcome
6
- * @typedef {import('../../types/validate/index.js').ValidatorName} ValidatorName
4
+ * @typedef {import('../../types/validate/index.js').ValidatorConfig} ValidatorConfig
5
+ * @typedef {import('../../types/validate/index.js').ValidatorParam} ValidatorParam
7
6
  * @typedef {import('../../types/validate/index.js').ValidationType} ValidationType
7
+ * @typedef {import('../../types/validate/index.js').ValidatorName} ValidatorName
8
8
  * @typedef {import('../FormControlMixin.js').FormControlHost} FormControlHost
9
9
  */
10
10
 
@@ -32,8 +32,22 @@ export class Validator extends EventTarget {
32
32
  * @type {ValidationType}
33
33
  */
34
34
  this.type = config?.type || 'error';
35
+ /**
36
+ * Disable dot notation to avoid the renaming for the prop during build/minification
37
+ */
35
38
  }
36
39
 
40
+ /**
41
+ * This unique marker allows us to identify Validator instances across different lion versions.
42
+ * It's meant to be used as a replacement for an instanceof check.
43
+ *
44
+ * N.B. it's important to keep the bracket notation, as `static _$isValidator$ = true;` will
45
+ * be renamed during minification and that leads to different names across different
46
+ * lion versions.
47
+ * @type {boolean}
48
+ */
49
+ static ['_$isValidator$'] = true;
50
+
37
51
  /**
38
52
  * The name under which validation results get registered. For convenience and predictability, this
39
53
  * should always be the same as the constructor name (since it will be obfuscated in js builds,
@@ -1,3 +1,4 @@
1
+ /* eslint-disable dot-notation */
1
2
  import { LitElement } from 'lit';
2
3
  import { defineCE, expect, fixture, html, unsafeStatic } from '@open-wc/testing';
3
4
  import sinon from 'sinon';
@@ -187,6 +188,13 @@ describe('Validator', () => {
187
188
  expect(disconnectSpy.calledWith(el)).to.equal(true);
188
189
  });
189
190
 
191
+ it('adds static ["_$isValidator$"] property as a marker to identify the Validator class across different lion versions (as instanceof cannot be used)', async () => {
192
+ const myValidator = new Validator();
193
+
194
+ expect(myValidator.constructor['_$isValidator$']).to.exist;
195
+ expect(myValidator.constructor['_$isValidator$']).to.be.true;
196
+ });
197
+
190
198
  describe('Types', () => {
191
199
  it('has type "error" by default', async () => {
192
200
  expect(new Validator().type).to.equal('error');
@@ -175,6 +175,11 @@ export class LionInputFile extends ScopedElementsMixin(LocalizeMixin(LionField))
175
175
 
176
176
  /** @private */
177
177
  this.__duplicateFileNamesValidator = new DuplicateFileNames({ show: false });
178
+ /**
179
+ * @private
180
+ * @type {FileList | null}
181
+ */
182
+ this.__previouslyParsedFiles = null;
178
183
  }
179
184
 
180
185
  /**
@@ -282,8 +287,20 @@ export class LionInputFile extends ScopedElementsMixin(LocalizeMixin(LionField))
282
287
  * @returns {InputFile[]} parsedValue
283
288
  */
284
289
  parser() {
285
- // @ts-ignore
286
- return this._inputNode.files ? Array.from(this._inputNode.files) : [];
290
+ // parser is called twice for one user event; one for 'user-input-change', another for 'change'
291
+ if (this.__previouslyParsedFiles === this._inputNode.files) {
292
+ return this.modelValue;
293
+ }
294
+ this.__previouslyParsedFiles = this._inputNode.files;
295
+
296
+ const files = this._inputNode.files
297
+ ? /** @type {InputFile[]} */ (Array.from(this._inputNode.files))
298
+ : [];
299
+ if (this.multiple) {
300
+ return [...(this.modelValue ?? []), ...files];
301
+ }
302
+
303
+ return files;
287
304
  }
288
305
 
289
306
  /**
@@ -481,16 +498,17 @@ export class LionInputFile extends ScopedElementsMixin(LocalizeMixin(LionField))
481
498
  }
482
499
 
483
500
  this._inputNode.files = ev.dataTransfer.files;
484
- // @ts-ignore
485
- this.modelValue = Array.from(ev.dataTransfer.files);
486
- // if same file is selected again, e.dataTransfer.files lists that file.
487
- // So filter if the file already exists
488
- // @ts-ignore
489
- // const newFiles = this.__computeNewAddedFiles(Array.from(ev.dataTransfer.files));
490
- // if (newFiles.length > 0) {
491
- // this._processFiles(newFiles);
492
- // }
493
- this._processFiles(Array.from(ev.dataTransfer.files));
501
+
502
+ if (this.multiple) {
503
+ const computedFiles = this.__computeNewAddedFiles(
504
+ /** @type {InputFile[]} */ (Array.from(ev.dataTransfer.files)),
505
+ );
506
+ this.modelValue = [...(this.modelValue ?? []), ...computedFiles];
507
+ } else {
508
+ this.modelValue = /** @type {InputFile[]} */ (Array.from(ev.dataTransfer.files));
509
+ }
510
+
511
+ this._processFiles(/** @type {InputFile[]} */ (Array.from(ev.dataTransfer.files)));
494
512
  }
495
513
 
496
514
  /**
@@ -1,7 +1,7 @@
1
1
  import '@lion/ui/define/lion-input-file.js';
2
2
  import { Required } from '@lion/ui/form-core.js';
3
3
  import { getInputMembers } from '@lion/ui/input-test-helpers.js';
4
- import { expect, fixture as _fixture, html, oneEvent } from '@open-wc/testing';
4
+ import { expect, fixture as _fixture, html, oneEvent, elementUpdated } from '@open-wc/testing';
5
5
  import sinon from 'sinon';
6
6
 
7
7
  /**
@@ -556,19 +556,22 @@ describe('lion-input-file', () => {
556
556
  });
557
557
  const fileListChangedEvent = await oneEvent(el, 'file-list-changed');
558
558
  filesListChanged(el, fileListChangedEvent);
559
- await el.updateComplete;
559
+ await elementUpdated(el);
560
560
 
561
561
  // @ts-expect-error [allow-protected-in-test]
562
562
  expect(el._selectedFilesMetaData.length).to.equal(2);
563
+ expect(el.modelValue.length).to.equal(2);
563
564
 
564
565
  setTimeout(() => {
565
566
  mimicSelectFile(el, [file3, file4]);
566
567
  });
567
568
  const fileListChangedEvent1 = await oneEvent(el, 'file-list-changed');
568
569
  filesListChanged(el, fileListChangedEvent1);
569
- await el.updateComplete;
570
+ await elementUpdated(el);
571
+
570
572
  // @ts-expect-error [allow-protected-in-test]
571
573
  expect(el._selectedFilesMetaData.length).to.equal(4);
574
+ expect(el.modelValue.length).to.equal(4);
572
575
  });
573
576
 
574
577
  it('should add multiple files and dispatch file-list-changed event ONLY with newly added file', async () => {
@@ -958,6 +961,37 @@ describe('lion-input-file', () => {
958
961
  expect(el.hasAttribute('is-dragging')).to.equal(false);
959
962
  });
960
963
 
964
+ it('should update modelValue on drop', async () => {
965
+ const list = new DataTransfer();
966
+ // @ts-ignore
967
+ list.items.add(file);
968
+ const droppedFiles = list.files;
969
+
970
+ // @ts-expect-error [allow-protected-in-test]
971
+ await el._processDroppedFiles({
972
+ // @ts-ignore
973
+ dataTransfer: { files: droppedFiles, items: [{ name: 'test.txt' }] },
974
+ preventDefault: () => {},
975
+ });
976
+ await el.updateComplete;
977
+
978
+ expect(el.modelValue.length).to.equal(1);
979
+
980
+ const list2 = new DataTransfer();
981
+ // @ts-ignore
982
+ list2.items.add(file2);
983
+
984
+ // @ts-expect-error [allow-protected-in-test]
985
+ await el._processDroppedFiles({
986
+ // @ts-ignore
987
+ dataTransfer: { files: list2.files, items: [{ name: 'test2.txt' }] },
988
+ preventDefault: () => {},
989
+ });
990
+ await el.updateComplete;
991
+
992
+ expect(el.modelValue.length).to.equal(2);
993
+ });
994
+
961
995
  it('should call _processFiles method', async () => {
962
996
  const list = new DataTransfer();
963
997
  // @ts-ignore