@lion/ui 0.0.9 → 0.0.10

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 (133) hide show
  1. package/components/core/src/SlotMixin.js +2 -1
  2. package/components/dialog/test/lion-dialog.test.js +3 -7
  3. package/components/form-integrations/test/form-group-methods.test.js +6 -4
  4. package/components/form-integrations/test/form-integrations.test.js +10 -5
  5. package/components/form-integrations/test/helpers/umbrella-form.js +10 -0
  6. package/components/form-integrations/test/model-value-consistency.test.js +29 -20
  7. package/components/input-datepicker/src/LionInputDatepicker.js +64 -100
  8. package/components/input-datepicker/src/localizeNamespaceLoader.js +188 -0
  9. package/components/input-datepicker/test/lion-input-datepicker.test.js +15 -20
  10. package/components/input-datepicker/test-helpers/DatepickerInputObject.js +3 -3
  11. package/components/input-tel/src/parsers.js +1 -1
  12. package/components/listbox/test-suites/ListboxMixin.suite.js +3 -3
  13. package/components/localize/test/number/formatNumber.test.js +2 -6
  14. package/components/overlays/src/OverlayController.js +236 -289
  15. package/components/overlays/src/OverlayMixin.js +17 -18
  16. package/components/overlays/src/OverlaysManager.js +28 -53
  17. package/components/overlays/src/overlayDocumentStyle.js +24 -0
  18. package/components/overlays/src/overlayShadowDomStyle.js +138 -0
  19. package/components/overlays/src/singleton.js +3 -1
  20. package/components/overlays/test/ArrowMixin.test.js +0 -1
  21. package/components/overlays/test/OverlayController.test.js +306 -273
  22. package/components/overlays/test/OverlaysManager.test.js +23 -32
  23. package/components/overlays/test/global-positioning.test.js +4 -15
  24. package/components/overlays/test/local-positioning.test.js +65 -38
  25. package/components/overlays/test-suites/OverlayMixin.suite.js +18 -26
  26. package/components/overlays/types/OverlayConfig.ts +32 -11
  27. package/components/overlays/types/OverlayMixinTypes.ts +2 -2
  28. package/components/select-rich/src/LionSelectInvoker.js +2 -3
  29. package/components/select-rich/src/LionSelectRich.js +22 -20
  30. package/components/select-rich/test/lion-select-rich.test.js +5 -7
  31. package/custom-elements.json +251 -362
  32. package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
  33. package/dist-types/components/form-integrations/test/helpers/umbrella-form.d.ts +4 -0
  34. package/dist-types/components/form-integrations/test/helpers/umbrella-form.d.ts.map +1 -1
  35. package/dist-types/components/form-integrations/test/model-value-consistency.test.d.ts.map +1 -1
  36. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +3 -3
  37. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
  38. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts +4 -0
  39. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -0
  40. package/dist-types/components/overlays/src/OverlayController.d.ts +46 -101
  41. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  42. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  43. package/dist-types/components/overlays/src/OverlaysManager.d.ts +0 -7
  44. package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
  45. package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts +2 -0
  46. package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts.map +1 -0
  47. package/dist-types/components/overlays/src/overlayShadowDomStyle.d.ts +2 -0
  48. package/dist-types/components/overlays/src/overlayShadowDomStyle.d.ts.map +1 -0
  49. package/dist-types/components/overlays/src/singleton.d.ts +2 -1
  50. package/dist-types/components/overlays/src/singleton.d.ts.map +1 -1
  51. package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
  52. package/dist-types/components/overlays/types/OverlayConfig.d.ts +14 -10
  53. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  54. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +2 -2
  55. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
  56. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts +3 -27
  57. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts.map +1 -1
  58. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  59. package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts.map +1 -1
  60. package/dist-types/exports/input-datepicker.d.ts +0 -1
  61. package/dist-types/exports/overlays.d.ts +0 -1
  62. package/dist-types/exports/types/overlays.d.ts +1 -0
  63. package/dist-types/exports/types/overlays.d.ts.map +1 -1
  64. package/dist-types/tsconfig.tsbuildinfo +1 -1
  65. package/docs/components/checkbox-group/overview.md +2 -2
  66. package/docs/components/collapsible/overview.md +1 -1
  67. package/docs/components/combobox/overview.md +1 -1
  68. package/docs/components/combobox/use-cases.md +1 -1
  69. package/docs/components/dialog/overview.md +5 -9
  70. package/docs/components/dialog/use-cases.md +43 -87
  71. package/docs/components/fieldset/overview.md +5 -5
  72. package/docs/components/form/overview.md +3 -3
  73. package/docs/components/icon/use-cases.md +1 -1
  74. package/docs/components/input/overview.md +1 -1
  75. package/docs/components/input-amount/overview.md +3 -3
  76. package/docs/components/input-date/overview.md +3 -3
  77. package/docs/components/input-datepicker/overview.md +5 -5
  78. package/docs/components/input-email/overview.md +2 -2
  79. package/docs/components/input-iban/overview.md +2 -2
  80. package/docs/components/input-range/overview.md +2 -2
  81. package/docs/components/input-stepper/overview.md +1 -1
  82. package/docs/components/input-tel/overview.md +1 -1
  83. package/docs/components/input-tel/use-cases.md +6 -6
  84. package/docs/components/input-tel-dropdown/overview.md +1 -1
  85. package/docs/components/radio-group/overview.md +3 -3
  86. package/docs/components/select-rich/use-cases.md +1 -1
  87. package/docs/components/tabs/examples.md +1 -1
  88. package/docs/fundamentals/index.md +4 -4
  89. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  90. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  91. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  92. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  93. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  94. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  95. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  96. package/docs/fundamentals/systems/core/overview.md +1 -1
  97. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  98. package/docs/fundamentals/systems/form/model-value.md +1 -1
  99. package/docs/fundamentals/systems/form/overview.md +28 -28
  100. package/docs/fundamentals/systems/form/use-cases.md +4 -0
  101. package/docs/fundamentals/systems/form/validate.md +1 -1
  102. package/docs/fundamentals/systems/localize/overview.md +4 -4
  103. package/docs/fundamentals/systems/overlays/assets/{applyDemoOverlayStyles.js → applyDemoOverlayStyles.mjs} +2 -1
  104. package/docs/fundamentals/systems/overlays/assets/demo-el-using-overlaymixin.mjs +119 -0
  105. package/docs/fundamentals/systems/overlays/assets/{demo-overlay-backdrop.js → demo-overlay-backdrop.mjs} +3 -4
  106. package/docs/fundamentals/systems/overlays/assets/demo-overlay-positioning.mjs +537 -0
  107. package/docs/fundamentals/systems/overlays/assets/umbrella-form.js +9 -2
  108. package/docs/fundamentals/systems/overlays/configuration.md +56 -54
  109. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  110. package/docs/fundamentals/systems/overlays/use-cases.md +83 -77
  111. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  112. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  113. package/docs/guides/how-to/create-a-custom-field.md +6 -6
  114. package/docs/guides/how-to/extend-a-native-input.md +3 -3
  115. package/docs/guides/index.md +8 -8
  116. package/docs/guides/principles/index.md +5 -5
  117. package/docs/guides/principles/styling.md +1 -1
  118. package/exports/input-datepicker.js +0 -1
  119. package/exports/overlays.js +0 -1
  120. package/exports/types/overlays.ts +1 -0
  121. package/package.json +2 -1
  122. package/components/input-datepicker/src/LionCalendarOverlayFrame.js +0 -125
  123. package/components/overlays/src/globalOverlaysStyle.js +0 -139
  124. package/dist-types/components/input-datepicker/src/LionCalendarOverlayFrame.d.ts +0 -10
  125. package/dist-types/components/input-datepicker/src/LionCalendarOverlayFrame.d.ts.map +0 -1
  126. package/dist-types/components/overlays/src/globalOverlaysStyle.d.ts +0 -2
  127. package/dist-types/components/overlays/src/globalOverlaysStyle.d.ts.map +0 -1
  128. package/dist-types/exports/define/lion-calendar-overlay-frame.d.ts +0 -2
  129. package/dist-types/exports/define/lion-calendar-overlay-frame.d.ts.map +0 -1
  130. package/docs/fundamentals/systems/overlays/assets/demo-overlay-system.js +0 -42
  131. package/docs/fundamentals/systems/overlays/form-integration.md +0 -65
  132. package/docs/fundamentals/systems/overlays/scope.md +0 -176
  133. package/exports/define/lion-calendar-overlay-frame.js +0 -3
