@lion/ui 0.17.0-menu-system.0 → 0.17.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 (212) hide show
  1. package/collapsible.js +0 -1
  2. package/components/button/src/LionButton.js +0 -4
  3. package/components/button/test-suites/LionButton.suite.js +0 -1
  4. package/components/calendar/src/LionCalendar.js +0 -2
  5. package/components/combobox/test/lion-combobox.test.js +0 -1
  6. package/components/form-core/src/form-group/FormGroupMixin.js +0 -7
  7. package/components/form-core/src/registration/FormRegistrarMixin.js +0 -11
  8. package/components/form-core/test/FormControlMixin.test.js +0 -1
  9. package/components/form-core/test/validate/Validator.test.js +0 -2
  10. package/components/form-core/test-suites/ValidateMixin.suite.js +0 -2
  11. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +0 -1
  12. package/components/input-datepicker/src/localizeNamespaceLoader.js +0 -1
  13. package/components/input-datepicker/test/lion-input-datepicker.test.js +6 -5
  14. package/components/localize/test/date/formatDate.test.js +0 -1
  15. package/components/overlays/src/OverlayController.js +76 -160
  16. package/components/overlays/src/OverlayMixin.js +11 -57
  17. package/components/overlays/src/OverlaysManager.js +2 -2
  18. package/components/overlays/src/utils/adopt-styles.js +1 -2
  19. package/components/overlays/src/utils/get-focusable-elements.js +0 -4
  20. package/components/overlays/src/utils/is-equal-config.js +1 -4
  21. package/components/overlays/test/OverlayController.test.js +2 -2
  22. package/components/overlays/types/OverlayConfig.ts +5 -10
  23. package/components/select-rich/test/lion-select-rich.test.js +0 -3
  24. package/custom-elements.json +19168 -31113
  25. package/dist-types/components/button/src/LionButton.d.ts +0 -1
  26. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  27. package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
  28. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  29. package/dist-types/components/dialog/src/LionDialog.d.ts +1 -2
  30. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  31. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
  32. package/dist-types/components/form-core/src/registration/FormRegistrarMixin.d.ts.map +1 -1
  33. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  34. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  35. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
  36. package/dist-types/components/overlays/src/OverlayController.d.ts +6 -6
  37. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  38. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  39. package/dist-types/components/overlays/src/utils/get-focusable-elements.d.ts.map +1 -1
  40. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  41. package/dist-types/components/overlays/types/OverlayConfig.d.ts +2 -5
  42. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  43. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +2 -7
  44. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  45. package/dist-types/exports/overlays.d.ts +0 -2
  46. package/dist-types/tsconfig.tsbuildinfo +1 -1
  47. package/docs/components/checkbox-group/overview.md +2 -2
  48. package/docs/components/collapsible/overview.md +1 -1
  49. package/docs/components/combobox/api-table.md +8 -21
  50. package/docs/components/combobox/overview.md +1 -1
  51. package/docs/components/combobox/use-cases.md +1 -1
  52. package/docs/components/dialog/api-table.md +6 -31
  53. package/docs/components/dialog/overview.md +1 -1
  54. package/docs/components/fieldset/overview.md +5 -5
  55. package/docs/components/form/overview.md +3 -3
  56. package/docs/components/form/use-cases.md +2 -2
  57. package/docs/components/icon/use-cases.md +1 -1
  58. package/docs/components/input/overview.md +1 -1
  59. package/docs/components/input-amount/overview.md +3 -3
  60. package/docs/components/input-date/overview.md +3 -3
  61. package/docs/components/input-datepicker/api-table.md +4 -21
  62. package/docs/components/input-datepicker/overview.md +5 -5
  63. package/docs/components/input-email/overview.md +2 -2
  64. package/docs/components/input-file/overview.md +1 -1
  65. package/docs/components/input-iban/overview.md +2 -2
  66. package/docs/components/input-range/overview.md +2 -2
  67. package/docs/components/input-stepper/overview.md +1 -1
  68. package/docs/components/input-tel/overview.md +1 -1
  69. package/docs/components/input-tel/use-cases.md +6 -6
  70. package/docs/components/input-tel-dropdown/overview.md +1 -1
  71. package/docs/components/listbox/use-cases.md +1 -1
  72. package/docs/components/radio-group/overview.md +3 -3
  73. package/docs/components/select/use-cases.md +1 -1
  74. package/docs/components/select-rich/api-table.md +5 -21
  75. package/docs/components/select-rich/use-cases.md +2 -2
  76. package/docs/components/tabs/examples.md +1 -1
  77. package/docs/components/tooltip/api-table.md +11 -36
  78. package/docs/fundamentals/index.md +4 -4
  79. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  80. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  81. package/docs/fundamentals/rationales/accessibility.md +1 -1
  82. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  83. package/docs/fundamentals/systems/core/overview.md +1 -1
  84. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  85. package/docs/fundamentals/systems/form/model-value.md +1 -1
  86. package/docs/fundamentals/systems/form/overview.md +28 -28
  87. package/docs/fundamentals/systems/form/validate.md +2 -2
  88. package/docs/fundamentals/systems/localize/overview.md +4 -4
  89. package/docs/fundamentals/systems/overlays/api-table.md +34 -34
  90. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  91. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  92. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  93. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  94. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  95. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  96. package/docs/guides/how-to/create-a-form.md +4 -4
  97. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  98. package/docs/guides/how-to/index.md +1 -1
  99. package/docs/guides/index.md +8 -8
  100. package/docs/guides/principles/index.md +5 -5
  101. package/docs/guides/principles/styling.md +1 -1
  102. package/exports/collapsible.js +0 -1
  103. package/exports/overlays.js +0 -2
  104. package/overlays.js +0 -2
  105. package/package.json +1 -1
  106. package/components/collapsible/src/DisclosureMixin.js +0 -313
  107. package/components/collapsible/types/DisclosureMixinTypes.ts +0 -48
  108. package/components/menu/CHANGELOG.md +0 -37
  109. package/components/menu/README.md +0 -335
  110. package/components/menu/index.js +0 -2
  111. package/components/menu/lion-menu-overlay.js +0 -3
  112. package/components/menu/lion-menu.js +0 -3
  113. package/components/menu/lion-spinbutton.js +0 -3
  114. package/components/menu/lion-toolbar.js +0 -3
  115. package/components/menu/lion-tree.js +0 -3
  116. package/components/menu/package.json +0 -46
  117. package/components/menu/requirements.temp.md +0 -12
  118. package/components/menu/src/InteractiveListMixin.js +0 -796
  119. package/components/menu/src/LionMenu.js +0 -250
  120. package/components/menu/src/LionMenuHybrid.js +0 -46
  121. package/components/menu/src/LionMenuOverlay.js +0 -155
  122. package/components/menu/src/LionSpinbutton.js +0 -213
  123. package/components/menu/src/LionToolbar.js +0 -94
  124. package/components/menu/src/LionTree.js +0 -52
  125. package/components/menu/src/MultiLevelListMixin.js +0 -275
  126. package/components/menu/src/utils/isInView.js +0 -26
  127. package/components/menu/src/utils/listItemInteractions.js +0 -104
  128. package/components/menu/src/utils/uuid.js +0 -3
  129. package/components/menu/test/lion-menu.test.js +0 -3
  130. package/components/menu/test-suites/InteractiveListMixin.suite.js +0 -142
  131. package/components/menu/types/InteractiveListMixinTypes.d.ts +0 -82
  132. package/components/navigation-bar/README.md +0 -1
  133. package/components/navigation-bar/src/LionNavigationBar.js +0 -449
  134. package/components/navigation-bar/src/types.js +0 -41
  135. package/components/overlays/NEXT.md +0 -49
  136. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +0 -3
  137. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +0 -1
  138. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +0 -24
  139. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +0 -1
  140. package/dist-types/components/menu/index.d.ts +0 -3
  141. package/dist-types/components/menu/index.d.ts.map +0 -1
  142. package/dist-types/components/menu/lion-menu-overlay.d.ts +0 -2
  143. package/dist-types/components/menu/lion-menu-overlay.d.ts.map +0 -1
  144. package/dist-types/components/menu/lion-menu.d.ts +0 -2
  145. package/dist-types/components/menu/lion-menu.d.ts.map +0 -1
  146. package/dist-types/components/menu/lion-spinbutton.d.ts +0 -2
  147. package/dist-types/components/menu/lion-spinbutton.d.ts.map +0 -1
  148. package/dist-types/components/menu/lion-toolbar.d.ts +0 -2
  149. package/dist-types/components/menu/lion-toolbar.d.ts.map +0 -1
  150. package/dist-types/components/menu/lion-tree.d.ts +0 -2
  151. package/dist-types/components/menu/lion-tree.d.ts.map +0 -1
  152. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +0 -611
  153. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +0 -1
  154. package/dist-types/components/menu/src/LionMenu.d.ts +0 -563
  155. package/dist-types/components/menu/src/LionMenu.d.ts.map +0 -1
  156. package/dist-types/components/menu/src/LionMenuHybrid.d.ts +0 -19
  157. package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +0 -1
  158. package/dist-types/components/menu/src/LionMenuOverlay.d.ts +0 -1006
  159. package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +0 -1
  160. package/dist-types/components/menu/src/LionSpinbutton.d.ts +0 -58
  161. package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +0 -1
  162. package/dist-types/components/menu/src/LionToolbar.d.ts +0 -8
  163. package/dist-types/components/menu/src/LionToolbar.d.ts.map +0 -1
  164. package/dist-types/components/menu/src/LionTree.d.ts +0 -445
  165. package/dist-types/components/menu/src/LionTree.d.ts.map +0 -1
  166. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +0 -493
  167. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +0 -1
  168. package/dist-types/components/menu/src/utils/isInView.d.ts +0 -9
  169. package/dist-types/components/menu/src/utils/isInView.d.ts.map +0 -1
  170. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +0 -42
  171. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +0 -1
  172. package/dist-types/components/menu/src/utils/uuid.d.ts +0 -2
  173. package/dist-types/components/menu/src/utils/uuid.d.ts.map +0 -1
  174. package/dist-types/components/menu/test/lion-menu.test.d.ts +0 -2
  175. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +0 -1
  176. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +0 -13
  177. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +0 -1
  178. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +0 -226
  179. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +0 -1
  180. package/dist-types/components/navigation-bar/src/types.d.ts +0 -85
  181. package/dist-types/components/navigation-bar/src/types.d.ts.map +0 -1
  182. package/dist-types/exports/define/lion-item.d.ts +0 -2
  183. package/dist-types/exports/define/lion-item.d.ts.map +0 -1
  184. package/dist-types/exports/define/lion-menu-overlay.d.ts +0 -2
  185. package/dist-types/exports/define/lion-menu-overlay.d.ts.map +0 -1
  186. package/dist-types/exports/define/lion-menu.d.ts +0 -2
  187. package/dist-types/exports/define/lion-menu.d.ts.map +0 -1
  188. package/dist-types/exports/define/lion-navigation-bar.d.ts +0 -2
  189. package/dist-types/exports/define/lion-navigation-bar.d.ts.map +0 -1
  190. package/dist-types/exports/define/lion-toolbar.d.ts +0 -2
  191. package/dist-types/exports/define/lion-toolbar.d.ts.map +0 -1
  192. package/dist-types/exports/define/lion-tree.d.ts +0 -2
  193. package/dist-types/exports/define/lion-tree.d.ts.map +0 -1
  194. package/dist-types/exports/menu.d.ts +0 -7
  195. package/dist-types/exports/menu.d.ts.map +0 -1
  196. package/dist-types/exports/navigation-bar.d.ts +0 -2
  197. package/dist-types/exports/navigation-bar.d.ts.map +0 -1
  198. package/docs/components/menu/api-table.md +0 -450
  199. package/docs/components/menu/applyMenuDemoStyles.js +0 -173
  200. package/docs/components/menu/extensions.md +0 -216
  201. package/docs/components/menu/index.md +0 -13
  202. package/docs/components/menu/overview.md +0 -422
  203. package/exports/define/lion-item.js +0 -3
  204. package/exports/define/lion-menu-overlay.js +0 -3
  205. package/exports/define/lion-menu.js +0 -3
  206. package/exports/define/lion-navigation-bar.js +0 -3
  207. package/exports/define/lion-toolbar.js +0 -3
  208. package/exports/define/lion-tree.js +0 -3
  209. package/exports/menu.js +0 -6
  210. package/exports/navigation-bar.js +0 -1
  211. package/menu.js +0 -6
  212. package/navigation-bar.js +0 -1
