@lion/ui 0.18.0-menu-system.2 → 0.18.0-menu-system.5

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 (88) hide show
  1. package/components/collapsible/test-suites/DisclosureMixin.suite.js +30 -0
  2. package/components/menu/src/InteractiveListMixin.js +57 -24
  3. package/components/menu/src/LionMenu.js +1 -1
  4. package/components/menu/src/LionToolbar.js +1 -1
  5. package/components/menu/src/MoreButtonMenuMixin.js +79 -92
  6. package/components/menu/src/MultiLevelListMixin.js +1 -1
  7. package/components/menu/src/utils/listItemInteractions.js +25 -6
  8. package/components/menu/test/lion-menu.test.js +2 -1
  9. package/components/menu/test-suites/InteractiveListMixin.suite.js +164 -2
  10. package/components/navigation-bar/src/LionNavigationBar.js +2 -2
  11. package/custom-elements.json +354 -54
  12. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts +2 -0
  13. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts.map +1 -0
  14. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +11 -5
  15. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -1
  16. package/dist-types/components/menu/src/LionMenu.d.ts +4 -2
  17. package/dist-types/components/menu/src/LionMenu.d.ts.map +1 -1
  18. package/dist-types/components/menu/src/LionMenuOverlay.d.ts +8 -4
  19. package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +1 -1
  20. package/dist-types/components/menu/src/LionTree.d.ts +4 -2
  21. package/dist-types/components/menu/src/LionTree.d.ts.map +1 -1
  22. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +11 -2
  23. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +1 -1
  24. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +4 -2
  25. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +1 -1
  26. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +8 -2
  27. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +1 -1
  28. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +6 -5
  29. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -1
  30. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +4 -4
  31. package/dist-types/exports/menu-test-suites.d.ts +2 -0
  32. package/dist-types/exports/menu-test-suites.d.ts.map +1 -0
  33. package/dist-types/tsconfig.tsbuildinfo +1 -1
  34. package/docs/components/checkbox-group/overview.md +2 -2
  35. package/docs/components/collapsible/overview.md +1 -1
  36. package/docs/components/combobox/overview.md +1 -1
  37. package/docs/components/combobox/use-cases.md +1 -1
  38. package/docs/components/dialog/overview.md +1 -1
  39. package/docs/components/fieldset/overview.md +5 -5
  40. package/docs/components/form/overview.md +3 -3
  41. package/docs/components/form/use-cases.md +2 -2
  42. package/docs/components/icon/use-cases.md +1 -1
  43. package/docs/components/input/overview.md +1 -1
  44. package/docs/components/input-amount/overview.md +3 -3
  45. package/docs/components/input-date/overview.md +3 -3
  46. package/docs/components/input-datepicker/overview.md +5 -5
  47. package/docs/components/input-email/overview.md +2 -2
  48. package/docs/components/input-file/overview.md +1 -1
  49. package/docs/components/input-iban/overview.md +2 -2
  50. package/docs/components/input-range/overview.md +2 -2
  51. package/docs/components/input-stepper/overview.md +1 -1
  52. package/docs/components/input-tel/overview.md +1 -1
  53. package/docs/components/input-tel/use-cases.md +6 -6
  54. package/docs/components/input-tel-dropdown/overview.md +1 -1
  55. package/docs/components/listbox/use-cases.md +1 -1
  56. package/docs/components/menu/api-table.md +197 -192
  57. package/docs/components/menu/extensions.md +27 -0
  58. package/docs/components/menu/overview.md +39 -39
  59. package/docs/components/radio-group/overview.md +3 -3
  60. package/docs/components/select/use-cases.md +1 -1
  61. package/docs/components/select-rich/use-cases.md +2 -2
  62. package/docs/components/tabs/examples.md +1 -1
  63. package/docs/fundamentals/index.md +4 -4
  64. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  65. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  66. package/docs/fundamentals/rationales/accessibility.md +1 -1
  67. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  68. package/docs/fundamentals/systems/core/overview.md +1 -1
  69. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  70. package/docs/fundamentals/systems/form/model-value.md +1 -1
  71. package/docs/fundamentals/systems/form/overview.md +28 -28
  72. package/docs/fundamentals/systems/form/validate.md +2 -2
  73. package/docs/fundamentals/systems/localize/overview.md +4 -4
  74. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  75. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  76. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  77. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  78. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  79. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  80. package/docs/guides/how-to/create-a-form.md +4 -4
  81. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  82. package/docs/guides/how-to/index.md +1 -1
  83. package/docs/guides/index.md +8 -8
  84. package/docs/guides/principles/index.md +5 -5
  85. package/docs/guides/principles/styling.md +1 -1
  86. package/exports/menu-test-suites.js +2 -0
  87. package/menu-test-suites.js +2 -0
  88. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