@@ -196,7 +196,8 @@ const SlotMixinImplementation = superclass =>
196
196
  this.__slotsThatNeedRerender.add(slotName);
197
197
  } else {
198
198
  throw new Error(
199
- 'Please provide a function inside "get slots()" returning TemplateResult | Node | {template:TemplateResult, afterRender?:function} | undefined',
199
+ `Slot "${slotName}" configured inside "get slots()" (in prototype) of ${this.constructor.name} may return these types: TemplateResult | Node | {template:TemplateResult, afterRender?:function} | undefined.
200
+ You provided: ${slotFunctionResult}`,
200
201
  );
201
202
  }
202
203
  }
@@ -12,7 +12,7 @@ describe('lion-dialog', () => {
12
12
  // For some reason, globalRootNode is not cleared properly on disconnectedCallback from previous overlay test fixtures...
13
13
  // Not sure why this "bug" happens...
14
14
  beforeEach(() => {
15
- const globalRootNode = document.querySelector('.global-overlays');
15
+ const globalRootNode = document.querySelector('.overlays');
16
16
  if (globalRootNode) {
17
17
  globalRootNode.innerHTML = '';
18
18
  }
@@ -57,15 +57,11 @@ describe('lion-dialog', () => {
57
57
  </lion-dialog>
58
58
  `);
59
59
 
60
- // @ts-expect-error you're not allowed to call protected _overlayInvokerNode in public context, but for testing it's okay
60
+ // @ts-expect-error [allow-protected] in tests
61
61
  el._overlayInvokerNode.click();
62
62
  expect(el.opened).to.be.true;
63
63
 
64
- const overlaysContainer = /** @type {HTMLElement} */ (
65
- document.querySelector('.global-overlays')
66
- );
67
- const wrapperNode = Array.from(overlaysContainer.children)[1];
68
- const nestedDialog = /** @type {LionDialog} */ (wrapperNode.querySelector('lion-dialog'));
64
+ const nestedDialog = /** @type {LionDialog} */ (el.querySelector('lion-dialog'));
69
65
  // @ts-expect-error you're not allowed to call protected _overlayInvokerNode in public context, but for testing it's okay
70
66
  nestedDialog?._overlayInvokerNode.click();
71
67
  expect(nestedDialog.opened).to.be.true;
@@ -96,15 +96,13 @@ describe(`Submitting/Resetting/Clearing Form`, async () => {
96
96
  it('pressing submit button of a form should make submitted true for all fields', async () => {
97
97
  const el = /** @type {UmbrellaForm} */ (await fixture(html`<umbrella-form></umbrella-form>`));
98
98
  await el.updateComplete;
99
+ await el.waitForAllChildrenUpdates();
100
+
99
101
  const formEl = el._lionFormNode;
100
102
 
101
103
  const allElements = getAllFieldsAndFormGroups(formEl);
102
104
 
103
105
  allElements.forEach((/** @type {LionField} */ field) => {
104
- if (field.tagName === 'LION-SWITCH') {
105
- // TODO: remove this when this is fixed: https://github.com/ing-bank/lion/issues/1204
106
- return;
107
- }
108
106
  // TODO: prefer submitted 'false' over 'undefined'
109
107
  expect(Boolean(field.submitted)).to.be.false;
110
108
  });
@@ -122,6 +120,8 @@ describe(`Submitting/Resetting/Clearing Form`, async () => {
122
120
  html`<umbrella-form .serializedValue="${fullyPrefilledSerializedValue}"></umbrella-form>`,
123
121
  )
124
122
  );
123
+ await el.waitForAllChildrenUpdates();
124
+
125
125
  await el.updateComplete;
126
126
  const formEl = el._lionFormNode;
127
127
 
@@ -168,6 +168,8 @@ describe(`Submitting/Resetting/Clearing Form`, async () => {
168
168
  html`<umbrella-form .serializedValue="${fullyPrefilledSerializedValue}"></umbrella-form>`,
169
169
  )
170
170
  );
171
+ await el.waitForAllChildrenUpdates();
172
+
171
173
  await el.updateComplete;
172
174
  const formEl = el._lionFormNode;
173
175
 
@@ -25,6 +25,7 @@ describe('Form Integrations', () => {
25
25
  it('".serializedValue" returns all non disabled fields based on form structure', async () => {
26
26
  const el = /** @type {UmbrellaForm} */ (await fixture(html`<umbrella-form></umbrella-form>`));
27
27
  await el.updateComplete;
28
+ await el.waitForAllChildrenUpdates();
28
29
  const formEl = el._lionFormNode;
29
30
 
30
31
  expect(formEl.serializedValue).to.eql({
@@ -46,7 +47,7 @@ describe('Form Integrations', () => {
46
47
  notifications: { value: '', checked: false },
47
48
  rsvp: '',
48
49
  tel: '',
49
- 'tel-dropdown': '',
50
+ 'tel-dropdown': '+44',
50
51
  comments: '',
51
52
  });
52
53
  });
@@ -110,6 +111,7 @@ describe('Form Integrations', () => {
110
111
  ></umbrella-form>`,
111
112
  )
112
113
  );
114
+ await el.waitForAllChildrenUpdates();
113
115
 
114
116
  await el._lionFormNode.initComplete;
115
117
  expect(el._lionFormNode.dirty).to.be.false;
@@ -162,9 +164,10 @@ describe('Form Integrations', () => {
162
164
  ];
163
165
 
164
166
  it('successfully registers all form components', async () => {
165
- const el = /** @type {UmbrellaForm} */ await fixture(html`<umbrella-form></umbrella-form>`);
166
- // @ts-ignore
167
- const formEl = /** @type {LionForm} */ (el._lionFormNode);
167
+ const el = /** @type {UmbrellaForm} */ (await fixture(html`<umbrella-form></umbrella-form>`));
168
+ await el.waitForAllChildrenUpdates();
169
+
170
+ const formEl = el._lionFormNode;
168
171
  await formEl.registrationComplete;
169
172
  const registeredEls = getAllTagNames(formEl);
170
173
 
@@ -172,8 +175,10 @@ describe('Form Integrations', () => {
172
175
  });
173
176
 
174
177
  it('successfully unregisters all form components', async () => {
175
- const el = /** @type {UmbrellaForm} */ await fixture(html`<umbrella-form></umbrella-form>`);
178
+ const el = /** @type {UmbrellaForm} */ (await fixture(html`<umbrella-form></umbrella-form>`));
176
179
  const offlineContainer = document.createElement('div');
180
+ await el.waitForAllChildrenUpdates();
181
+
177
182
  // @ts-ignore
178
183
  const formEl = /** @type {LionForm} */ (el._lionFormNode);
179
184
  await formEl.registrationComplete;
@@ -11,10 +11,13 @@ import '@lion/ui/define/lion-input-email.js';
11
11
  import '@lion/ui/define/lion-input-tel.js';
12
12
  import '@lion/ui/define/lion-input-tel-dropdown.js';
13
13
  import '@lion/ui/define/lion-checkbox-group.js';
14
+ import '@lion/ui/define/lion-checkbox.js';
14
15
  import '@lion/ui/define/lion-radio-group.js';
16
+ import '@lion/ui/define/lion-radio.js';
15
17
  import '@lion/ui/define/lion-select.js';
16
18
  import '@lion/ui/define/lion-select-rich.js';
17
19
  import '@lion/ui/define/lion-listbox.js';
20
+ import '@lion/ui/define/lion-option.js';
18
21
  import '@lion/ui/define/lion-combobox.js';
19
22
  import '@lion/ui/define/lion-input-range.js';
20
23
  import '@lion/ui/define/lion-textarea.js';
@@ -36,6 +39,13 @@ export class UmbrellaForm extends LitElement {
36
39
  this.__serializedValue = v;
37
40
  }
38
41
 
42
+ /**
43
+ * Prevents errors outside test from being thrown
44
+ */
45
+ async waitForAllChildrenUpdates() {
46
+ return Promise.all(this._lionFormNode.formElements.map(child => child.updateComplete));
47
+ }
48
+
39
49
  render() {
40
50
  return html`
41
51
  <lion-form .serializedValue="${this.__serializedValue}">
@@ -11,23 +11,19 @@ import '@lion/ui/define/lion-input-email.js';
11
11
  import '@lion/ui/define/lion-input-iban.js';
12
12
  import '@lion/ui/define/lion-input-range.js';
13
13
  import '@lion/ui/define/lion-input-stepper.js';
14
-
14
+ import '@lion/ui/define/lion-input-tel.js';
15
+ import '@lion/ui/define/lion-input-tel-dropdown.js';
15
16
  import '@lion/ui/define/lion-textarea.js';
16
-
17
17
  import '@lion/ui/define/lion-checkbox.js';
18
18
  import '@lion/ui/define/lion-checkbox-group.js';
19
-
20
19
  import '@lion/ui/define/lion-radio.js';
21
20
  import '@lion/ui/define/lion-radio-group.js';
22
21
  import '@lion/ui/define/lion-switch.js';
23
-
24
22
  import '@lion/ui/define/lion-select.js';
25
23
  import '@lion/ui/define/lion-option.js';
26
-
27
24
  import '@lion/ui/define/lion-combobox.js';
28
25
  import '@lion/ui/define/lion-listbox.js';
29
26
  import '@lion/ui/define/lion-select-rich.js';
30
-
31
27
  import '@lion/ui/define/lion-fieldset.js';
32
28
  import '@lion/ui/define/lion-form.js';
33
29
  import '@lion/ui/define/lion-field.js';
@@ -344,7 +340,6 @@ describe('lion-fieldset', () => {
344
340
 
345
341
  describe('detail.isTriggeredByUser', () => {
346
342
  const allFormControls = [
347
- 'switch', // TODO: move back below when scoped-elements (polyfill) fixed side effects
348
343
  // 1) Fields
349
344
  'field',
350
345
  // 1a) Input Fields
@@ -356,12 +351,14 @@ describe('detail.isTriggeredByUser', () => {
356
351
  'input-iban',
357
352
  'input-range',
358
353
  'input-stepper',
354
+ 'input-tel',
355
+ 'input-tel-dropdown',
359
356
  'textarea',
360
357
  // 1b) Choice Fields
361
358
  'option',
362
359
  'checkbox',
363
360
  'radio',
364
- // 'switch',
361
+ 'switch',
365
362
  // 1c) Choice Group Fields
366
363
  'select',
367
364
  'listbox',
@@ -423,9 +420,10 @@ describe('detail.isTriggeredByUser', () => {
423
420
  /**
424
421
  * @param {FormControl & {value: string;}} el
425
422
  * @param {string} newViewValue
426
- * @param {{ triggerType?: string, labelInsteadOfInput?: boolean }} [optionals]
423
+ * @param {{ triggerType?: string, labelInsteadOfInput?: boolean, parent?: HTMLElement }} options
427
424
  */
428
- function mimicUserInput(el, newViewValue, optionals) {
425
+ function mimicUserInput(el, newViewValue, options = {}) {
426
+ // @ts-ignore
429
427
  const { _inputNode, _labelNode } = getFormControlMembers(el);
430
428
  const type = detectType(el);
431
429
  let userInputEv;
@@ -434,15 +432,15 @@ describe('detail.isTriggeredByUser', () => {
434
432
  el.value = newViewValue; // eslint-disable-line no-param-reassign
435
433
  _inputNode.dispatchEvent(new Event(userInputEv, { bubbles: true }));
436
434
  } else if (type === 'ChoiceField') {
437
- if (optionals?.labelInsteadOfInput) {
435
+ if (options?.labelInsteadOfInput) {
438
436
  _labelNode.click();
439
437
  } else {
440
438
  _inputNode.click();
441
439
  }
442
440
  } else if (type === 'OptionChoiceField') {
443
- if (!optionals?.triggerType) {
441
+ if (!options?.triggerType) {
444
442
  el.dispatchEvent(new Event('click', { bubbles: true }));
445
- } else if (optionals?.triggerType === 'keypress') {
443
+ } else if (options?.triggerType === 'keypress') {
446
444
  el.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true }));
447
445
  el.dispatchEvent(new KeyboardEvent('keyup', { key: 'ArrowDown', bubbles: true }));
448
446
  el.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }));
@@ -503,9 +501,12 @@ describe('detail.isTriggeredByUser', () => {
503
501
 
504
502
  /**
505
503
  * @param {FormControl & {value: string;}} formControl
506
- * @param {boolean | undefined} [testKeyboardBehavior]
504
+ * @param {{parent?: FormControl; testKeyboardBehavior?: boolean}} moreOpts
507
505
  */
508
- async function expectCorrectEventMetaChoiceField(formControl, testKeyboardBehavior) {
506
+ async function expectCorrectEventMetaChoiceField(
507
+ formControl,
508
+ { parent, testKeyboardBehavior } = {},
509
+ ) {
509
510
  const type = detectType(formControl);
510
511
 
511
512
  await resetChoiceFieldToForceRepropagation(formControl);
@@ -526,14 +527,19 @@ describe('detail.isTriggeredByUser', () => {
526
527
  formControl.modelValue = { value: 'programmaticValue', checked: false };
527
528
  expect(spy.secondCall.args[0].detail.isTriggeredByUser).to.be.false;
528
529
 
529
- if (type === 'OptionChoiceField' && testKeyboardBehavior) {
530
+ if (
531
+ type === 'OptionChoiceField' &&
532
+ testKeyboardBehavior &&
533
+ parent?.constructor.name !== 'LionCombobox' // modelValue only changeable via click or textbox
534
+ ) {
530
535
  await resetChoiceFieldToForceRepropagation(formControl);
531
- mimicUserInput(formControl, 'userValue', { triggerType: 'keypress' });
532
- // TODO: get rid of try/catch (?)...
536
+ mimicUserInput(formControl, 'userValue', { triggerType: 'keypress', parent });
533
537
  try {
534
538
  expect(spy.firstCall.args[0].detail.isTriggeredByUser).to.be.true;
535
539
  } catch (e) {
536
- console.log(formControl);
540
+ throw new Error(
541
+ `model-value-changed of ${formControl.constructor.name} with parent ${parent?.constructor.name} not caught`,
542
+ );
537
543
  }
538
544
  }
539
545
  }
@@ -556,7 +562,10 @@ describe('detail.isTriggeredByUser', () => {
556
562
  );
557
563
  el.appendChild(childrenEls);
558
564
  await el.registrationComplete;
559
- await expectCorrectEventMetaChoiceField(el.formElements[0], true);
565
+ await expectCorrectEventMetaChoiceField(el.formElements[0], {
566
+ testKeyboardBehavior: true,
567
+ parent: el,
568
+ });
560
569
  } else if (type === 'FormOrFieldset') {
561
570
  const childrenEls = await fixture(
562
571
  html`<div><lion-input name="one"></lion-input><lion-input name="two"></lion-input></div>`,
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable import/no-extraneous-dependencies */
2
2
  import { LionCalendar } from '@lion/ui/calendar.js';
3
3
  import { ScopedElementsMixin } from '@open-wc/scoped-elements';
4
- import { html, render } from 'lit';
4
+ import { html, css } from 'lit';
5
5
  import { ifDefined } from 'lit/directives/if-defined.js';
6
6
  import { LionInputDate } from '@lion/ui/input-date.js';
7
7
  import {
@@ -10,7 +10,8 @@ import {
10
10
  withModalDialogConfig,
11
11
  ArrowMixin,
12
12
  } from '@lion/ui/overlays.js';
13
- import { LionCalendarOverlayFrame } from './LionCalendarOverlayFrame.js';
13
+ import { LocalizeMixin } from '@lion/ui/localize.js';
14
+ import { localizeNamespaceLoader } from './localizeNamespaceLoader.js';
14
15
 
15
16
  /**
16
17
  * @typedef {import('../../form-core/src/validate/Validator.js').Validator} Validator
@@ -21,16 +22,49 @@ import { LionCalendarOverlayFrame } from './LionCalendarOverlayFrame.js';
21
22
  * @customElement lion-input-datepicker
22
23
  */
23
24
  export class LionInputDatepicker extends ScopedElementsMixin(
24
- ArrowMixin(OverlayMixin(LionInputDate)),
25
+ ArrowMixin(OverlayMixin(LocalizeMixin(LionInputDate))),
25
26
  ) {
26
27
  static get scopedElements() {
27
28
  return {
28
29
  ...super.scopedElements,
29
30
  'lion-calendar': LionCalendar,
30
- 'lion-calendar-overlay-frame': LionCalendarOverlayFrame,
31
31
  };
32
32
  }
33
33
 
34
+ static get styles() {
35
+ return [
36
+ ...super.styles,
37
+ css`
38
+ .calendar__overlay-frame {
39
+ display: inline-block;
40
+ background: white;
41
+ position: relative;
42
+ }
43
+
44
+ .calendar-overlay__header {
45
+ display: flex;
46
+ }
47
+
48
+ .calendar-overlay__heading {
49
+ padding: 16px 16px 8px;
50
+ flex: 1;
51
+ }
52
+
53
+ .calendar-overlay__heading > .calendar-overlay__close-button {
54
+ flex: none;
55
+ }
56
+
57
+ .calendar-overlay__close-button {
58
+ min-width: 40px;
59
+ min-height: 32px;
60
+ border-width: 0;
61
+ padding: 0;
62
+ font-size: 24px;
63
+ }
64
+ `,
65
+ ];
66
+ }
67
+
34
68
  /** @type {any} */
35
69
  static get properties() {
36
70
  return {
@@ -68,101 +102,12 @@ export class LionInputDatepicker extends ScopedElementsMixin(
68
102
  get slots() {
69
103
  return {
70
104
  ...super.slots,
71
- [this._calendarInvokerSlot]: () => {
72
- const renderParent = document.createElement('div');
73
- render(
74
- this._invokerTemplate(),
75
- renderParent,
76
- /** @type {RenderOptions} */ ({
77
- scopeName: this.localName,
78
- eventContext: this,
79
- }),
80
- );
81
- return /** @type {HTMLElement} */ (renderParent.firstElementChild);
82
- },
105
+ [this._calendarInvokerSlot]: () => this._invokerTemplate(),
83
106
  };
84
107
  }
85
108
 
86
109
  static get localizeNamespaces() {
87
- return [
88
- {
89
- 'lion-input-datepicker': /** @param {string} locale */ locale => {
90
- switch (locale) {
91
- case 'bg-BG':
92
- return import('@lion/ui/input-datepicker-translations/bg-BG.js');
93
- case 'bg':
94
- return import('@lion/ui/input-datepicker-translations/bg.js');
95
- case 'cs-CZ':
96
- return import('@lion/ui/input-datepicker-translations/cs-CZ.js');
97
- case 'cs':
98
- return import('@lion/ui/input-datepicker-translations/cs.js');
99
- case 'de-DE':
100
- return import('@lion/ui/input-datepicker-translations/de-DE.js');
101
- case 'de':
102
- return import('@lion/ui/input-datepicker-translations/de.js');
103
- case 'en-AU':
104
- return import('@lion/ui/input-datepicker-translations/en-AU.js');
105
- case 'en-GB':
106
- return import('@lion/ui/input-datepicker-translations/en-GB.js');
107
- case 'en-US':
108
- return import('@lion/ui/input-datepicker-translations/en-US.js');
109
- case 'en-PH':
110
- case 'en':
111
- return import('@lion/ui/input-datepicker-translations/en.js');
112
- case 'es-ES':
113
- return import('@lion/ui/input-datepicker-translations/es-ES.js');
114
- case 'es':
115
- return import('@lion/ui/input-datepicker-translations/es.js');
116
- case 'fr-FR':
117
- return import('@lion/ui/input-datepicker-translations/fr-FR.js');
118
- case 'fr-BE':
119
- return import('@lion/ui/input-datepicker-translations/fr-BE.js');
120
- case 'fr':
121
- return import('@lion/ui/input-datepicker-translations/fr.js');
122
- case 'hu-HU':
123
- return import('@lion/ui/input-datepicker-translations/hu-HU.js');
124
- case 'hu':
125
- return import('@lion/ui/input-datepicker-translations/hu.js');
126
- case 'it-IT':
127
- return import('@lion/ui/input-datepicker-translations/it-IT.js');
128
- case 'it':
129
- return import('@lion/ui/input-datepicker-translations/it.js');
130
- case 'nl-BE':
131
- return import('@lion/ui/input-datepicker-translations/nl-BE.js');
132
- case 'nl-NL':
133
- return import('@lion/ui/input-datepicker-translations/nl-NL.js');
134
- case 'nl':
135
- return import('@lion/ui/input-datepicker-translations/nl.js');
136
- case 'pl-PL':
137
- return import('@lion/ui/input-datepicker-translations/pl-PL.js');
138
- case 'pl':
139
- return import('@lion/ui/input-datepicker-translations/pl.js');
140
- case 'ro-RO':
141
- return import('@lion/ui/input-datepicker-translations/ro-RO.js');
142
- case 'ro':
143
- return import('@lion/ui/input-datepicker-translations/ro.js');
144
- case 'ru-RU':
145
- return import('@lion/ui/input-datepicker-translations/ru-RU.js');
146
- case 'ru':
147
- return import('@lion/ui/input-datepicker-translations/ru.js');
148
- case 'sk-SK':
149
- return import('@lion/ui/input-datepicker-translations/sk-SK.js');
150
- case 'sk':
151
- return import('@lion/ui/input-datepicker-translations/sk.js');
152
- case 'uk-UA':
153
- return import('@lion/ui/input-datepicker-translations/uk-UA.js');
154
- case 'uk':
155
- return import('@lion/ui/input-datepicker-translations/uk.js');
156
- case 'zh-CN':
157
- case 'zh':
158
- return import('@lion/ui/input-datepicker-translations/zh.js');
159
- default:
160
- return import('@lion/ui/input-datepicker-translations/en.js');
161
- }
162
- },
163
- },
164
- ...super.localizeNamespaces,
165
- ];
110
+ return [{ 'lion-input-datepicker': localizeNamespaceLoader }, ...super.localizeNamespaces];
166
111
  }
167
112
 
168
113
  /**
@@ -262,11 +207,29 @@ export class LionInputDatepicker extends ScopedElementsMixin(
262
207
  // This would make first paint quicker
263
208
  return html`
264
209
  <div id="overlay-content-node-wrapper">
265
- <lion-calendar-overlay-frame class="calendar__overlay-frame">
266
- <span slot="heading">${this.calendarHeading}</span>
267
- ${this._calendarTemplate()}
268
- </lion-calendar-overlay-frame>
269
- ${this._arrowNodeTemplate()}
210
+ ${this._overlayFrameTemplate()} ${this._arrowNodeTemplate()}
211
+ </div>
212
+ `;
213
+ }
214
+
215
+ _overlayFrameTemplate() {
216
+ return html`
217
+ <div class="calendar__overlay-frame">
218
+ <div class="calendar-overlay">
219
+ <div class="calendar-overlay__header">
220
+ <h1 class="calendar-overlay__heading">${this.calendarHeading}</h1>
221
+ <button
222
+ @click="${() => this._overlayCtrl.hide()}"
223
+ id="close-button"
224
+ title="${this.msgLit('lion-input-datepicker:close')}"
225
+ aria-label="${this.msgLit('lion-input-datepicker:close')}"
226
+ class="calendar-overlay__close-button"
227
+ >
228
+ <slot name="close-icon">&times;</slot>
229
+ </button>
230
+ </div>
231
+ <div>${this._calendarTemplate()}</div>
232
+ </div>
270
233
  </div>
271
234
  `;
272
235
  }
@@ -466,6 +429,7 @@ export class LionInputDatepicker extends ScopedElementsMixin(
466
429
  this._cachedOverlayContentNode = /** @type {HTMLElement} */ (
467
430
  /** @type {ShadowRoot} */ (this.shadowRoot).querySelector('.calendar__overlay-frame')
468
431
  );
432
+
469
433
  return this._cachedOverlayContentNode;
470
434
  }
471
435
  }