@lion/ui 0.4.0-prerelease-bypass-export-map.0 → 0.4.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.
Files changed (87) hide show
  1. package/components/accordion/src/LionAccordion.js +20 -3
  2. package/components/accordion/test/lion-accordion.test.js +19 -0
  3. package/components/calendar/src/LionCalendar.js +5 -2
  4. package/components/calendar/src/utils/createMonth.js +1 -2
  5. package/components/calendar/test/lion-calendar.test.js +83 -4
  6. package/components/calendar/test/utils/createMonth.test.js +15 -0
  7. package/components/form-core/src/form-group/FormGroupMixin.js +7 -0
  8. package/components/form-core/src/validate/ValidateMixin.js +197 -153
  9. package/components/form-core/test-suites/ValidateMixin.suite.js +4 -4
  10. package/components/form-core/test-suites/form-group/FormGroupMixin-input.suite.js +1 -1
  11. package/components/form-core/test-suites/form-group/FormGroupMixin.suite.js +22 -7
  12. package/components/input-datepicker/src/LionInputDatepicker.js +4 -4
  13. package/components/input-datepicker/test/lion-input-datepicker.test.js +23 -0
  14. package/components/localize/types/LocalizeMixinTypes.ts +1 -1
  15. package/components/overlays/src/OverlayController.js +2 -4
  16. package/components/progress-indicator/src/LionProgressIndicator.js +1 -1
  17. package/components/progress-indicator/test/lion-progress-indicator.test.js +18 -1
  18. package/custom-elements.json +415 -379
  19. package/dist-types/components/accordion/src/LionAccordion.d.ts +10 -0
  20. package/dist-types/components/accordion/src/LionAccordion.d.ts.map +1 -1
  21. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  22. package/dist-types/components/calendar/src/utils/createMonth.d.ts.map +1 -1
  23. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
  24. package/dist-types/components/form-core/src/validate/ValidateMixin.d.ts +1 -0
  25. package/dist-types/components/form-core/src/validate/ValidateMixin.d.ts.map +1 -1
  26. package/dist-types/components/form-core/test-suites/form-group/FormGroupMixin.suite.d.ts.map +1 -1
  27. package/dist-types/components/input-file/src/LionInputFile.d.ts +1 -1
  28. package/dist-types/components/input-file/src/LionInputFile.d.ts.map +1 -1
  29. package/dist-types/components/input-file/src/LionSelectedFileList.d.ts +1 -1
  30. package/dist-types/components/input-file/src/LionSelectedFileList.d.ts.map +1 -1
  31. package/dist-types/components/input-tel/src/LionInputTel.d.ts +1 -1
  32. package/dist-types/components/input-tel/src/LionInputTel.d.ts.map +1 -1
  33. package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts +1 -1
  34. package/dist-types/components/localize/types/LocalizeMixinTypes.d.ts.map +1 -1
  35. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  36. package/dist-types/tsconfig.tsbuildinfo +1 -1
  37. package/docs/components/checkbox-group/overview.md +2 -2
  38. package/docs/components/collapsible/overview.md +1 -1
  39. package/docs/components/combobox/overview.md +1 -1
  40. package/docs/components/combobox/use-cases.md +1 -1
  41. package/docs/components/dialog/overview.md +1 -1
  42. package/docs/components/fieldset/overview.md +5 -5
  43. package/docs/components/form/overview.md +3 -3
  44. package/docs/components/icon/use-cases.md +1 -1
  45. package/docs/components/input/overview.md +1 -1
  46. package/docs/components/input-amount/overview.md +3 -3
  47. package/docs/components/input-date/overview.md +3 -3
  48. package/docs/components/input-datepicker/overview.md +5 -5
  49. package/docs/components/input-email/overview.md +2 -2
  50. package/docs/components/input-file/overview.md +1 -1
  51. package/docs/components/input-iban/overview.md +2 -2
  52. package/docs/components/input-range/overview.md +2 -2
  53. package/docs/components/input-stepper/overview.md +1 -1
  54. package/docs/components/input-tel/overview.md +1 -1
  55. package/docs/components/input-tel/use-cases.md +6 -6
  56. package/docs/components/input-tel-dropdown/overview.md +1 -1
  57. package/docs/components/radio-group/overview.md +3 -3
  58. package/docs/components/select-rich/use-cases.md +1 -1
  59. package/docs/components/tabs/examples.md +1 -1
  60. package/docs/fundamentals/index.md +4 -4
  61. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  62. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  63. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  64. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  65. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  66. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  67. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  68. package/docs/fundamentals/rationales/accessibility.md +1 -1
  69. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  70. package/docs/fundamentals/systems/core/overview.md +1 -1
  71. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  72. package/docs/fundamentals/systems/form/model-value.md +1 -1
  73. package/docs/fundamentals/systems/form/overview.md +28 -28
  74. package/docs/fundamentals/systems/form/validate.md +1 -1
  75. package/docs/fundamentals/systems/localize/overview.md +4 -4
  76. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  77. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  78. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  79. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  80. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  81. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  82. package/docs/guides/how-to/create-a-form.md +4 -4
  83. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  84. package/docs/guides/index.md +8 -8
  85. package/docs/guides/principles/index.md +5 -5
  86. package/docs/guides/principles/styling.md +1 -1
  87. package/package.json +1 -1