- import { expect, html, fixture, unsafeStatic, defineCE } from '@open-wc/testing';
2
+ import { expect, html, fixture as _fixture, unsafeStatic, defineCE } from '@open-wc/testing';
3
3
  import { InteractiveListMixin } from '../src/InteractiveListMixin.js';
4
4
 
5
5
  class InteractiveListClass extends InteractiveListMixin(LitElement) {}
@@ -20,10 +20,15 @@ const supportedRoles = [
20
20
  ];
21
21
 
22
22
  /**
23
- * @typedef {Object} TestConfig
23
+ * @typedef {import('../src/LionMenu.js').LionMenu} LionMenu
24
+ * @typedef {import('lit').TemplateResult} TemplateResult
25
+ *
26
+ * * @typedef {Object} TestConfig
24
27
  * @property {string} tagString
25
28
  */
26
29
 
30
+ const fixture = /** @type {(arg: TemplateResult) => Promise<LionMenu>} */ (_fixture);
31
+
27
32
  /**
28
33
  * @param {TestConfig} [customConfig]
29
34
  */
@@ -122,6 +127,163 @@ export function runInteractiveListMixinSuite(customConfig) {
122
127
  });
123
128
  });
124
129
 
130
+ describe('Programmatic interaction', () => {
131
+ // If we have the item line directly in the fixture the linting rule lit-a11y/role-has-required-aria-attrs
132
+ // will fail. Inside our code we set the required aria attributes, but the linter doesn't know that.
133
+ const item = /** @param {number} i, @param {string} role */ (i, role) => html`
134
+ <div role="${role}" id="item${i}">Item ${i}</div>
135
+ `;
136
+
137
+ it('set checked state sets aria-current attribute with role="listitem"', async () => {
138
+ const el = await fixture(html`
139
+ <${tag}>
140
+ ${item(1, 'listitem')}
141
+ ${item(2, 'listitem')}
142
+ </${tag}>
143
+ `);
144
+ el.setCheckedIndex(1);
145
+ const item1 = el.listItems[1];
146
+ expect(item1.getAttribute('aria-current')).to.equal('true');
147
+ el.setCheckedIndex(0);
148
+ expect(item1.getAttribute('aria-current')).to.equal('false');
149
+ });
150
+
151
+ it('set checked state sets aria-selected attribute with role="option"', async () => {
152
+ const el = await fixture(html`
153
+ <${tag}>
154
+ ${item(1, 'option')}
155
+ ${item(2, 'option')}
156
+ </${tag}>
157
+ `);
158
+ console.debug('listItems', el.listItems);
159
+ const item1 = el.listItems[1];
160
+ expect(item1.getAttribute('aria-selected')).to.equal('false');
161
+
162
+ el.setCheckedIndex(1);
163
+ expect(item1.getAttribute('aria-selected')).to.equal('true');
164
+
165
+ el.setCheckedIndex(0);
166
+ expect(item1.getAttribute('aria-selected')).to.equal('false');
167
+ });
168
+
169
+ it('set checked state sets aria-selected attribute with role="treeitem"', async () => {
170
+ const el = await fixture(html`
171
+ <${tag}>
172
+ ${item(1, 'treeitem')}
173
+ ${item(2, 'treeitem')}
174
+ </${tag}>
175
+ `);
176
+ el.setCheckedIndex(1);
177
+ // @ts-ignore - test element with InteractiveListMixin properties
178
+ const item1 = el.listItems[1];
179
+ expect(item1.getAttribute('aria-selected')).to.equal('true');
180
+ el.setCheckedIndex(0);
181
+ expect(item1.getAttribute('aria-selected')).to.equal('false');
182
+ });
183
+
184
+ it('set checked state sets aria-current attribute with role="menuitem"', async () => {
185
+ const el = await fixture(html`
186
+ <${tag}>
187
+ ${item(1, 'menuitem')}
188
+ ${item(2, 'menuitem')}
189
+ </${tag}>
190
+ `);
191
+ el.setCheckedIndex(1);
192
+ const item1 = el.listItems[1];
193
+ expect(item1.getAttribute('aria-current')).to.equal('true');
194
+ el.setCheckedIndex(0);
195
+ expect(item1.getAttribute('aria-current')).to.equal('false');
196
+ });
197
+
198
+ it('set checked state sets aria-checked attribute with role="menuitemradio"', async () => {
199
+ const el = await fixture(html`
200
+ <${tag}>
201
+ ${item(1, 'menuitemradio')}
202
+ ${item(2, 'menuitemradio')}
203
+ </${tag}>
204
+ `);
205
+ el.setCheckedIndex(1);
206
+ const item1 = el.listItems[1];
207
+ expect(item1.getAttribute('aria-checked')).to.equal('true');
208
+ el.setCheckedIndex(0);
209
+ expect(item1.getAttribute('aria-checked')).to.equal('false');
210
+ });
211
+
212
+ it('set checked state sets aria-checked attribute with role="menuitemcheckbox"', async () => {
213
+ const el = await fixture(html`
214
+ <${tag}>
215
+ ${item(1, 'menuitemcheckbox')}
216
+ ${item(2, 'menuitemcheckbox')}
217
+ </${tag}>
218
+ `);
219
+ el.setCheckedIndex(1);
220
+ const item1 = el.listItems[1];
221
+ expect(item1.getAttribute('aria-checked')).to.equal('true');
222
+ el.setCheckedIndex(0);
223
+ // As this is multiple choice it doesn't unset the checked state
224
+ expect(item1.getAttribute('aria-checked')).to.equal('true');
225
+ });
226
+
227
+ it('can set checked state to "page" for role="listitem"', async () => {
228
+ const el = await fixture(html`
229
+ <${tag}>
230
+ <a role="listitem" id="item1" href="#">Item 1</a>
231
+ <a role="listitem" id="item2" href="#">Item 2</a>
232
+ </${tag}>
233
+ `);
234
+ el.setCheckedIndex(1);
235
+ const item1 = el.listItems[1];
236
+ expect(item1.getAttribute('aria-current')).to.equal('page');
237
+ el.setCheckedIndex(0);
238
+ expect(item1.getAttribute('aria-current')).to.equal('false');
239
+ });
240
+
241
+ it('can set checked state to "mixed" for role="menuitemcheckbox"', async () => {
242
+ const el = await fixture(html`
243
+ <${tag}>
244
+ ${item(1, 'menuitemcheckbox')}
245
+ ${item(2, 'menuitemcheckbox')}
246
+ </${tag}>
247
+ `);
248
+ const item1 = el.listItems[1];
249
+ // @ts-ignore - not yet supported property
250
+ item1.mixedState = true;
251
+ el.setCheckedIndex(1);
252
+ expect(item1.getAttribute('aria-checked')).to.equal('mixed');
253
+ el.setCheckedIndex(0);
254
+ expect(item1.getAttribute('aria-checked')).to.equal('mixed');
255
+ });
256
+
257
+ it('does not allow to set checkedIndex or activeIndex to be out of bound', async () => {
258
+ const el = await fixture(html`
259
+ <${tag} has-no-default-selected autocomplete="list">
260
+ <div role="menuitem" id="item1">Item 1</div>
261
+ </${tag}>
262
+ `);
263
+ expect(() => {
264
+ el.checkedIndex = -1;
265
+ el.checkedIndex = 1;
266
+ }).to.not.throw();
267
+ expect(el.checkedIndex).to.equal(-1);
268
+ });
269
+
270
+ it('unsets checked on other options when option becomes checked', async () => {
271
+ const el = await fixture(html`
272
+ <${tag}>
273
+ <div role="menuitem" id="item1">Item 1</div>
274
+ <div role="menuitem" id="item2">Item 2</div>
275
+ </${tag}>
276
+ `);
277
+ const { listItems } = el;
278
+ el.setCheckedIndex(0);
279
+ expect(listItems[0].hasAttribute('checked')).to.be.true;
280
+ expect(listItems[1].hasAttribute('checked')).to.be.false;
281
+ el.setCheckedIndex(1);
282
+ expect(listItems[0].hasAttribute('checked')).to.be.false;
283
+ expect(listItems[1].hasAttribute('checked')).to.be.true;
284
+ });
285
+ });
286
+
125
287
  // Copy tests from ListboxMixin. Later, make this mixin a fundament of the ListboxMixin
126
288
 
127
289
  // orientation
@@ -199,7 +199,7 @@ export class LionNavigationBar extends ScopedElementsMixin(LitElement) {
199
199
  openableConfig: {
200
200
  // We want to do the absolute positioning ourselves, popper is not suited for this...
201
201
  placementMode: 'custom',
202
- isOpenable: false,
202
+ isActivated: false,
203
203
  hidesOnOutsideClick: false,
204
204
  inheritsReferenceWidth: 'none',
205
205
  },
@@ -231,7 +231,7 @@ export class LionNavigationBar extends ScopedElementsMixin(LitElement) {
231
231
  // We want disclosure behavior
232
232
  placementMode: 'custom',
233
233
  // N.B. we don't have an invoker...
234
- isOpenable: false,
234
+ isActivated: false,
235
235
  inheritsReferenceWidth: 'none',
236
236
  focusContentOnOpen: true,
237
237
  },