@@ -1,142 +0,0 @@
1
- import { LitElement } from 'lit';
2
- import { expect, html, fixture, unsafeStatic, defineCE } from '@open-wc/testing';
3
- import { InteractiveListMixin } from '../src/InteractiveListMixin.js';
4
-
5
- class InteractiveListClass extends InteractiveListMixin(LitElement) {}
6
-
7
- /**
8
- * @typedef {import('../types/InteractiveListMixinTypes.js').InteractiveListItemRole} InteractiveListItemRole
9
- */
10
-
11
- /** @type {InteractiveListItemRole[]} */
12
- const supportedRoles = [
13
- 'menuitem',
14
- 'menuitemcheckbox',
15
- 'menuitemradio',
16
- 'option',
17
- 'treeitem',
18
- 'radio',
19
- 'checkbox',
20
- ];
21
-
22
- /**
23
- * @typedef {Object} TestConfig
24
- * @property {string} tagString
25
- */
26
-
27
- /**
28
- * @param {TestConfig} [customConfig]
29
- */
30
- export function runInteractiveListMixinSuite(customConfig) {
31
- const cfg = {
32
- tagString: customConfig?.tagString || defineCE(InteractiveListClass),
33
- };
34
-
35
- const { tagString } = cfg;
36
- const tag = unsafeStatic(tagString);
37
-
38
- describe('InteractiveListMixin', () => {
39
- it(`supports items with role="${supportedRoles.join('|')}"`, async () => {
40
- const el = await fixture(html`
41
- <${tag} name="foo">
42
- ${supportedRoles.map(role => html` <div role="${role}"></div> `)}
43
- </${tag}>
44
- `);
45
- // @ts-ignore - test element with InteractiveListMixin properties
46
- expect(el.listItems.length).to.equal(supportedRoles.length);
47
- supportedRoles.forEach((role, i) => {
48
- // @ts-ignore - test element with InteractiveListMixin properties
49
- expect(el.listItems[i].getAttribute('role')).to.equal(role);
50
- });
51
- });
52
-
53
- it('moves elements to a private [slot=list] for optimal DX and a11y', async () => {
54
- const el = await fixture(html`
55
- <${tag} name="foo">
56
- <div role="menuitem" id="item1">Item 1</div>
57
- <div role="menuitem" id="item2">Item 2</div>
58
- </${tag}>
59
- `);
60
- // @ts-ignore - test element with InteractiveListMixin properties
61
- const listSlotNode = Array.from(el.children).find(c => c.slot === 'list');
62
- // @ts-ignore - accessing children property
63
- const listItemEls = Array.from(listSlotNode.children);
64
- // @ts-ignore - test element with InteractiveListMixin properties
65
- expect(listItemEls.includes(el.listItems[0])).to.be.true;
66
- // @ts-ignore - test element with InteractiveListMixin properties
67
- expect(listItemEls.includes(el.listItems[1])).to.be.true;
68
- });
69
-
70
- it('inherits from DisclosureMixin', async () => {});
71
-
72
- describe('Active mode', async () => {
73
- it('supports "activedescendant" pattern', async () => {
74
- const el = await fixture(html`
75
- <${tag} name="foo" ._activeMode="${'activedescendant'}">
76
- <div role="menuitem" id="item1">Item 1</div>
77
- <div role="menuitem" id="item2">Item 2</div>
78
- </${tag}>
79
- `);
80
- // @ts-ignore - test element with InteractiveListMixin properties
81
- el.checkedIndex = 0;
82
- // @ts-ignore - test element with InteractiveListMixin properties
83
- const listSlotNode = Array.from(el.children).find(c => c.slot === 'list');
84
-
85
- // @ts-ignore - test element with InteractiveListMixin properties
86
- // @ts-ignore - test element with InteractiveListMixin properties
87
- expect(el.listItems[0].hasAttribute('id')).to.be.true;
88
- // @ts-ignore - test element with InteractiveListMixin properties
89
- expect(el.listItems[1].hasAttribute('id')).to.be.true;
90
- expect(listSlotNode?.hasAttribute('aria-activedescendant')).to.be.false;
91
- // @ts-ignore - test element with InteractiveListMixin properties
92
- el.activeIndex = 1;
93
- expect(listSlotNode?.hasAttribute('aria-activedescendant')).to.be.true;
94
- });
95
-
96
- it('supports "roving-tabindex" pattern', async () => {
97
- const el = await fixture(html`
98
- <${tag} name="foo" ._activeMode="${'roving-tabindex'}">
99
- <div role="menuitem" id="item1">Item 1</div>
100
- <div role="menuitem" id="item2">Item 2</div>
101
- </${tag}>
102
- `);
103
-
104
- // @ts-ignore - test element with InteractiveListMixin properties
105
- el.activeIndex = 0;
106
- // @ts-ignore - test element with InteractiveListMixin properties
107
- expect(el.listItems[0].getAttribute('tabindex')).to.equal('0');
108
- // @ts-ignore - test element with InteractiveListMixin properties
109
- expect(el.listItems[1].getAttribute('tabindex')).to.equal('-1');
110
-
111
- // @ts-ignore - test element with InteractiveListMixin properties
112
- el.activeIndex = 1;
113
- // @ts-ignore - test element with InteractiveListMixin properties
114
- expect(el.listItems[0].getAttribute('tabindex')).to.equal('-1');
115
- // @ts-ignore - test element with InteractiveListMixin properties
116
- expect(el.listItems[1].getAttribute('tabindex')).to.equal('0');
117
-
118
- // @ts-ignore - test element with InteractiveListMixin properties
119
- el.activeIndex = 1;
120
- // @ts-ignore - test element with InteractiveListMixin properties
121
- expect(document.activeElement).to.equal(el.listItems[1]);
122
- });
123
- });
124
-
125
- // Copy tests from ListboxMixin. Later, make this mixin a fundament of the ListboxMixin
126
-
127
- // orientation
128
- // multipleChoice
129
- // selectionFollowsFocus
130
- // rotateKeyboardNavigation
131
- // noPreselect
132
- // _scrollTargetNode
133
-
134
- describe('Widget extensions', () => {
135
- it('can be extended to [role=listbox]', async () => {});
136
- it('can be extended to [role=menu]', async () => {});
137
- it('can be extended to [role=menubar]', async () => {});
138
- it('can be extended to [role=toolbar]', async () => {});
139
- it('can be extended to [role=tree]', async () => {});
140
- });
141
- });
142
- }
@@ -1,82 +0,0 @@
1
- import { Constructor } from '@open-wc/dedupe-mixin';
2
- import { LitElement } from 'lit';
3
- import { SlotHost } from '../../core/types/SlotMixinTypes.js';
4
- import { DisabledHost } from '../../core/types/DisabledMixinTypes.js';
5
-
6
- export type InteractiveListItemRole =
7
- | 'menuitem'
8
- | 'menuitemcheckbox'
9
- | 'menuitemradio'
10
- | 'option'
11
- | 'treeitem'
12
- | 'radio'
13
- | 'checkbox';
14
-
15
- export declare class InteractiveListHost {
16
- /**
17
- * When true, will synchronize activedescendant and selected element on
18
- * arrow key navigation.
19
- * This behavior can usually be seen on <select> on the Windows platform.
20
- * Note that this behavior cannot be used when multiple-choice is true.
21
- * See: https://www.w3.org/TR/wai-aria-practices/#kbd_selection_follows_focus
22
- */
23
- public selectionFollowsFocus: Boolean;
24
- /**
25
- * Will give first option active state when navigated to the next option from
26
- * last option.
27
- */
28
- public rotateKeyboardNavigation: Boolean;
29
- /**
30
- * Informs screen reader and affects keyboard navigation.
31
- * By default 'vertical'
32
- */
33
- public orientation: 'vertical' | 'horizontal';
34
-
35
- public hasNoDefaultSelected: boolean;
36
-
37
- public singleOption: boolean;
38
-
39
- public checkedIndex: number | number[];
40
-
41
- public activeIndex: number;
42
-
43
- public listItems: HTMLElement[];
44
-
45
- public setCheckedIndex(index: number): void;
46
-
47
- protected _scrollTargetNode: HTMLElement;
48
-
49
- protected _listNode: HTMLElement;
50
-
51
- // private __setupListboxNode(): void;
52
-
53
- protected _getPreviousEnabledOption(currentIndex: number, offset?: number): number;
54
-
55
- protected _getNextEnabledOption(currentIndex: number, offset?: number): number;
56
-
57
- protected _onListKeyDown(ev: KeyboardEvent): void;
58
-
59
- protected _onListKeyUp(ev: KeyboardEvent): void;
60
-
61
- // protected _setupListboxNode(): void;
62
-
63
- // protected _teardownListboxNode(): void;
64
-
65
- protected _onListClick(ev: MouseEvent): void;
66
-
67
- // protected _setupListboxInteractions(): void;
68
-
69
- // protected _onChildActiveChanged(ev: Event): void;
70
- }
71
-
72
- export declare function InteractiveListHostImplementation<T extends Constructor<LitElement>>(
73
- superclass: T,
74
- ): T &
75
- Constructor<InteractiveListHost> &
76
- InteractiveListHost &
77
- Constructor<DisabledHost> &
78
- typeof DisabledHost &
79
- Constructor<SlotHost> &
80
- typeof SlotHost;
81
-
82
- export type InteractiveListMixin = typeof InteractiveListHostImplementation;
@@ -1 +0,0 @@
1
- N.B. api is very very beta
@@ -1,449 +0,0 @@
1
- import { LitElement, html, css } from 'lit';
2
- import { LionMenuHybrid } from '@lion/ui/menu.js';
3
- import { ScopedElementsMixin } from '../../core/src/ScopedElementsMixin.js';
4
-
5
- /**
6
- * @typedef {import('./types.js').NavBarResponsiveMode} NavBarResponsiveMode
7
- * @typedef {import('./types.js').MenuItem} MenuItem
8
- * @typedef {import('./types.js').CtaLink} CtaLink
9
- * @typedef {import('./types.js').Logo} Logo
10
- * @typedef {import('./types.js').LevelConfig} LevelConfig
11
- */
12
-
13
- export class LionNavigationBar extends ScopedElementsMixin(LitElement) {
14
- static get properties() {
15
- return {
16
- responsiveMode: { type: String, reflect: true, attribute: 'responsive-mode' },
17
- // logo: { type: String },
18
- menuItems: { type: Array },
19
- menuSupportItems: { type: Array },
20
- ctaPrimary: { type: Object },
21
- ctaSecondary: { type: Object },
22
- suggestions: { type: Array },
23
- showOnMobile: { type: Array, attribute: 'show-on-mobile', reflect: true },
24
-
25
- _levelCfg: { state: true },
26
- };
27
- }
28
-
29
- static get scopedElements() {
30
- return {
31
- // 'lion-menu-overlay': LionMenuOverlay,
32
- 'lion-menu-hybrid': LionMenuHybrid,
33
- };
34
- }
35
-
36
- static get styles() {
37
- return [
38
- css`
39
- /** specific styles */
40
-
41
- :host([responsive-mode='desktop']) [data-has-full-width-flyout] > [slot='list'] {
42
- /** make sure that we give the right styles */
43
- position: relative;
44
- }
45
-
46
- :host([responsive-mode='desktop'])
47
- [data-has-full-width-flyout]
48
- > [slot='list']
49
- [level='2']
50
- > [slot='list'] {
51
- position: absolute;
52
- width: 100%;
53
- left: 0;
54
- right: 0;
55
- min-height: 300px;
56
- padding: 1em;
57
- background-color: white;
58
- border: 1px solid gray;
59
- box-sizing: border-box;
60
- }
61
-
62
- :host([responsive-mode='desktop']) [level='3'] > [slot='list'] {
63
- position: absolute;
64
- left: 33.333%;
65
- width: 33.333%;
66
- top: 0;
67
- padding: 1em;
68
- background-color: white;
69
- box-sizing: border-box;
70
- height: 100%;
71
- }
72
-
73
- :host([responsive-mode='mobile']) nav {
74
- border: 1px solid black;
75
- display: block;
76
- position: fixed;
77
- top: 0;
78
- bottom: 0;
79
- right: 0;
80
- min-width: 500px;
81
- }
82
-
83
- :host([responsive-mode='mobile']) [level][opened] > [slot='list'] {
84
- left: 0;
85
- width: 100%;
86
- top: 0;
87
- box-sizing: border-box;
88
- }
89
-
90
- :host([responsive-mode='mobile']) [slot='list'] {
91
- position: relative;
92
- padding: 1em;
93
- background-color: white;
94
- }
95
-
96
- :host([responsive-mode='mobile']) [level='2'] > [slot='list'],
97
- :host([responsive-mode='mobile']) [level='3'] > [slot='list'] {
98
- position: absolute;
99
- left: 100%;
100
- top: 0;
101
- box-sizing: border-box;
102
- padding-bottom: 200%;
103
- }
104
-
105
- :host([responsive-mode='mobile']) nav {
106
- display: flex;
107
- flex-direction: column;
108
- /* height: 100%;
109
- justify-content: space-between; */
110
- }
111
-
112
- /* :host([responsive-mode='mobile']) .cta-items {
113
- position: absolute;
114
- bottom: 0;
115
- width: 100%;
116
- padding: 1em;
117
- background-color: white;
118
- box-sizing: border-box;
119
- } */
120
-
121
- :host([responsive-mode='mobile']) .logo-and-close {
122
- padding: 1em;
123
- }
124
- `,
125
- ];
126
- }
127
-
128
- constructor() {
129
- super();
130
-
131
- /** @type {Logo} */
132
- this.logo = { type: 'ing', alt: 'ING homepage', href: '/' };
133
- /** @type {MenuItem[]} */
134
- this.menuSupportItems = [];
135
- // /**
136
- // * @type {string[]}
137
- // * @description Choose which items to show on mobile when in default mode, maximum of two. Possible values: 'search', 'ctaPrimary', 'ctaSecondary', 'avatarMenu'
138
- // */
139
- // this.showOnMobile = [];
140
- /**
141
- * @type {CtaLink}
142
- */
143
- // @ts-ignore
144
- this.ctaPrimary = {};
145
- /**
146
- * @type {CtaLink}
147
- */
148
- // @ts-ignore
149
- this.ctaSecondary = {};
150
- /** @type {MenuItem[]} */
151
- this.menuItems = [];
152
- // /** @type {Boolean} */
153
- // this.searchDisabled = false;
154
- this.breakpointMin = 1400; // force desktop
155
- /** @type {string[]} */
156
- this.suggestions = [];
157
-
158
- this.prefilledSuggestion = '';
159
-
160
- // Assign styles as a property, so that subclasses can augment it
161
- // this.styles = styles;
162
- // this.menuOpened = false;
163
-
164
- const mql = window.matchMedia(`(width <= ${this.breakpointMin}px)`);
165
- /** @type {NavBarResponsiveMode} */
166
- this.responsiveMode = mql.matches ? 'mobile' : 'desktop';
167
- this._levelCfg = LionNavigationBar.#getLevelCfg(this.responsiveMode);
168
- this._levelSecondaryCfg = this.#getSecondaryLevelCfg();
169
-
170
- mql.addEventListener('change', () => {
171
- this.responsiveMode = mql.matches ? 'mobile' : 'desktop';
172
- this._levelCfg = LionNavigationBar.#getLevelCfg(this.responsiveMode);
173
- this._levelSecondaryCfg = this.#getSecondaryLevelCfg();
174
- });
175
-
176
- this.#storeLatestFocusedElementId();
177
- this.#delegateAnalyticsEvents();
178
- }
179
-
180
- #getSecondaryLevelCfg() {
181
- if (this.responsiveMode === 'mobile') {
182
- return {
183
- l1: {
184
- isBar: true,
185
- },
186
- l2: {
187
- isBar: false,
188
- },
189
- };
190
- }
191
-
192
- return {
193
- l1: {
194
- isBar: true,
195
- },
196
- l2: {
197
- isBar: false,
198
- },
199
- };
200
- }
201
-
202
- /** @type {string | null} */
203
- #latestFocusedElementId = null;
204
-
205
- #storeLatestFocusedElementId() {
206
- this.addEventListener('focusin', ({ target }) => {
207
- // @ts-ignore
208
- this.#latestFocusedElementId = target.id;
209
- });
210
- }
211
-
212
- #syncLatestFocusedElementForNewResponsiveMode() {
213
- // We might show/hide or rerender some elements (with same ids) in different positions in the DOM.
214
- // As these are physically different elements, we must move focus (as otherwise it would be reset to body)
215
- if (!this.#latestFocusedElementId) return;
216
- const newFocusedElement = this.shadowRoot?.querySelector(`#${this.#latestFocusedElementId}`);
217
- if (newFocusedElement instanceof HTMLElement) {
218
- newFocusedElement.focus();
219
- }
220
- }
221
-
222
- #delegateAnalyticsEvents() {
223
- this.addEventListener('click', ({ target }) => {
224
- if (!target || !(target instanceof HTMLElement)) return;
225
-
226
- // @ts-expect-error
227
- const isButton = target.tagName === 'BUTTON' || target.constructor._$isLionButton$;
228
- const isAnchor = target.tagName === 'A';
229
- if (!isButton && !isAnchor) return;
230
-
231
- if (!target.id) return;
232
-
233
- // TODO: do in extension layer
234
- this.dispatchEvent(
235
- new CustomEvent('nav-item-click', {
236
- // N.B. we can also retrive the item
237
- detail: {
238
- item: {
239
- id: target.id,
240
- label: target.textContent?.trim() || '',
241
- href: isAnchor ? target.getAttribute('href') : undefined,
242
- },
243
- },
244
- // bubbles: true,
245
- // composed: true,
246
- }),
247
- );
248
- });
249
- }
250
-
251
- /**
252
- * @param {NavBarResponsiveMode} responsiveMode
253
- */
254
- static #getLevelCfg(responsiveMode) {
255
- // N.B. we're fighting some of the overlay configs provided by LionMenuOverlay here,
256
- // the idea is to take over all of that when depending on LionMenu, after removing LonMenuOverlay and LionMenuHybrid components altogether.
257
-
258
- if (responsiveMode === 'mobile') {
259
- return {
260
- l1: {
261
- isBar: false,
262
- openableConfig: {
263
- // We want to do the absolute positioning ourselves, popper is not suited for this...
264
- placementMode: 'custom',
265
- isOpenable: false,
266
- hidesOnOutsideClick: false,
267
- inheritsReferenceWidth: 'none',
268
- },
269
- },
270
- l2: {
271
- openableConfig: {
272
- // We want disclosure behavior
273
- placementMode: 'custom',
274
- hidesOnOutsideClick: false,
275
- inheritsReferenceWidth: 'none',
276
- },
277
- },
278
- l3: {
279
- openableConfig: {
280
- // We want disclosure behavior
281
- placementMode: 'custom',
282
- hidesOnOutsideClick: false,
283
- inheritsReferenceWidth: 'none',
284
- },
285
- },
286
- };
287
- }
288
-
289
- return {
290
- l1: {
291
- isBar: true,
292
- hasFullWidthFlyout: true,
293
- openableConfig: {
294
- // We want disclosure behavior
295
- placementMode: 'custom',
296
- // N.B. we don't have an invoker...
297
- isOpenable: false,
298
- inheritsReferenceWidth: 'none',
299
- focusContentOnOpen: true,
300
- },
301
- },
302
- l2: {
303
- openableConfig: {
304
- // We want disclosure behavior
305
- placementMode: 'custom',
306
- hidesOnOutsideClick: true,
307
- hidesOnEscape: true,
308
- inheritsReferenceWidth: 'none',
309
- focusContentOnOpen: true,
310
- },
311
- },
312
- l3: {
313
- openableConfig: {
314
- // We want disclosure behavior
315
- placementMode: 'custom',
316
- inheritsReferenceWidth: 'none',
317
- focusContentOnOpen: true,
318
- // TODO: implement in OverlayController
319
- hideVisually: true,
320
- },
321
- },
322
- };
323
- }
324
-
325
- /**
326
- * @param {import('lit').PropertyValues} changedProperties
327
- */
328
- updated(changedProperties) {
329
- if (changedProperties.has('responsiveMode')) {
330
- this._levelCfg = LionNavigationBar.#getLevelCfg(this.responsiveMode);
331
- this.#syncLatestFocusedElementForNewResponsiveMode();
332
- }
333
- }
334
-
335
- render() {
336
- return html`
337
- <nav>
338
- <div class="nav-header">
339
- <div class="logo-and-close">
340
- <a href="${this.logo.href || '#'}">
341
- <img src="${this.logo.src || ''}" alt="${this.logo.alt || ''}" />
342
- </a>
343
- ${this.responsiveMode === 'mobile'
344
- ? html`<button data-close data-level="1">✖️</button>`
345
- : ''}
346
- </div>
347
- ${LionNavigationBar._searchTemplate(this.suggestions, this.prefilledSuggestion)}
348
- </div>
349
- <div class="nav-body">
350
- ${this._menulevelTemplate(this.menuSupportItems, 1, this._levelSecondaryCfg.l1, '')}
351
- ${this.responsiveMode === 'desktop'
352
- ? LionNavigationBar._ctaTemplate(this.ctaPrimary, this.ctaSecondary)
353
- : ''}
354
- ${this._menulevelTemplate(this.menuItems, 1, this._levelCfg.l1, '')}
355
- </div>
356
- ${this.responsiveMode === 'mobile'
357
- ? html`<div class="nav-footer">
358
- ${LionNavigationBar._ctaTemplate(this.ctaPrimary, this.ctaSecondary)}
359
- </div>`
360
- : ''}
361
- </nav>
362
- `;
363
- }
364
-
365
- /**
366
- * @param {string[]} suggestions
367
- * @returns {import('lit').TemplateResult}
368
- */
369
- static _searchTemplate(suggestions, prefilledSuggestion = '') {
370
- return html` <form role="search">
371
- <input
372
- type="search"
373
- list="search-list"
374
- placeholder="What are you looking for?"
375
- .value="${prefilledSuggestion}"
376
- />
377
- <datalist id="search-list">
378
- ${suggestions.map(suggestion => html`<option value="${suggestion}"></option>`)}
379
- </datalist>
380
- <input type="submit" value="Search" />
381
- </form>`;
382
- }
383
-
384
- /**
385
- * @param {CtaLink} ctaPrimary
386
- * @param {CtaLink} ctaSecondary
387
- * @returns {import('lit').TemplateResult}
388
- */
389
- static _ctaTemplate(ctaPrimary, ctaSecondary) {
390
- return html`<div class="cta-items">
391
- ${ctaSecondary?.href
392
- ? html`<div class="cta-secondary">
393
- <a id="${ctaSecondary.id}" href="${ctaSecondary.href}">${ctaSecondary.label} </a>
394
- </div>`
395
- : ''}
396
- ${ctaPrimary?.href
397
- ? html`<div class="cta-primary">
398
- <a id="${ctaPrimary.id}" href="${ctaPrimary.href}">${ctaPrimary.label} </a>
399
- </div>`
400
- : ''}
401
- </div>`;
402
- }
403
-
404
- /**
405
- * @param {MenuItem[]} menuItemsForLevel
406
- * @param {number} level
407
- * @param {LevelConfig} cfgForLevel
408
- * @returns {import('lit').TemplateResult}
409
- */
410
- _menulevelTemplate(menuItemsForLevel, level, cfgForLevel, prevText = '') {
411
- // @ts-ignore
412
- const cfgForNextLevel = this._levelCfg[`l${level + 1}`];
413
-
414
- const getId = (/** @type {import("./types.js").MenuItem} */ menuItem) =>
415
- menuItem.id || `l${level}-${menuItem.title}`;
416
-
417
- return html`<lion-menu-hybrid
418
- .config="${cfgForLevel.openableConfig || {}}"
419
- .bar="${cfgForLevel.isBar}"
420
- ?data-has-full-width-flyout="${cfgForLevel.hasFullWidthFlyout}"
421
- ._activeMode="${'tabbable-disclosure'}"
422
- >
423
- ${level > 1 && this.responsiveMode === 'mobile'
424
- ? html` <div role="listitem">
425
- <button data-close data-level="${level}">&lt; ${prevText}</button>
426
- </div>`
427
- : ''}
428
- ${menuItemsForLevel.map(
429
- menuItem => html`
430
- <div role="listitem">
431
- ${menuItem.sub
432
- ? html` <button id="${getId(menuItem)}" data-invoker>${menuItem.title}</button>
433
- ${menuItem.sub
434
- ? this._menulevelTemplate(
435
- menuItem.sub,
436
- level + 1,
437
- cfgForNextLevel,
438
- menuItem.title,
439
- )
440
- : ''}`
441
- : html` <a id="${getId(menuItem)}" href="${menuItem.link || ''}"
442
- >${menuItem.title}</a
443
- >`}
444
- </div>
445
- `,
446
- )}
447
- </lion-menu-hybrid>`;
448
- }
449
- }