@@ -10,6 +10,7 @@ import { uuid } from '@lion/ui/core.js';
10
10
  * @property {HTMLElement} content content node
11
11
  * @property {(event: Event) => unknown} clickHandler executed on click event
12
12
  * @property {(event: Event) => unknown} keydownHandler executed on keydown event
13
+ * @property {(event: Event) => unknown} focusHandler executed on focusin event
13
14
  */
14
15
 
15
16
  /**
@@ -197,6 +198,7 @@ export class LionAccordion extends LitElement {
197
198
  content,
198
199
  clickHandler: this.__createInvokerClickHandler(index),
199
200
  keydownHandler: this.__handleInvokerKeydown.bind(this),
201
+ focusHandler: this.__createInvokerFocusHandler(index),
200
202
  };
201
203
  this._setupContent(entry);
202
204
  this._setupInvoker(entry);
@@ -248,6 +250,19 @@ export class LionAccordion extends LitElement {
248
250
  };
249
251
  }
250
252
 
253
+ /**
254
+ * @param {number} index
255
+ * @private
256
+ */
257
+ __createInvokerFocusHandler(index) {
258
+ return () => {
259
+ if (index === this.focusedIndex) {
260
+ return;
261
+ }
262
+ this.focusedIndex = index;
263
+ };
264
+ }
265
+
251
266
  /**
252
267
  * @param {Event} e
253
268
  * @private
@@ -304,7 +319,7 @@ export class LionAccordion extends LitElement {
304
319
  * @protected
305
320
  */
306
321
  _setupInvoker(entry) {
307
- const { invoker, uid, index, clickHandler, keydownHandler } = entry;
322
+ const { invoker, uid, index, clickHandler, keydownHandler, focusHandler } = entry;
308
323
  invoker.style.setProperty('order', `${index + 1}`);
309
324
  const firstChild = invoker.firstElementChild;
310
325
  if (firstChild) {
@@ -312,6 +327,7 @@ export class LionAccordion extends LitElement {
312
327
  firstChild.setAttribute('aria-controls', `content-${uid}`);
313
328
  firstChild.addEventListener('click', clickHandler);
314
329
  firstChild.addEventListener('keydown', keydownHandler);
330
+ firstChild.addEventListener('focusin', focusHandler);
315
331
  }
316
332
  }
317
333
 
@@ -320,13 +336,14 @@ export class LionAccordion extends LitElement {
320
336
  * @protected
321
337
  */
322
338
  _cleanInvoker(entry) {
323
- const { invoker, clickHandler, keydownHandler } = entry;
339
+ const { invoker, clickHandler, keydownHandler, focusHandler } = entry;
324
340
  const firstChild = invoker.firstElementChild;
325
341
  if (firstChild) {
326
342
  firstChild.removeAttribute('id');
327
343
  firstChild.removeAttribute('aria-controls');
328
344
  firstChild.removeEventListener('click', clickHandler);
329
345
  firstChild.removeEventListener('keydown', keydownHandler);
346
+ firstChild.removeEventListener('focusin', focusHandler);
330
347
  }
331
348
  }
332
349
 
@@ -424,7 +441,7 @@ export class LionAccordion extends LitElement {
424
441
  * @private
425
442
  */
426
443
  __toggleExpanded(value) {
427
- const { expanded } = this;
444
+ const expanded = [...this.expanded];
428
445
  const index = expanded.indexOf(value);
429
446
 
430
447
  if (index === -1) {
@@ -80,6 +80,14 @@ describe('<lion-accordion>', () => {
80
80
  ).to.equal('invoker 1');
81
81
  });
82
82
 
83
+ it('updates expanded with a new array when an invoker is clicked', async () => {
84
+ const el = /** @type {LionAccordion} */ (await fixture(basicAccordion));
85
+ const invokers = getInvokers(el);
86
+ const oldExpanded = el.expanded;
87
+ invokers[1].firstElementChild?.dispatchEvent(new Event('click'));
88
+ expect(el.expanded).to.not.equal(oldExpanded);
89
+ });
90
+
83
91
  it('has [expanded] on current expanded invoker which serves as styling hook', async () => {
84
92
  const el = /** @type {LionAccordion} */ (await fixture(basicAccordion));
85
93
  const invokers = getInvokers(el);
@@ -213,6 +221,17 @@ describe('<lion-accordion>', () => {
213
221
  el.focusedIndex = 1;
214
222
  expect(spy).to.have.been.calledOnce;
215
223
  });
224
+
225
+ it('tabbing sets the focusedIndex correctly', async () => {
226
+ const el = /** @type {LionAccordion} */ (await fixture(basicAccordion));
227
+ const invokers = getInvokers(el);
228
+ el.focusedIndex = 0;
229
+ expect(el.focusedIndex).to.equal(0);
230
+ invokers[2].firstElementChild?.dispatchEvent(new Event('focusin'));
231
+ expect(el.focusedIndex).to.equal(2);
232
+ invokers[1].firstElementChild?.dispatchEvent(new Event('focusin'));
233
+ expect(el.focusedIndex).to.equal(1);
234
+ });
216
235
  });
217
236
 
218
237
  describe('Accordion Contents (slot=content)', () => {
@@ -250,7 +250,10 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
250
250
  }
251
251
 
252
252
  focusCentralDate() {
253
- const button = /** @type {HTMLElement} */ (this.shadowRoot?.querySelector('[tabindex="0"]'));
253
+ const datesTable = /** @type {HTMLElement} */ (
254
+ this.shadowRoot?.querySelector('#js-content-wrapper')
255
+ );
256
+ const button = /** @type {HTMLElement} */ (datesTable.querySelector('[tabindex="0"]'));
254
257
  button.focus();
255
258
  this.__focusedDate = this.centralDate;
256
259
  }
@@ -835,7 +838,7 @@ export class LionCalendar extends LocalizeMixin(LitElement) {
835
838
  * @private
836
839
  */
837
840
  __dayButtonSelection(el) {
838
- if (isDayButton(el)) {
841
+ if (isDayButton(el) && !isDisabledDayButton(el)) {
839
842
  this.__dateSelectedByUser(el.date);
840
843
  }
841
844
  }
@@ -13,7 +13,6 @@ export function createMonth(date, { firstDayOfWeek = 0 } = {}) {
13
13
  }
14
14
  const firstDayOfMonth = new Date(date);
15
15
  firstDayOfMonth.setDate(1);
16
- const monthNumber = firstDayOfMonth.getMonth();
17
16
  const weekOptions = { firstDayOfWeek };
18
17
 
19
18
  const month = {
@@ -27,7 +26,7 @@ export function createMonth(date, { firstDayOfWeek = 0 } = {}) {
27
26
  const firstDayOfNextWeek = new Date(nextWeek.days[6].date); // last day of current week
28
27
  firstDayOfNextWeek.setDate(firstDayOfNextWeek.getDate() + 1); // make it first day of next week
29
28
  nextWeek = createWeek(firstDayOfNextWeek, weekOptions);
30
- } while (nextWeek.days[0].date.getMonth() === monthNumber);
29
+ } while (month.weeks.length !== 6);
31
30
 
32
31
  return month;
33
32
  }
@@ -221,7 +221,7 @@ describe('<lion-calendar>', () => {
221
221
  expect(isSameDate(el.centralDate, new Date('2019/06/15'))).to.be.true;
222
222
  });
223
223
 
224
- it('sends event "user-selected-date-changed" when user selects a date', async () => {
224
+ it('sends event "user-selected-date-changed" when user selects a date via mouse', async () => {
225
225
  const dateChangedSpy = sinon.spy();
226
226
  const el = await fixture(html`
227
227
  <lion-calendar
@@ -239,7 +239,7 @@ describe('<lion-calendar>', () => {
239
239
  ).to.equal(true);
240
240
  });
241
241
 
242
- it('doesn\'t send event "user-selected-date-changed" when user selects a disabled date', async () => {
242
+ it('doesn\'t send event "user-selected-date-changed" when user selects a disabled date via mouse', async () => {
243
243
  const dateChangedSpy = sinon.spy();
244
244
  const disable15th = /** @param {Date} d */ d => d.getDate() === 15;
245
245
  const el = await fixture(html`
@@ -253,6 +253,57 @@ describe('<lion-calendar>', () => {
253
253
  elObj.getDayEl(15).click();
254
254
  await el.updateComplete;
255
255
  expect(dateChangedSpy.called).to.equal(false);
256
+ expect(isSameDate(/** @type {Date} */ (el.selectedDate), new Date('2000/12/12'))).to.be.true;
257
+ });
258
+
259
+ it.skip('sends event "user-selected-date-changed" when user selects a date via [Enter]', async () => {
260
+ /**
261
+ * TODO fix me
262
+ * The dispatchEvent of [Enter] should has to be on contentWrapperElement to be called
263
+ * But to get "selected" a check is done if the action comes from a button.
264
+ */
265
+ const dateChangedSpy = sinon.spy();
266
+ const el = await fixture(html`
267
+ <lion-calendar
268
+ .selectedDate="${new Date('2000/10/12')}"
269
+ @user-selected-date-changed="${dateChangedSpy}"
270
+ ></lion-calendar>
271
+ `);
272
+ const elObj = new CalendarObject(el);
273
+
274
+ el.__contentWrapperElement?.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }));
275
+ await el.updateComplete;
276
+ expect(elObj.activeMonth).to.equal('October');
277
+ expect(elObj.activeYear).to.equal('2000');
278
+ expect(elObj.focusedDayObj?.monthday).to.equal(11);
279
+
280
+ el.__contentWrapperElement?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
281
+ await el.updateComplete;
282
+ expect(isSameDate(/** @type {Date} */ (el.selectedDate), new Date('2000/10/11'))).to.be.true;
283
+ expect(dateChangedSpy.called).to.equal(true);
284
+ });
285
+
286
+ it('doesn\'t send event "user-selected-date-changed" when user selects a disabled date via [Enter]', async () => {
287
+ const dateChangedSpy = sinon.spy();
288
+ const el = await fixture(html`
289
+ <lion-calendar
290
+ .selectedDate="${new Date('2000/10/12')}"
291
+ .minDate="${new Date('2000/10/12')}"
292
+ @user-selected-date-changed="${dateChangedSpy}"
293
+ ></lion-calendar>
294
+ `);
295
+ const elObj = new CalendarObject(el);
296
+
297
+ el.__contentWrapperElement?.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }));
298
+ await el.updateComplete;
299
+ expect(elObj.activeMonth).to.equal('October');
300
+ expect(elObj.activeYear).to.equal('2000');
301
+ expect(elObj.focusedDayObj?.monthday).to.equal(11);
302
+
303
+ el.__contentWrapperElement?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));
304
+ await el.updateComplete;
305
+ expect(isSameDate(/** @type {Date} */ (el.selectedDate), new Date('2000/10/12'))).to.be.true;
306
+ expect(dateChangedSpy.called).to.equal(false);
256
307
  });
257
308
 
258
309
  it('exposes focusedDate getter', async () => {
@@ -1280,11 +1331,25 @@ describe('<lion-calendar>', () => {
1280
1331
  expect(previousMonthDayObjs[2].cellIndex).to.equal(2);
1281
1332
  expect(previousMonthDayObjs[2].monthday).to.equal(31);
1282
1333
 
1283
- expect(nextMonthDayObjs.length).to.equal(2);
1334
+ expect(nextMonthDayObjs.length).to.equal(9);
1284
1335
  expect(nextMonthDayObjs[0].cellIndex).to.equal(5);
1285
1336
  expect(nextMonthDayObjs[0].monthday).to.equal(1);
1286
1337
  expect(nextMonthDayObjs[1].cellIndex).to.equal(6);
1287
1338
  expect(nextMonthDayObjs[1].monthday).to.equal(2);
1339
+ expect(nextMonthDayObjs[2].cellIndex).to.equal(0);
1340
+ expect(nextMonthDayObjs[2].monthday).to.equal(3);
1341
+ expect(nextMonthDayObjs[3].cellIndex).to.equal(1);
1342
+ expect(nextMonthDayObjs[3].monthday).to.equal(4);
1343
+ expect(nextMonthDayObjs[4].cellIndex).to.equal(2);
1344
+ expect(nextMonthDayObjs[4].monthday).to.equal(5);
1345
+ expect(nextMonthDayObjs[5].cellIndex).to.equal(3);
1346
+ expect(nextMonthDayObjs[5].monthday).to.equal(6);
1347
+ expect(nextMonthDayObjs[6].cellIndex).to.equal(4);
1348
+ expect(nextMonthDayObjs[6].monthday).to.equal(7);
1349
+ expect(nextMonthDayObjs[7].cellIndex).to.equal(5);
1350
+ expect(nextMonthDayObjs[7].monthday).to.equal(8);
1351
+ expect(nextMonthDayObjs[8].cellIndex).to.equal(6);
1352
+ expect(nextMonthDayObjs[8].monthday).to.equal(9);
1288
1353
  });
1289
1354
 
1290
1355
  it('renders days for next months in the last month of the year', async () => {
@@ -1294,11 +1359,25 @@ describe('<lion-calendar>', () => {
1294
1359
  `),
1295
1360
  );
1296
1361
  const { nextMonthDayObjs } = elObj;
1297
- expect(nextMonthDayObjs.length).to.equal(2);
1362
+ expect(nextMonthDayObjs.length).to.equal(9);
1298
1363
  expect(nextMonthDayObjs[0].cellIndex).to.equal(5);
1299
1364
  expect(nextMonthDayObjs[0].monthday).to.equal(1);
1300
1365
  expect(nextMonthDayObjs[1].cellIndex).to.equal(6);
1301
1366
  expect(nextMonthDayObjs[1].monthday).to.equal(2);
1367
+ expect(nextMonthDayObjs[2].cellIndex).to.equal(0);
1368
+ expect(nextMonthDayObjs[2].monthday).to.equal(3);
1369
+ expect(nextMonthDayObjs[3].cellIndex).to.equal(1);
1370
+ expect(nextMonthDayObjs[3].monthday).to.equal(4);
1371
+ expect(nextMonthDayObjs[4].cellIndex).to.equal(2);
1372
+ expect(nextMonthDayObjs[4].monthday).to.equal(5);
1373
+ expect(nextMonthDayObjs[5].cellIndex).to.equal(3);
1374
+ expect(nextMonthDayObjs[5].monthday).to.equal(6);
1375
+ expect(nextMonthDayObjs[6].cellIndex).to.equal(4);
1376
+ expect(nextMonthDayObjs[6].monthday).to.equal(7);
1377
+ expect(nextMonthDayObjs[7].cellIndex).to.equal(5);
1378
+ expect(nextMonthDayObjs[7].monthday).to.equal(8);
1379
+ expect(nextMonthDayObjs[8].cellIndex).to.equal(6);
1380
+ expect(nextMonthDayObjs[8].monthday).to.equal(9);
1302
1381
  });
1303
1382
 
1304
1383
  it('renders days for previous months in the first month of the year', async () => {
@@ -46,4 +46,19 @@ describe('createMonth', () => {
46
46
  }),
47
47
  );
48
48
  });
49
+
50
+ it('creates exactly 6 weeks in every months', () => {
51
+ expect(compareMonth(createMonth(new Date('2026/02/12')))).to.deep.equal(
52
+ compareMonth({
53
+ weeks: [
54
+ createWeek(new Date('2026/02/01'), { firstDayOfWeek: 0 }),
55
+ createWeek(new Date('2026/02/08'), { firstDayOfWeek: 0 }),
56
+ createWeek(new Date('2026/02/15'), { firstDayOfWeek: 0 }),
57
+ createWeek(new Date('2026/02/22'), { firstDayOfWeek: 0 }),
58
+ createWeek(new Date('2026/03/01'), { firstDayOfWeek: 0 }),
59
+ createWeek(new Date('2026/03/08'), { firstDayOfWeek: 0 }),
60
+ ],
61
+ }),
62
+ );
63
+ });
49
64
  });
@@ -584,6 +584,13 @@ const FormGroupMixinImplementation = superclass =>
584
584
  }
585
585
  this.__unlinkParentMessages(el);
586
586
  }
587
+
588
+ /**
589
+ * @override FormControlMixin
590
+ */
591
+ _isEmpty() {
592
+ return this.formElements.every(el => el._isEmpty?.());
593
+ }
587
594
  };
588
595
 
589
596
  export const FormGroupMixin = dedupeMixin(FormGroupMixinImplementation);